diff --git a/app/Api/V1/Controllers/BudgetController.php b/app/Api/V1/Controllers/BudgetController.php index ee41e4efda..22f6efc5b3 100644 --- a/app/Api/V1/Controllers/BudgetController.php +++ b/app/Api/V1/Controllers/BudgetController.php @@ -25,7 +25,8 @@ namespace FireflyIII\Api\V1\Controllers; use Exception; use FireflyIII\Api\V1\Requests\BudgetLimitRequest; -use FireflyIII\Api\V1\Requests\BudgetRequest; +use FireflyIII\Api\V1\Requests\BudgetStoreRequest; +use FireflyIII\Api\V1\Requests\BudgetUpdateRequest; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Models\Budget; @@ -179,13 +180,13 @@ class BudgetController extends Controller /** * Store a budget. * - * @param BudgetRequest $request + * @param BudgetStoreRequest $request * * @return JsonResponse * @throws FireflyException * */ - public function store(BudgetRequest $request): JsonResponse + public function store(BudgetStoreRequest $request): JsonResponse { $budget = $this->repository->store($request->getAll()); $manager = $this->getManager(); @@ -291,12 +292,12 @@ class BudgetController extends Controller /** * Update a budget. * - * @param BudgetRequest $request + * @param BudgetUpdateRequest $request * @param Budget $budget * * @return JsonResponse */ - public function update(BudgetRequest $request, Budget $budget): JsonResponse + public function update(BudgetUpdateRequest $request, Budget $budget): JsonResponse { $data = $request->getAll(); $budget = $this->repository->update($budget, $data); diff --git a/app/Api/V1/Controllers/Chart/AvailableBudgetController.php b/app/Api/V1/Controllers/Chart/AvailableBudgetController.php index 5181dcc707..62b39fe4ac 100644 --- a/app/Api/V1/Controllers/Chart/AvailableBudgetController.php +++ b/app/Api/V1/Controllers/Chart/AvailableBudgetController.php @@ -85,7 +85,7 @@ class AvailableBudgetController extends Controller } $left = bcadd($availableBudget->amount, (string)$spent); // left less than zero? Set to zero. - if (bccomp($left, '0') === -1) { + if (-1 === bccomp($left, '0')) { $left = '0'; } diff --git a/app/Api/V1/Controllers/Search/AccountController.php b/app/Api/V1/Controllers/Search/AccountController.php index 6fcea80239..72b44ce2ea 100644 --- a/app/Api/V1/Controllers/Search/AccountController.php +++ b/app/Api/V1/Controllers/Search/AccountController.php @@ -1,4 +1,5 @@ . + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V1\Requests; + +use FireflyIII\Rules\IsBoolean; +use Illuminate\Validation\Validator; + +/** + * Class BudgetStoreRequest + * + * @codeCoverageIgnore + */ +class BudgetStoreRequest extends Request +{ + /** + * Authorize logged in users. + * + * @return bool + */ + public function authorize(): bool + { + // Only allow authenticated users + return auth()->check(); + } + + /** + * Get all data from the request. + * + * @return array + */ + public function getAll(): array + { + $active = true; + if (null !== $this->get('active')) { + $active = $this->boolean('active'); + } + + return [ + 'name' => $this->string('name'), + 'active' => $active, + 'order' => 0, + 'auto_budget_type' => $this->string('auto_budget_type'), + 'transaction_currency_id' => $this->integer('auto_budget_currency_id'), + 'transaction_currency_code' => $this->string('auto_budget_currency_code'), + 'auto_budget_amount' => $this->string('auto_budget_amount'), + 'auto_budget_period' => $this->string('auto_budget_period'), + ]; + } + + /** + * The rules that the incoming request must be matched against. + * + * @return array + */ + public function rules(): array + { + return [ + 'name' => 'required|between:1,100|uniqueObjectForUser:budgets,name', + 'active' => [new IsBoolean], + 'auto_budget_type' => 'in:reset,rollover', + 'auto_budget_currency_id' => 'exists:transaction_currencies,id', + 'auto_budget_currency_code' => 'exists:transaction_currencies,code', + 'auto_budget_amount' => 'min:0|max:1000000000', + 'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly', + ]; + } + + + /** + * Configure the validator instance with special rules for after the basic validation rules. + * + * @param Validator $validator + * + * @return void + */ + public function withValidator(Validator $validator): void + { + $validator->after( + function (Validator $validator) { + // validate all account info + $this->validateAutoBudgetAmount($validator); + } + ); + } +} diff --git a/app/Api/V1/Requests/BudgetRequest.php b/app/Api/V1/Requests/BudgetUpdateRequest.php similarity index 71% rename from app/Api/V1/Requests/BudgetRequest.php rename to app/Api/V1/Requests/BudgetUpdateRequest.php index b33244d599..738c5ff35a 100644 --- a/app/Api/V1/Requests/BudgetRequest.php +++ b/app/Api/V1/Requests/BudgetUpdateRequest.php @@ -1,6 +1,6 @@ 'required|between:1,100|uniqueObjectForUser:budgets,name', + $budget = $this->route()->parameter('budget'); + + return [ + 'name' => sprintf('required|between:1,100|uniqueObjectForUser:budgets,name,%d', $budget->id), 'active' => [new IsBoolean], ]; - switch ($this->method()) { - default: - break; - case 'PUT': - case 'PATCH': - /** @var Budget $budget */ - $budget = $this->route()->parameter('budget'); - $rules['name'] = sprintf('required|between:1,100|uniqueObjectForUser:budgets,name,%d', $budget->id); - break; - } - - return $rules; } } diff --git a/app/Api/V1/Requests/Request.php b/app/Api/V1/Requests/Request.php index 05495c314d..5c3989c7b1 100644 --- a/app/Api/V1/Requests/Request.php +++ b/app/Api/V1/Requests/Request.php @@ -34,4 +34,5 @@ use FireflyIII\Http\Requests\Request as FireflyIIIRequest; */ class Request extends FireflyIIIRequest { + } diff --git a/app/Api/V1/Requests/Search/TransferRequest.php b/app/Api/V1/Requests/Search/TransferRequest.php index 6ee29592f8..52a046170c 100644 --- a/app/Api/V1/Requests/Search/TransferRequest.php +++ b/app/Api/V1/Requests/Search/TransferRequest.php @@ -1,4 +1,5 @@ $this->string('name'), 'active' => $this->boolean('active'), - 'auto_budget_option' => $this->integer('auto_budget_option'), + 'auto_budget_type' => $this->integer('auto_budget_type'), 'transaction_currency_id' => $this->integer('transaction_currency_id'), 'auto_budget_amount' => $this->string('auto_budget_amount'), 'auto_budget_period' => $this->string('auto_budget_period'), diff --git a/app/Http/Requests/Request.php b/app/Http/Requests/Request.php index f98e2e0b61..efbdad3311 100644 --- a/app/Http/Requests/Request.php +++ b/app/Http/Requests/Request.php @@ -387,17 +387,27 @@ class Request extends FormRequest return $data; } + /** * @param Validator $validator */ protected function validateAutoBudgetAmount(Validator $validator): void { - $data = $validator->getData(); - $option = (int)$data['auto_budget_option']; - $amount = $data['auto_budget_amount'] ?? ''; - switch ($option) { + $data = $validator->getData(); + $type = $data['auto_budget_type'] ?? ''; + $amount = $data['auto_budget_amount'] ?? ''; + $period = (string)($data['auto_budget_period'] ?? ''); + $currencyId = $data['auto_budget_currency_id'] ?? ''; + $currencyCode = $data['auto_budget_currency_code'] ?? ''; + if (is_numeric($type)) { + $type = (int)$type; + } + + switch ($type) { case AutoBudget::AUTO_BUDGET_RESET: case AutoBudget::AUTO_BUDGET_ROLLOVER: + case 'reset': + case 'rollover': // basic float check: if ('' === $amount) { $validator->errors()->add('auto_budget_amount', (string)trans('validation.amount_required_for_auto_budget')); @@ -405,8 +415,16 @@ class Request extends FormRequest if (1 !== bccomp((string)$amount, '0')) { $validator->errors()->add('auto_budget_amount', (string)trans('validation.auto_budget_amount_positive')); } + if ('' === $period) { + $validator->errors()->add('auto_budget_period', (string)trans('validation.auto_budget_period_mandatory')); + } + if('' === $currencyCode && '' === $currencyId) { + $validator->errors()->add('auto_budget_amount', (string)trans('validation.require_currency_info')); + } + break; } } + } diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index e4ae35eeec..b83d0da209 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -25,13 +25,14 @@ namespace FireflyIII\Repositories\Budget; use Carbon\Carbon; use DB; use Exception; -use FireflyIII\Models\AutoBudget; use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\AutoBudget; use FireflyIII\Models\Budget; use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\RecurrenceTransactionMeta; use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleTrigger; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Services\Internal\Destroy\BudgetDestroyService; use FireflyIII\User; use Illuminate\Database\QueryException; @@ -290,17 +291,37 @@ class BudgetRepository implements BudgetRepositoryInterface } // try to create associated auto budget: - $option = $data['auto_budget_option'] ?? 0; - if (0 === $option) { + $type = $data['auto_budget_type'] ?? 0; + if (0 === $type) { return $newBudget; } + if ('reset' === $type) { + $type = AutoBudget::AUTO_BUDGET_RESET; + } + if ('rollover' === $type) { + $type = AutoBudget::AUTO_BUDGET_ROLLOVER; + } + $repos = app(CurrencyRepositoryInterface::class); + $currencyId = (int)($data['transaction_currency_id'] ?? 0); + $currencyCode = (string)($data['transaction_currency_code'] ?? ''); + + + $currency = $repos->findNull($currencyId); + if(null === $currency) { + $currency = $repos->findByCodeNull($currencyCode); + } + if(null === $currency) { + $currency = app('amount')->getDefaultCurrencyByUser($this->user); + } + $autoBudget = new AutoBudget; $autoBudget->budget()->associate($newBudget); - $autoBudget->transaction_currency_id = $data['transaction_currency_id'] ?? 1; - $autoBudget->auto_budget_type = $option; + $autoBudget->transaction_currency_id = $currency->id; + $autoBudget->auto_budget_type = $type; $autoBudget->amount = $data['auto_budget_amount'] ?? '1'; $autoBudget->period = $data['auto_budget_period'] ?? 'monthly'; $autoBudget->save(); + return $newBudget; } diff --git a/app/Transformers/BudgetTransformer.php b/app/Transformers/BudgetTransformer.php index 245683107a..f87630b84a 100644 --- a/app/Transformers/BudgetTransformer.php +++ b/app/Transformers/BudgetTransformer.php @@ -98,11 +98,11 @@ class BudgetTransformer extends AbstractTransformer 'updated_at' => $budget->updated_at->toAtomString(), 'active' => $budget->active, 'name' => $budget->name, + 'auto_budget_type' => $abType, + 'auto_budget_period' => $abPeriod, 'auto_budget_currency_id' => $abCurrencyId, 'auto_budget_currency_code' => $abCurrencyCode, - 'auto_budget_type' => $abType, 'auto_budget_amount' => $abAmount, - 'auto_budget_period' => $abPeriod, 'spent' => $spent, 'links' => [ [ diff --git a/resources/lang/en_US/validation.php b/resources/lang/en_US/validation.php index caaed38148..1cfa4b0898 100644 --- a/resources/lang/en_US/validation.php +++ b/resources/lang/en_US/validation.php @@ -204,4 +204,5 @@ return [ 'amount_required_for_auto_budget' => 'The amount is required.', 'auto_budget_amount_positive' => 'The amount must be more than zero.', + 'auto_budget_period_mandatory' => 'The auto budget period is a mandatory field.', ];