From 6a62f781e9e8e0a92f17466576ac666e50347ae4 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Dec 2024 17:32:03 +0100 Subject: [PATCH] Multi account piggy banks. --- .../Commands/Upgrade/UpgradeDatabase.php | 1 + .../Upgrade/UpgradeMultiPiggyBanks.php | 2 +- app/Factory/PiggyBankFactory.php | 30 +- .../PiggyBank/AmountController.php | 165 +++++--- .../Controllers/PiggyBank/EditController.php | 17 +- .../Controllers/PiggyBank/ShowController.php | 1 + app/Http/Requests/PiggyBankUpdateRequest.php | 78 +++- app/Models/Account.php | 5 +- .../PiggyBank/ModifiesPiggyBanks.php | 113 +++--- .../PiggyBank/PiggyBankRepository.php | 84 ++-- .../PiggyBankRepositoryInterface.php | 19 +- app/Support/Steam.php | 368 +++++++++--------- .../Actions/UpdatePiggybank.php | 5 + app/Transformers/PiggyBankTransformer.php | 2 +- app/User.php | 4 + config/notifications.php | 4 +- resources/views/list/piggy-bank-events.twig | 4 +- resources/views/piggy-banks/add-mobile.twig | 18 +- resources/views/piggy-banks/add.twig | 14 +- resources/views/piggy-banks/create.twig | 2 +- resources/views/piggy-banks/edit.twig | 5 +- .../views/piggy-banks/remove-mobile.twig | 18 +- resources/views/piggy-banks/remove.twig | 9 +- resources/views/piggy-banks/show.twig | 8 +- 24 files changed, 572 insertions(+), 404 deletions(-) diff --git a/app/Console/Commands/Upgrade/UpgradeDatabase.php b/app/Console/Commands/Upgrade/UpgradeDatabase.php index 5aea98ad90..8090c16c90 100644 --- a/app/Console/Commands/Upgrade/UpgradeDatabase.php +++ b/app/Console/Commands/Upgrade/UpgradeDatabase.php @@ -72,6 +72,7 @@ class UpgradeDatabase extends Command 'firefly-iii:create-group-memberships', 'firefly-iii:upgrade-group-information', 'firefly-iii:upgrade-currency-preferences', + 'firefly-iii:upgrade-multi-piggies', 'firefly-iii:correct-database', ]; $args = []; diff --git a/app/Console/Commands/Upgrade/UpgradeMultiPiggyBanks.php b/app/Console/Commands/Upgrade/UpgradeMultiPiggyBanks.php index e425277e1b..af1d492a82 100644 --- a/app/Console/Commands/Upgrade/UpgradeMultiPiggyBanks.php +++ b/app/Console/Commands/Upgrade/UpgradeMultiPiggyBanks.php @@ -93,7 +93,7 @@ class UpgradeMultiPiggyBanks extends Command { $this->repository->setUser($piggyBank->account->user); $this->accountRepository->setUser($piggyBank->account->user); - $repetition = $this->repository->getRepetition($piggyBank); + $repetition = $this->repository->getRepetition($piggyBank, true); $currency = $this->accountRepository->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrencyByUserGroup($piggyBank->account->user->userGroup); // update piggy bank to have a currency. diff --git a/app/Factory/PiggyBankFactory.php b/app/Factory/PiggyBankFactory.php index 84dbab3853..4f58734d05 100644 --- a/app/Factory/PiggyBankFactory.php +++ b/app/Factory/PiggyBankFactory.php @@ -42,12 +42,22 @@ class PiggyBankFactory public User $user { set(User $value) { $this->user = $value; + $this->currencyRepository->setUser($value); + $this->accountRepository->setUser($value); + $this->piggyBankRepository->setUser($value); } } private CurrencyRepositoryInterface $currencyRepository; private AccountRepositoryInterface $accountRepository; private PiggyBankRepositoryInterface $piggyBankRepository; + public function __construct() + { + $this->currencyRepository = app(CurrencyRepositoryInterface::class); + $this->accountRepository = app(AccountRepositoryInterface::class); + $this->piggyBankRepository = app(PiggyBankRepositoryInterface::class); + } + /** * Store a piggy bank or come back with an exception. * @@ -56,12 +66,7 @@ class PiggyBankFactory * @return PiggyBank */ public function store(array $data): PiggyBank { - $this->currencyRepository = app(CurrencyRepositoryInterface::class); - $this->accountRepository = app(AccountRepositoryInterface::class); - $this->piggyBankRepository = app(PiggyBankRepositoryInterface::class); - $this->currencyRepository->setUser($this->user); - $this->accountRepository->setUser($this->user); - $this->piggyBankRepository->setUser($this->user); + $piggyBankData =$data; // unset some fields @@ -202,14 +207,23 @@ class PiggyBankFactory } - private function linkToAccountIds(PiggyBank $piggyBank, array $accounts): void { + public function linkToAccountIds(PiggyBank $piggyBank, array $accounts): void { + $toBeLinked = []; /** @var array $info */ foreach($accounts as $info) { $account = $this->accountRepository->find((int)($info['account_id'] ?? 0)); if(null === $account) { continue; } - $piggyBank->accounts()->syncWithoutDetaching([$account->id => ['current_amount' => $info['current_amount'] ?? '0']]); + if(array_key_exists('current_amount',$info)) { + $toBeLinked[$account->id] = ['current_amount' => $info['current_amount']]; + //$piggyBank->accounts()->syncWithoutDetaching([$account->id => ['current_amount' => $info['current_amount'] ?? '0']]); + } + if(!array_key_exists('current_amount', $info)) { + $toBeLinked[$account->id] = []; + //$piggyBank->accounts()->syncWithoutDetaching([$account->id]); + } } + $piggyBank->accounts()->sync($toBeLinked); } } diff --git a/app/Http/Controllers/PiggyBank/AmountController.php b/app/Http/Controllers/PiggyBank/AmountController.php index d14446d291..857d377c26 100644 --- a/app/Http/Controllers/PiggyBank/AmountController.php +++ b/app/Http/Controllers/PiggyBank/AmountController.php @@ -26,12 +26,14 @@ namespace FireflyIII\Http\Controllers\PiggyBank; use Carbon\Carbon; use FireflyIII\Http\Controllers\Controller; +use FireflyIII\Models\Account; use FireflyIII\Models\PiggyBank; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use Illuminate\Contracts\View\Factory; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Log; use Illuminate\View\View; /** @@ -51,7 +53,7 @@ class AmountController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string)trans('firefly.piggyBanks')); + app('view')->share('title', (string) trans('firefly.piggyBanks')); app('view')->share('mainTitleIcon', 'fa-bullseye'); $this->piggyRepos = app(PiggyBankRepositoryInterface::class); @@ -69,16 +71,26 @@ class AmountController extends Controller */ public function add(PiggyBank $piggyBank) { - $leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, today(config('app.timezone'))); - $savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank); - $maxAmount = $leftOnAccount; - if (0 !== bccomp($piggyBank->target_amount, '0')) { - $leftToSave = bcsub($piggyBank->target_amount, $savedSoFar); - $maxAmount = min($leftOnAccount, $leftToSave); + $accounts = []; + $total = '0'; + $totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank); + $leftToSave = bcsub($piggyBank->target_amount, $totalSaved); + foreach ($piggyBank->accounts as $account) { + $leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, today(config('app.timezone'))->endOfDay()); + $savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account); + $maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftToSave : min($leftOnAccount, $leftToSave); + $accounts[] = [ + 'account' => $account, + 'left_on_account' => $leftOnAccount, + 'saved_so_far' => $savedSoFar, + 'left_to_save' => $leftToSave, + 'max_amount' => $maxAmount, + ]; + $total = bcadd($total, $leftOnAccount); } - $currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency(); + $total = (float) $total; // intentional float. - return view('piggy-banks.add', compact('piggyBank', 'maxAmount', 'currency')); + return view('piggy-banks.add', compact('piggyBank', 'accounts', 'total')); } /** @@ -89,18 +101,24 @@ class AmountController extends Controller public function addMobile(PiggyBank $piggyBank) { /** @var Carbon $date */ - $date = session('end', today(config('app.timezone'))); - $leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $date); - $savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank); - $maxAmount = $leftOnAccount; - - if (0 !== bccomp($piggyBank->target_amount, '0')) { - $leftToSave = bcsub($piggyBank->target_amount, $savedSoFar); - $maxAmount = min($leftOnAccount, $leftToSave); + $date = session('end', today(config('app.timezone'))); + $accounts = []; + $total = '0'; + foreach ($piggyBank->accounts as $account) { + $leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date); + $savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account); + $leftToSave = bcsub($piggyBank->target_amount, $savedSoFar); + $accounts[] = [ + 'account' => $account, + 'left_on_account' => $leftOnAccount, + 'saved_so_far' => $savedSoFar, + 'left_to_save' => $leftToSave, + 'max_amount' => 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave), + ]; + $total = bcadd($total, $leftOnAccount); } - $currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency(); - return view('piggy-banks.add-mobile', compact('piggyBank', 'maxAmount', 'currency')); + return view('piggy-banks.add-mobile', compact('piggyBank', 'total', 'accounts')); } /** @@ -108,32 +126,47 @@ class AmountController extends Controller */ public function postAdd(Request $request, PiggyBank $piggyBank): RedirectResponse { - $amount = $request->get('amount') ?? '0'; - $currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency(); - // if amount is negative, make positive and continue: - if (-1 === bccomp($amount, '0')) { - $amount = bcmul($amount, '-1'); + $data = $request->all(); + $amounts = $data['amount'] ?? []; + $total = '0'; + Log::debug('Start with loop.'); + /** @var Account $account */ + foreach ($piggyBank->accounts as $account) { + $amount = (string) ($amounts[$account->id] ?? '0'); + if ('' === $amount || 0 === bccomp($amount, '0')) { + continue; + } + if (-1 === bccomp($amount, '0')) { + $amount = bcmul($amount, '-1'); + } + + // small check to see if the $amount is not more than the total "left to save" value + $currentAmount = $this->piggyRepos->getCurrentAmount($piggyBank); + $leftToSave = 0 === bccomp($piggyBank->target_amount, '0') ? '0' : bcsub($piggyBank->target_amount, $currentAmount); + if (bccomp($amount, $leftToSave) > 0 && 0 !== bccomp($leftToSave, '0')) { + Log::debug(sprintf('Amount "%s" is more than left to save "%s". Using left to save.', $amount, $leftToSave)); + $amount = $leftToSave; + } + + $canAddAmount = $this->piggyRepos->canAddAmount($piggyBank, $account, $amount); + if ($canAddAmount) { + $this->piggyRepos->addAmount($piggyBank, $account, $amount); + $total = bcadd($total, $amount); + } + $piggyBank->refresh(); } - if ($this->piggyRepos->canAddAmount($piggyBank, $amount)) { - $this->piggyRepos->addAmount($piggyBank, $amount); - session()->flash( - 'success', - (string)trans( - 'firefly.added_amount_to_piggy', - ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name] - ) - ); + if (0 !== bccomp($total, '0')) { + session()->flash('success', (string) trans('firefly.added_amount_to_piggy', ['amount' => app('amount')->formatAnything($piggyBank->transactionCurrency, $total, false), 'name' => $piggyBank->name])); app('preferences')->mark(); return redirect(route('piggy-banks.index')); } - - app('log')->error('Cannot add '.$amount.' because canAddAmount returned false.'); + app('log')->error(sprintf('Cannot add %s because canAddAmount returned false.', $total)); session()->flash( 'error', - (string)trans( + (string) trans( 'firefly.cannot_add_amount_piggy', - ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)] + ['amount' => app('amount')->formatAnything($piggyBank->transactionCurrency, $total, false), 'name' => e($piggyBank->name)] ) ); @@ -145,32 +178,43 @@ class AmountController extends Controller */ public function postRemove(Request $request, PiggyBank $piggyBank): RedirectResponse { - $amount = $request->get('amount') ?? '0'; - $currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency(); - // if amount is negative, make positive and continue: - if (-1 === bccomp($amount, '0')) { - $amount = bcmul($amount, '-1'); + $amounts = $request->get('amount') ?? []; + if (!is_array($amounts)) { + $amounts = []; } - if ($this->piggyRepos->canRemoveAmount($piggyBank, $amount)) { - $this->piggyRepos->removeAmount($piggyBank, $amount); + $total = '0'; + /** @var Account $account */ + foreach ($piggyBank->accounts as $account) { + $amount = (string) ($amounts[$account->id] ?? '0'); + if ('' === $amount || 0 === bccomp($amount, '0')) { + continue; + } + if (-1 === bccomp($amount, '0')) { + $amount = bcmul($amount, '-1'); + } + if ($this->piggyRepos->canRemoveAmount($piggyBank, $account, $amount)) { + $this->piggyRepos->removeAmount($piggyBank, $account, $amount); + $total = bcadd($total, $amount); + } + } + if (0 !== bccomp($total, '0')) { session()->flash( 'success', - (string)trans( + (string) trans( 'firefly.removed_amount_from_piggy', - ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name] + ['amount' => app('amount')->formatAnything($piggyBank->transactionCurrency, $total, false), 'name' => $piggyBank->name] ) ); app('preferences')->mark(); return redirect(route('piggy-banks.index')); } - $amount = (string)$request->get('amount'); session()->flash( 'error', - (string)trans( + (string) trans( 'firefly.cannot_remove_from_piggy', - ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)] + ['amount' => app('amount')->formatAnything($piggyBank->transactionCurrency, $total, false), 'name' => e($piggyBank->name)] ) ); @@ -184,10 +228,14 @@ class AmountController extends Controller */ public function remove(PiggyBank $piggyBank) { - $repetition = $this->piggyRepos->getRepetition($piggyBank); - $currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency(); - - return view('piggy-banks.remove', compact('piggyBank', 'repetition', 'currency')); + $accounts = []; + foreach ($piggyBank->accounts as $account) { + $accounts[] = [ + 'account' => $account, + 'saved_so_far' => $this->piggyRepos->getCurrentAmount($piggyBank, $account), + ]; + } + return view('piggy-banks.remove', compact('piggyBank', 'accounts')); } /** @@ -197,9 +245,14 @@ class AmountController extends Controller */ public function removeMobile(PiggyBank $piggyBank) { - $repetition = $this->piggyRepos->getRepetition($piggyBank); - $currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency(); + $accounts = []; + foreach ($piggyBank->accounts as $account) { + $accounts[] = [ + 'account' => $account, + 'saved_so_far' => $this->piggyRepos->getCurrentAmount($piggyBank, $account), + ]; + } - return view('piggy-banks.remove-mobile', compact('piggyBank', 'repetition', 'currency')); + return view('piggy-banks.remove-mobile', compact('piggyBank', 'accounts')); } } diff --git a/app/Http/Controllers/PiggyBank/EditController.php b/app/Http/Controllers/PiggyBank/EditController.php index 6df3ec3101..0a3d8a377b 100644 --- a/app/Http/Controllers/PiggyBank/EditController.php +++ b/app/Http/Controllers/PiggyBank/EditController.php @@ -79,22 +79,21 @@ class EditController extends Controller // Flash some data to fill the form. $targetDate = $piggyBank->target_date?->format('Y-m-d'); $startDate = $piggyBank->start_date?->format('Y-m-d'); - $currency = $this->accountRepository->getAccountCurrency($piggyBank->account); - if (null === $currency) { - $currency = app('amount')->getDefaultCurrency(); - } $preFilled = [ 'name' => $piggyBank->name, - 'account_id' => $piggyBank->account_id, - 'targetamount' => app('steam')->bcround($piggyBank->target_amount, $currency->decimal_places), - 'targetdate' => $targetDate, - 'startdate' => $startDate, + 'target_amount' => app('steam')->bcround($piggyBank->target_amount, $piggyBank->transactionCurrency->decimal_places), + 'target_date' => $targetDate, + 'start_date' => $startDate, + 'accounts' => [], 'object_group' => null !== $piggyBank->objectGroups->first() ? $piggyBank->objectGroups->first()->title : '', 'notes' => null === $note ? '' : $note->text, ]; + foreach($piggyBank->accounts as $account) { + $preFilled['accounts'][] = $account->id; + } if (0 === bccomp($piggyBank->target_amount, '0')) { - $preFilled['targetamount'] = ''; + $preFilled['target_amount'] = ''; } session()->flash('preFilled', $preFilled); diff --git a/app/Http/Controllers/PiggyBank/ShowController.php b/app/Http/Controllers/PiggyBank/ShowController.php index 2fd69286ae..b3bc52bc1c 100644 --- a/app/Http/Controllers/PiggyBank/ShowController.php +++ b/app/Http/Controllers/PiggyBank/ShowController.php @@ -83,6 +83,7 @@ class ShowController extends Controller $subTitle = $piggyBank->name; $attachments = $this->piggyRepos->getAttachments($piggyBank); + return view('piggy-banks.show', compact('piggyBank', 'events', 'subTitle', 'piggy', 'attachments')); } } diff --git a/app/Http/Requests/PiggyBankUpdateRequest.php b/app/Http/Requests/PiggyBankUpdateRequest.php index 7f10011678..5c2192ffdd 100644 --- a/app/Http/Requests/PiggyBankUpdateRequest.php +++ b/app/Http/Requests/PiggyBankUpdateRequest.php @@ -24,6 +24,8 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; use FireflyIII\Models\PiggyBank; +use FireflyIII\Models\TransactionCurrency; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; @@ -44,15 +46,22 @@ class PiggyBankUpdateRequest extends FormRequest */ public function getPiggyBankData(): array { - return [ + $accounts = $this->get('accounts'); + $data = [ 'name' => $this->convertString('name'), - 'startdate' => $this->getCarbonDate('startdate'), - 'account_id' => $this->convertInteger('account_id'), - 'targetamount' => trim($this->convertString('targetamount')), - 'targetdate' => $this->getCarbonDate('targetdate'), + 'start_date' => $this->getCarbonDate('start_date'), + 'target_amount' => trim($this->convertString('target_amount')), + 'target_date' => $this->getCarbonDate('target_date'), 'notes' => $this->stringWithNewlines('notes'), 'object_group_title' => $this->convertString('object_group'), ]; + if (!is_array($accounts)) { + $accounts = []; + } + foreach ($accounts as $item) { + $data['accounts'][] = ['account_id' => (int) $item]; + } + return $data; } /** @@ -64,21 +73,62 @@ class PiggyBankUpdateRequest extends FormRequest $piggy = $this->route()->parameter('piggyBank'); return [ - 'name' => sprintf('required|min:1|max:255|uniquePiggyBankForUser:%d', $piggy->id), - 'account_id' => 'required|belongsToUser:accounts', - 'targetamount' => ['nullable', new IsValidPositiveAmount()], - 'startdate' => 'date', - 'targetdate' => 'date|nullable', - 'order' => 'integer|max:32768|min:1', - 'object_group' => 'min:0|max:255', - 'notes' => 'min:1|max:32768|nullable', + 'name' => sprintf('required|min:1|max:255|uniquePiggyBankForUser:%d', $piggy->id), + 'accounts' => 'required|array', + 'accounts.*' => 'required|belongsToUser:accounts', + 'target_amount' => ['nullable', new IsValidPositiveAmount()], + 'start_date' => 'date', + 'target_date' => 'date|nullable', + 'order' => 'integer|max:32768|min:1', + 'object_group' => 'min:0|max:255', + 'notes' => 'min:1|max:32768|nullable', ]; } public function withValidator(Validator $validator): void - { + { // need to have more than one account. + // accounts need to have the same currency or be multi-currency(?). + $validator->after( + function (Validator $validator): void { + // validate start before end only if both are there. + $data = $validator->getData(); + $currency = $this->getCurrencyFromData($data); + if (array_key_exists('accounts', $data) && is_array($data['accounts'])) { + $repository = app(AccountRepositoryInterface::class); + $types = config('firefly.piggy_bank_account_types'); + foreach ($data['accounts'] as $value) { + $accountId = (int) $value; + $account = $repository->find($accountId); + if (null !== $account) { + // check currency here. + $accountCurrency = $repository->getAccountCurrency($account); + $isMultiCurrency = $repository->getMetaValue($account, 'is_multi_currency'); + if ($accountCurrency->id !== $currency->id && 'true' !== $isMultiCurrency) { + $validator->errors()->add('accounts', trans('validation.invalid_account_currency')); + } + $type = $account->accountType->type; + if (!in_array($type, $types, true)) { + $validator->errors()->add('accounts', trans('validation.invalid_account_type')); + } + } + } + } + } + ); + + if ($validator->fails()) { Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); } } + private function getCurrencyFromData(array $data): TransactionCurrency + { + $currencyId = (int) ($data['transaction_currency_id'] ?? 0); + $currency = TransactionCurrency::find($currencyId); + if (null === $currency) { + return app('amount')->getDefaultCurrency(); + } + + return $currency; + } } diff --git a/app/Models/Account.php b/app/Models/Account.php index fe523e2fe4..f77143d846 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -32,6 +32,7 @@ use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\Relations\MorphToMany; @@ -159,9 +160,9 @@ class Account extends Model return $this->morphToMany(ObjectGroup::class, 'object_groupable'); } - public function piggyBanks(): HasMany + public function piggyBanks(): BelongsToMany { - return $this->hasMany(PiggyBank::class); + return $this->belongsToMany(PiggyBank::class); } public function scopeAccountTypeIn(EloquentBuilder $query, array $types): void diff --git a/app/Repositories/PiggyBank/ModifiesPiggyBanks.php b/app/Repositories/PiggyBank/ModifiesPiggyBanks.php index 61f21c39d0..b7c53c9ea2 100644 --- a/app/Repositories/PiggyBank/ModifiesPiggyBanks.php +++ b/app/Repositories/PiggyBank/ModifiesPiggyBanks.php @@ -27,12 +27,14 @@ namespace FireflyIII\Repositories\PiggyBank; use FireflyIII\Events\Model\PiggyBank\ChangedAmount; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Factory\PiggyBankFactory; +use FireflyIII\Models\Account; use FireflyIII\Models\Note; use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBankRepetition; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups; use FireflyIII\Support\Facades\Amount; +use Illuminate\Support\Facades\Log; /** * Trait ModifiesPiggyBanks @@ -55,30 +57,42 @@ trait ModifiesPiggyBanks } } - public function removeAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool + public function removeAmount(PiggyBank $piggyBank,Account $account, string $amount, ?TransactionJournal $journal = null): bool { - $repetition = $this->getRepetition($piggyBank); - if (null === $repetition) { - return false; - } - $repetition->current_amount = bcsub($repetition->current_amount, $amount); - $repetition->save(); + $currentAmount = $this->getCurrentAmount($piggyBank, $account); + $pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot; + $pivot->current_amount = bcsub($currentAmount, $amount); + $pivot->save(); - app('log')->debug('addAmount [a]: Trigger change for negative amount.'); + app('log')->debug('removeAmount [a]: Trigger change for negative amount.'); event(new ChangedAmount($piggyBank, bcmul($amount, '-1'), $journal, null)); return true; } - public function addAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool + public function removeAmountFromAll(PiggyBank $piggyBank, string $amount): void { - $repetition = $this->getRepetition($piggyBank); - if (null === $repetition) { - return false; + foreach($piggyBank->accounts as $account) { + $current = $account->pivot->current_amount; + // if this account contains more than the amount, remove the amount and return. + if (1 === bccomp($current, $amount)) { + $this->removeAmount($piggyBank, $account, $amount); + return; + } + // if this account contains less than the amount, remove the current amount, update the amount and continue. + if (bccomp($current, $amount) < 1) { + $this->removeAmount($piggyBank, $account, $current); + $amount = bcsub($amount, $current); + } } - $currentAmount = $repetition->current_amount ?? '0'; - $repetition->current_amount = bcadd($currentAmount, $amount); - $repetition->save(); + } + + public function addAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool + { + $currentAmount = $this->getCurrentAmount($piggyBank, $account); + $pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot; + $pivot->current_amount = bcadd($currentAmount, $amount); + $pivot->save(); app('log')->debug('addAmount [b]: Trigger change for positive amount.'); event(new ChangedAmount($piggyBank, $amount, $journal, null)); @@ -86,37 +100,36 @@ trait ModifiesPiggyBanks return true; } - public function canAddAmount(PiggyBank $piggyBank, string $amount): bool + public function canAddAmount(PiggyBank $piggyBank, Account $account, string $amount): bool { - $today = today(config('app.timezone')); - $leftOnAccount = $this->leftOnAccount($piggyBank, $today); - $savedSoFar = $this->getRepetition($piggyBank)->current_amount; + Log::debug('Now in canAddAmount'); + $today = today(config('app.timezone'))->endOfDay(); + $leftOnAccount = $this->leftOnAccount($piggyBank, $account, $today); + $savedSoFar = $this->getCurrentAmount($piggyBank); $maxAmount = $leftOnAccount; - $leftToSave = null; + + app('log')->debug(sprintf('Left on account: %s on %s', $leftOnAccount, $today->format('Y-m-d H:i:s'))); + app('log')->debug(sprintf('Saved so far: %s', $savedSoFar)); + + if (0 !== bccomp($piggyBank->target_amount, '0')) { $leftToSave = bcsub($piggyBank->target_amount, $savedSoFar); $maxAmount = 1 === bccomp($leftOnAccount, $leftToSave) ? $leftToSave : $leftOnAccount; + app('log')->debug(sprintf('Left to save: %s', $leftToSave)); + app('log')->debug(sprintf('Maximum amount: %s', $maxAmount)); } $compare = bccomp($amount, $maxAmount); $result = $compare <= 0; - app('log')->debug(sprintf('Left on account: %s on %s', $leftOnAccount, $today->format('Y-m-d'))); - app('log')->debug(sprintf('Saved so far: %s', $savedSoFar)); - app('log')->debug(sprintf('Left to save: %s', $leftToSave)); - app('log')->debug(sprintf('Maximum amount: %s', $maxAmount)); - app('log')->debug(sprintf('Compare <= 0? %d, so %s', $compare, var_export($result, true))); + app('log')->debug(sprintf('Compare <= 0? %d, so canAddAmount is %s', $compare, var_export($result, true))); return $result; } - public function canRemoveAmount(PiggyBank $piggyBank, string $amount): bool + public function canRemoveAmount(PiggyBank $piggyBank, Account $account, string $amount): bool { - $repetition = $this->getRepetition($piggyBank); - if (null === $repetition) { - return false; - } - $savedSoFar = $repetition->current_amount; + $savedSoFar = $this->getCurrentAmount($piggyBank, $account); return bccomp($amount, $savedSoFar) <= 0; } @@ -244,17 +257,24 @@ trait ModifiesPiggyBanks $this->setOrder($piggyBank, $newOrder); } + // update the accounts + $factory = new PiggyBankFactory(); + $factory->user = $this->user; + $factory->linkToAccountIds($piggyBank, $data['accounts']); + + // if the piggy bank is now smaller than the current relevant rep, // remove money from the rep. - $repetition = $this->getRepetition($piggyBank); - if (null !== $repetition && $repetition->current_amount > $piggyBank->target_amount && 0 !== bccomp($piggyBank->target_amount, '0')) { - $difference = bcsub($piggyBank->target_amount, $repetition->current_amount); + $currentAmount = $this->getCurrentAmount($piggyBank); + if (1 === bccomp($currentAmount, '100') && 0 !== bccomp($piggyBank->target_amount, '0')) { + $difference = bcsub($piggyBank->target_amount, $currentAmount); // an amount will be removed, create "negative" event: event(new ChangedAmount($piggyBank, $difference, null, null)); - $repetition->current_amount = $piggyBank->target_amount; - $repetition->save(); + // question is, from which account(s) to remove the difference? + // solution: just start from the top until there is no more money left to remove. + $this->removeAmountFromAll($piggyBank, app('steam')->positive($difference)); } // update using name: @@ -295,22 +315,19 @@ trait ModifiesPiggyBanks if (array_key_exists('name', $data) && '' !== $data['name']) { $piggyBank->name = $data['name']; } - if (array_key_exists('account_id', $data) && 0 !== $data['account_id']) { - $piggyBank->account_id = (int)$data['account_id']; + if (array_key_exists('target_amount', $data) && '' !== $data['target_amount']) { + $piggyBank->target_amount = $data['target_amount']; } - if (array_key_exists('targetamount', $data) && '' !== $data['targetamount']) { - $piggyBank->target_amount = $data['targetamount']; - } - if (array_key_exists('targetamount', $data) && '' === $data['targetamount']) { + if (array_key_exists('target_amount', $data) && '' === $data['target_amount']) { $piggyBank->target_amount = '0'; } - if (array_key_exists('targetdate', $data) && '' !== $data['targetdate']) { - $piggyBank->target_date = $data['targetdate']; - $piggyBank->target_date_tz = $data['targetdate']?->format('e'); + if (array_key_exists('target_date', $data) && '' !== $data['target_date']) { + $piggyBank->target_date = $data['target_date']; + $piggyBank->target_date_tz = $data['target_date']?->format('e'); } - if (array_key_exists('startdate', $data)) { - $piggyBank->start_date = $data['startdate']; - $piggyBank->start_date_tz = $data['targetdate']?->format('e'); + if (array_key_exists('start_date', $data)) { + $piggyBank->start_date = $data['start_date']; + $piggyBank->start_date_tz = $data['target_date']?->format('e'); } $piggyBank->save(); diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php index 0d9943b5c3..7d7c8c3e2b 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepository.php +++ b/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\PiggyBank; use Carbon\Carbon; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Factory\PiggyBankFactory; +use FireflyIII\Models\Account; use FireflyIII\Models\Attachment; use FireflyIII\Models\Note; use FireflyIII\Models\PiggyBank; @@ -95,7 +96,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface public function getAttachments(PiggyBank $piggyBank): Collection { - $set = $piggyBank->attachments()->get(); + $set = $piggyBank->attachments()->get(); /** @var \Storage $disk */ $disk = \Storage::disk('upload'); @@ -114,22 +115,28 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface /** * Get current amount saved in piggy bank. */ - public function getCurrentAmount(PiggyBank $piggyBank): string + public function getCurrentAmount(PiggyBank $piggyBank, ?Account $account = null): string { $sum = '0'; - foreach ($piggyBank->accounts as $account) { - $amount = (string) $account->pivot->current_amount; + foreach ($piggyBank->accounts as $current) { + if(null !== $account && $account->id !== $current->id) { + continue; + } + $amount = (string) $current->pivot->current_amount; $amount = '' === $amount ? '0' : $amount; $sum = bcadd($sum, $amount); } + Log::debug(sprintf('Current amount in piggy bank #%d ("%s") is %s', $piggyBank->id, $piggyBank->name, $sum)); return $sum; } - public function getRepetition(PiggyBank $piggyBank): ?PiggyBankRepetition + public function getRepetition(PiggyBank $piggyBank, bool $overrule = false): ?PiggyBankRepetition { - throw new FireflyException('[b] Piggy bank repetitions are EOL.'); - + if (false === $overrule) { + throw new FireflyException('[b] Piggy bank repetitions are EOL.'); + } + Log::warning('Piggy bank repetitions are EOL.'); return $piggyBank->piggyBankRepetitions()->first(); } @@ -148,15 +155,15 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface throw new FireflyException('[c] Piggy bank repetitions are EOL.'); app('log')->debug(sprintf('Now in getExactAmount(%d, %d, %d)', $piggyBank->id, $repetition->id, $journal->id)); - $operator = null; - $currency = null; + $operator = null; + $currency = null; /** @var JournalRepositoryInterface $journalRepost */ - $journalRepost = app(JournalRepositoryInterface::class); + $journalRepost = app(JournalRepositoryInterface::class); $journalRepost->setUser($this->user); /** @var AccountRepositoryInterface $accountRepos */ - $accountRepos = app(AccountRepositoryInterface::class); + $accountRepos = app(AccountRepositoryInterface::class); $accountRepos->setUser($this->user); $defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup); @@ -165,10 +172,10 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface app('log')->debug(sprintf('Piggy bank #%d currency is %s', $piggyBank->id, $piggyBankCurrency->code)); /** @var Transaction $source */ - $source = $journal->transactions()->with(['account'])->where('amount', '<', 0)->first(); + $source = $journal->transactions()->with(['account'])->where('amount', '<', 0)->first(); /** @var Transaction $destination */ - $destination = $journal->transactions()->with(['account'])->where('amount', '>', 0)->first(); + $destination = $journal->transactions()->with(['account'])->where('amount', '>', 0)->first(); // matches source, which means amount will be removed from piggy: if ($source->account_id === $piggyBank->account_id) { @@ -190,7 +197,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface } // currency of the account + the piggy bank currency are almost the same. // which amount from the transaction matches? - $amount = null; + $amount = null; if ((int) $source->transaction_currency_id === $currency->id) { app('log')->debug('Use normal amount'); $amount = app('steam')->{$operator}($source->amount); // @phpstan-ignore-line @@ -206,8 +213,8 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface } app('log')->debug(sprintf('The currency is %s and the amount is %s', $currency->code, $amount)); - $room = bcsub($piggyBank->target_amount, $repetition->current_amount); - $compare = bcmul($repetition->current_amount, '-1'); + $room = bcsub($piggyBank->target_amount, $repetition->current_amount); + $compare = bcmul($repetition->current_amount, '-1'); if (0 === bccomp($piggyBank->target_amount, '0')) { // amount is zero? then the "room" is positive amount of we wish to add or remove. @@ -239,7 +246,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface return (string) $amount; } - public function setUser(null|Authenticatable|User $user): void + public function setUser(null | Authenticatable | User $user): void { if ($user instanceof User) { $this->user = $user; @@ -264,12 +271,12 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface { $currency = app('amount')->getDefaultCurrency(); - $set = $this->getPiggyBanks(); + $set = $this->getPiggyBanks(); /** @var PiggyBank $piggy */ foreach ($set as $piggy) { $currentAmount = $this->getRepetition($piggy)->current_amount ?? '0'; - $piggy->name = $piggy->name.' ('.app('amount')->formatAnything($currency, $currentAmount, false).')'; + $piggy->name = $piggy->name . ' (' . app('amount')->formatAnything($currency, $currentAmount, false) . ')'; } return $set; @@ -278,16 +285,15 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface public function getPiggyBanks(): Collection { return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') - ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') - ->where('accounts.user_id', auth()->user()->id) - ->with( - [ - 'account', - 'objectGroups', - ] - ) - ->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']) - ; + ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') + ->where('accounts.user_id', auth()->user()->id) + ->with( + [ + 'account', + 'objectGroups', + ] + ) + ->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*']); } /** @@ -320,21 +326,22 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface /** * Get for piggy account what is left to put in piggies. */ - public function leftOnAccount(PiggyBank $piggyBank, Carbon $date): string + public function leftOnAccount(PiggyBank $piggyBank, Account $account, Carbon $date): string { - $balance = app('steam')->balanceIgnoreVirtual($piggyBank->account, $date); + Log::debug(sprintf('leftOnAccount("%s","%s","%s")', $piggyBank->name, $account->name, $date->format('Y-m-d H:i:s'))); + $balance = app('steam')->balanceConvertedIgnoreVirtual($account, $date, $piggyBank->transactionCurrency); + Log::debug(sprintf('Balance is: %s', $balance)); /** @var Collection $piggies */ - $piggies = $piggyBank->account->piggyBanks; + $piggies = $account->piggyBanks; /** @var PiggyBank $current */ foreach ($piggies as $current) { - $repetition = $this->getRepetition($current); - if (null !== $repetition) { - $balance = bcsub($balance, $repetition->current_amount); - } + $amount = $this->getCurrentAmount($current, $account); + $balance = bcsub($balance, $amount); + Log::debug(sprintf('Piggy bank: #%d with amount %s, balance is now %s', $current->id, $amount, $balance)); } - + Log::debug(sprintf('Final balance is: %s', $balance)); return $balance; } @@ -345,8 +352,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface $search->whereLike('piggy_banks.name', sprintf('%%%s%%', $query)); } $search->orderBy('piggy_banks.order', 'ASC') - ->orderBy('piggy_banks.name', 'ASC') - ; + ->orderBy('piggy_banks.name', 'ASC'); return $search->take($limit)->get(); } diff --git a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php index b1168bdaa0..29338df6ee 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php +++ b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php @@ -25,6 +25,7 @@ namespace FireflyIII\Repositories\PiggyBank; use Carbon\Carbon; use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\Account; use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBankRepetition; use FireflyIII\Models\TransactionJournal; @@ -37,13 +38,13 @@ use Illuminate\Support\Collection; */ interface PiggyBankRepositoryInterface { - public function addAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool; + public function addAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool; public function addAmountToRepetition(PiggyBankRepetition $repetition, string $amount, TransactionJournal $journal): void; - public function canAddAmount(PiggyBank $piggyBank, string $amount): bool; + public function canAddAmount(PiggyBank $piggyBank, Account $account, string $amount): bool; - public function canRemoveAmount(PiggyBank $piggyBank, string $amount): bool; + public function canRemoveAmount(PiggyBank $piggyBank, Account $account, string $amount): bool; /** * Destroy piggy bank. @@ -68,7 +69,10 @@ interface PiggyBankRepositoryInterface /** * Get current amount saved in piggy bank. */ - public function getCurrentAmount(PiggyBank $piggyBank): string; + public function getCurrentAmount(PiggyBank $piggyBank, ?Account $account = null): string; + /** + * Get current amount saved in piggy bank. + */ /** * Get all events. @@ -97,7 +101,7 @@ interface PiggyBankRepositoryInterface */ public function getPiggyBanksWithAmount(): Collection; - public function getRepetition(PiggyBank $piggyBank): ?PiggyBankRepetition; + public function getRepetition(PiggyBank $piggyBank, bool $overrule = false): ?PiggyBankRepetition; /** * Returns the suggested amount the user should save per month, or "". @@ -107,9 +111,10 @@ interface PiggyBankRepositoryInterface /** * Get for piggy account what is left to put in piggies. */ - public function leftOnAccount(PiggyBank $piggyBank, Carbon $date): string; + public function leftOnAccount(PiggyBank $piggyBank,Account $account, Carbon $date): string; - public function removeAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool; + public function removeAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool; + public function removeAmountFromAll(PiggyBank $piggyBank, string $amount): void; public function removeObjectGroup(PiggyBank $piggyBank): PiggyBank; diff --git a/app/Support/Steam.php b/app/Support/Steam.php index a08d243652..fba143a4fb 100644 --- a/app/Support/Steam.php +++ b/app/Support/Steam.php @@ -44,34 +44,52 @@ class Steam */ public function balanceIgnoreVirtual(Account $account, Carbon $date): string { - // Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__)); + throw new FireflyException('Deprecated method balanceIgnoreVirtual.'); /** @var AccountRepositoryInterface $repository */ - $repository = app(AccountRepositoryInterface::class); + $repository = app(AccountRepositoryInterface::class); $repository->setUser($account->user); - $currencyId = (int) $repository->getMetaValue($account, 'currency_id'); - $transactions = $account->transactions() - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->where('transactions.transaction_currency_id', $currencyId) - ->get(['transactions.amount'])->toArray() - ; - $nativeBalance = $this->sumTransactions($transactions, 'amount'); + $currencyId = (int) $repository->getMetaValue($account, 'currency_id'); + $transactions = $account->transactions() + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->where('transactions.transaction_currency_id', $currencyId) + ->get(['transactions.amount'])->toArray(); + $nativeBalance = $this->sumTransactions($transactions, 'amount'); // get all balances in foreign currency: - $transactions = $account->transactions() - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->where('transactions.foreign_currency_id', $currencyId) - ->where('transactions.transaction_currency_id', '!=', $currencyId) - ->get(['transactions.foreign_amount'])->toArray() - ; + $transactions = $account->transactions() + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->where('transactions.foreign_currency_id', $currencyId) + ->where('transactions.transaction_currency_id', '!=', $currencyId) + ->get(['transactions.foreign_amount'])->toArray(); $foreignBalance = $this->sumTransactions($transactions, 'foreign_amount'); return bcadd($nativeBalance, $foreignBalance); } + + public function balanceConvertedIgnoreVirtual(Account $account, Carbon $date, TransactionCurrency $currency): string + { + $balance = $this->balanceConverted($account, $date, $currency); + $virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance; + + // currency of account + $repository = app(AccountRepositoryInterface::class); + $repository->setUser($account->user); + $accountCurrency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup); + if ($accountCurrency->id !== $currency->id && 0 !== bccomp($virtual, '0')) { + // convert amount to given currency. + Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__)); + $converter = new ExchangeRateConverter(); + $virtual = $converter->convert($accountCurrency, $currency, $date, $virtual); + } + + return bcsub($balance, $virtual); + } + public function sumTransactions(array $transactions, string $key): string { $sum = '0'; @@ -96,7 +114,7 @@ class Steam public function balanceInRange(Account $account, Carbon $start, Carbon $end, ?TransactionCurrency $currency = null): array { // Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__)); - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($account->id); $cache->addProperty('balance-in-range'); $cache->addProperty(null !== $currency ? $currency->id : 0); @@ -108,42 +126,41 @@ class Steam $start->subDay(); $end->addDay(); - $balances = []; - $formatted = $start->format('Y-m-d'); - $startBalance = $this->balance($account, $start, $currency); + $balances = []; + $formatted = $start->format('Y-m-d'); + $startBalance = $this->balance($account, $start, $currency); $balances[$formatted] = $startBalance; if (null === $currency) { $repository = app(AccountRepositoryInterface::class); $repository->setUser($account->user); - $currency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup); + $currency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup); } - $currencyId = $currency->id; + $currencyId = $currency->id; $start->addDay(); // query! - $set = $account->transactions() - ->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') - ->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d 23:59:59')) - ->groupBy('transaction_journals.date') - ->groupBy('transactions.transaction_currency_id') - ->groupBy('transactions.foreign_currency_id') - ->orderBy('transaction_journals.date', 'ASC') - ->whereNull('transaction_journals.deleted_at') - ->get( - [ // @phpstan-ignore-line - 'transaction_journals.date', - 'transactions.transaction_currency_id', - \DB::raw('SUM(transactions.amount) AS modified'), - 'transactions.foreign_currency_id', - \DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'), - ] - ) - ; + $set = $account->transactions() + ->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d 23:59:59')) + ->groupBy('transaction_journals.date') + ->groupBy('transactions.transaction_currency_id') + ->groupBy('transactions.foreign_currency_id') + ->orderBy('transaction_journals.date', 'ASC') + ->whereNull('transaction_journals.deleted_at') + ->get( + [ // @phpstan-ignore-line + 'transaction_journals.date', + 'transactions.transaction_currency_id', + \DB::raw('SUM(transactions.amount) AS modified'), + 'transactions.foreign_currency_id', + \DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'), + ] + ); - $currentBalance = $startBalance; + $currentBalance = $startBalance; /** @var Transaction $entry */ foreach ($set as $entry) { @@ -173,7 +190,7 @@ class Steam public function balanceByTransactions(Account $account, Carbon $date, ?TransactionCurrency $currency): array { - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($account->id); $cache->addProperty('balance-by-transactions'); $cache->addProperty($date); @@ -182,13 +199,12 @@ class Steam return $cache->get(); } - $query = $account->transactions() - ->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') - ->orderBy('transaction_journals.date', 'desc') - ->orderBy('transaction_journals.order', 'asc') - ->orderBy('transaction_journals.description', 'desc') - ->orderBy('transactions.amount', 'desc') - ; + $query = $account->transactions() + ->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->orderBy('transaction_journals.date', 'desc') + ->orderBy('transaction_journals.order', 'asc') + ->orderBy('transaction_journals.description', 'desc') + ->orderBy('transactions.amount', 'desc'); if (null !== $currency) { $query->where('transactions.transaction_currency_id', $currency->id); $query->limit(1); @@ -203,7 +219,7 @@ class Steam $return = []; $result = $query->get(['transactions.transaction_currency_id', 'transactions.balance_after']); foreach ($result as $entry) { - $key = (int) $entry->transaction_currency_id; + $key = (int) $entry->transaction_currency_id; if (array_key_exists($key, $return)) { continue; } @@ -222,7 +238,7 @@ class Steam { // Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__)); // abuse chart properties: - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($account->id); $cache->addProperty('balance'); $cache->addProperty($date); @@ -232,26 +248,24 @@ class Steam } /** @var AccountRepositoryInterface $repository */ - $repository = app(AccountRepositoryInterface::class); + $repository = app(AccountRepositoryInterface::class); if (null === $currency) { $currency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup); } // first part: get all balances in own currency: - $transactions = $account->transactions() - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->where('transactions.transaction_currency_id', $currency->id) - ->get(['transactions.amount'])->toArray() - ; - $nativeBalance = $this->sumTransactions($transactions, 'amount'); + $transactions = $account->transactions() + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->where('transactions.transaction_currency_id', $currency->id) + ->get(['transactions.amount'])->toArray(); + $nativeBalance = $this->sumTransactions($transactions, 'amount'); // get all balances in foreign currency: $transactions = $account->transactions() - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->where('transactions.foreign_currency_id', $currency->id) - ->where('transactions.transaction_currency_id', '!=', $currency->id) - ->get(['transactions.foreign_amount'])->toArray() - ; + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->where('transactions.foreign_currency_id', $currency->id) + ->where('transactions.transaction_currency_id', '!=', $currency->id) + ->get(['transactions.foreign_amount'])->toArray(); $foreignBalance = $this->sumTransactions($transactions, 'foreign_amount'); $balance = bcadd($nativeBalance, $foreignBalance); $virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance; @@ -270,7 +284,7 @@ class Steam public function balanceInRangeConverted(Account $account, Carbon $start, Carbon $end, TransactionCurrency $native): array { // Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__)); - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($account->id); $cache->addProperty('balance-in-range-converted'); $cache->addProperty($native->id); @@ -290,35 +304,34 @@ class Steam Log::debug(sprintf('Start balance on %s is %s', $formatted, $startBalance)); Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__)); - $converter = new ExchangeRateConverter(); + $converter = new ExchangeRateConverter(); // not sure why this is happening: $start->addDay(); // grab all transactions between start and end: - $set = $account->transactions() - ->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') - ->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d 23:59:59')) - ->orderBy('transaction_journals.date', 'ASC') - ->whereNull('transaction_journals.deleted_at') - ->get( - [ - 'transaction_journals.date', - 'transactions.transaction_currency_id', - 'transactions.amount', - 'transactions.foreign_currency_id', - 'transactions.foreign_amount', - ] - )->toArray() - ; + $set = $account->transactions() + ->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d 23:59:59')) + ->orderBy('transaction_journals.date', 'ASC') + ->whereNull('transaction_journals.deleted_at') + ->get( + [ + 'transaction_journals.date', + 'transactions.transaction_currency_id', + 'transactions.amount', + 'transactions.foreign_currency_id', + 'transactions.foreign_amount', + ] + )->toArray(); // loop the set and convert if necessary: - $currentBalance = $startBalance; + $currentBalance = $startBalance; /** @var Transaction $transaction */ foreach ($set as $transaction) { - $day = false; + $day = false; try { $day = Carbon::parse($transaction['date'], config('app.timezone')); @@ -328,7 +341,7 @@ class Steam if (false === $day) { $day = today(config('app.timezone')); } - $format = $day->format('Y-m-d'); + $format = $day->format('Y-m-d'); // if the transaction is in the expected currency, change nothing. if ((int) $transaction['transaction_currency_id'] === $native->id) { // change the current balance, set it to today, continue the loop. @@ -351,21 +364,21 @@ class Steam $currency = $currencies[$currencyId] ?? TransactionCurrency::find($currencyId); $currencies[$currencyId] = $currency; - $rate = $converter->getCurrencyRate($currency, $native, $day); - $convertedAmount = bcmul($transaction['amount'], $rate); - $currentBalance = bcadd($currentBalance, $convertedAmount); - $balances[$format] = $currentBalance; + $rate = $converter->getCurrencyRate($currency, $native, $day); + $convertedAmount = bcmul($transaction['amount'], $rate); + $currentBalance = bcadd($currentBalance, $convertedAmount); + $balances[$format] = $currentBalance; Log::debug(sprintf( - '%s: transaction in %s(!). Conversion rate is %s. %s %s = %s %s', - $format, - $currency->code, - $rate, - $currency->code, - $transaction['amount'], - $native->code, - $convertedAmount - )); + '%s: transaction in %s(!). Conversion rate is %s. %s %s = %s %s', + $format, + $currency->code, + $rate, + $currency->code, + $transaction['amount'], + $native->code, + $convertedAmount + )); } $cache->store($balances); @@ -397,7 +410,7 @@ class Steam { // Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__)); Log::debug(sprintf('Now in balanceConverted (%s) for account #%d, converting to %s', $date->format('Y-m-d'), $account->id, $native->code)); - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($account->id); $cache->addProperty('balance'); $cache->addProperty($date); @@ -418,72 +431,66 @@ class Steam return $this->balance($account, $date); } - $new = []; - $existing = []; - $new[] = $account->transactions() // 1 - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->where('transactions.transaction_currency_id', $currency->id) - ->whereNull('transactions.foreign_currency_id') - ->get(['transaction_journals.date', 'transactions.amount'])->toArray() - ; + $new = []; + $existing = []; + $new[] = $account->transactions() // 1 + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->where('transactions.transaction_currency_id', $currency->id) + ->whereNull('transactions.foreign_currency_id') + ->get(['transaction_journals.date', 'transactions.amount'])->toArray(); Log::debug(sprintf('%d transaction(s) in set #1', count($new[0]))); $existing[] = $account->transactions() // 2 - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->where('transactions.transaction_currency_id', $native->id) - ->whereNull('transactions.foreign_currency_id') - ->get(['transactions.amount'])->toArray() - ; + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->where('transactions.transaction_currency_id', $native->id) + ->whereNull('transactions.foreign_currency_id') + ->get(['transactions.amount'])->toArray(); Log::debug(sprintf('%d transaction(s) in set #2', count($existing[0]))); - $new[] = $account->transactions() // 3 - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->where('transactions.transaction_currency_id', '!=', $currency->id) - ->where('transactions.transaction_currency_id', '!=', $native->id) - ->whereNull('transactions.foreign_currency_id') - ->get(['transaction_journals.date', 'transactions.amount'])->toArray() - ; + $new[] = $account->transactions() // 3 + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->where('transactions.transaction_currency_id', '!=', $currency->id) + ->where('transactions.transaction_currency_id', '!=', $native->id) + ->whereNull('transactions.foreign_currency_id') + ->get(['transaction_journals.date', 'transactions.amount'])->toArray(); Log::debug(sprintf('%d transactions in set #3', count($new[1]))); $existing[] = $account->transactions() // 4 - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->where('transactions.foreign_currency_id', $native->id) - ->whereNotNull('transactions.foreign_amount') - ->get(['transactions.foreign_amount'])->toArray() - ; + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->where('transactions.foreign_currency_id', $native->id) + ->whereNotNull('transactions.foreign_amount') + ->get(['transactions.foreign_amount'])->toArray(); Log::debug(sprintf('%d transactions in set #4', count($existing[1]))); - $new[] = $account->transactions()// 5 - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->where('transactions.transaction_currency_id', $currency->id) - ->where('transactions.foreign_currency_id', '!=', $native->id) - ->whereNotNull('transactions.foreign_amount') - ->get(['transaction_journals.date', 'transactions.amount'])->toArray() - ; + $new[] = $account->transactions()// 5 + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->where('transactions.transaction_currency_id', $currency->id) + ->where('transactions.foreign_currency_id', '!=', $native->id) + ->whereNotNull('transactions.foreign_amount') + ->get(['transaction_journals.date', 'transactions.amount'])->toArray(); Log::debug(sprintf('%d transactions in set #5', count($new[2]))); - $new[] = $account->transactions()// 6 - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->where('transactions.transaction_currency_id', '!=', $currency->id) - ->where('transactions.foreign_currency_id', '!=', $native->id) - ->whereNotNull('transactions.foreign_amount') - ->get(['transaction_journals.date', 'transactions.amount'])->toArray() - ; + $new[] = $account->transactions()// 6 + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->where('transactions.transaction_currency_id', '!=', $currency->id) + ->where('transactions.foreign_currency_id', '!=', $native->id) + ->whereNotNull('transactions.foreign_amount') + ->get(['transaction_journals.date', 'transactions.amount'])->toArray(); Log::debug(sprintf('%d transactions in set #6', count($new[3]))); // process both sets of transactions. Of course, no need to convert set "existing". - $balance = $this->sumTransactions($existing[0], 'amount'); - $balance = bcadd($balance, $this->sumTransactions($existing[1], 'foreign_amount')); + $balance = $this->sumTransactions($existing[0], 'amount'); + $balance = bcadd($balance, $this->sumTransactions($existing[1], 'foreign_amount')); Log::debug(sprintf('Balance from set #2 and #4 is %f', $balance)); // need to convert the others. All sets use the "amount" value as their base (that's easy) // but we need to convert each transaction separately because the date difference may // incur huge currency changes. Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__)); - $start = clone $date; - $end = clone $date; - $converter = new ExchangeRateConverter(); + $start = clone $date; + $end = clone $date; + $converter = new ExchangeRateConverter(); foreach ($new as $set) { foreach ($set as $transaction) { $currentDate = false; @@ -506,7 +513,7 @@ class Steam foreach ($new as $set) { foreach ($set as $transaction) { - $currentDate = false; + $currentDate = false; try { $currentDate = Carbon::parse($transaction['date'], config('app.timezone')); @@ -523,9 +530,9 @@ class Steam } // add virtual balance (also needs conversion) - $virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance; - $virtual = $converter->convert($currency, $native, $account->created_at, $virtual); - $balance = bcadd($balance, $virtual); + $virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance; + $virtual = $converter->convert($currency, $native, $account->created_at, $virtual); + $balance = bcadd($balance, $virtual); $converter->summarize(); $cache->store($balance); @@ -542,9 +549,9 @@ class Steam public function balancesByAccounts(Collection $accounts, Carbon $date): array { // Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__)); - $ids = $accounts->pluck('id')->toArray(); + $ids = $accounts->pluck('id')->toArray(); // cache this property. - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($ids); $cache->addProperty('balances'); $cache->addProperty($date); @@ -573,9 +580,9 @@ class Steam public function balancesByAccountsConverted(Collection $accounts, Carbon $date): array { // Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__)); - $ids = $accounts->pluck('id')->toArray(); + $ids = $accounts->pluck('id')->toArray(); // cache this property. - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($ids); $cache->addProperty('balances-converted'); $cache->addProperty($date); @@ -591,9 +598,9 @@ class Steam $default = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup); $result[$account->id] = [ - 'balance' => $this->balance($account, $date), - 'native_balance' => $this->balanceConverted($account, $date, $default), - ]; + 'balance' => $this->balance($account, $date), + 'native_balance' => $this->balanceConverted($account, $date, $default), + ]; } $cache->store($result); @@ -607,9 +614,9 @@ class Steam public function balancesPerCurrencyByAccounts(Collection $accounts, Carbon $date): array { // Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__)); - $ids = $accounts->pluck('id')->toArray(); + $ids = $accounts->pluck('id')->toArray(); // cache this property. - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($ids); $cache->addProperty('balances-per-currency'); $cache->addProperty($date); @@ -634,7 +641,7 @@ class Steam { // Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__)); // abuse chart properties: - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($account->id); $cache->addProperty('balance-per-currency'); $cache->addProperty($date); @@ -642,10 +649,9 @@ class Steam return $cache->get(); } $query = $account->transactions() - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) - ->groupBy('transactions.transaction_currency_id') - ; + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) + ->groupBy('transactions.transaction_currency_id'); $balances = $query->get(['transactions.transaction_currency_id', \DB::raw('SUM(transactions.amount) as sum_for_currency')]); // @phpstan-ignore-line $return = []; @@ -677,10 +683,10 @@ class Steam // Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision)); if (str_contains($number, '.')) { if ('-' !== $number[0]) { - return bcadd($number, '0.'.str_repeat('0', $precision).'5', $precision); + return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision); } - return bcsub($number, '0.'.str_repeat('0', $precision).'5', $precision); + return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision); } return $number; @@ -763,15 +769,15 @@ class Steam { $list = []; - $set = auth()->user()->transactions() - ->whereIn('transactions.account_id', $accounts) - ->groupBy(['transactions.account_id', 'transaction_journals.user_id']) - ->get(['transactions.account_id', \DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line + $set = auth()->user()->transactions() + ->whereIn('transactions.account_id', $accounts) + ->groupBy(['transactions.account_id', 'transaction_journals.user_id']) + ->get(['transactions.account_id', \DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line ; /** @var Transaction $entry */ foreach ($set as $entry) { - $date = new Carbon($entry->max_date, config('app.timezone')); + $date = new Carbon($entry->max_date, config('app.timezone')); $date->setTimezone(config('app.timezone')); $list[$entry->account_id] = $date; } @@ -846,9 +852,9 @@ class Steam public function getSafeUrl(string $unknownUrl, string $safeUrl): string { // Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl)); - $returnUrl = $safeUrl; - $unknownHost = parse_url($unknownUrl, PHP_URL_HOST); - $safeHost = parse_url($safeUrl, PHP_URL_HOST); + $returnUrl = $safeUrl; + $unknownHost = parse_url($unknownUrl, PHP_URL_HOST); + $safeHost = parse_url($safeUrl, PHP_URL_HOST); if (null !== $unknownHost && $unknownHost === $safeHost) { $returnUrl = $unknownUrl; @@ -885,7 +891,7 @@ class Steam */ public function floatalize(string $value): string { - $value = strtoupper($value); + $value = strtoupper($value); if (!str_contains($value, 'E')) { return $value; } diff --git a/app/TransactionRules/Actions/UpdatePiggybank.php b/app/TransactionRules/Actions/UpdatePiggybank.php index 1e748c1926..c437318018 100644 --- a/app/TransactionRules/Actions/UpdatePiggybank.php +++ b/app/TransactionRules/Actions/UpdatePiggybank.php @@ -26,6 +26,7 @@ namespace FireflyIII\TransactionRules\Actions; use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray; use FireflyIII\Events\TriggeredAuditLog; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\PiggyBank; use FireflyIII\Models\RuleAction; use FireflyIII\Models\Transaction; @@ -81,6 +82,7 @@ class UpdatePiggybank implements ActionInterface if ($source->account_id === $piggyBank->account_id) { app('log')->debug('Piggy bank account is linked to source, so remove amount from piggy bank.'); + throw new FireflyException('Reference the correct account here.'); $this->removeAmount($piggyBank, $journal, $journalObj, $destination->amount); event( @@ -161,6 +163,7 @@ class UpdatePiggybank implements ActionInterface } // make sure we can remove amount: + throw new FireflyException('Reference the correct account here.'); if (false === $repository->canRemoveAmount($piggyBank, $amount)) { app('log')->warning(sprintf('Cannot remove %s from piggy bank.', $amount)); event(new RuleActionFailedOnArray($this->action, $array, trans('rules.cannot_remove_from_piggy', ['amount' => $amount, 'name' => $piggyBank->name]))); @@ -169,6 +172,7 @@ class UpdatePiggybank implements ActionInterface } app('log')->debug(sprintf('Will now remove %s from piggy bank.', $amount)); + throw new FireflyException('Reference the correct account here.'); $repository->removeAmount($piggyBank, $amount, $journal); } @@ -199,6 +203,7 @@ class UpdatePiggybank implements ActionInterface } // make sure we can add amount: + throw new FireflyException('Reference the correct account here.'); if (false === $repository->canAddAmount($piggyBank, $amount)) { app('log')->warning(sprintf('Cannot add %s to piggy bank.', $amount)); event(new RuleActionFailedOnArray($this->action, $array, trans('rules.cannot_add_to_piggy', ['amount' => $amount, 'name' => $piggyBank->name]))); diff --git a/app/Transformers/PiggyBankTransformer.php b/app/Transformers/PiggyBankTransformer.php index 98a0fe4a4f..4a094dbfcc 100644 --- a/app/Transformers/PiggyBankTransformer.php +++ b/app/Transformers/PiggyBankTransformer.php @@ -78,7 +78,7 @@ class PiggyBankTransformer extends AbstractTransformer // get currently saved amount: $currency = $piggyBank->transactionCurrency; - $currentAmount = app('steam')->bcround($this->piggyRepos->getCurrentAmount($piggyBank), $currency->decimal_places); + $currentAmount = $this->piggyRepos->getCurrentAmount($piggyBank); // Amounts, depending on 0.0 state of target amount $percentage = null; diff --git a/app/User.php b/app/User.php index 00ca3d2e74..c32c6d2ad6 100644 --- a/app/User.php +++ b/app/User.php @@ -106,6 +106,10 @@ class User extends Authenticatable return $this->hasMany(Account::class); } + public function piggyBanks() { + throw new FireflyException('Method no longer supported.'); + } + /** * Link to attachments */ diff --git a/config/notifications.php b/config/notifications.php index cc137cc174..7e33c2b223 100644 --- a/config/notifications.php +++ b/config/notifications.php @@ -28,8 +28,8 @@ return [ 'slack' => ['enabled' => true, 'ui_configurable' => 1], 'ntfy' => ['enabled' => true, 'ui_configurable' => 1], 'pushover' => ['enabled' => true, 'ui_configurable' => 1], - 'gotify' => ['enabled' => false, 'ui_configurable' => 0], - 'pushbullet' => ['enabled' => false, 'ui_configurable' => 0], +// 'gotify' => ['enabled' => false, 'ui_configurable' => 0], +// 'pushbullet' => ['enabled' => false, 'ui_configurable' => 0], ], 'notifications' => [ 'user' => [ diff --git a/resources/views/list/piggy-bank-events.twig b/resources/views/list/piggy-bank-events.twig index eb916e9161..bc7eca413a 100644 --- a/resources/views/list/piggy-bank-events.twig +++ b/resources/views/list/piggy-bank-events.twig @@ -25,9 +25,9 @@ {% if event.amount < 0 %} - {{ trans('firefly.removed_amount', {amount: formatAmountByAccount(event.piggyBank.account, event.amount, false)})|raw }} + {{ trans('firefly.removed_amount', {amount: formatAmountBySymbol(event.amount,event.piggyBank.transactionCurrency.symbol, false)})|raw }} {% else %} - {{ trans('firefly.added_amount', {amount: formatAmountByAccount(event.piggyBank.account, event.amount, false)})|raw }} + {{ trans('firefly.added_amount', {amount: formatAmountBySymbol(event.amount, event.piggyBank.transactionCurrency.symbol, false)})|raw }} {% endif %} diff --git a/resources/views/piggy-banks/add-mobile.twig b/resources/views/piggy-banks/add-mobile.twig index c66c09078d..79aeec0cd2 100644 --- a/resources/views/piggy-banks/add-mobile.twig +++ b/resources/views/piggy-banks/add-mobile.twig @@ -14,16 +14,16 @@

{{ trans('firefly.add_money_to_piggy', {name: piggyBank.name}) }}

- {% if maxAmount > 0 %} -

- {{ 'max_amount_add'|_ }}: {{ formatAmountByCurrency(currency,maxAmount) }}. -

+ {% if total > 0 %} -
-
{{ currency.symbol|raw }}
- -
+ + {% for account in accounts %} + {{ account.account.name }} ({{ 'max_amount_add'|_ }}: {{ formatAmountByCurrency(piggyBank.transactionCurrency, account.max_amount) }}) +
+
{{ piggyBank.transactionCurrency.symbol|raw }}
+ +
+ {% endfor %}

 

diff --git a/resources/views/piggy-banks/add.twig b/resources/views/piggy-banks/add.twig index 9c4da8d832..3f07365ed8 100644 --- a/resources/views/piggy-banks/add.twig +++ b/resources/views/piggy-banks/add.twig @@ -5,19 +5,17 @@
- {% if maxAmount > 0 %} + {% if total > 0 %}
diff --git a/resources/views/piggy-banks/remove-mobile.twig b/resources/views/piggy-banks/remove-mobile.twig index b0046f55a4..192f5e7d53 100644 --- a/resources/views/piggy-banks/remove-mobile.twig +++ b/resources/views/piggy-banks/remove-mobile.twig @@ -14,15 +14,17 @@
-

- {{ 'max_amount_remove'|_ }}: {{ formatAmountByCurrency(currency, repetition.currentamount) }}. -

+ {% for account in accounts %} +

+ {{ account.account.name }}: {{ 'max_amount_remove'|_ }}: {{ formatAmountByCurrency(piggyBank.transactionCurrency, account.saved_so_far) }}. +

+
+
{{ piggyBank.transactionCurrency.symbol|raw }}
+ +
+ {% endfor %} -
-
{{ currency.symbol|raw }}
- -

 

diff --git a/resources/views/piggy-banks/remove.twig b/resources/views/piggy-banks/remove.twig index 7527b7d798..e4b381aa8d 100644 --- a/resources/views/piggy-banks/remove.twig +++ b/resources/views/piggy-banks/remove.twig @@ -10,15 +10,16 @@
+ {% endfor %}