diff --git a/app/Http/Controllers/PiggyBank/AmountController.php b/app/Http/Controllers/PiggyBank/AmountController.php index 7de19b79ea..0489c76a12 100644 --- a/app/Http/Controllers/PiggyBank/AmountController.php +++ b/app/Http/Controllers/PiggyBank/AmountController.php @@ -55,7 +55,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); @@ -77,9 +77,12 @@ class AmountController extends Controller { $leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, today(config('app.timezone'))); $savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank); - $leftToSave = bcsub($piggyBank->targetamount, $savedSoFar); - $maxAmount = min($leftOnAccount, $leftToSave); - $currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency(); + $maxAmount = $leftOnAccount; + if (0.000 !== (float) $piggyBank->targetamount) { + $leftToSave = bcsub($piggyBank->targetamount, $savedSoFar); + $maxAmount = min($leftOnAccount, $leftToSave); + } + $currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency(); return view('piggy-banks.add', compact('piggyBank', 'maxAmount', 'currency')); } @@ -97,9 +100,13 @@ class AmountController extends Controller $date = session('end', today(config('app.timezone'))); $leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $date); $savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank); - $leftToSave = bcsub($piggyBank->targetamount, $savedSoFar); - $maxAmount = min($leftOnAccount, $leftToSave); - $currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency(); + $maxAmount = $leftOnAccount; + + if (0.000 !== (float) $piggyBank->targetamount) { + $leftToSave = bcsub($piggyBank->targetamount, $savedSoFar); + $maxAmount = min($leftOnAccount, $leftToSave); + } + $currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency(); return view('piggy-banks.add-mobile', compact('piggyBank', 'maxAmount', 'currency')); } @@ -125,7 +132,7 @@ class AmountController extends Controller $this->piggyRepos->createEvent($piggyBank, $amount); session()->flash( 'success', - (string)trans( + (string) trans( 'firefly.added_amount_to_piggy', ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name] ) @@ -138,7 +145,7 @@ class AmountController extends Controller Log::error('Cannot add ' . $amount . ' because canAddAmount returned false.'); session()->flash( 'error', - (string)trans( + (string) trans( 'firefly.cannot_add_amount_piggy', ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)] ) @@ -167,7 +174,7 @@ class AmountController extends Controller $this->piggyRepos->removeAmount($piggyBank, $amount); session()->flash( 'success', - (string)trans( + (string) trans( 'firefly.removed_amount_from_piggy', ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name] ) @@ -176,11 +183,11 @@ class AmountController extends Controller return redirect(route('piggy-banks.index')); } - $amount = number_format((float)$request->get('amount'), 12, '.', ''); + $amount = number_format((float) $request->get('amount'), 12, '.', ''); session()->flash( 'error', - (string)trans( + (string) trans( 'firefly.cannot_remove_from_piggy', ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)] ) diff --git a/app/Http/Controllers/PiggyBank/EditController.php b/app/Http/Controllers/PiggyBank/EditController.php index 3cdefe2e8e..c93bc8729d 100644 --- a/app/Http/Controllers/PiggyBank/EditController.php +++ b/app/Http/Controllers/PiggyBank/EditController.php @@ -30,6 +30,7 @@ use FireflyIII\Http\Requests\PiggyBankUpdateRequest; use FireflyIII\Models\PiggyBank; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; +use Amount; use Illuminate\Contracts\View\Factory; use Illuminate\Http\RedirectResponse; use Illuminate\Routing\Redirector; @@ -55,11 +56,11 @@ class EditController 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->attachments = app(AttachmentHelperInterface::class); - $this->piggyRepos = app(PiggyBankRepositoryInterface::class); + $this->attachments = app(AttachmentHelperInterface::class); + $this->piggyRepos = app(PiggyBankRepositoryInterface::class); $this->accountRepository = app(AccountRepositoryInterface::class); return $next($request); } @@ -75,24 +76,28 @@ class EditController extends Controller */ public function edit(PiggyBank $piggyBank) { - $subTitle = (string)trans('firefly.update_piggy_title', ['name' => $piggyBank->name]); + $subTitle = (string) trans('firefly.update_piggy_title', ['name' => $piggyBank->name]); $subTitleIcon = 'fa-pencil'; - $targetDate = null; - $startDate = null; $note = $piggyBank->notes()->first(); // Flash some data to fill the form. $targetDate = $piggyBank->targetdate?->format('Y-m-d'); $startDate = $piggyBank->startdate?->format('Y-m-d'); - $currency = $this->accountRepository->getAccountCurrency($piggyBank->account); + $currency = $this->accountRepository->getAccountCurrency($piggyBank->account); + if (null === $currency) { + $currency = Amount::getDefaultCurrency(); + } $preFilled = ['name' => $piggyBank->name, 'account_id' => $piggyBank->account_id, - 'targetamount' => number_format((float)$piggyBank->targetamount, $currency->decimal_places,'.',''), + 'targetamount' => number_format((float) $piggyBank->targetamount, $currency->decimal_places, '.', ''), 'targetdate' => $targetDate, 'startdate' => $startDate, 'object_group' => $piggyBank->objectGroups->first() ? $piggyBank->objectGroups->first()->title : '', 'notes' => null === $note ? '' : $note->text, ]; + if(0.0 === (float) $piggyBank->targetamount) { + $preFilled['targetamount'] = ''; + } session()->flash('preFilled', $preFilled); // put previous url in session if not redirect from store (not "return_to_edit"). @@ -117,7 +122,7 @@ class EditController extends Controller $data = $request->getPiggyBankData(); $piggyBank = $this->piggyRepos->update($piggyBank, $data); - session()->flash('success', (string)trans('firefly.updated_piggy_bank', ['name' => $piggyBank->name])); + session()->flash('success', (string) trans('firefly.updated_piggy_bank', ['name' => $piggyBank->name])); app('preferences')->mark(); // store new attachment(s): @@ -127,7 +132,7 @@ class EditController extends Controller $this->attachments->saveAttachmentsForModel($piggyBank, $files); } if (null !== $files && auth()->user()->hasRole('demo')) { - session()->flash('info', (string)trans('firefly.no_att_demo_user')); + session()->flash('info', (string) trans('firefly.no_att_demo_user')); } if (count($this->attachments->getMessages()->get('attachments')) > 0) { @@ -135,7 +140,7 @@ class EditController extends Controller } $redirect = redirect($this->getPreviousUri('piggy-banks.edit.uri')); - if (1 === (int)$request->get('return_to_edit')) { + if (1 === (int) $request->get('return_to_edit')) { session()->put('piggy-banks.edit.fromUpdate', true); diff --git a/app/Http/Requests/PiggyBankStoreRequest.php b/app/Http/Requests/PiggyBankStoreRequest.php index 109e64e860..9e5a62b96f 100644 --- a/app/Http/Requests/PiggyBankStoreRequest.php +++ b/app/Http/Requests/PiggyBankStoreRequest.php @@ -61,7 +61,7 @@ class PiggyBankStoreRequest extends FormRequest return [ 'name' => 'required|between:1,255|uniquePiggyBankForUser', 'account_id' => 'required|belongsToUser:accounts', - 'targetamount' => 'required|numeric|gte:0.01|max:1000000000', + 'targetamount' => 'nullable|numeric|max:1000000000', 'startdate' => 'date', 'targetdate' => 'date|nullable', 'order' => 'integer|min:1', diff --git a/app/Http/Requests/PiggyBankUpdateRequest.php b/app/Http/Requests/PiggyBankUpdateRequest.php index 2aa30af498..c15dfa9ca9 100644 --- a/app/Http/Requests/PiggyBankUpdateRequest.php +++ b/app/Http/Requests/PiggyBankUpdateRequest.php @@ -65,7 +65,7 @@ class PiggyBankUpdateRequest extends FormRequest return [ 'name' => sprintf('required|between:1,255|uniquePiggyBankForUser:%d', $piggy->id), 'account_id' => 'required|belongsToUser:accounts', - 'targetamount' => 'required|numeric|gte:0.01|max:1000000000', + 'targetamount' => 'nullable|numeric|max:1000000000', 'startdate' => 'date', 'targetdate' => 'date|nullable', 'order' => 'integer|min:1', diff --git a/app/Models/Budget.php b/app/Models/Budget.php index 800b88ab8c..91a8dc6f45 100644 --- a/app/Models/Budget.php +++ b/app/Models/Budget.php @@ -77,6 +77,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; * @property string $email * @property int|null $user_group_id * @method static \Illuminate\Database\Eloquent\Builder|Budget whereUserGroupId($value) + * @property-read Collection|\FireflyIII\Models\Note[] $notes + * @property-read int|null $notes_count */ class Budget extends Model { diff --git a/app/Repositories/PiggyBank/ModifiesPiggyBanks.php b/app/Repositories/PiggyBank/ModifiesPiggyBanks.php index 3a631be562..1a84c1fd33 100644 --- a/app/Repositories/PiggyBank/ModifiesPiggyBanks.php +++ b/app/Repositories/PiggyBank/ModifiesPiggyBanks.php @@ -90,11 +90,16 @@ trait ModifiesPiggyBanks { $today = today(config('app.timezone')); $leftOnAccount = $this->leftOnAccount($piggyBank, $today); - $savedSoFar = (string)$this->getRepetition($piggyBank)->currentamount; - $leftToSave = bcsub($piggyBank->targetamount, $savedSoFar); - $maxAmount = 1 === bccomp($leftOnAccount, $leftToSave) ? $leftToSave : $leftOnAccount; - $compare = bccomp($amount, $maxAmount); - $result = $compare <= 0; + $savedSoFar = (string) $this->getRepetition($piggyBank)->currentamount; + $maxAmount = $leftOnAccount; + $leftToSave = null; + if (0.0 !== (float) $piggyBank->targetamount) { + $leftToSave = bcsub($piggyBank->targetamount, $savedSoFar); + $maxAmount = 1 === bccomp($leftOnAccount, $leftToSave) ? $leftToSave : $leftOnAccount; + } + + $compare = bccomp($amount, $maxAmount); + $result = $compare <= 0; Log::debug(sprintf('Left on account: %s on %s', $leftOnAccount, $today->format('Y-m-d'))); Log::debug(sprintf('Saved so far: %s', $savedSoFar)); @@ -208,7 +213,7 @@ trait ModifiesPiggyBanks $set = $this->user->piggyBanks()->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']); $current = 1; foreach ($set as $piggyBank) { - if ((int)$piggyBank->order !== $current) { + if ((int) $piggyBank->order !== $current) { Log::debug(sprintf('Piggy bank #%d ("%s") was at place %d but should be on %d', $piggyBank->id, $piggyBank->name, $piggyBank->order, $current)); $piggyBank->order = $current; $piggyBank->save(); @@ -262,7 +267,7 @@ trait ModifiesPiggyBanks */ public function setOrder(PiggyBank $piggyBank, int $newOrder): bool { - $oldOrder = (int)$piggyBank->order; + $oldOrder = (int) $piggyBank->order; Log::debug(sprintf('Will move piggy bank #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder)); if ($newOrder > $oldOrder) { $this->user->piggyBanks()->where('piggy_banks.order', '<=', $newOrder)->where('piggy_banks.order', '>', $oldOrder) @@ -332,7 +337,7 @@ trait ModifiesPiggyBanks } // try also with ID - $objectGroupId = (int)($data['object_group_id'] ?? 0); + $objectGroupId = (int) ($data['object_group_id'] ?? 0); if (0 !== $objectGroupId) { $objectGroup = $this->findObjectGroupById($objectGroupId); if (null !== $objectGroup) { @@ -354,12 +359,12 @@ trait ModifiesPiggyBanks { $piggyBank = $this->updateProperties($piggyBank, $data); if (array_key_exists('notes', $data)) { - $this->updateNote($piggyBank, (string)$data['notes']); + $this->updateNote($piggyBank, (string) $data['notes']); } // update the order of the piggy bank: - $oldOrder = (int)$piggyBank->order; - $newOrder = (int)($data['order'] ?? $oldOrder); + $oldOrder = (int) $piggyBank->order; + $newOrder = (int) ($data['order'] ?? $oldOrder); if ($oldOrder !== $newOrder) { $this->setOrder($piggyBank, $newOrder); } @@ -377,7 +382,7 @@ trait ModifiesPiggyBanks // update using name: if (array_key_exists('object_group_title', $data)) { - $objectGroupTitle = (string)$data['object_group_title']; + $objectGroupTitle = (string) $data['object_group_title']; if ('' !== $objectGroupTitle) { $objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle); if (null !== $objectGroup) { @@ -396,7 +401,7 @@ trait ModifiesPiggyBanks // try also with ID: if (array_key_exists('object_group_id', $data)) { - $objectGroupId = (int)($data['object_group_id'] ?? 0); + $objectGroupId = (int) ($data['object_group_id'] ?? 0); if (0 !== $objectGroupId) { $objectGroup = $this->findObjectGroupById($objectGroupId); if (null !== $objectGroup) { @@ -454,7 +459,7 @@ trait ModifiesPiggyBanks $piggyBank->name = $data['name']; } if (array_key_exists('account_id', $data) && 0 !== $data['account_id']) { - $piggyBank->account_id = (int)$data['account_id']; + $piggyBank->account_id = (int) $data['account_id']; } if (array_key_exists('targetamount', $data) && '' !== $data['targetamount']) { $piggyBank->targetamount = $data['targetamount']; diff --git a/app/Transformers/PiggyBankTransformer.php b/app/Transformers/PiggyBankTransformer.php index 43abb9da39..39dd7932cd 100644 --- a/app/Transformers/PiggyBankTransformer.php +++ b/app/Transformers/PiggyBankTransformer.php @@ -79,47 +79,55 @@ class PiggyBankTransformer extends AbstractTransformer /** @var ObjectGroup $objectGroup */ $objectGroup = $piggyBank->objectGroups->first(); if (null !== $objectGroup) { - $objectGroupId = (int)$objectGroup->id; - $objectGroupOrder = (int)$objectGroup->order; + $objectGroupId = (int) $objectGroup->id; + $objectGroupOrder = (int) $objectGroup->order; $objectGroupTitle = $objectGroup->title; } // get currently saved amount: $currentAmountStr = $this->piggyRepos->getCurrentAmount($piggyBank); - $currentAmount = number_format((float)$currentAmountStr, $currency->decimal_places, '.', ''); + $currentAmount = number_format((float) $currentAmountStr, $currency->decimal_places, '.', ''); - // left to save: - $leftToSave = bcsub($piggyBank->targetamount, $currentAmountStr); + // Amounts, depending on 0.0 state of target amount + $percentage = null; + $targetAmountString = null; + $leftToSaveString = null; + $savePerMonth = null; + if (0.000 !== (float) $piggyBank->targetamount) { + $leftToSave = bcsub($piggyBank->targetamount, $currentAmountStr); + $targetAmount = (string) $piggyBank->targetamount; + $targetAmount = 1 === bccomp('0.01', $targetAmount) ? '0.01' : $targetAmount; + $percentage = (int) (0 !== bccomp('0', $currentAmountStr) ? $currentAmountStr / $targetAmount * 100 : 0); + $targetAmountString = number_format((float) $targetAmount, $currency->decimal_places, '.', ''); + $leftToSaveString = number_format((float) $leftToSave, $currency->decimal_places, '.', ''); + $savePerMonth = number_format((float) $this->piggyRepos->getSuggestedMonthlyAmount($piggyBank), $currency->decimal_places, '.', ''); + } $startDate = $piggyBank->startdate?->toAtomString(); $targetDate = $piggyBank->targetdate?->toAtomString(); - // target and percentage: - $targetAmount = $piggyBank->targetamount; - $targetAmount = 1 === bccomp('0.01', (string)$targetAmount) ? '0.01' : $targetAmount; - $percentage = (int)(0 !== bccomp('0', $currentAmountStr) ? $currentAmountStr / $targetAmount * 100 : 0); return [ - 'id' => (string)$piggyBank->id, + 'id' => (string) $piggyBank->id, 'created_at' => $piggyBank->created_at->toAtomString(), 'updated_at' => $piggyBank->updated_at->toAtomString(), - 'account_id' => (string)$piggyBank->account_id, + 'account_id' => (string) $piggyBank->account_id, 'account_name' => $piggyBank->account->name, 'name' => $piggyBank->name, - 'currency_id' => (string)$currency->id, + 'currency_id' => (string) $currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, - 'target_amount' => number_format((float)$targetAmount, $currency->decimal_places, '.', ''), + 'currency_decimal_places' => (int) $currency->decimal_places, + 'target_amount' => $targetAmountString, 'percentage' => $percentage, 'current_amount' => $currentAmount, - 'left_to_save' => number_format((float)$leftToSave, $currency->decimal_places, '.', ''), - 'save_per_month' => number_format((float)$this->piggyRepos->getSuggestedMonthlyAmount($piggyBank), $currency->decimal_places, '.', ''), + 'left_to_save' => $leftToSaveString, + 'save_per_month' => $savePerMonth, 'start_date' => $startDate, 'target_date' => $targetDate, - 'order' => (int)$piggyBank->order, + 'order' => (int) $piggyBank->order, 'active' => true, 'notes' => $notes, - 'object_group_id' => $objectGroupId ? (string)$objectGroupId : null, + 'object_group_id' => $objectGroupId ? (string) $objectGroupId : null, 'object_group_order' => $objectGroupOrder, 'object_group_title' => $objectGroupTitle, 'links' => [ diff --git a/resources/views/list/piggy-banks.twig b/resources/views/list/piggy-banks.twig index c530ff3cb4..222187ee8a 100644 --- a/resources/views/list/piggy-banks.twig +++ b/resources/views/list/piggy-banks.twig @@ -57,6 +57,7 @@ + {% if null != piggy.percentage %}
+ {% endif %} - {% if piggy.left_to_save > 0 %} + {% if piggy.left_to_save > 0 or null == piggy.left_to_save %} {% endif %} - {{ formatAmountBySymbol(piggy.target_amount,piggy.currency_symbol,piggy.currency_decimal_places) }} + {% if null != piggy.target_amount %} + {{ formatAmountBySymbol(piggy.target_amount,piggy.currency_symbol,piggy.currency_decimal_places) }} + {% endif %} {% if piggy.left_to_save > 0 %} diff --git a/resources/views/piggy-banks/show.twig b/resources/views/piggy-banks/show.twig index 1b61c73149..d4dfbbe2a1 100644 --- a/resources/views/piggy-banks/show.twig +++ b/resources/views/piggy-banks/show.twig @@ -42,24 +42,28 @@ {{ piggy.object_group_title }} {% endif %} + {% if null != piggy.target_amount %} {{ 'target_amount'|_ }} {{ formatAmountBySymbol(piggy.target_amount, piggy.currency_symbol, piggy.currency_decimal_places) }} + {% endif %} {{ 'saved_so_far'|_ }} {{ formatAmountBySymbol(piggy.current_amount, piggy.currency_symbol, piggy.currency_decimal_places) }} + {% if null != piggy.left_to_save %} {{ 'left_to_save'|_ }} {{ formatAmountBySymbol(piggy.left_to_save, piggy.currency_symbol, piggy.currency_decimal_places) }} + {% endif %} {{ 'start_date'|_ }}