From 07cfba1b3ad7559fcb784b3d9e806e25cddd945d Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 25 Aug 2018 21:33:22 +0200 Subject: [PATCH] Add the ability to make transfers to and from liability accounts. --- app/Factory/TransactionFactory.php | 34 +++++++++++++++---- app/Http/Controllers/JavascriptController.php | 2 +- .../Account/AccountRepository.php | 2 +- app/Support/ExpandedForm.php | 24 ++++++++++--- resources/lang/en_US/firefly.php | 6 +++- resources/lang/en_US/form.php | 4 +-- resources/views/errors/FireflyException.twig | 14 +++++++- .../views/transactions/single/create.twig | 2 +- 8 files changed, 69 insertions(+), 19 deletions(-) diff --git a/app/Factory/TransactionFactory.php b/app/Factory/TransactionFactory.php index 57fb616b4b..26a8f454fe 100644 --- a/app/Factory/TransactionFactory.php +++ b/app/Factory/TransactionFactory.php @@ -121,13 +121,9 @@ class TransactionFactory } Log::debug(sprintf('Source type is "%s", destination type is "%s"', $sourceAccount->accountType->type, $destinationAccount->accountType->type)); - // throw big fat error when source type === dest type and it's not a transfer or reconciliation. - if ($sourceAccount->accountType->type === $destinationAccount->accountType->type && $journal->transactionType->type !== TransactionType::TRANSFER) { - throw new FireflyException(sprintf('Source and destination account cannot be both of the type "%s"', $destinationAccount->accountType->type)); - } - if ($sourceAccount->accountType->type !== AccountType::ASSET && $destinationAccount->accountType->type !== AccountType::ASSET) { - throw new FireflyException('At least one of the accounts must be an asset account.'); - } + + // based on the source type, destination type and transaction type, the system can start throwing FireflyExceptions. + $this->validateTransaction($sourceAccount->accountType->type, $destinationAccount->accountType->type, $journal->transactionType->type); $source = $this->create( [ @@ -194,5 +190,29 @@ class TransactionFactory $this->user = $user; } + /** + * @param string $sourceType + * @param string $destinationType + * @param string $transactionType + * + * @throws FireflyException + */ + private function validateTransaction(string $sourceType, string $destinationType, string $transactionType): void + { + // throw big fat error when source type === dest type and it's not a transfer or reconciliation. + if ($sourceType === $destinationType && $transactionType !== TransactionType::TRANSFER) { + throw new FireflyException(sprintf('Source and destination account cannot be both of the type "%s"', $destinationType)); + } + // source must be in this list AND dest must be in this list: + $list = [AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT, AccountType::MORTGAGE, AccountType::LOAN, AccountType::MORTGAGE]; + if ( + !\in_array($sourceType, $list, true) && + !\in_array($destinationType, $list, true)) { + throw new FireflyException(sprintf('At least one of the accounts must be an asset account (%s, %s).', $sourceType, $destinationType)); + } + // either of these must be asset or default account. + + } + } diff --git a/app/Http/Controllers/JavascriptController.php b/app/Http/Controllers/JavascriptController.php index faf5a7872a..d5527846a6 100644 --- a/app/Http/Controllers/JavascriptController.php +++ b/app/Http/Controllers/JavascriptController.php @@ -48,7 +48,7 @@ class JavascriptController extends Controller */ public function accounts(AccountRepositoryInterface $repository, CurrencyRepositoryInterface $currencyRepository): Response { - $accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]); + $accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT,AccountType::LOAN,AccountType::MORTGAGE, AccountType::CREDITCARD]); $preference = app('preferences')->get('currencyPreference', config('firefly.default_currency', 'EUR')); /** @noinspection NullPointerExceptionInspection */ $default = $currencyRepository->findByCodeNull($preference->data); diff --git a/app/Repositories/Account/AccountRepository.php b/app/Repositories/Account/AccountRepository.php index 12d57fd97b..d70c7d665a 100644 --- a/app/Repositories/Account/AccountRepository.php +++ b/app/Repositories/Account/AccountRepository.php @@ -247,7 +247,7 @@ class AccountRepository implements AccountRepositoryInterface $result = $query->get(['accounts.*']); $result = $result->sortBy( function (Account $account) { - return strtolower($account->name); + return sprintf('%02d', $account->account_type_id) . strtolower($account->name); } ); diff --git a/app/Support/ExpandedForm.php b/app/Support/ExpandedForm.php index 08709f9661..79d4fd557c 100644 --- a/app/Support/ExpandedForm.php +++ b/app/Support/ExpandedForm.php @@ -66,19 +66,27 @@ class ExpandedForm /** @var CurrencyRepositoryInterface $currencyRepos */ $currencyRepos = app(CurrencyRepositoryInterface::class); - $assetAccounts = $repository->getActiveAccountsByType([AccountType::ASSET, AccountType::DEFAULT]); + $accountList = $repository->getActiveAccountsByType( + [AccountType::ASSET, AccountType::DEFAULT, AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,] + ); + $liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN]; $defaultCurrency = app('amount')->getDefaultCurrency(); $grouped = []; // group accounts: /** @var Account $account */ - foreach ($assetAccounts as $account) { + foreach ($accountList as $account) { $balance = app('steam')->balance($account, new Carbon); $currencyId = (int)$repository->getMetaValue($account, 'currency_id'); $currency = $currencyRepos->findNull($currencyId); $role = $repository->getMetaValue($account, 'accountRole'); - if ('' === $role) { + if ('' === $role && !\in_array($account->accountType->type, $liabilityTypes, true)) { $role = 'no_account_type'; // @codeCoverageIgnore } + + if (\in_array($account->accountType->type, $liabilityTypes, true)) { + $role = 'l_' . $account->accountType->type; // @codeCoverageIgnore + } + if (null === $currency) { $currency = $defaultCurrency; } @@ -192,12 +200,13 @@ class ExpandedForm /** @var CurrencyRepositoryInterface $currencyRepos */ $currencyRepos = app(CurrencyRepositoryInterface::class); - $assetAccounts = $repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]); + $accountList = $repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT, AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,]); + $liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN]; $defaultCurrency = app('amount')->getDefaultCurrency(); $grouped = []; // group accounts: /** @var Account $account */ - foreach ($assetAccounts as $account) { + foreach ($accountList as $account) { $balance = app('steam')->balance($account, new Carbon); $currencyId = (int)$repository->getMetaValue($account, 'currency_id'); $currency = $currencyRepos->findNull($currencyId); @@ -205,6 +214,11 @@ class ExpandedForm if ('' === $role) { $role = 'no_account_type'; // @codeCoverageIgnore } + + if (\in_array($account->accountType->type, $liabilityTypes, true)) { + $role = 'l_' . $account->accountType->type; // @codeCoverageIgnore + } + if (null === $currency) { $currency = $defaultCurrency; } diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index b3ff588e14..ad4002464f 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -593,7 +593,6 @@ return [ 'invalid_convert_selection' => 'The account you have selected is already used in this transaction or does not exist.', 'source_or_dest_invalid' => 'Cannot find the correct transaction details. Conversion is not possible.', - // create new stuff: 'create_new_withdrawal' => 'Create new withdrawal', 'create_new_deposit' => 'Create new deposit', @@ -816,12 +815,17 @@ return [ 'perm-delete-many' => 'Deleting many items in one go can be very disruptive. Please be cautious.', 'mass_deleted_transactions_success' => 'Deleted :amount transaction(s).', 'mass_edited_transactions_success' => 'Updated :amount transaction(s)', + 'opt_group_' => '(no account type)', 'opt_group_no_account_type' => '(no account type)', 'opt_group_defaultAsset' => 'Default asset accounts', 'opt_group_savingAsset' => 'Savings accounts', 'opt_group_sharedAsset' => 'Shared asset accounts', 'opt_group_ccAsset' => 'Credit cards', 'opt_group_cashWalletAsset' => 'Cash wallets', + 'opt_group_l_Loan' => 'Liability: Loan', + 'opt_group_l_Debt' => 'Liability: Debt', + 'opt_group_l_Mortgage' => 'Liability: Mortgage', + 'opt_group_l_Credit card' => 'Liability: Credit card', 'notes' => 'Notes', 'unknown_journal_error' => 'Could not store the transaction. Please check the log files.', diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index 2007f077a9..e797e2cdbc 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -50,8 +50,8 @@ return [ 'source_account' => 'Source account', 'destination_account' => 'Destination account', 'journal_destination_id' => 'Asset account (destination)', - 'asset_destination_account' => 'Asset account (destination)', - 'asset_source_account' => 'Asset account (source)', + 'asset_destination_account' => 'Destination account', + 'asset_source_account' => 'Source account', 'journal_description' => 'Description', 'note' => 'Notes', 'split_journal' => 'Split this transaction', diff --git a/resources/views/errors/FireflyException.twig b/resources/views/errors/FireflyException.twig index 19bfb45cc9..d3d7eb0c7b 100644 --- a/resources/views/errors/FireflyException.twig +++ b/resources/views/errors/FireflyException.twig @@ -7,8 +7,20 @@ - + + {# CSS things #} + + {# libraries #} + + + + + + {# the theme #} + + + {# Firefly III customisations #} {# favicons #} diff --git a/resources/views/transactions/single/create.twig b/resources/views/transactions/single/create.twig index fdb718ca40..e12b777faa 100644 --- a/resources/views/transactions/single/create.twig +++ b/resources/views/transactions/single/create.twig @@ -33,7 +33,7 @@ {{ ExpandedForm.text('description') }} {# SELECTABLE SOURCE ACCOUNT ONLY FOR WITHDRAWALS AND TRANSFERS #} - {{ ExpandedForm.activeAssetAccountList('source_id', null, {label: trans('form.asset_source_account')}) }} + {{ ExpandedForm.activeAssetAccountList('source_id', null, {label: trans('form.asset_source_account') }) }} {# FREE FORMAT SOURCE ACCOUNT ONLY FOR DEPOSITS #} {{ ExpandedForm.text('source_name', null, {label: trans('form.revenue_account')}) }}