diff --git a/app/Repositories/UserGroups/Account/AccountRepository.php b/app/Repositories/UserGroups/Account/AccountRepository.php index 2da67f1629..8e69ddef29 100644 --- a/app/Repositories/UserGroups/Account/AccountRepository.php +++ b/app/Repositories/UserGroups/Account/AccountRepository.php @@ -251,6 +251,7 @@ class AccountRepository implements AccountRepositoryInterface // process filters // TODO this should be repeatable, it feels like a hack when you do it here. + // TODO some fields cannot be filtered using the query, and a second filter must be applied on the collection. foreach($filters as $column => $value) { // filter on NULL values if(null === $value) { @@ -259,6 +260,9 @@ class AccountRepository implements AccountRepositoryInterface if ('active' === $column) { $query->where('accounts.active', $value); } + if('name' === $column) { + $query->where('accounts.name', 'LIKE', sprintf('%%%s%%', $value)); + } } diff --git a/app/Support/Request/GetFilterInstructions.php b/app/Support/Request/GetFilterInstructions.php index fc432bbe89..7d1b5ca7de 100644 --- a/app/Support/Request/GetFilterInstructions.php +++ b/app/Support/Request/GetFilterInstructions.php @@ -50,6 +50,8 @@ trait GetFilterInstructions case 'boolean': $filterValue = $this->booleanInstruction($filterValue); break; + case 'string': + break; } $result[$column] = $filterValue; } diff --git a/app/Transformers/V2/AccountTransformer.php b/app/Transformers/V2/AccountTransformer.php index bd68755b33..fbe210ebd0 100644 --- a/app/Transformers/V2/AccountTransformer.php +++ b/app/Transformers/V2/AccountTransformer.php @@ -41,6 +41,7 @@ class AccountTransformer extends AbstractTransformer { private array $accountMeta; private array $accountTypes; + private array $fullTypes; private array $balanceDifferences; private array $convertedBalances; private array $currencies; @@ -55,6 +56,7 @@ class AccountTransformer extends AbstractTransformer $this->currencies = []; $this->accountMeta = []; $this->accountTypes = []; + $this->fullTypes = []; $this->lastActivity = []; $this->convertedBalances = []; $this->balanceDifferences = []; @@ -74,7 +76,7 @@ class AccountTransformer extends AbstractTransformer // get last activity: $this->getLastActivity($objects); - // TODO add balance difference + // add balance difference if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { $this->getBalanceDifference($objects, $this->parameters->get('start'), $this->parameters->get('end')); } @@ -97,21 +99,28 @@ class AccountTransformer extends AbstractTransformer */ public function transform(Account $account): array { - $id = $account->id; + $id = $account->id; // various meta - $accountRole = $this->accountMeta[$id]['account_role'] ?? null; - $accountType = $this->accountTypes[$id]; - $order = $account->order; + $accountRole = $this->accountMeta[$id]['account_role'] ?? null; + $accountType = $this->accountTypes[$id]; + $order = $account->order; + + // liability type + $liabilityType = $accountType === 'liabilities' ? $this->fullTypes[$id] : null; + $liabilityDirection = $this->accountMeta[$id]['liability_direction'] ?? null; + $interest = $this->accountMeta[$id]['interest'] ?? null; + $interestPeriod = $this->accountMeta[$id]['interest_period'] ?? null; + $currentDebt = $this->accountMeta[$id]['current_debt'] ?? null; // no currency? use default - $currency = $this->default; + $currency = $this->default; if (array_key_exists($id, $this->accountMeta) && 0 !== (int) ($this->accountMeta[$id]['currency_id'] ?? 0)) { $currency = $this->currencies[(int) $this->accountMeta[$id]['currency_id']]; } // amounts and calculation. - $balance = $this->balances[$id]['balance'] ?? null; - $nativeBalance = $this->convertedBalances[$id]['native_balance'] ?? null; + $balance = $this->balances[$id]['balance'] ?? null; + $nativeBalance = $this->convertedBalances[$id]['native_balance'] ?? null; // no order for some accounts: if (!in_array(strtolower($accountType), ['liability', 'liabilities', 'asset'], true)) { @@ -131,20 +140,20 @@ class AccountTransformer extends AbstractTransformer } return [ - 'id' => (string) $account->id, - 'created_at' => $account->created_at->toAtomString(), - 'updated_at' => $account->updated_at->toAtomString(), - 'active' => $account->active, - 'order' => $order, - 'name' => $account->name, - 'iban' => '' === (string) $account->iban ? null : $account->iban, - 'account_number' => $this->accountMeta[$id]['account_number'] ?? null, - 'type' => strtolower($accountType), - 'account_role' => $accountRole, - 'currency_id' => (string) $currency->id, - 'currency_code' => $currency->code, - 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => $currency->decimal_places, + 'id' => (string) $account->id, + 'created_at' => $account->created_at->toAtomString(), + 'updated_at' => $account->updated_at->toAtomString(), + 'active' => $account->active, + 'order' => $order, + 'name' => $account->name, + 'iban' => '' === (string) $account->iban ? null : $account->iban, + 'account_number' => $this->accountMeta[$id]['account_number'] ?? null, + 'type' => strtolower($accountType), + 'account_role' => $accountRole, + 'currency_id' => (string) $currency->id, + 'currency_code' => $currency->code, + 'currency_symbol' => $currency->symbol, + 'currency_decimal_places' => $currency->decimal_places, 'native_currency_id' => (string) $this->default->id, 'native_currency_code' => $this->default->code, @@ -165,19 +174,20 @@ class AccountTransformer extends AbstractTransformer // more meta 'last_activity' => array_key_exists($id, $this->lastActivity) ? $this->lastActivity[$id]->toAtomString() : null, + // liability stuff + 'liability_type' => $liabilityType, + 'liability_direction' => $liabilityDirection, + 'interest' => $interest, + 'interest_period' => $interestPeriod, + 'current_debt' => $currentDebt, + // 'notes' => $this->repository->getNoteText($account), // 'monthly_payment_date' => $monthlyPaymentDate, // 'credit_card_type' => $creditCardType, - // 'account_number' => $this->repository->getMetaValue($account, 'account_number'), // 'bic' => $this->repository->getMetaValue($account, 'BIC'), // 'virtual_balance' => number_format((float) $account->virtual_balance, $decimalPlaces, '.', ''), // 'opening_balance' => $openingBalance, // 'opening_balance_date' => $openingBalanceDate, - // 'liability_type' => $liabilityType, - // 'liability_direction' => $liabilityDirection, - // 'interest' => $interest, - // 'interest_period' => $interestPeriod, - // 'current_debt' => $this->repository->getMetaValue($account, 'current_debt'), // 'include_net_worth' => $includeNetWorth, // 'longitude' => $longitude, // 'latitude' => $latitude, @@ -185,7 +195,7 @@ class AccountTransformer extends AbstractTransformer 'links' => [ [ 'rel' => 'self', - 'uri' => '/accounts/'.$account->id, + 'uri' => '/accounts/' . $account->id, ], ], ]; @@ -208,14 +218,14 @@ class AccountTransformer extends AbstractTransformer private function collectAccountMetaData(Collection $accounts): void { /** @var CurrencyRepositoryInterface $repository */ - $repository = app(CurrencyRepositoryInterface::class); + $repository = app(CurrencyRepositoryInterface::class); /** @var AccountRepositoryInterface $accountRepository */ $accountRepository = app(AccountRepositoryInterface::class); - $metaFields = $accountRepository->getMetaValues($accounts, ['currency_id', 'account_role', 'account_number']); + $metaFields = $accountRepository->getMetaValues($accounts, ['currency_id', 'account_role', 'account_number', 'liability_direction', 'interest', 'interest_period', 'current_debt']); $currencyIds = $metaFields->where('name', 'currency_id')->pluck('data')->toArray(); - $currencies = $repository->getByIds($currencyIds); + $currencies = $repository->getByIds($currencyIds); foreach ($currencies as $currency) { $id = $currency->id; $this->currencies[$id] = $currency; @@ -235,6 +245,7 @@ class AccountTransformer extends AbstractTransformer /** @var AccountType $row */ foreach ($accountTypes as $row) { $this->accountTypes[$row->id] = (string) config(sprintf('firefly.shortNamesByFullName.%s', $row->type)); + $this->fullTypes[$row->id] = $row->type; } } @@ -275,6 +286,9 @@ class AccountTransformer extends AbstractTransformer if ('balance_difference' === $column) { $accounts = $this->sortByBalanceDifference($accounts, $direction); } + if ('current_debt' === $column) { + $accounts = $this->sortByCurrentDebt($accounts, $direction); + } } return $accounts; @@ -365,4 +379,19 @@ class AccountTransformer extends AbstractTransformer return $rightBalance <=> $leftBalance; }); } + + private function sortByCurrentDebt(Collection $accounts, string $direction): Collection + { + $amounts = $this->accountMeta; + + return $accounts->sort(function (Account $left, Account $right) use ($amounts, $direction) { + $leftCurrent = (float) ($amounts[$left->id]['current_debt'] ?? 0); + $rightCurrent = (float) ($amounts[$right->id]['current_debt'] ?? 0); + if ('asc' === $direction) { + return $leftCurrent <=> $rightCurrent; + } + + return $rightCurrent <=> $leftCurrent; + }); + } } diff --git a/config/firefly.php b/config/firefly.php index e2bd27b962..260eec67c3 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -924,7 +924,7 @@ return [ 'filters' => [ 'allowed' => [ 'accounts' => [ - 'name' => '*', + 'name' => 'string', 'active' => 'boolean', 'iban' => 'iban', 'balance' => 'numeric', @@ -938,7 +938,7 @@ return [ 'sorting' => [ 'allowed' => [ 'transactions' => ['description', 'amount'], - 'accounts' => ['name', 'active', 'iban', 'balance', 'last_activity', 'balance_difference'], + 'accounts' => ['name', 'active', 'iban', 'balance', 'last_activity', 'balance_difference','current_debt'], ], ], ]; diff --git a/config/translations.php b/config/translations.php index f8706a0ea7..68f48e52b2 100644 --- a/config/translations.php +++ b/config/translations.php @@ -52,6 +52,15 @@ return [ 'bad_type_destination', ], 'firefly' => [ + 'liability_direction_debit_short', + 'liability_direction_credit_short', + 'interest_calc_yearly', + 'interest_calc_', + 'interest_calc_daily', + 'interest_calc_monthly', + 'interest_calc_weekly', + 'interest_calc_half-year', + 'interest_calc_quarterly', 'spent', 'administration_owner', 'administration_you', diff --git a/resources/assets/v2/src/boot/bootstrap.js b/resources/assets/v2/src/boot/bootstrap.js index b9a9432ec5..7ed690b6de 100644 --- a/resources/assets/v2/src/boot/bootstrap.js +++ b/resources/assets/v2/src/boot/bootstrap.js @@ -43,6 +43,7 @@ store.addPlugin(observePlugin); window.bootstrapped = false; window.store = store; +window.bootstrap = bootstrap; diff --git a/resources/assets/v2/src/pages/accounts/index.js b/resources/assets/v2/src/pages/accounts/index.js index dfa7dd42f5..3c925c1576 100644 --- a/resources/assets/v2/src/pages/accounts/index.js +++ b/resources/assets/v2/src/pages/accounts/index.js @@ -32,7 +32,6 @@ import {showWizardButton} from "../../support/page-settings/show-wizard-button.j import {setVariable} from "../../store/set-variable.js"; import {getVariables} from "../../store/get-variables.js"; import pageNavigation from "../../support/page-navigation.js"; -import {getCacheKey} from "../../support/get-cache-key.js"; // set type from URL @@ -144,10 +143,36 @@ let index = function () { }, editors: {}, accounts: [], + lastClickedFilter: '', + lastFilterInput: '', goToPage(page) { this.page = page; this.loadAccounts(); }, + applyFilter() { + this.filters[this.lastClickedFilter] = this.lastFilterInput; + this.page = 1; + setVariable(this.getPreferenceKey('filters'), this.filters); + + // hide modal + window.bootstrap.Modal.getInstance(document.getElementById('filterModal')).hide(); + this.loadAccounts(); + + }, + removeFilter(field) { + this.filters[field] = null; + this.page = 1; + setVariable(this.getPreferenceKey('filters'), this.filters); + this.loadAccounts(); + }, + hasFilters() { + return this.filters.name !== null; + }, + showFilterDialog(field) { + this.lastFilterInput = this.filters[field] ?? ''; + this.lastClickedFilter = field; + document.getElementById('filterInput').focus(); + }, accountRole(roleName) { return i18next.t('firefly.account_role_' + roleName); }, @@ -159,7 +184,7 @@ let index = function () { }, sort(column) { - this.page =1; + this.page = 1; this.pageOptions.sortingColumn = column; this.pageOptions.sortDirection = this.pageOptions.sortDirection === 'asc' ? 'desc' : 'asc'; @@ -179,7 +204,7 @@ let index = function () { }, generatePageUrl(includePageNr) { let url = './accounts/' + type + '?column=' + this.pageOptions.sortingColumn + '&direction=' + this.pageOptions.sortDirection + '&page='; - if(includePageNr) { + if (includePageNr) { return url + this.page } return url; @@ -204,6 +229,15 @@ let index = function () { }, init() { + // modal filter thing + const myModalEl = document.getElementById('filterModal') + myModalEl.addEventListener('shown.bs.modal', event => { + document.getElementById('filterInput').focus(); + }) + + + + // some opts this.pageOptions.isLoading = true; this.notifications.wait.show = true; this.page = page; @@ -230,7 +264,7 @@ let index = function () { this.pageOptions.sortDirection = '' === this.pageOptions.sortDirection ? res[2] : this.pageOptions.sortDirection; // filters - for(let k in res[3]) { + for (let k in res[3]) { if (res[3].hasOwnProperty(k) && this.filters.hasOwnProperty(k)) { this.filters[k] = res[3][k]; } @@ -241,13 +275,13 @@ let index = function () { }, saveActiveFilter(e) { this.page = 1; - if('both' === e.currentTarget.value) { + if ('both' === e.currentTarget.value) { this.filters.active = null; } - if('active' === e.currentTarget.value) { + if ('active' === e.currentTarget.value) { this.filters.active = true; } - if('inactive' === e.currentTarget.value) { + if ('inactive' === e.currentTarget.value) { this.filters.active = false; } setVariable(this.getPreferenceKey('filters'), this.filters); @@ -301,8 +335,8 @@ let index = function () { // filter instructions let filters = []; - for(let k in this.filters) { - if(this.filters.hasOwnProperty(k) && null !== this.filters[k]) { + for (let k in this.filters) { + if (this.filters.hasOwnProperty(k) && null !== this.filters[k]) { filters.push({column: k, filter: this.filters[k]}); } } @@ -351,7 +385,12 @@ let index = function () { native_currency_code: current.attributes.native_currency_code, last_activity: null === current.attributes.last_activity ? '' : format(new Date(current.attributes.last_activity), i18next.t('config.month_and_day_fns')), balance_difference: current.attributes.balance_difference, - native_balance_difference: current.attributes.native_balance_difference + native_balance_difference: current.attributes.native_balance_difference, + liability_type: current.attributes.liability_type, + liability_direction: current.attributes.liability_direction, + interest: current.attributes.interest, + interest_period: current.attributes.interest_period, + current_debt: current.attributes.current_debt, }; this.accounts.push(account); } diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 9fb1d992c0..c329e81f9b 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -2327,6 +2327,15 @@ return [ 'no_tags' => '(no tags)', 'nothing_found' => '(nothing found)', + // page settings and wizard dialogs + + 'page_settings_header' => 'Page settings', + 'visible_columns' => 'Visible columns', + 'accounts_to_show' => 'Accounts to show', + 'active_accounts_only' => 'Active accounts only', + 'in_active_accounts_only' => 'Inactive accounts only', + 'show_all_accounts' => 'Show all accounts', + // piggy banks: 'event_history' => 'Event history', 'add_money_to_piggy' => 'Add money to piggy bank ":name"', diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index 6fd9115e2d..b3590f715a 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -28,6 +28,7 @@ return [ // new user: 'bank_name' => 'Bank name', 'bank_balance' => 'Balance', + 'current_balance' => 'Current balance', 'savings_balance' => 'Savings balance', 'credit_card_limit' => 'Credit card limit', 'automatch' => 'Match automatically', diff --git a/resources/views/v2/accounts/index.blade.php b/resources/views/v2/accounts/index.blade.php index 55337ebb70..9ef64c775e 100644 --- a/resources/views/v2/accounts/index.blade.php +++ b/resources/views/v2/accounts/index.blade.php @@ -7,30 +7,30 @@
- "Filtered" + "" + | @@ -95,60 +96,69 @@ | - Active? + {{ __('list.active') }} | - Name + {{ __('list.name') }} - + + + | -Type | +{{ __('list.type') }} | - Liability type + {{ __('list.liability_type') }} | - Liability direction + {{ __('list.liability_direction') }} | - Liability interest + {{ __('list.interest') }} | - Account number + + {{ __('list.account_number') }} + | - Current balance + + {{ __('list.current_balance') }} + | - Amount due - + {{ __('list.amount_due') }} + + - | - Last activity + + {{ __('list.last_activity') }} + |
- Balance
- difference
+
+ {{ __('list.balance_difference') }}
"
-
- |
- |
+ |
+
+ |
+
+
+ |
+
+ %
+ ()
+ |
@@ -245,7 +262,10 @@
x-text="formatMoney(account.native_current_balance, account.currency_code)">
|
- TODO
+
+
+
|
@@ -304,12 +324,12 @@
| |
---|