From b627d42160a5e5678318a06cf12d4811a5724951 Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 22 Feb 2018 20:07:14 +0100 Subject: [PATCH] Code removal. The code removed from these classes must move to respective services. --- app/Factory/BillFactory.php | 35 ++ .../Events/StoredJournalEventHandler.php | 55 --- .../Transaction/BulkController.php | 12 +- app/Http/Requests/AccountFormRequest.php | 31 +- app/Providers/EventServiceProvider.php | 1 - .../Account/AccountRepository.php | 109 +----- .../Account/FindAccountsTrait.php | 36 +- app/Repositories/Bill/BillRepository.php | 109 ++---- .../Journal/JournalRepository.php | 338 +----------------- .../Journal/JournalRepositoryInterface.php | 66 ---- .../Journal/SupportJournalsTrait.php | 2 +- app/Rules/UniqueIban.php | 89 +++++ .../Internal/Destroy/BillDestroyService.php | 46 +++ .../Destroy/JournalDestroyService.php | 39 ++ .../Internal/Support/BillServiceTrait.php | 62 ++++ .../Internal/Update/BillUpdateService.php | 66 ++++ 16 files changed, 431 insertions(+), 665 deletions(-) create mode 100644 app/Rules/UniqueIban.php create mode 100644 app/Services/Internal/Destroy/BillDestroyService.php create mode 100644 app/Services/Internal/Destroy/JournalDestroyService.php create mode 100644 app/Services/Internal/Support/BillServiceTrait.php create mode 100644 app/Services/Internal/Update/BillUpdateService.php diff --git a/app/Factory/BillFactory.php b/app/Factory/BillFactory.php index 386b5c1173..e8addafd1e 100644 --- a/app/Factory/BillFactory.php +++ b/app/Factory/BillFactory.php @@ -25,6 +25,7 @@ namespace FireflyIII\Factory; use FireflyIII\Models\Bill; use FireflyIII\Repositories\Bill\BillRepositoryInterface; +use FireflyIII\Services\Internal\Support\BillServiceTrait; use FireflyIII\User; /** @@ -32,6 +33,7 @@ use FireflyIII\User; */ class BillFactory { + use BillServiceTrait; /** @var BillRepositoryInterface */ private $repository; /** @var User */ @@ -86,4 +88,37 @@ class BillFactory } + /** + * @param array $data + * + * @return Bill|null + */ + public function store(array $data): ?Bill + { + $matchArray = explode(',', $data['match']); + $matchArray = array_unique($matchArray); + $match = join(',', $matchArray); + + /** @var Bill $bill */ + $bill = Bill::create( + [ + 'name' => $data['name'], + 'match' => $match, + 'amount_min' => $data['amount_min'], + 'user_id' => $this->user->id, + 'amount_max' => $data['amount_max'], + 'date' => $data['date'], + 'repeat_freq' => $data['repeat_freq'], + 'skip' => $data['skip'], + 'automatch' => $data['automatch'], + 'active' => $data['active'], + ] + ); + + // update note: + if (isset($data['notes'])) { + $this->updateNote($bill, $data['notes']); + } + } + } \ No newline at end of file diff --git a/app/Handlers/Events/StoredJournalEventHandler.php b/app/Handlers/Events/StoredJournalEventHandler.php index 2dd019b57d..ef6a26bcc0 100644 --- a/app/Handlers/Events/StoredJournalEventHandler.php +++ b/app/Handlers/Events/StoredJournalEventHandler.php @@ -61,61 +61,6 @@ class StoredJournalEventHandler $this->ruleGroupRepository = $ruleGroupRepository; } - /** - * This method connects a new transfer to a piggy bank. - * - * @param StoredTransactionJournal $event - * - * @return bool - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function connectToPiggyBank(StoredTransactionJournal $event): bool - { - $journal = $event->journal; - $piggyBankId = $event->piggyBankId; - $piggyBank = $this->repository->find($piggyBankId); - - // is a transfer? - if (!$this->journalRepository->isTransfer($journal)) { - Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id)); - - return true; - } - - // piggy exists? - if (null === $piggyBank) { - Log::error(sprintf('There is no piggy bank with ID #%d', $piggyBankId)); - - return true; - } - - // repetition exists? - $repetition = $this->repository->getRepetition($piggyBank, $journal->date); - if (null === $repetition->id) { - Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d'))); - - return true; - } - - // get the amount - $amount = $this->repository->getExactAmount($piggyBank, $repetition, $journal); - if (0 === bccomp($amount, '0')) { - Log::debug('Amount is zero, will not create event.'); - - return true; - } - - // update amount - $this->repository->addAmountToRepetition($repetition, $amount); - $event = $this->repository->createEventWithJournal($piggyBank, $amount, $journal); - - Log::debug(sprintf('Created piggy bank event #%d', $event->id)); - - return true; - } - /** * This method grabs all the users rules and processes them. * diff --git a/app/Http/Controllers/Transaction/BulkController.php b/app/Http/Controllers/Transaction/BulkController.php index 86e2151ef3..001bb514fc 100644 --- a/app/Http/Controllers/Transaction/BulkController.php +++ b/app/Http/Controllers/Transaction/BulkController.php @@ -31,6 +31,7 @@ use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use FireflyIII\Services\Internal\Update\JournalUpdateService; use Illuminate\Http\Request; use Illuminate\Support\Collection; use Log; @@ -137,30 +138,35 @@ class BulkController extends Controller */ public function update(BulkEditJournalRequest $request, JournalRepositoryInterface $repository) { + /** @var JournalUpdateService $service */ + $service = app(JournalUpdateService::class); $journalIds = $request->get('journals'); $ignoreCategory = intval($request->get('ignore_category')) === 1; $ignoreBudget = intval($request->get('ignore_budget')) === 1; $ignoreTags = intval($request->get('ignore_tags')) === 1; $count = 0; + if (is_array($journalIds)) { foreach ($journalIds as $journalId) { $journal = $repository->find(intval($journalId)); if (!is_null($journal)) { + // TODO need to move this to update service. $count++; Log::debug(sprintf('Found journal #%d', $journal->id)); // update category if not told to ignore if ($ignoreCategory === false) { Log::debug(sprintf('Set category to %s', $request->string('category'))); - $repository->updateCategory($journal, $request->string('category')); + + $service->updateCategory($journal, $request->string('category')); } // update budget if not told to ignore (and is withdrawal) if ($ignoreBudget === false) { Log::debug(sprintf('Set budget to %d', $request->integer('budget_id'))); - $repository->updateBudget($journal, $request->integer('budget_id')); + $service->updateBudget($journal, $request->integer('budget_id')); } if ($ignoreTags === false) { Log::debug(sprintf('Set tags to %s', $request->string('budget_id'))); - $repository->updateTags($journal, explode(',', $request->string('tags'))); + $service->updateTags($journal, explode(',', $request->string('tags'))); } // update tags if not told to ignore (and is withdrawal) } diff --git a/app/Http/Requests/AccountFormRequest.php b/app/Http/Requests/AccountFormRequest.php index e10b8f2185..c3a867f7e4 100644 --- a/app/Http/Requests/AccountFormRequest.php +++ b/app/Http/Requests/AccountFormRequest.php @@ -22,7 +22,8 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; -use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Models\Account; +use FireflyIII\Rules\UniqueIban; /** * Class AccountFormRequest. @@ -67,25 +68,14 @@ class AccountFormRequest extends Request */ public function rules() { - /** @var AccountRepositoryInterface $repository */ - $repository = app(AccountRepositoryInterface::class); $accountRoles = join(',', config('firefly.accountRoles')); $types = join(',', array_keys(config('firefly.subTitlesByIdentifier'))); $ccPaymentTypes = join(',', array_keys(config('firefly.ccTypes'))); - - $nameRule = 'required|min:1|uniqueAccountForUser'; - $idRule = ''; - if (null !== $repository->find(intval($this->get('id')))->id) { - $idRule = 'belongsToUser:accounts'; - $nameRule = 'required|min:1|uniqueAccountForUser:' . intval($this->get('id')); - } - - return [ - 'id' => $idRule, - 'name' => $nameRule, + $rules = [ + 'name' => 'required|min:1|uniqueAccountForUser', 'openingBalance' => 'numeric|required_with:openingBalanceDate|nullable', 'openingBalanceDate' => 'date|required_with:openingBalance|nullable', - 'iban' => 'iban|nullable', + 'iban' => ['iban', 'nullable', new UniqueIban(null)], 'BIC' => 'bic|nullable', 'virtualBalance' => 'numeric|nullable', 'currency_id' => 'exists:transaction_currencies,id', @@ -98,5 +88,16 @@ class AccountFormRequest extends Request 'amount_currency_id_virtualBalance' => 'exists:transaction_currencies,id', 'what' => 'in:' . $types, ]; + + /** @var Account $account */ + $account = $this->route()->parameter('account'); + if (!is_null($account)) { + // add rules: + $rules['id'] = 'belongsToUser:accounts'; + $rules['name'] = 'required|min:1|uniqueAccountForUser:' . intval($this->get('id')); + $rules['iban'] = ['iban', 'nullable', new UniqueIban($account)]; + } + + return $rules; } } diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 55ef84493d..6fbe340aae 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -77,7 +77,6 @@ class EventServiceProvider extends ServiceProvider // is a Transaction Journal related event. 'FireflyIII\Events\StoredTransactionJournal' => [ 'FireflyIII\Handlers\Events\StoredJournalEventHandler@scanBills', - 'FireflyIII\Handlers\Events\StoredJournalEventHandler@connectToPiggyBank', 'FireflyIII\Handlers\Events\StoredJournalEventHandler@processRules', ], // is a Transaction Journal related event. diff --git a/app/Repositories/Account/AccountRepository.php b/app/Repositories/Account/AccountRepository.php index c9c7b9b6f1..8f7103b749 100644 --- a/app/Repositories/Account/AccountRepository.php +++ b/app/Repositories/Account/AccountRepository.php @@ -23,42 +23,29 @@ declare(strict_types=1); namespace FireflyIII\Repositories\Account; use Carbon\Carbon; -use DB; +use Exception; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Factory\AccountFactory; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; -use FireflyIII\Models\Category; use FireflyIII\Models\Note; -use FireflyIII\Models\Tag; -use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; -use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Services\Internal\Destroy\AccountDestroyService; use FireflyIII\Services\Internal\Update\AccountUpdateService; +use FireflyIII\Services\Internal\Update\JournalUpdateService; use FireflyIII\User; -use Log; /** * Class AccountRepository. */ class AccountRepository implements AccountRepositoryInterface { - + use FindAccountsTrait; /** @var User */ private $user; - /** @var array */ - private $validAssetFields = ['accountRole', 'accountNumber', 'currency_id', 'BIC']; - - use FindAccountsTrait; - /** @var array */ - private $validCCFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType', 'accountNumber', 'currency_id', 'BIC']; - /** @var array */ - private $validFields = ['accountNumber', 'currency_id', 'BIC']; /** - * Moved here from account CRUD. - * * @param array $types * * @return int @@ -239,6 +226,8 @@ class AccountRepository implements AccountRepositoryInterface * @param array $data * * @return Account + * @throws FireflyException + * @throws Exception */ public function store(array $data): Account { @@ -254,6 +243,8 @@ class AccountRepository implements AccountRepositoryInterface * @param Account $account * @param array $data * + * @throws FireflyException + * @throws Exception * @return Account */ public function update(Account $account, array $data): Account @@ -270,90 +261,16 @@ class AccountRepository implements AccountRepositoryInterface * @param array $data * * @return TransactionJournal + * @throws FireflyException + * @throws Exception */ public function updateReconciliation(TransactionJournal $journal, array $data): TransactionJournal { - // update journal - // update actual journal: - $data['amount'] = strval($data['amount']); - - // unlink all categories, recreate them: - $journal->categories()->detach(); - - $this->storeCategoryWithJournal($journal, strval($data['category'])); - - // update amounts - /** @var Transaction $transaction */ - foreach ($journal->transactions as $transaction) { - $transaction->amount = bcmul($data['amount'], '-1'); - if (AccountType::ASSET === $transaction->account->accountType->type) { - $transaction->amount = $data['amount']; - } - $transaction->save(); - } - - $journal->save(); - - // update tags: - if (isset($data['tags']) && is_array($data['tags'])) { - $this->updateTags($journal, $data['tags']); - } + /** @var JournalUpdateService $service */ + $service = app(JournalUpdateService::class); + $journal = $service->update($journal, $data); return $journal; } - /** - * @param TransactionJournal $journal - * @param string $category - */ - protected function storeCategoryWithJournal(TransactionJournal $journal, string $category) - { - if (strlen($category) > 0) { - $category = Category::firstOrCreateEncrypted(['name' => $category, 'user_id' => $journal->user_id]); - $journal->categories()->save($category); - } - } - - /** - * @param TransactionJournal $journal - * @param array $array - * - * @return bool - */ - protected function updateTags(TransactionJournal $journal, array $array): bool - { - // create tag repository - /** @var TagRepositoryInterface $tagRepository */ - $tagRepository = app(TagRepositoryInterface::class); - - // find or create all tags: - $tags = []; - $ids = []; - foreach ($array as $name) { - if (strlen(trim($name)) > 0) { - $tag = Tag::firstOrCreateEncrypted(['tag' => $name, 'user_id' => $journal->user_id]); - $tags[] = $tag; - $ids[] = $tag->id; - } - } - - // delete all tags connected to journal not in this array: - if (count($ids) > 0) { - DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal->id)->whereNotIn('tag_id', $ids)->delete(); - } - // if count is zero, delete them all: - if (0 === count($ids)) { - DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal->id)->delete(); - } - - // connect each tag to journal (if not yet connected): - /** @var Tag $tag */ - foreach ($tags as $tag) { - Log::debug(sprintf('Will try to connect tag #%d to journal #%d.', $tag->id, $journal->id)); - $tagRepository->connect($journal, $tag); - } - - return true; - } - } diff --git a/app/Repositories/Account/FindAccountsTrait.php b/app/Repositories/Account/FindAccountsTrait.php index 59a92b4f89..dca6580210 100644 --- a/app/Repositories/Account/FindAccountsTrait.php +++ b/app/Repositories/Account/FindAccountsTrait.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Repositories\Account; use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Factory\AccountFactory; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; use FireflyIII\User; @@ -44,6 +45,7 @@ trait FindAccountsTrait */ public function find(int $accountId): Account { + /** @var Account $account */ $account = $this->user->accounts()->find($accountId); if (null === $account) { return new Account; @@ -56,6 +58,7 @@ trait FindAccountsTrait * @param string $number * @param array $types * + * @deprecated * @return Account */ public function findByAccountNumber(string $number, array $types): Account @@ -83,6 +86,7 @@ trait FindAccountsTrait * @param string $iban * @param array $types * + * @deprecated * @return Account */ public function findByIban(string $iban, array $types): Account @@ -213,15 +217,15 @@ trait FindAccountsTrait * @return Account * * @throws FireflyException + * @throws \Exception */ public function getCashAccount(): Account { - $type = AccountType::where('type', AccountType::CASH)->first(); - $account = Account::firstOrCreateEncrypted( - ['user_id' => $this->user->id, 'account_type_id' => $type->id, 'name' => 'Cash account'] - ); - $account->active = true; - $account->save(); + $type = AccountType::where('type', AccountType::CASH)->first(); + /** @var AccountFactory $factory */ + $factory = app(AccountFactory::class); + $factory->setUser($this->user); + $account = $factory->findOrCreate('Cash account', $type->type); return $account; } @@ -232,6 +236,7 @@ trait FindAccountsTrait * @return Account|null * * @throws FireflyException + * @throws \Exception */ public function getReconciliation(Account $account): ?Account { @@ -247,23 +252,12 @@ trait FindAccountsTrait return $account; } } - // assume nothing was found. create it! - $data = [ - 'accountType' => 'reconcile', - 'name' => $name, - 'iban' => null, - 'virtualBalance' => '0', - 'active' => true, - ]; - $account = $this->storeAccount($data); + /** @var AccountFactory $factory */ + $factory = app(AccountFactory::class); + $factory->setUser($account->user); + $account = $factory->findOrCreate($name, $type->type); return $account; } - /** - * @param array $data - * - * @return Account - */ - abstract protected function storeAccount(array $data): Account; } diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php index f61cc41538..bf4f03cf1a 100644 --- a/app/Repositories/Bill/BillRepository.php +++ b/app/Repositories/Bill/BillRepository.php @@ -24,18 +24,19 @@ namespace FireflyIII\Repositories\Bill; use Carbon\Carbon; use DB; +use FireflyIII\Factory\BillFactory; use FireflyIII\Models\Bill; -use FireflyIII\Models\Note; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; +use FireflyIII\Services\Internal\Destroy\BillDestroyService; +use FireflyIII\Services\Internal\Update\BillUpdateService; use FireflyIII\Support\CacheProperties; use FireflyIII\User; use Illuminate\Database\Query\JoinClause; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Log; -use Navigation; /** * Class BillRepository. @@ -54,7 +55,9 @@ class BillRepository implements BillRepositoryInterface */ public function destroy(Bill $bill): bool { - $bill->delete(); + /** @var BillDestroyService $service */ + $service = app(BillDestroyService::class); + $service->destroy($bill); return true; } @@ -103,12 +106,8 @@ class BillRepository implements BillRepositoryInterface /** @var Collection $set */ $set = $this->user->bills() ->where('active', 1) - ->get( - [ - 'bills.*', - DB::raw('((bills.amount_min + bills.amount_max) / 2) AS expectedAmount'), - ] - )->sortBy('name'); + ->sortBy('name') + ->get(['bills.*', DB::raw('((bills.amount_min + bills.amount_max) / 2) AS expectedAmount'),]); return $set; } @@ -221,6 +220,7 @@ class BillRepository implements BillRepositoryInterface * @param Carbon $end * * @return string + * @throws \FireflyIII\Exceptions\FireflyException */ public function getBillsUnpaidInRange(Carbon $start, Carbon $end): string { @@ -302,6 +302,7 @@ class BillRepository implements BillRepositoryInterface * @param Carbon $end * * @return Collection + * @throws \FireflyIII\Exceptions\FireflyException */ public function getPayDatesInRange(Bill $bill, Carbon $start, Carbon $end): Collection { @@ -418,11 +419,11 @@ class BillRepository implements BillRepositoryInterface while ($start < $date) { Log::debug(sprintf('$start (%s) < $date (%s)', $start->format('Y-m-d'), $date->format('Y-m-d'))); - $start = Navigation::addPeriod($start, $bill->repeat_freq, $bill->skip); + $start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); Log::debug('Start is now ' . $start->format('Y-m-d')); } - $end = Navigation::addPeriod($start, $bill->repeat_freq, $bill->skip); + $end = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); Log::debug('nextDateMatch: Final start is ' . $start->format('Y-m-d')); Log::debug('nextDateMatch: Matching end is ' . $end->format('Y-m-d')); @@ -455,11 +456,11 @@ class BillRepository implements BillRepositoryInterface while ($start < $date) { Log::debug(sprintf('$start (%s) < $date (%s)', $start->format('Y-m-d'), $date->format('Y-m-d'))); - $start = Navigation::addPeriod($start, $bill->repeat_freq, $bill->skip); + $start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); Log::debug('Start is now ' . $start->format('Y-m-d')); } - $end = Navigation::addPeriod($start, $bill->repeat_freq, $bill->skip); + $end = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); // see if the bill was paid in this period. $journalCount = $bill->transactionJournals()->before($end)->after($start)->count(); @@ -468,7 +469,7 @@ class BillRepository implements BillRepositoryInterface // this period had in fact a bill. The new start is the current end, and we create a new end. Log::debug(sprintf('Journal count is %d, so start becomes %s', $journalCount, $end->format('Y-m-d'))); $start = clone $end; - $end = Navigation::addPeriod($start, $bill->repeat_freq, $bill->skip); + $end = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); } Log::debug('nextExpectedMatch: Final start is ' . $start->format('Y-m-d')); Log::debug('nextExpectedMatch: Matching end is ' . $end->format('Y-m-d')); @@ -479,9 +480,12 @@ class BillRepository implements BillRepositoryInterface } /** + * TODO move to a service. + * * @param Bill $bill * @param TransactionJournal $journal * + * @deprecated * @return bool */ public function scan(Bill $bill, TransactionJournal $journal): bool @@ -533,30 +537,11 @@ class BillRepository implements BillRepositoryInterface */ public function store(array $data): Bill { - $matchArray = explode(',', $data['match']); - $matchArray = array_unique($matchArray); - $match = join(',', $matchArray); + /** @var BillFactory $factory */ + $factory = app(BillFactory::class); + $factory->setUser($this->user); + $bill = $factory->store($data); - /** @var Bill $bill */ - $bill = Bill::create( - [ - 'name' => $data['name'], - 'match' => $match, - 'amount_min' => $data['amount_min'], - 'user_id' => $this->user->id, - 'amount_max' => $data['amount_max'], - 'date' => $data['date'], - 'repeat_freq' => $data['repeat_freq'], - 'skip' => $data['skip'], - 'automatch' => $data['automatch'], - 'active' => $data['active'], - ] - ); - - // update note: - if (isset($data['notes'])) { - $this->updateNote($bill, $data['notes']); - } return $bill; } @@ -569,27 +554,10 @@ class BillRepository implements BillRepositoryInterface */ public function update(Bill $bill, array $data): Bill { - $matchArray = explode(',', $data['match']); - $matchArray = array_unique($matchArray); - $match = join(',', $matchArray); + /** @var BillUpdateService $service */ + $service = app(BillUpdateService::class); - $bill->name = $data['name']; - $bill->match = $match; - $bill->amount_min = $data['amount_min']; - $bill->amount_max = $data['amount_max']; - $bill->date = $data['date']; - $bill->repeat_freq = $data['repeat_freq']; - $bill->skip = $data['skip']; - $bill->automatch = $data['automatch']; - $bill->active = $data['active']; - $bill->save(); - - // update note: - if (isset($data['notes']) && null !== $data['notes']) { - $this->updateNote($bill, strval($data['notes'])); - } - - return $bill; + return $service->update($bill, $data); } /** @@ -629,31 +597,4 @@ class BillRepository implements BillRepositoryInterface return $wordMatch; } - - /** - * @param Bill $bill - * @param string $note - * - * @return bool - */ - protected function updateNote(Bill $bill, string $note): bool - { - if (0 === strlen($note)) { - $dbNote = $bill->notes()->first(); - if (null !== $dbNote) { - $dbNote->delete(); - } - - return true; - } - $dbNote = $bill->notes()->first(); - if (null === $dbNote) { - $dbNote = new Note(); - $dbNote->noteable()->associate($bill); - } - $dbNote->text = trim($note); - $dbNote->save(); - - return true; - } } diff --git a/app/Repositories/Journal/JournalRepository.php b/app/Repositories/Journal/JournalRepository.php index 7e275e2d1c..a8c0bbeac0 100644 --- a/app/Repositories/Journal/JournalRepository.php +++ b/app/Repositories/Journal/JournalRepository.php @@ -22,16 +22,16 @@ declare(strict_types=1); namespace FireflyIII\Repositories\Journal; -use Carbon\Carbon; -use DB; +use Exception; +use FireflyIII\Factory\TransactionJournalFactory; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; use FireflyIII\Models\Note; -use FireflyIII\Models\Tag; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; -use FireflyIII\Repositories\Tag\TagRepositoryInterface; +use FireflyIII\Services\Internal\Destroy\JournalDestroyService; +use FireflyIII\Services\Internal\Update\JournalUpdateService; use FireflyIII\User; use Illuminate\Support\Collection; use Illuminate\Support\MessageBag; @@ -109,7 +109,9 @@ class JournalRepository implements JournalRepositoryInterface */ public function destroy(TransactionJournal $journal): bool { - $journal->delete(); + /** @var JournalDestroyService $service */ + $service = app(JournalDestroyService::class); + $service->destroy($journal); return true; } @@ -229,31 +231,6 @@ class JournalRepository implements JournalRepositoryInterface return $set; } - /** - * @param TransactionJournal $journal - * - * @return bool - */ - public function isTransfer(TransactionJournal $journal): bool - { - return TransactionType::TRANSFER === $journal->transactionType->type; - } - - /** - * Mark journal as completed and return it. - * - * @param TransactionJournal $journal - * - * @return TransactionJournal - */ - public function markCompleted(TransactionJournal $journal): TransactionJournal - { - $journal->completed = true; - $journal->save(); - - return $journal; - } - /** * @param Transaction $transaction * @@ -311,109 +288,11 @@ class JournalRepository implements JournalRepositoryInterface */ public function store(array $data): TransactionJournal { - // find transaction type. - /** @var TransactionType $transactionType */ - $transactionType = TransactionType::where('type', ucfirst($data['what']))->first(); - $accounts = $this->storeAccounts($this->user, $transactionType, $data); - $data = $this->verifyNativeAmount($data, $accounts); - $amount = strval($data['amount']); - $dateString = $data['date']; - if ($data['date'] instanceof Carbon) { - $dateString = $data['date']->format('Y-m-d 00:00:00'); - } - $journal = new TransactionJournal( - [ - 'user_id' => $this->user->id, - 'transaction_type_id' => $transactionType->id, - 'transaction_currency_id' => $data['currency_id'], // no longer used. - 'description' => $data['description'], - 'completed' => 0, - 'date' => $dateString, - ] - ); - $journal->save(); + /** @var TransactionJournalFactory $factory */ + $factory = app(TransactionJournalFactory::class); + $factory->setUser($this->user); - // store stuff: - $this->storeCategoryWithJournal($journal, strval($data['category'])); - $this->storeBudgetWithJournal($journal, $data['budget_id']); - - // store two transactions: - - $one = [ - 'journal' => $journal, - 'account' => $accounts['source'], - 'amount' => bcmul($amount, '-1'), - 'transaction_currency_id' => $data['currency_id'], - 'foreign_amount' => null === $data['foreign_amount'] ? null : bcmul(strval($data['foreign_amount']), '-1'), - 'foreign_currency_id' => $data['foreign_currency_id'], - 'description' => null, - 'category' => null, - 'budget' => null, - 'identifier' => 0, - ]; - $this->storeTransaction($one); - - $two = [ - 'journal' => $journal, - 'account' => $accounts['destination'], - 'amount' => $amount, - 'transaction_currency_id' => $data['currency_id'], - 'foreign_amount' => $data['foreign_amount'], - 'foreign_currency_id' => $data['foreign_currency_id'], - 'description' => null, - 'category' => null, - 'budget' => null, - 'identifier' => 0, - ]; - - $this->storeTransaction($two); - - // store tags - if (isset($data['tags']) && is_array($data['tags'])) { - $this->saveTags($journal, $data['tags']); - } - - // update note: - if (isset($data['notes'])) { - $this->updateNote($journal, $data['notes']); - } - - foreach ($data as $key => $value) { - if (in_array($key, $this->validMetaFields)) { - $journal->setMeta($key, $value); - continue; - } - Log::debug(sprintf('Could not store meta field "%s" with value "%s" for journal #%d', json_encode($key), json_encode($value), $journal->id)); - } - - $journal->completed = 1; - $journal->save(); - - return $journal; - } - - /** - * Store a new transaction journal based on the values given. - * - * @param array $values - * - * @return TransactionJournal - */ - public function storeBasic(array $values): TransactionJournal - { - return TransactionJournal::create($values); - } - - /** - * Store a new transaction based on the values given. - * - * @param array $values - * - * @return Transaction - */ - public function storeBasicTransaction(array $values): Transaction - { - return Transaction::create($values); + return $factory->create($data); } /** @@ -423,201 +302,14 @@ class JournalRepository implements JournalRepositoryInterface * @return TransactionJournal * * @throws \FireflyIII\Exceptions\FireflyException - * @throws \FireflyIII\Exceptions\FireflyException - * @throws \FireflyIII\Exceptions\FireflyException - * @throws \FireflyIII\Exceptions\FireflyException + * @throws Exception */ public function update(TransactionJournal $journal, array $data): TransactionJournal { - // update actual journal: - $journal->description = $data['description']; - $journal->date = $data['date']; - $accounts = $this->storeAccounts($this->user, $journal->transactionType, $data); - $data = $this->verifyNativeAmount($data, $accounts); - $data['amount'] = strval($data['amount']); - $data['foreign_amount'] = null === $data['foreign_amount'] ? null : strval($data['foreign_amount']); + /** @var JournalUpdateService $service */ + $service = app(JournalUpdateService::class); - // unlink all categories, recreate them: - $journal->categories()->detach(); - $journal->budgets()->detach(); - - $this->storeCategoryWithJournal($journal, strval($data['category'])); - $this->storeBudgetWithJournal($journal, $data['budget_id']); - - // negative because source loses money. - $this->updateSourceTransaction($journal, $accounts['source'], $data); - - // positive because destination gets money. - $this->updateDestinationTransaction($journal, $accounts['destination'], $data); - - $journal->save(); - - // update tags: - if (isset($data['tags']) && is_array($data['tags'])) { - $this->updateTags($journal, $data['tags']); - } - - // update note: - if (isset($data['notes']) && null !== $data['notes']) { - $this->updateNote($journal, strval($data['notes'])); - } - - // update meta fields: - $result = $journal->save(); - if ($result) { - foreach ($data as $key => $value) { - if (in_array($key, $this->validMetaFields)) { - $journal->setMeta($key, $value); - continue; - } - Log::debug(sprintf('Could not store meta field "%s" with value "%s" for journal #%d', json_encode($key), json_encode($value), $journal->id)); - } - - return $journal; - } - - return $journal; + return $service->update($journal, $data); } - /** - * @param TransactionJournal $journal - * @param int $budgetId - * - * @return TransactionJournal - */ - public function updateBudget(TransactionJournal $journal, int $budgetId): TransactionJournal - { - if ($budgetId === 0) { - $journal->budgets()->detach(); - $journal->save(); - - return $journal; - } - $this->storeBudgetWithJournal($journal, $budgetId); - - return $journal; - } - - /** - * @param TransactionJournal $journal - * @param string $category - * - * @return TransactionJournal - */ - public function updateCategory(TransactionJournal $journal, string $category): TransactionJournal - { - Log::debug(sprintf('In updateCategory("%s")', $category)); - $journal->categories()->detach(); - if (strlen($category) === 0) { - return $journal; - } - $this->storeCategoryWithJournal($journal, $category); - - return $journal; - } - - /** - * Same as above but for transaction journal with multiple transactions. - * - * @param TransactionJournal $journal - * @param array $data - * - * @return TransactionJournal - */ - public function updateSplitJournal(TransactionJournal $journal, array $data): TransactionJournal - { - // update actual journal: - $journal->description = $data['journal_description']; - $journal->date = $data['date']; - $journal->save(); - Log::debug(sprintf('Updated split journal #%d', $journal->id)); - - // unlink all categories: - $journal->categories()->detach(); - $journal->budgets()->detach(); - - // update note: - if (isset($data['notes']) && null !== $data['notes']) { - $this->updateNote($journal, strval($data['notes'])); - } - - // update meta fields: - $result = $journal->save(); - if ($result) { - foreach ($data as $key => $value) { - if (in_array($key, $this->validMetaFields)) { - $journal->setMeta($key, $value); - continue; - } - Log::debug(sprintf('Could not store meta field "%s" with value "%s" for journal #%d', json_encode($key), json_encode($value), $journal->id)); - } - } - - // update tags: - if (isset($data['tags']) && is_array($data['tags'])) { - $this->updateTags($journal, $data['tags']); - } - - // delete original transactions, and recreate them. - $journal->transactions()->delete(); - - // store each transaction. - $identifier = 0; - Log::debug(sprintf('Count %d transactions in updateSplitJournal()', count($data['transactions']))); - - foreach ($data['transactions'] as $transaction) { - Log::debug(sprintf('Split journal update split transaction %d', $identifier)); - $transaction = $this->appendTransactionData($transaction, $data); - $this->storeSplitTransaction($journal, $transaction, $identifier); - ++$identifier; - } - - $journal->save(); - - return $journal; - } - - /** - * Update tags. - * - * @param TransactionJournal $journal - * @param array $array - * - * @return bool - */ - public function updateTags(TransactionJournal $journal, array $array): bool - { - // create tag repository - /** @var TagRepositoryInterface $tagRepository */ - $tagRepository = app(TagRepositoryInterface::class); - - // find or create all tags: - $tags = []; - $ids = []; - foreach ($array as $name) { - if (strlen(trim($name)) > 0) { - $tag = Tag::firstOrCreateEncrypted(['tag' => $name, 'user_id' => $journal->user_id]); - $tags[] = $tag; - $ids[] = $tag->id; - } - } - - // delete all tags connected to journal not in this array: - if (count($ids) > 0) { - DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal->id)->whereNotIn('tag_id', $ids)->delete(); - } - // if count is zero, delete them all: - if (0 === count($ids)) { - DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal->id)->delete(); - } - - // connect each tag to journal (if not yet connected): - /** @var Tag $tag */ - foreach ($tags as $tag) { - Log::debug(sprintf('Will try to connect tag #%d to journal #%d.', $tag->id, $journal->id)); - $tagRepository->connect($journal, $tag); - } - - return true; - } } diff --git a/app/Repositories/Journal/JournalRepositoryInterface.php b/app/Repositories/Journal/JournalRepositoryInterface.php index 1e242b5833..7877ea37ec 100644 --- a/app/Repositories/Journal/JournalRepositoryInterface.php +++ b/app/Repositories/Journal/JournalRepositoryInterface.php @@ -118,22 +118,6 @@ interface JournalRepositoryInterface */ public function getTransactionsById(array $transactionIds): Collection; - /** - * @param TransactionJournal $journal - * - * @return bool - */ - public function isTransfer(TransactionJournal $journal): bool; - - /** - * Mark journal as completed and return it. - * - * @param TransactionJournal $journal - * - * @return TransactionJournal - */ - public function markCompleted(TransactionJournal $journal): TransactionJournal; - /** * @param Transaction $transaction * @@ -161,24 +145,6 @@ interface JournalRepositoryInterface */ public function store(array $data): TransactionJournal; - /** - * Store a new transaction journal based on the values given. - * - * @param array $values - * - * @return TransactionJournal - */ - public function storeBasic(array $values): TransactionJournal; - - /** - * Store a new transaction based on the values given. - * - * @param array $values - * - * @return Transaction - */ - public function storeBasicTransaction(array $values): Transaction; - /** * @param TransactionJournal $journal * @param array $data @@ -186,36 +152,4 @@ interface JournalRepositoryInterface * @return TransactionJournal */ public function update(TransactionJournal $journal, array $data): TransactionJournal; - - /** - * @param TransactionJournal $journal - * @param int $budgetId - * - * @return TransactionJournal - */ - public function updateBudget(TransactionJournal $journal, int $budgetId): TransactionJournal; - - /** - * @param TransactionJournal $journal - * @param string $category - * - * @return TransactionJournal - */ - public function updateCategory(TransactionJournal $journal, string $category): TransactionJournal; - - /** - * @param TransactionJournal $journal - * @param array $data - * - * @return TransactionJournal - */ - public function updateSplitJournal(TransactionJournal $journal, array $data): TransactionJournal; - - /** - * @param TransactionJournal $journal - * @param array $tags - * - * @return bool - */ - public function updateTags(TransactionJournal $journal, array $tags): bool; } diff --git a/app/Repositories/Journal/SupportJournalsTrait.php b/app/Repositories/Journal/SupportJournalsTrait.php index 5815cc8a4f..0ea65efd29 100644 --- a/app/Repositories/Journal/SupportJournalsTrait.php +++ b/app/Repositories/Journal/SupportJournalsTrait.php @@ -231,7 +231,7 @@ trait SupportJournalsTrait protected function verifyNativeAmount(array $data, array $accounts): array { /** @var TransactionType $transactionType */ - $transactionType = TransactionType::where('type', ucfirst($data['what']))->first(); + $transactionType = TransactionType::where('type', ucfirst($data['type']))->first(); $submittedCurrencyId = $data['currency_id']; $data['foreign_amount'] = null; $data['foreign_currency_id'] = null; diff --git a/app/Rules/UniqueIban.php b/app/Rules/UniqueIban.php new file mode 100644 index 0000000000..39a760f391 --- /dev/null +++ b/app/Rules/UniqueIban.php @@ -0,0 +1,89 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Rules; + +use FireflyIII\Models\Account; +use Illuminate\Contracts\Validation\Rule; +use Illuminate\Support\Collection; + +/** + * Class UniqueIban + */ +class UniqueIban implements Rule +{ + /** @var Account */ + private $account; + + /** + * Create a new rule instance. + * + * @return void + */ + public function __construct(?Account $account) + { + $this->account = $account; + } + + /** + * Get the validation error message. + * + * @return string + */ + public function message() + { + return trans('validation.unique_iban_for_user'); + } + + /** + * Determine if the validation rule passes. + * + * @param string $attribute + * @param mixed $value + * + * @return bool + */ + public function passes($attribute, $value) + { + if (!auth()->check()) { + return true; // @codeCoverageIgnore + } + + $query = auth()->user()->accounts(); + if (!is_null($this->account)) { + $query->where('accounts.id', '!=', $this->account->id); + } + + /** @var Collection $accounts */ + $accounts = $query->get(); + + /** @var Account $account */ + foreach ($accounts as $account) { + if ($account->iban === $value) { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/app/Services/Internal/Destroy/BillDestroyService.php b/app/Services/Internal/Destroy/BillDestroyService.php new file mode 100644 index 0000000000..c9816a110d --- /dev/null +++ b/app/Services/Internal/Destroy/BillDestroyService.php @@ -0,0 +1,46 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Internal\Destroy; + +use Exception; +use FireflyIII\Models\Bill; + +/** + * Class BillDestroyService + */ +class BillDestroyService +{ + /** + * @param Bill $bill + */ + public function destroy(Bill $bill): void + { + try { + $bill->delete(); + } catch (Exception $e) { + // don't care. + } + } + +} \ No newline at end of file diff --git a/app/Services/Internal/Destroy/JournalDestroyService.php b/app/Services/Internal/Destroy/JournalDestroyService.php new file mode 100644 index 0000000000..869860a9ca --- /dev/null +++ b/app/Services/Internal/Destroy/JournalDestroyService.php @@ -0,0 +1,39 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Internal\Destroy; +use FireflyIII\Models\TransactionJournal; + +/** + * Class JournalDestroyService + */ +class JournalDestroyService +{ + /** + * @param TransactionJournal $journal + */ + public function destroy(TransactionJournal $journal): void { + + } + +} \ No newline at end of file diff --git a/app/Services/Internal/Support/BillServiceTrait.php b/app/Services/Internal/Support/BillServiceTrait.php new file mode 100644 index 0000000000..7269c82828 --- /dev/null +++ b/app/Services/Internal/Support/BillServiceTrait.php @@ -0,0 +1,62 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Internal\Support; +use FireflyIII\Models\Bill; +use FireflyIII\Models\Note; + +/** + * Trait BillServiceTrait + * + * @package FireflyIII\Services\Internal\Support + */ +trait BillServiceTrait +{ + /** + * @param Bill $bill + * @param string $note + * + * @return bool + */ + public function updateNote(Bill $bill, string $note): bool + { + if (0 === strlen($note)) { + $dbNote = $bill->notes()->first(); + if (null !== $dbNote) { + $dbNote->delete(); + } + + return true; + } + $dbNote = $bill->notes()->first(); + if (null === $dbNote) { + $dbNote = new Note(); + $dbNote->noteable()->associate($bill); + } + $dbNote->text = trim($note); + $dbNote->save(); + + return true; + } + +} \ No newline at end of file diff --git a/app/Services/Internal/Update/BillUpdateService.php b/app/Services/Internal/Update/BillUpdateService.php new file mode 100644 index 0000000000..366ecfbbb3 --- /dev/null +++ b/app/Services/Internal/Update/BillUpdateService.php @@ -0,0 +1,66 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Internal\Update; + +use FireflyIII\Models\Bill; +use FireflyIII\Services\Internal\Support\BillServiceTrait; + +/** + * Class BillUpdateService + */ +class BillUpdateService +{ + use BillServiceTrait; + + /** + * @param Bill $bill + * @param array $data + */ + public function update(Bill $bill, array $data): Bill + { + + $matchArray = explode(',', $data['match']); + $matchArray = array_unique($matchArray); + $match = join(',', $matchArray); + + $bill->name = $data['name']; + $bill->match = $match; + $bill->amount_min = $data['amount_min']; + $bill->amount_max = $data['amount_max']; + $bill->date = $data['date']; + $bill->repeat_freq = $data['repeat_freq']; + $bill->skip = $data['skip']; + $bill->automatch = $data['automatch']; + $bill->active = $data['active']; + $bill->save(); + + // update note: + if (isset($data['notes']) && null !== $data['notes']) { + $this->updateNote($bill, strval($data['notes'])); + } + + return $bill; + } + +} \ No newline at end of file