diff --git a/app/Http/Controllers/Budget/CreateController.php b/app/Http/Controllers/Budget/CreateController.php index 81dd47e09b..d7b79673d8 100644 --- a/app/Http/Controllers/Budget/CreateController.php +++ b/app/Http/Controllers/Budget/CreateController.php @@ -24,7 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers\Budget; -use FireflyIII\AutoBudget; +use FireflyIII\Models\AutoBudget; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Requests\BudgetFormStoreRequest; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; @@ -85,9 +85,11 @@ class CreateController extends Controller 'half_year' => (string)trans('firefly.auto_budget_period_half_year'), 'yearly' => (string)trans('firefly.auto_budget_period_yearly'), ]; + $currency = app('amount')->getDefaultCurrency(); $preFilled = [ - 'auto_budget_period' => $hasOldInput ? (bool)$request->old('auto_budget_period') : 'monthly', + 'auto_budget_period' => $hasOldInput ? (bool)$request->old('auto_budget_period') : 'monthly', + 'transaction_currency_id' => $hasOldInput ? (int)$request->old('transaction_currency_id') : $currency->id, ]; $request->session()->flash('preFilled', $preFilled); diff --git a/app/Http/Controllers/Budget/EditController.php b/app/Http/Controllers/Budget/EditController.php index 91125c6e4d..536f827c73 100644 --- a/app/Http/Controllers/Budget/EditController.php +++ b/app/Http/Controllers/Budget/EditController.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers\Budget; +use FireflyIII\Models\AutoBudget; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Requests\BudgetFormUpdateRequest; use FireflyIII\Models\Budget; @@ -69,13 +70,35 @@ class EditController extends Controller */ public function edit(Request $request, Budget $budget) { - $subTitle = (string)trans('firefly.edit_budget', ['name' => $budget->name]); + $subTitle = (string)trans('firefly.edit_budget', ['name' => $budget->name]); + $autoBudget = $this->repository->getAutoBudget($budget); + // auto budget options + $autoBudgetOptions = [ + 0 => (string)trans('firefly.auto_budget_none'), + AutoBudget::AUTO_BUDGET_RESET => (string)trans('firefly.auto_budget_reset'), + AutoBudget::AUTO_BUDGET_ROLLOVER => (string)trans('firefly.auto_budget_rollover'), + ]; + $autoBudgetPeriods = [ + 'daily' => (string)trans('firefly.auto_budget_period_daily'), + 'weekly' => (string)trans('firefly.auto_budget_period_weekly'), + 'monthly' => (string)trans('firefly.auto_budget_period_monthly'), + 'quarterly' => (string)trans('firefly.auto_budget_period_quarterly'), + 'half_year' => (string)trans('firefly.auto_budget_period_half_year'), + 'yearly' => (string)trans('firefly.auto_budget_period_yearly'), + ]; // code to handle active-checkboxes $hasOldInput = null !== $request->old('_token'); $preFilled = [ - 'active' => $hasOldInput ? (bool)$request->old('active') : $budget->active, + 'active' => $hasOldInput ? (bool)$request->old('active') : $budget->active, ]; + if($autoBudget) { + $preFilled['auto_budget_amount'] = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount; + //'auto_budget_option' => $request->, + //'transaction_currency_id' => 'required|exists:transaction_currencies,id', + //'auto_budget_amount' => $request->old('auto_budget_amount'), + //'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly', + } // put previous url in session if not redirect from store (not "return_to_edit"). if (true !== session('budgets.edit.fromUpdate')) { @@ -84,7 +107,7 @@ class EditController extends Controller $request->session()->forget('budgets.edit.fromUpdate'); $request->session()->flash('preFilled', $preFilled); - return view('budgets.edit', compact('budget', 'subTitle')); + return view('budgets.edit', compact('budget', 'subTitle', 'autoBudgetOptions', 'autoBudgetPeriods', 'autoBudget')); } /** diff --git a/app/Http/Requests/BudgetFormStoreRequest.php b/app/Http/Requests/BudgetFormStoreRequest.php index f7287c4ff3..9e27e337f1 100644 --- a/app/Http/Requests/BudgetFormStoreRequest.php +++ b/app/Http/Requests/BudgetFormStoreRequest.php @@ -22,7 +22,6 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; -use FireflyIII\AutoBudget; use Illuminate\Validation\Validator; /** @@ -87,30 +86,9 @@ class BudgetFormStoreRequest extends Request $validator->after( function (Validator $validator) { // validate all account info - $this->validateAmount($validator); + $this->validateAutoBudgetAmount($validator); } ); } - /** - * @param Validator $validator - */ - private function validateAmount(Validator $validator): void - { - $data = $validator->getData(); - $option = (int)$data['auto_budget_option']; - $amount = $data['auto_budget_amount'] ?? ''; - switch ($option) { - case AutoBudget::AUTO_BUDGET_RESET: - case AutoBudget::AUTO_BUDGET_ROLLOVER: - // basic float check: - if ('' === $amount) { - $validator->errors()->add('auto_budget_amount', (string)trans('validation.amount_required_for_auto_budget')); - } - if (1 !== bccomp((string)$amount, '0')) { - $validator->errors()->add('auto_budget_amount', (string)trans('validation.auto_budget_amount_positive')); - } - break; - } - } } diff --git a/app/Http/Requests/BudgetFormUpdateRequest.php b/app/Http/Requests/BudgetFormUpdateRequest.php index ed01f1ee6c..d9c54cfb5f 100644 --- a/app/Http/Requests/BudgetFormUpdateRequest.php +++ b/app/Http/Requests/BudgetFormUpdateRequest.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; use FireflyIII\Models\Budget; +use Illuminate\Validation\Validator; /** * @codeCoverageIgnore @@ -48,8 +49,12 @@ class BudgetFormUpdateRequest extends Request public function getBudgetData(): array { return [ - 'name' => $this->string('name'), - 'active' => $this->boolean('active'), + 'name' => $this->string('name'), + 'active' => $this->boolean('active'), + 'auto_budget_option' => $this->integer('auto_budget_option'), + 'transaction_currency_id' => $this->integer('transaction_currency_id'), + 'auto_budget_amount' => $this->string('auto_budget_amount'), + 'auto_budget_period' => $this->string('auto_budget_period'), ]; } @@ -70,8 +75,29 @@ class BudgetFormUpdateRequest extends Request } return [ - 'name' => $nameRule, - 'active' => 'numeric|between:0,1', + 'name' => $nameRule, + 'active' => 'numeric|between:0,1', + 'auto_budget_option' => 'numeric|between:0,2', + 'transaction_currency_id' => 'required|exists:transaction_currencies,id', + '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/Http/Requests/Request.php b/app/Http/Requests/Request.php index d85310ff38..f98e2e0b61 100644 --- a/app/Http/Requests/Request.php +++ b/app/Http/Requests/Request.php @@ -25,7 +25,9 @@ namespace FireflyIII\Http\Requests; use Carbon\Carbon; use Carbon\Exceptions\InvalidDateException; use Exception; +use FireflyIII\Models\AutoBudget; use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Validation\Validator; use Log; /** @@ -385,4 +387,26 @@ 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) { + case AutoBudget::AUTO_BUDGET_RESET: + case AutoBudget::AUTO_BUDGET_ROLLOVER: + // basic float check: + if ('' === $amount) { + $validator->errors()->add('auto_budget_amount', (string)trans('validation.amount_required_for_auto_budget')); + } + if (1 !== bccomp((string)$amount, '0')) { + $validator->errors()->add('auto_budget_amount', (string)trans('validation.auto_budget_amount_positive')); + } + break; + } + } + } diff --git a/app/Models/AutoBudget.php b/app/Models/AutoBudget.php index fef108460d..4d9dd6c834 100644 --- a/app/Models/AutoBudget.php +++ b/app/Models/AutoBudget.php @@ -19,9 +19,8 @@ * along with this program. If not, see . */ -namespace FireflyIII; +namespace FireflyIII\Models; -use FireflyIII\Models\Budget; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\SoftDeletes; @@ -46,4 +45,13 @@ class AutoBudget extends Model { return $this->belongsTo(Budget::class); } + + /** + * @codeCoverageIgnore + * @return BelongsTo + */ + public function transactionCurrency(): BelongsTo + { + return $this->belongsTo(TransactionCurrency::class); + } } diff --git a/app/Models/Budget.php b/app/Models/Budget.php index 298a7c7475..a9b44ba18a 100644 --- a/app/Models/Budget.php +++ b/app/Models/Budget.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace FireflyIII\Models; use Carbon\Carbon; -use FireflyIII\AutoBudget; use FireflyIII\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; diff --git a/app/Models/RecurrenceTransaction.php b/app/Models/RecurrenceTransaction.php index 87ad759a8f..cedd49f236 100644 --- a/app/Models/RecurrenceTransaction.php +++ b/app/Models/RecurrenceTransaction.php @@ -50,7 +50,6 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $deleted_at * @property int $recurrence_id - * @property int $transaction_currency_id * @method static bool|null forceDelete() * @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\RecurrenceTransaction newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\RecurrenceTransaction newQuery() diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 1ac9eca663..e4ae35eeec 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -25,7 +25,7 @@ namespace FireflyIII\Repositories\Budget; use Carbon\Carbon; use DB; use Exception; -use FireflyIII\AutoBudget; +use FireflyIII\Models\AutoBudget; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Budget; use FireflyIII\Models\BudgetLimit; @@ -316,6 +316,22 @@ class BudgetRepository implements BudgetRepositoryInterface $budget->name = $data['name']; $budget->active = $data['active']; $budget->save(); + + // update or create auto-budget: + $autoBudgetType = $data['auto_budget_option'] ?? 0; + if (0 !== $autoBudgetType) { + $autoBudget = $this->getAutoBudget($budget); + if (null === $autoBudget) { + $autoBudget = new AutoBudget; + $autoBudget->budget()->associate($budget); + } + $autoBudget->transaction_currency_id = $data['transaction_currency_id'] ?? 1; + $autoBudget->auto_budget_type = $autoBudgetType; + $autoBudget->amount = $data['auto_budget_amount'] ?? '0'; + $autoBudget->period = $data['auto_budget_period'] ?? 'monthly'; + $autoBudget->save(); + } + $this->updateRuleTriggers($oldName, $data['name']); $this->updateRuleActions($oldName, $data['name']); app('preferences')->mark(); @@ -380,4 +396,12 @@ class BudgetRepository implements BudgetRepositoryInterface $budget->delete(); } } + + /** + * @inheritDoc + */ + public function getAutoBudget(Budget $budget): ?AutoBudget + { + return $budget->autoBudgets()->first(); + } } diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index b1bf472bc9..a58d29a96f 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Repositories\Budget; use Carbon\Carbon; +use FireflyIII\Models\AutoBudget; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Budget; use FireflyIII\User; @@ -38,6 +39,13 @@ interface BudgetRepositoryInterface */ public function destroyAll(): void; + /** + * @param Budget $budget + * + * @return AutoBudget|null + */ + public function getAutoBudget(Budget $budget): ?AutoBudget; + /** * @return bool diff --git a/app/Services/Internal/Destroy/BudgetDestroyService.php b/app/Services/Internal/Destroy/BudgetDestroyService.php index f1573ab384..745c4886fd 100644 --- a/app/Services/Internal/Destroy/BudgetDestroyService.php +++ b/app/Services/Internal/Destroy/BudgetDestroyService.php @@ -49,12 +49,18 @@ class BudgetDestroyService */ public function destroy(Budget $budget): void { + try { $budget->delete(); } catch (Exception $e) { // @codeCoverageIgnore Log::error(sprintf('Could not delete budget: %s', $e->getMessage())); // @codeCoverageIgnore } + // also delete auto budget: + foreach ($budget->autoBudgets()->get() as $autoBudget) { + $autoBudget->delete(); + } + // also delete all relations between categories and transaction journals: DB::table('budget_transaction_journal')->where('budget_id', (int)$budget->id)->delete(); diff --git a/app/Transformers/BudgetTransformer.php b/app/Transformers/BudgetTransformer.php index 2f4e8eedda..245683107a 100644 --- a/app/Transformers/BudgetTransformer.php +++ b/app/Transformers/BudgetTransformer.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Transformers; +use FireflyIII\Models\AutoBudget; use FireflyIII\Models\Budget; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; @@ -37,6 +38,8 @@ class BudgetTransformer extends AbstractTransformer { /** @var OperationsRepositoryInterface */ private $opsRepository; + /** @var BudgetRepositoryInterface */ + private $repository; /** * BudgetTransformer constructor. @@ -46,6 +49,7 @@ class BudgetTransformer extends AbstractTransformer public function __construct() { $this->opsRepository = app(OperationsRepositoryInterface::class); + $this->repository = app(BudgetRepositoryInterface::class); if ('testing' === config('app.env')) { Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this))); } @@ -61,21 +65,46 @@ class BudgetTransformer extends AbstractTransformer public function transform(Budget $budget): array { $this->opsRepository->setUser($budget->user); - $start = $this->parameters->get('start'); - $end = $this->parameters->get('end'); - $spent = []; + $start = $this->parameters->get('start'); + $end = $this->parameters->get('end'); + $autoBudget = $this->repository->getAutoBudget($budget); + $spent = []; if (null !== $start && null !== $end) { $spent = array_values($this->opsRepository->sumExpenses($start, $end, null, new Collection([$budget]))); } + $abCurrencyId = null; + $abCurrencyCode = null; + $abType = null; + $abAmount = null; + $abPeriod = null; + + $types = [ + AutoBudget::AUTO_BUDGET_RESET => 'reset', + AutoBudget::AUTO_BUDGET_ROLLOVER => 'rollover', + ]; + + if (null !== $autoBudget) { + $abCurrencyId = $autoBudget->transactionCurrency->id; + $abCurrencyCode = $autoBudget->transactionCurrency->code; + $abType = $types[$autoBudget->auto_budget_type]; + $abAmount = $autoBudget->amount; + $abPeriod = $autoBudget->period; + } + $data = [ - 'id' => (int)$budget->id, - 'created_at' => $budget->created_at->toAtomString(), - 'updated_at' => $budget->updated_at->toAtomString(), - 'active' => $budget->active, - 'name' => $budget->name, - 'spent' => $spent, - 'links' => [ + 'id' => (int)$budget->id, + 'created_at' => $budget->created_at->toAtomString(), + 'updated_at' => $budget->updated_at->toAtomString(), + 'active' => $budget->active, + 'name' => $budget->name, + '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' => [ [ 'rel' => 'self', 'uri' => '/budgets/' . $budget->id, diff --git a/resources/views/v1/budgets/create.twig b/resources/views/v1/budgets/create.twig index 7b78db5cdb..91713d29e8 100644 --- a/resources/views/v1/budgets/create.twig +++ b/resources/views/v1/budgets/create.twig @@ -33,11 +33,7 @@ {{ ExpandedForm.amountNoCurrency('auto_budget_amount') }} {{ ExpandedForm.select('auto_budget_period', autoBudgetPeriods, null) }} - -
diff --git a/resources/views/v1/budgets/edit.twig b/resources/views/v1/budgets/edit.twig index dd0c49b6a0..4b64626a92 100644 --- a/resources/views/v1/budgets/edit.twig +++ b/resources/views/v1/budgets/edit.twig @@ -22,8 +22,18 @@
- {# auto budget#} - bla bla + {# panel for auto-budget #} +
+
+

{{ 'optionalFields'|_ }}

+
+
+ {{ ExpandedForm.select('auto_budget_option', autoBudgetOptions, autoBudget.auto_budget_type) }} + {{ CurrencyForm.currencyList('transaction_currency_id', autoBudget.transaction_currency_id) }} + {{ ExpandedForm.amountNoCurrency('auto_budget_amount', preFilled.auto_budget_amount) }} + {{ ExpandedForm.select('auto_budget_period', autoBudgetPeriods, autoBudget.period) }} +
+