From cd076cc069b7c6f703a9afc091abc23cca8435f1 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Jul 2018 08:33:13 +0200 Subject: [PATCH 01/86] Fix a bug where transfers would be stored reversed (ie. source and destination switched). --- app/Factory/TransactionJournalFactory.php | 2 +- .../Import/Placeholder/ImportTransaction.php | 13 +++++++------ .../Routine/File/ImportableConverter.php | 18 ++++-------------- config/csv.php | 13 +++++++++++++ resources/lang/en_US/import.php | 1 + resources/lang/en_US/list.php | 1 + resources/views/transactions/show.twig | 2 +- 7 files changed, 28 insertions(+), 22 deletions(-) diff --git a/app/Factory/TransactionJournalFactory.php b/app/Factory/TransactionJournalFactory.php index 42061110f8..9096d8099d 100644 --- a/app/Factory/TransactionJournalFactory.php +++ b/app/Factory/TransactionJournalFactory.php @@ -104,7 +104,7 @@ class TransactionJournalFactory // store date meta fields (if present): $fields = ['sepa-cc', 'sepa-ct-op', 'sepa-ct-id', 'sepa-db', 'sepa-country', 'sepa-ep', 'sepa-ci', 'interest_date', 'book_date', 'process_date', 'due_date', 'recurrence_id', 'payment_date', 'invoice_date', 'internal_reference', 'bunq_payment_id', 'importHash', 'importHashV2', - 'external_id']; + 'external_id','sepa-batch-id']; foreach ($fields as $field) { $this->storeMeta($journal, $data, $field); diff --git a/app/Support/Import/Placeholder/ImportTransaction.php b/app/Support/Import/Placeholder/ImportTransaction.php index ccc64a7a57..4d070a3393 100644 --- a/app/Support/Import/Placeholder/ImportTransaction.php +++ b/app/Support/Import/Placeholder/ImportTransaction.php @@ -203,13 +203,14 @@ class ImportTransaction case 'external-id': $this->externalId = $columnValue->getValue(); break; - case 'sepa-ct-id'; - case 'sepa-ct-op'; - case 'sepa-db'; + case 'sepa-ct-id': + case 'sepa-ct-op': + case 'sepa-db': case 'sepa-cc': - case 'sepa-country'; - case 'sepa-ep'; - case 'sepa-ci'; + case 'sepa-country': + case 'sepa-batch-id': + case 'sepa-ep': + case 'sepa-ci': case 'internal-reference': case 'date-interest': case 'date-invoice': diff --git a/app/Support/Import/Routine/File/ImportableConverter.php b/app/Support/Import/Routine/File/ImportableConverter.php index 00cc33d789..42ab262aa3 100644 --- a/app/Support/Import/Routine/File/ImportableConverter.php +++ b/app/Support/Import/Routine/File/ImportableConverter.php @@ -183,8 +183,8 @@ class ImportableConverter $transactionType = 'transfer'; } - // amount is positive and its not a transfer? Then switch: - if ($transactionType !== 'transfer' && bccomp($amount, '0') === 1) { + // amount is positive? Then switch: + if (1 === bccomp($amount, '0')) { [$destination, $source] = [$source, $destination]; Log::debug( @@ -194,17 +194,6 @@ class ImportableConverter ) ); } - // amount is negative and type is transfer? then switch. - if ($transactionType === 'transfer' && bccomp($amount, '0') === -1) { - // amount is positive? Then switch: - [$destination, $source] = [$source, $destination]; - Log::debug( - sprintf( - '%s is negative, so "%s" (#%d) is now source and "%s" (#%d) is now destination.', - $amount, $source->name, $source->id, $destination->name, $destination->id - ) - ); - } // get currency preference from source asset account (preferred) // or destination asset account @@ -273,9 +262,10 @@ class ImportableConverter 'sepa-ct-op' => $importable->meta['sepa-ct-op'] ?? null, 'sepa-ct-id' => $importable->meta['sepa-ct-id'] ?? null, 'sepa-db' => $importable->meta['sepa-db'] ?? null, - 'sepa-country' => $importable->meta['sepa-countru'] ?? null, + 'sepa-country' => $importable->meta['sepa-country'] ?? null, 'sepa-ep' => $importable->meta['sepa-ep'] ?? null, 'sepa-ci' => $importable->meta['sepa-ci'] ?? null, + 'sepa-batch-id' => $importable->meta['sepa-batch-id'] ?? null, 'interest_date' => $this->convertDateValue($importable->meta['date-interest'] ?? null), 'book_date' => $this->convertDateValue($importable->meta['date-book'] ?? null), 'process_date' => $this->convertDateValue($importable->meta['date-process'] ?? null), diff --git a/config/csv.php b/config/csv.php index 4af268d126..3e1d1a9d10 100644 --- a/config/csv.php +++ b/config/csv.php @@ -283,6 +283,12 @@ return [ 'converter' => 'AssetAccountNumber', 'mapper' => 'AssetAccounts', ], + 'account-bic' => [ + 'mappable' => false, + 'pre-process-map' => false, + 'field' => 'asset-account-bic', + 'converter' => 'AccountBic', + ], 'opposing-id' => [ 'mappable' => true, 'pre-process-map' => false, @@ -391,6 +397,13 @@ return [ 'converter' => 'Description', 'field' => 'sepa_ci', ], + // SEPA Batch ID + 'sepa-batch-id' => [ + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'Description', + 'field' => 'sepa_batch', + ], // Internal reference 'internal-reference' => [ 'mappable' => false, diff --git a/resources/lang/en_US/import.php b/resources/lang/en_US/import.php index 824704689e..f6b93c10eb 100644 --- a/resources/lang/en_US/import.php +++ b/resources/lang/en_US/import.php @@ -219,6 +219,7 @@ return [ 'column_account-iban' => 'Asset account (IBAN)', 'column_account-id' => 'Asset account ID (matching FF3)', 'column_account-name' => 'Asset account (name)', + 'column_account-bic' => 'Asset account (BIC)', 'column_amount' => 'Amount', 'column_amount_foreign' => 'Amount (in foreign currency)', 'column_amount_debit' => 'Amount (debit column)', diff --git a/resources/lang/en_US/list.php b/resources/lang/en_US/list.php index 171a7acf23..8932fdf83a 100644 --- a/resources/lang/en_US/list.php +++ b/resources/lang/en_US/list.php @@ -112,6 +112,7 @@ return [ 'sepa-cc' => 'SEPA Clearing Code', 'sepa-ep' => 'SEPA External Purpose', 'sepa-ci' => 'SEPA Creditor Identifier', + 'sepa-batch-id' => 'SEPA Batch ID', 'external_id' => 'External ID', 'account_at_bunq' => 'Account with bunq', 'file_name' => 'File name', diff --git a/resources/views/transactions/show.twig b/resources/views/transactions/show.twig index f184c82dbe..099f163687 100644 --- a/resources/views/transactions/show.twig +++ b/resources/views/transactions/show.twig @@ -210,7 +210,7 @@ {% endif %} {% endfor %} {# all other meta values #} - {% for metaField in ['external_id','bunq_payment_id','internal_reference','sepa-ct-id','sepa-ct-op','sepa-db','sepa-country','sepa-cc','sepa-ep','sepa-ci'] %} + {% for metaField in ['external_id','bunq_payment_id','internal_reference','sepa-batch-id','sepa-ct-id','sepa-ct-op','sepa-db','sepa-country','sepa-cc','sepa-ep','sepa-ci'] %} {% if journalHasMeta(journal, metaField) %} {{ trans('list.'~metaField) }} From 2ca642120609026ea7e0b425530e691e8cf6c09d Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Jul 2018 08:34:27 +0200 Subject: [PATCH 02/86] Remove Rabobank description fix from available fixes. --- config/csv.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/config/csv.php b/config/csv.php index 3e1d1a9d10..81f7edd603 100644 --- a/config/csv.php +++ b/config/csv.php @@ -25,7 +25,6 @@ declare(strict_types=1); use FireflyIII\Import\Specifics\AbnAmroDescription; use FireflyIII\Import\Specifics\IngDescription; use FireflyIII\Import\Specifics\PresidentsChoice; -use FireflyIII\Import\Specifics\RabobankDescription; use FireflyIII\Import\Specifics\SnsDescription; return [ @@ -34,11 +33,10 @@ return [ * Configuration for the CSV specifics. */ 'import_specifics' => [ - 'IngDescription' => IngDescription::class, - 'RabobankDescription' => RabobankDescription::class, - 'AbnAmroDescription' => AbnAmroDescription::class, - 'SnsDescription' => SnsDescription::class, - 'PresidentsChoice' => PresidentsChoice::class, + 'IngDescription' => IngDescription::class, + 'AbnAmroDescription' => AbnAmroDescription::class, + 'SnsDescription' => SnsDescription::class, + 'PresidentsChoice' => PresidentsChoice::class, ], /* From a95fdb903b86a17af7b8b697fef845cc9db1cbb7 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Jul 2018 11:16:12 +0200 Subject: [PATCH 03/86] Refactor account controller and some associated tests. --- .../Controllers/Account/CreateController.php | 125 +++++++++ .../Controllers/Account/DeleteController.php | 101 ++++++++ .../Controllers/Account/EditController.php | 153 +++++++++++ .../Account/ReconcileController.php | 3 + app/Http/Controllers/AccountController.php | 186 -------------- routes/web.php | 28 +- .../Account/CreateControllerTest.php | 128 +++++++++ .../Account/DeleteControllerTest.php | 86 +++++++ .../Account/EditControllerTest.php | 170 ++++++++++++ .../Controllers/AccountControllerTest.php | 242 ------------------ .../Routine/File/ImportableConverterTest.php | 11 +- 11 files changed, 792 insertions(+), 441 deletions(-) create mode 100644 app/Http/Controllers/Account/CreateController.php create mode 100644 app/Http/Controllers/Account/DeleteController.php create mode 100644 app/Http/Controllers/Account/EditController.php create mode 100644 tests/Feature/Controllers/Account/CreateControllerTest.php create mode 100644 tests/Feature/Controllers/Account/DeleteControllerTest.php create mode 100644 tests/Feature/Controllers/Account/EditControllerTest.php diff --git a/app/Http/Controllers/Account/CreateController.php b/app/Http/Controllers/Account/CreateController.php new file mode 100644 index 0000000000..5627fbe8e4 --- /dev/null +++ b/app/Http/Controllers/Account/CreateController.php @@ -0,0 +1,125 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Http\Controllers\Account; + + +use FireflyIII\Http\Controllers\Controller; +use FireflyIII\Http\Requests\AccountFormRequest; +use FireflyIII\Models\AccountType; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use Illuminate\Http\Request; +use Preferences; + +/** + * + * Class CreateController + */ +class CreateController extends Controller +{ + /** @var AccountRepositoryInterface */ + private $repository; + + /** + * + */ + public function __construct() + { + parent::__construct(); + + // translations: + $this->middleware( + function ($request, $next) { + app('view')->share('mainTitleIcon', 'fa-credit-card'); + app('view')->share('title', trans('firefly.accounts')); + + $this->repository = app(AccountRepositoryInterface::class); + + return $next($request); + } + ); + } + + /** + * @param Request $request + * @param string|null $what + * + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function create(Request $request, string $what = null) + { + $what = $what ?? 'asset'; + $defaultCurrency = app('amount')->getDefaultCurrency(); + $subTitleIcon = config('firefly.subIconsByIdentifier.' . $what); + $subTitle = trans('firefly.make_new_' . $what . '_account'); + $roles = []; + foreach (config('firefly.accountRoles') as $role) { + $roles[$role] = (string)trans('firefly.account_role_' . $role); + } + + // pre fill some data + $request->session()->flash('preFilled', ['currency_id' => $defaultCurrency->id]); + + // put previous url in session if not redirect from store (not "create another"). + if (true !== session('accounts.create.fromStore')) { + $this->rememberPreviousUri('accounts.create.uri'); + } + $request->session()->forget('accounts.create.fromStore'); + + return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'roles')); + } + + + /** + * @param AccountFormRequest $request + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function store(AccountFormRequest $request) + { + $data = $request->getAccountData(); + $account = $this->repository->store($data); + $request->session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name])); + app('preferences')->mark(); + + // update preferences if necessary: + $frontPage = Preferences::get('frontPageAccounts', [])->data; + if (AccountType::ASSET === $account->accountType->type && \count($frontPage) > 0) { + // @codeCoverageIgnoreStart + $frontPage[] = $account->id; + Preferences::set('frontPageAccounts', $frontPage); + // @codeCoverageIgnoreEnd + } + // redirect to previous URL. + $redirect = redirect($this->getPreviousUri('accounts.create.uri')); + if (1 === (int)$request->get('create_another')) { + // set value so create routine will not overwrite URL: + $request->session()->put('accounts.create.fromStore', true); + + $redirect = redirect(route('accounts.create', [$request->input('what')]))->withInput(); + } + + return $redirect; + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Account/DeleteController.php b/app/Http/Controllers/Account/DeleteController.php new file mode 100644 index 0000000000..cdae3afeee --- /dev/null +++ b/app/Http/Controllers/Account/DeleteController.php @@ -0,0 +1,101 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Http\Controllers\Account; + + +use ExpandedForm; +use FireflyIII\Http\Controllers\Controller; +use FireflyIII\Models\Account; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use Illuminate\Http\Request; + +/** + * + * Class DeleteController + */ +class DeleteController extends Controller +{ + /** @var AccountRepositoryInterface */ + private $repository; + + /** + * + */ + public function __construct() + { + parent::__construct(); + + // translations: + $this->middleware( + function ($request, $next) { + app('view')->share('mainTitleIcon', 'fa-credit-card'); + app('view')->share('title', trans('firefly.accounts')); + + $this->repository = app(AccountRepositoryInterface::class); + + return $next($request); + } + ); + } + + /** + * @param Account $account + * + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function delete(Account $account) + { + $typeName = config('firefly.shortNamesByFullName.' . $account->accountType->type); + $subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]); + $accountList = ExpandedForm::makeSelectListWithEmpty($this->repository->getAccountsByType([$account->accountType->type])); + unset($accountList[$account->id]); + + // put previous url in session + $this->rememberPreviousUri('accounts.delete.uri'); + + return view('accounts.delete', compact('account', 'subTitle', 'accountList')); + } + + /** + * @param Request $request + * @param Account $account + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function destroy(Request $request, Account $account) + { + $type = $account->accountType->type; + $typeName = config('firefly.shortNamesByFullName.' . $type); + $name = $account->name; + $moveTo = $this->repository->findNull((int)$request->get('move_account_before_delete')); + + $this->repository->destroy($account, $moveTo); + + $request->session()->flash('success', (string)trans('firefly.' . $typeName . '_deleted', ['name' => $name])); + app('preferences')->mark(); + + return redirect($this->getPreviousUri('accounts.delete.uri')); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Account/EditController.php b/app/Http/Controllers/Account/EditController.php new file mode 100644 index 0000000000..5fad8ba628 --- /dev/null +++ b/app/Http/Controllers/Account/EditController.php @@ -0,0 +1,153 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Http\Controllers\Account; + + +use FireflyIII\Http\Controllers\Controller; +use FireflyIII\Http\Requests\AccountFormRequest; +use FireflyIII\Models\Account; +use FireflyIII\Models\Note; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use Illuminate\Http\Request; + +/** + * + * Class EditController + */ +class EditController extends Controller +{ + /** @var CurrencyRepositoryInterface */ + private $currencyRepos; + /** @var AccountRepositoryInterface */ + private $repository; + + /** + * + */ + public function __construct() + { + parent::__construct(); + + // translations: + $this->middleware( + function ($request, $next) { + app('view')->share('mainTitleIcon', 'fa-credit-card'); + app('view')->share('title', trans('firefly.accounts')); + + $this->repository = app(AccountRepositoryInterface::class); + $this->currencyRepos = app(CurrencyRepositoryInterface::class); + + return $next($request); + } + ); + } + + /** + * @param Request $request + * @param Account $account + * @param AccountRepositoryInterface $repository + * + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function edit(Request $request, Account $account, AccountRepositoryInterface $repository) + { + $what = config('firefly.shortNamesByFullName')[$account->accountType->type]; + $subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]); + $subTitleIcon = config('firefly.subIconsByIdentifier.' . $what); + $roles = []; + foreach (config('firefly.accountRoles') as $role) { + $roles[$role] = (string)trans('firefly.account_role_' . $role); + } + + // put previous url in session if not redirect from store (not "return_to_edit"). + if (true !== session('accounts.edit.fromUpdate')) { + $this->rememberPreviousUri('accounts.edit.uri'); + } + $request->session()->forget('accounts.edit.fromUpdate'); + + // pre fill some useful values. + + // the opening balance is tricky: + $openingBalanceAmount = (string)$repository->getOpeningBalanceAmount($account); + $openingBalanceDate = $repository->getOpeningBalanceDate($account); + $default = app('amount')->getDefaultCurrency(); + $currency = $this->currencyRepos->findNull((int)$repository->getMetaValue($account, 'currency_id')); + if (null === $currency) { + $currency = $default; + } + + // code to handle active-checkboxes + $hasOldInput = null !== $request->old('_token'); + $preFilled = [ + 'accountNumber' => $repository->getMetaValue($account, 'accountNumber'), + 'accountRole' => $repository->getMetaValue($account, 'accountRole'), + 'ccType' => $repository->getMetaValue($account, 'ccType'), + 'ccMonthlyPaymentDate' => $repository->getMetaValue($account, 'ccMonthlyPaymentDate'), + 'BIC' => $repository->getMetaValue($account, 'BIC'), + 'openingBalanceDate' => $openingBalanceDate, + 'openingBalance' => $openingBalanceAmount, + 'virtualBalance' => $account->virtual_balance, + 'currency_id' => $currency->id, + 'notes' => '', + 'active' => $hasOldInput ? (bool)$request->old('active') : $account->active, + ]; + /** @var Note $note */ + $note = $this->repository->getNote($account); + if (null !== $note) { + $preFilled['notes'] = $note->text; + } + + $request->session()->flash('preFilled', $preFilled); + + return view('accounts.edit', compact('account', 'currency', 'subTitle', 'subTitleIcon', 'what', 'roles', 'preFilled')); + } + + + /** + * @param AccountFormRequest $request + * @param Account $account + * + * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function update(AccountFormRequest $request, Account $account) + { + $data = $request->getAccountData(); + $this->repository->update($account, $data); + + $request->session()->flash('success', (string)trans('firefly.updated_account', ['name' => $account->name])); + app('preferences')->mark(); + + $redirect = redirect($this->getPreviousUri('accounts.edit.uri')); + if (1 === (int)$request->get('return_to_edit')) { + // set value so edit routine will not overwrite URL: + $request->session()->put('accounts.edit.fromUpdate', true); + + $redirect = redirect(route('accounts.edit', [$account->id]))->withInput(['return_to_edit' => 1]); + } + + return $redirect; + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index f1c96b4055..09f8101ba6 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -284,6 +284,9 @@ class ReconcileController extends Controller * @param TransactionJournal $journal * * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function update(ReconciliationUpdateRequest $request, TransactionJournal $journal) { diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 7859efca25..58ddb87578 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -30,7 +30,6 @@ use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Http\Requests\AccountFormRequest; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; -use FireflyIII\Models\Note; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; @@ -74,134 +73,6 @@ class AccountController extends Controller ); } - /** - * @param Request $request - * @param string|null $what - * - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function create(Request $request, string $what = null) - { - $what = $what ?? 'asset'; - $defaultCurrency = app('amount')->getDefaultCurrency(); - $subTitleIcon = config('firefly.subIconsByIdentifier.' . $what); - $subTitle = trans('firefly.make_new_' . $what . '_account'); - $roles = []; - foreach (config('firefly.accountRoles') as $role) { - $roles[$role] = (string)trans('firefly.account_role_' . $role); - } - - // pre fill some data - $request->session()->flash('preFilled', ['currency_id' => $defaultCurrency->id]); - - // put previous url in session if not redirect from store (not "create another"). - if (true !== session('accounts.create.fromStore')) { - $this->rememberPreviousUri('accounts.create.uri'); - } - $request->session()->forget('accounts.create.fromStore'); - - return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'roles')); - } - - /** - * @param Account $account - * - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function delete(Account $account) - { - $typeName = config('firefly.shortNamesByFullName.' . $account->accountType->type); - $subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]); - $accountList = ExpandedForm::makeSelectListWithEmpty($this->repository->getAccountsByType([$account->accountType->type])); - unset($accountList[$account->id]); - - // put previous url in session - $this->rememberPreviousUri('accounts.delete.uri'); - - return view('accounts.delete', compact('account', 'subTitle', 'accountList')); - } - - /** - * @param Request $request - * @param Account $account - * - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function destroy(Request $request, Account $account) - { - $type = $account->accountType->type; - $typeName = config('firefly.shortNamesByFullName.' . $type); - $name = $account->name; - $moveTo = $this->repository->findNull((int)$request->get('move_account_before_delete')); - - $this->repository->destroy($account, $moveTo); - - $request->session()->flash('success', (string)trans('firefly.' . $typeName . '_deleted', ['name' => $name])); - app('preferences')->mark(); - - return redirect($this->getPreviousUri('accounts.delete.uri')); - } - - /** - * @param Request $request - * @param Account $account - * @param AccountRepositoryInterface $repository - * - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function edit(Request $request, Account $account, AccountRepositoryInterface $repository) - { - $what = config('firefly.shortNamesByFullName')[$account->accountType->type]; - $subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]); - $subTitleIcon = config('firefly.subIconsByIdentifier.' . $what); - $roles = []; - foreach (config('firefly.accountRoles') as $role) { - $roles[$role] = (string)trans('firefly.account_role_' . $role); - } - - // put previous url in session if not redirect from store (not "return_to_edit"). - if (true !== session('accounts.edit.fromUpdate')) { - $this->rememberPreviousUri('accounts.edit.uri'); - } - $request->session()->forget('accounts.edit.fromUpdate'); - - // pre fill some useful values. - - // the opening balance is tricky: - $openingBalanceAmount = (string)$repository->getOpeningBalanceAmount($account); - $openingBalanceDate = $repository->getOpeningBalanceDate($account); - $default = app('amount')->getDefaultCurrency(); - $currency = $this->currencyRepos->findNull((int)$repository->getMetaValue($account, 'currency_id')); - if (null === $currency) { - $currency = $default; - } - - // code to handle active-checkboxes - $hasOldInput = null !== $request->old('_token'); - $preFilled = [ - 'accountNumber' => $repository->getMetaValue($account, 'accountNumber'), - 'accountRole' => $repository->getMetaValue($account, 'accountRole'), - 'ccType' => $repository->getMetaValue($account, 'ccType'), - 'ccMonthlyPaymentDate' => $repository->getMetaValue($account, 'ccMonthlyPaymentDate'), - 'BIC' => $repository->getMetaValue($account, 'BIC'), - 'openingBalanceDate' => $openingBalanceDate, - 'openingBalance' => $openingBalanceAmount, - 'virtualBalance' => $account->virtual_balance, - 'currency_id' => $currency->id, - 'notes' => '', - 'active' => $hasOldInput ? (bool)$request->old('active') : $account->active, - ]; - /** @var Note $note */ - $note = $this->repository->getNote($account); - if (null !== $note) { - $preFilled['notes'] = $note->text; - } - - $request->session()->flash('preFilled', $preFilled); - - return view('accounts.edit', compact('account', 'currency', 'subTitle', 'subTitleIcon', 'what', 'roles', 'preFilled')); - } - /** * @param Request $request * @param string $what @@ -351,63 +222,6 @@ class AccountController extends Controller ); } - /** - * @param AccountFormRequest $request - * - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function store(AccountFormRequest $request) - { - $data = $request->getAccountData(); - $account = $this->repository->store($data); - $request->session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name])); - app('preferences')->mark(); - - // update preferences if necessary: - $frontPage = Preferences::get('frontPageAccounts', [])->data; - if (AccountType::ASSET === $account->accountType->type && \count($frontPage) > 0) { - // @codeCoverageIgnoreStart - $frontPage[] = $account->id; - Preferences::set('frontPageAccounts', $frontPage); - // @codeCoverageIgnoreEnd - } - // redirect to previous URL. - $redirect = redirect($this->getPreviousUri('accounts.create.uri')); - if (1 === (int)$request->get('create_another')) { - // set value so create routine will not overwrite URL: - $request->session()->put('accounts.create.fromStore', true); - - $redirect = redirect(route('accounts.create', [$request->input('what')]))->withInput(); - } - - return $redirect; - } - - /** - * @param AccountFormRequest $request - * @param Account $account - * - * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function update(AccountFormRequest $request, Account $account) - { - $data = $request->getAccountData(); - $this->repository->update($account, $data); - - $request->session()->flash('success', (string)trans('firefly.updated_account', ['name' => $account->name])); - app('preferences')->mark(); - - $redirect = redirect($this->getPreviousUri('accounts.edit.uri')); - if (1 === (int)$request->get('return_to_edit')) { - // set value so edit routine will not overwrite URL: - $request->session()->put('accounts.edit.fromUpdate', true); - - $redirect = redirect(route('accounts.edit', [$account->id]))->withInput(['return_to_edit' => 1]); - } - - return $redirect; - } - /** * @param array $array * @param int $entryId diff --git a/routes/web.php b/routes/web.php index 3232892b16..9de923e8c3 100755 --- a/routes/web.php +++ b/routes/web.php @@ -109,30 +109,40 @@ Route::group( Route::group( ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'accounts', 'as' => 'accounts.'], function () { Route::get('{what}', ['uses' => 'AccountController@index', 'as' => 'index'])->where('what', 'revenue|asset|expense'); - Route::get('create/{what}', ['uses' => 'AccountController@create', 'as' => 'create'])->where('what', 'revenue|asset|expense'); - Route::get('edit/{account}', ['uses' => 'AccountController@edit', 'as' => 'edit']); - Route::get('delete/{account}', ['uses' => 'AccountController@delete', 'as' => 'delete']); + + + // create + Route::get('create/{what}', ['uses' => 'Account\CreateController@create', 'as' => 'create'])->where('what', 'revenue|asset|expense'); + Route::post('store', ['uses' => 'Account\CreateController@store', 'as' => 'store']); + + + // edit + Route::get('edit/{account}', ['uses' => 'Account\EditController@edit', 'as' => 'edit']); + Route::post('update/{account}', ['uses' => 'Account\EditController@update', 'as' => 'update']); + + // delete + Route::get('delete/{account}', ['uses' => 'Account\DeleteController@delete', 'as' => 'delete']); + Route::post('destroy/{account}', ['uses' => 'Account\DeleteController@destroy', 'as' => 'destroy']); + + // show Route::get('show/{account}/all', ['uses' => 'AccountController@showAll', 'as' => 'show.all']); Route::get('show/{account}/{start_date?}/{end_date?}', ['uses' => 'AccountController@show', 'as' => 'show']); // reconcile routes: Route::get('reconcile/{account}/index/{start_date?}/{end_date?}', ['uses' => 'Account\ReconcileController@reconcile', 'as' => 'reconcile']); - - Route::post('reconcile/{account}/submit/{start_date?}/{end_date?}', ['uses' => 'Account\ReconcileController@submit', 'as' => 'reconcile.submit']); // reconcile JSON routes Route::get('reconcile/{account}/overview/{start_date?}/{end_date?}', ['uses' => 'Json\ReconcileController@overview', 'as' => 'reconcile.overview']); - Route::get('reconcile/{account}/transactions/{start_date?}/{end_date?}', ['uses' => 'Json\ReconcileController@transactions', 'as' => 'reconcile.transactions']); + Route::get( + 'reconcile/{account}/transactions/{start_date?}/{end_date?}', ['uses' => 'Json\ReconcileController@transactions', 'as' => 'reconcile.transactions'] + ); // show reconciliation Route::get('reconcile/show/{tj}', ['uses' => 'Account\ReconcileController@show', 'as' => 'reconcile.show']); Route::get('reconcile/edit/{tj}', ['uses' => 'Account\ReconcileController@edit', 'as' => 'reconcile.edit']); Route::post('reconcile/update/{tj}', ['uses' => 'Account\ReconcileController@update', 'as' => 'reconcile.update']); - Route::post('store', ['uses' => 'AccountController@store', 'as' => 'store']); - Route::post('update/{account}', ['uses' => 'AccountController@update', 'as' => 'update']); - Route::post('destroy/{account}', ['uses' => 'AccountController@destroy', 'as' => 'destroy']); } ); diff --git a/tests/Feature/Controllers/Account/CreateControllerTest.php b/tests/Feature/Controllers/Account/CreateControllerTest.php new file mode 100644 index 0000000000..1df0d40739 --- /dev/null +++ b/tests/Feature/Controllers/Account/CreateControllerTest.php @@ -0,0 +1,128 @@ +. + */ + +declare(strict_types=1); + +namespace Tests\Feature\Controllers\Account; + + +use FireflyIII\Models\Account; +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use Illuminate\Support\Collection; +use Log; +use Preferences; +use Tests\TestCase; + +/** + * + * Class CreateControllerTest + */ +class CreateControllerTest extends TestCase +{ + /** + * + */ + public function setUp(): void + { + parent::setUp(); + Log::debug(sprintf('Now in %s.', \get_class($this))); + } + + + /** + * @covers \FireflyIII\Http\Controllers\Account\CreateController + */ + public function testCreate(): void + { + // mock stuff + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $repository = $this->mock(CurrencyRepositoryInterface::class); + $repository->shouldReceive('get')->andReturn(new Collection); + $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); + + $this->be($this->user()); + $response = $this->get(route('accounts.create', ['asset'])); + $response->assertStatus(200); + // has bread crumb + $response->assertSee('