diff --git a/app/Api/V1/Controllers/PiggyBankController.php b/app/Api/V1/Controllers/PiggyBankController.php index d69fd30ccf..724972bdaf 100644 --- a/app/Api/V1/Controllers/PiggyBankController.php +++ b/app/Api/V1/Controllers/PiggyBankController.php @@ -226,7 +226,14 @@ class PiggyBankController extends Controller */ public function update(PiggyBankRequest $request, PiggyBank $piggyBank): JsonResponse { - $piggyBank = $this->repository->update($piggyBank, $request->getAll()); + $data = $request->getAll(); + $piggyBank = $this->repository->update($piggyBank, $data); + + if ('' !== $data['current_amount']) { + $this->repository->setCurrentAmount($piggyBank, $data['current_amount']); + } + + $manager = new Manager(); $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; $manager->setSerializer(new JsonApiSerializer($baseUrl)); diff --git a/app/Api/V1/Requests/PiggyBankRequest.php b/app/Api/V1/Requests/PiggyBankRequest.php index e3c8ea655a..68c5046844 100644 --- a/app/Api/V1/Requests/PiggyBankRequest.php +++ b/app/Api/V1/Requests/PiggyBankRequest.php @@ -25,6 +25,7 @@ namespace FireflyIII\Api\V1\Requests; use FireflyIII\Models\PiggyBank; use FireflyIII\Rules\IsAssetAccountId; +use FireflyIII\Rules\LessThanPiggyTarget; use FireflyIII\Rules\ZeroOrMore; /** @@ -53,14 +54,11 @@ class PiggyBankRequest extends Request */ public function getAll(): array { - $current = $this->string('current_amount'); - $current = '' === $current ? '0' : $current; - return [ 'name' => $this->string('name'), 'account_id' => $this->integer('account_id'), 'targetamount' => $this->string('target_amount'), - 'current_amount' => $current, + 'current_amount' => $this->string('current_amount'), 'startdate' => $this->date('start_date'), 'targetdate' => $this->date('target_date'), 'notes' => $this->string('notes'), @@ -76,8 +74,6 @@ class PiggyBankRequest extends Request { $rules = [ 'name' => 'required|between:1,255|uniquePiggyBankForUser', - 'account_id' => ['required', 'belongsToUser:accounts', new IsAssetAccountId], - 'target_amount' => 'required|numeric|more:0', 'current_amount' => ['numeric', new ZeroOrMore, 'lte:target_amount'], 'start_date' => 'date|nullable', 'target_date' => 'date|nullable|after:start_date', @@ -90,8 +86,11 @@ class PiggyBankRequest extends Request case 'PUT': case 'PATCH': /** @var PiggyBank $piggyBank */ - $piggyBank = $this->route()->parameter('piggyBank'); - $rules['name'] = 'required|between:1,255|uniquePiggyBankForUser:' . $piggyBank->id; + $piggyBank = $this->route()->parameter('piggyBank'); + $rules['name'] = 'between:1,255|uniquePiggyBankForUser:' . $piggyBank->id; + $rules['account_id'] = ['belongsToUser:accounts', new IsAssetAccountId]; + $rules['target_amount'] = 'numeric|more:0'; + $rules['current_amount'] = ['numeric', new ZeroOrMore, new LessThanPiggyTarget]; break; } diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php index bc1fa1eb8d..0b4dfa3e2c 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepository.php +++ b/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -534,20 +534,27 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface */ public function update(PiggyBank $piggyBank, array $data): PiggyBank { - $piggyBank->name = $data['name']; - $piggyBank->account_id = (int)$data['account_id']; - $piggyBank->targetamount = $data['targetamount']; - $piggyBank->targetdate = $data['targetdate']; + if (isset($data['name']) && '' !== $data['name']) { + $piggyBank->name = $data['name']; + } + if (isset($data['account_id']) && 0 !== $data['account_id']) { + $piggyBank->account_id = (int)$data['account_id']; + } + if (isset($data['targetamount']) && '' !== $data['targetamount']) { + $piggyBank->targetamount = $data['targetamount']; + } + if (isset($data['targetdate']) && '' !== $data['targetdate']) { + $piggyBank->targetdate = $data['targetdate']; + } $piggyBank->startdate = $data['startdate'] ?? $piggyBank->startdate; - $piggyBank->save(); - $this->updateNote($piggyBank, $data['notes']); + $this->updateNote($piggyBank, $data['notes'] ?? ''); // if the piggy bank is now smaller than the current relevant rep, // remove money from the rep. $repetition = $this->getRepetition($piggyBank); - if ($repetition->currentamount > $piggyBank->targetamount) { + if (null !== $repetition && $repetition->currentamount > $piggyBank->targetamount) { $diff = bcsub($piggyBank->targetamount, $repetition->currentamount); $this->createEvent($piggyBank, $diff); @@ -558,12 +565,36 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface return $piggyBank; } + /** + * @param PiggyBank $piggyBank + * @param string $amount + * + * @return PiggyBank + */ + public function setCurrentAmount(PiggyBank $piggyBank, string $amount): PiggyBank + { + $repetition = $this->getRepetition($piggyBank); + if (null === $repetition) { + return $piggyBank; + } + $max = $piggyBank->targetamount; + if (1 === bccomp($amount, $max)) { + $amount = $max; + } + $repetition->currentamount = $amount; + $repetition->save(); + + // create event + $this->createEvent($piggyBank, $amount); + + return $piggyBank; + } + /** * @param PiggyBank $piggyBank * @param string $note * * @return bool - * @throws \Exception */ private function updateNote(PiggyBank $piggyBank, string $note): bool { diff --git a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php index 631d522521..fe9b044184 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php +++ b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php @@ -35,6 +35,14 @@ use Illuminate\Support\Collection; */ interface PiggyBankRepositoryInterface { + /** + * @param PiggyBank $piggyBank + * @param string $amount + * + * @return PiggyBank + */ + public function setCurrentAmount(PiggyBank $piggyBank, string $amount): PiggyBank; + /** * @param PiggyBank $piggyBank * @param string $amount diff --git a/app/Rules/LessThanPiggyTarget.php b/app/Rules/LessThanPiggyTarget.php new file mode 100644 index 0000000000..0afea016ea --- /dev/null +++ b/app/Rules/LessThanPiggyTarget.php @@ -0,0 +1,34 @@ + 'The :attribute must be a string.', 'url' => 'The :attribute format is invalid.', 'timezone' => 'The :attribute must be a valid zone.', - '2fa_code' => 'The :attribute field is invalid.', - 'dimensions' => 'The :attribute has invalid image dimensions.', - 'distinct' => 'The :attribute field has a duplicate value.', - 'file' => 'The :attribute must be a file.', - 'in_array' => 'The :attribute field does not exist in :other.', - 'present' => 'The :attribute field must be present.', - 'amount_zero' => 'The total amount cannot be zero.', - 'unique_piggy_bank_for_user' => 'The name of the piggy bank must be unique.', - 'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password-security', - 'valid_recurrence_rep_type' => 'Invalid repetition type for recurring transactions.', - 'valid_recurrence_rep_moment' => 'Invalid repetition moment for this type of repetition.', - 'invalid_account_info' => 'Invalid account information.', + '2fa_code' => 'The :attribute field is invalid.', + 'dimensions' => 'The :attribute has invalid image dimensions.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'file' => 'The :attribute must be a file.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'present' => 'The :attribute field must be present.', + 'amount_zero' => 'The total amount cannot be zero.', + 'current_target_amount' => 'The current amount must be less than the target amount.', + 'unique_piggy_bank_for_user' => 'The name of the piggy bank must be unique.', + 'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password-security', + 'valid_recurrence_rep_type' => 'Invalid repetition type for recurring transactions.', + 'valid_recurrence_rep_moment' => 'Invalid repetition moment for this type of repetition.', + 'invalid_account_info' => 'Invalid account information.', 'attributes' => [ 'email' => 'email address', 'description' => 'description',