diff --git a/app/Console/Commands/Correction/CorrectsInvertedBudgetLimits.php b/app/Console/Commands/Correction/CorrectsInvertedBudgetLimits.php index 2cd3acdccc..6c2162f69f 100644 --- a/app/Console/Commands/Correction/CorrectsInvertedBudgetLimits.php +++ b/app/Console/Commands/Correction/CorrectsInvertedBudgetLimits.php @@ -68,6 +68,11 @@ class CorrectsInvertedBudgetLimits extends Command $budgetLimit->end_date = $start; $budgetLimit->saveQuietly(); } + + if($set->count() > 0) { + // FIXME here be a available budget event. + } + if (1 === $set->count()) { $this->friendlyInfo('Corrected one budget limit to have the right start/end dates.'); diff --git a/app/Console/Commands/Upgrade/UpgradesBudgetLimitPeriods.php b/app/Console/Commands/Upgrade/UpgradesBudgetLimitPeriods.php index 4c1327760c..589fa26f0f 100644 --- a/app/Console/Commands/Upgrade/UpgradesBudgetLimitPeriods.php +++ b/app/Console/Commands/Upgrade/UpgradesBudgetLimitPeriods.php @@ -91,7 +91,7 @@ class UpgradesBudgetLimitPeriods extends Command return; } $limit->period = $period; - $limit->save(); + $limit->saveQuietly(); $msg = sprintf( 'Budget limit #%d (%s - %s) period is "%s".', diff --git a/app/Console/Commands/Upgrade/UpgradesBudgetLimits.php b/app/Console/Commands/Upgrade/UpgradesBudgetLimits.php index e85705c3a2..e9bf49b176 100644 --- a/app/Console/Commands/Upgrade/UpgradesBudgetLimits.php +++ b/app/Console/Commands/Upgrade/UpgradesBudgetLimits.php @@ -70,7 +70,7 @@ class UpgradesBudgetLimits extends Command if (null !== $user) { $currency = Amount::getPrimaryCurrencyByUserGroup($user->userGroup); $budgetLimit->transaction_currency_id = $currency->id; - $budgetLimit->save(); + $budgetLimit->saveQuietly(); $this->friendlyInfo(sprintf( 'Budget limit #%d (part of budget "%s") now has a currency setting (%s).', $budgetLimit->id, diff --git a/app/Events/Model/BudgetLimit/CreatedBudgetLimit.php b/app/Events/Model/BudgetLimit/CreatedBudgetLimit.php new file mode 100644 index 0000000000..a44a6aebd4 --- /dev/null +++ b/app/Events/Model/BudgetLimit/CreatedBudgetLimit.php @@ -0,0 +1,35 @@ +. + */ + +namespace FireflyIII\Events\Model\BudgetLimit; + +use FireflyIII\Events\Event; +use FireflyIII\Models\BudgetLimit; +use FireflyIII\User; +use Illuminate\Queue\SerializesModels; + +class CreatedBudgetLimit extends Event +{ + use SerializesModels; + + public function __construct(public BudgetLimit $budgetLimit) {} + +} diff --git a/app/Events/Model/BudgetLimit/DestroyedBudgetLimit.php b/app/Events/Model/BudgetLimit/DestroyedBudgetLimit.php new file mode 100644 index 0000000000..826f2acf91 --- /dev/null +++ b/app/Events/Model/BudgetLimit/DestroyedBudgetLimit.php @@ -0,0 +1,34 @@ +. + */ + +namespace FireflyIII\Events\Model\BudgetLimit; + +use FireflyIII\Events\Event; +use FireflyIII\User; +use Illuminate\Queue\SerializesModels; + +class DestroyedBudgetLimit extends Event +{ + use SerializesModels; + + public function __construct(public User $user) {} + +} diff --git a/app/Events/Model/BudgetLimit/UpdatedBudgetLimit.php b/app/Events/Model/BudgetLimit/UpdatedBudgetLimit.php new file mode 100644 index 0000000000..330064d530 --- /dev/null +++ b/app/Events/Model/BudgetLimit/UpdatedBudgetLimit.php @@ -0,0 +1,33 @@ +. + */ + +namespace FireflyIII\Events\Model\BudgetLimit; + +use FireflyIII\Events\Event; +use FireflyIII\Models\BudgetLimit; +use Illuminate\Queue\SerializesModels; + +class UpdatedBudgetLimit extends Event +{ + use SerializesModels; + + public function __construct(public BudgetLimit $budgetLimit) {} +} diff --git a/app/Http/Controllers/Budget/BudgetLimitController.php b/app/Http/Controllers/Budget/BudgetLimitController.php index b48da47928..c37d802934 100644 --- a/app/Http/Controllers/Budget/BudgetLimitController.php +++ b/app/Http/Controllers/Budget/BudgetLimitController.php @@ -97,7 +97,7 @@ class BudgetLimitController extends Controller return true; }); - return view('budgets.budget-limits.create', ['start' => $start, 'end' => $end, 'currencies' => $currencies, 'budget' => $budget]); + return view('budgets.budget-limits.create', ['start' => $start, 'end' => $end, 'currencies' => $currencies, 'budget' => $budget]); } public function delete(BudgetLimit $budgetLimit): Redirector|RedirectResponse @@ -167,8 +167,8 @@ class BudgetLimitController extends Controller $this->blRepository->destroyBudgetLimit($limit); } - // return empty=ish array: - return response()->json(); + // return empty array: + return response()->json([]); } if ((int) $amount > 268435456) { // intentional cast to integer $amount = '268435456'; @@ -178,8 +178,7 @@ class BudgetLimitController extends Controller } if ($limit instanceof BudgetLimit) { - $limit->amount = $amount; - $limit->save(); + $this->blRepository->update($limit, ['amount' => $amount]); } if (!$limit instanceof BudgetLimit) { $limit = $this->blRepository->store([ diff --git a/app/Jobs/CreateAutoBudgetLimits.php b/app/Jobs/CreateAutoBudgetLimits.php index 0def88b17f..34c9fddae4 100644 --- a/app/Jobs/CreateAutoBudgetLimits.php +++ b/app/Jobs/CreateAutoBudgetLimits.php @@ -30,6 +30,7 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\AutoBudget; use FireflyIII\Models\Budget; use FireflyIII\Models\BudgetLimit; +use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; use FireflyIII\Support\Facades\Navigation; use Illuminate\Bus\Queueable; @@ -58,7 +59,7 @@ class CreateAutoBudgetLimits implements ShouldQueue public function __construct(?Carbon $date) { if ($date instanceof Carbon) { - $newDate = clone $date; + $newDate = clone $date; $newDate->startOfDay(); $this->date = $newDate; Log::debug(sprintf('Created new CreateAutoBudgetLimits("%s")', $this->date->format('Y-m-d'))); @@ -98,34 +99,34 @@ class CreateAutoBudgetLimits implements ShouldQueue } if (!$this->isMagicDay($autoBudget)) { Log::info(sprintf( - 'Today (%s) is not a magic day for %s auto-budget #%d (part of budget #%d "%s")', - $this->date->format('Y-m-d'), - $autoBudget->period, - $autoBudget->id, - $autoBudget->budget->id, - $autoBudget->budget->name - )); + 'Today (%s) is not a magic day for %s auto-budget #%d (part of budget #%d "%s")', + $this->date->format('Y-m-d'), + $autoBudget->period, + $autoBudget->id, + $autoBudget->budget->id, + $autoBudget->budget->name + )); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id)); return; } Log::info(sprintf( - 'Today (%s) is a magic day for %s auto-budget #%d (part of budget #%d "%s")', - $this->date->format('Y-m-d'), - $autoBudget->period, - $autoBudget->id, - $autoBudget->budget->id, - $autoBudget->budget->name - )); + 'Today (%s) is a magic day for %s auto-budget #%d (part of budget #%d "%s")', + $this->date->format('Y-m-d'), + $autoBudget->period, + $autoBudget->id, + $autoBudget->budget->id, + $autoBudget->budget->name + )); // get date range for budget limit, based on range in auto-budget - $start = Navigation::startOfPeriod($this->date, $autoBudget->period); - $end = Navigation::endOfPeriod($start, $autoBudget->period); + $start = Navigation::startOfPeriod($this->date, $autoBudget->period); + $end = Navigation::endOfPeriod($start, $autoBudget->period); // find budget limit: $budgetLimit = $this->findBudgetLimit($autoBudget->budget, $start, $end); - if (!$budgetLimit instanceof BudgetLimit && AutoBudgetType::AUTO_BUDGET_RESET->value === (int) $autoBudget->auto_budget_type) { + if (!$budgetLimit instanceof BudgetLimit && AutoBudgetType::AUTO_BUDGET_RESET->value === (int)$autoBudget->auto_budget_type) { // that's easy: create one. // do nothing else. $this->createBudgetLimit($autoBudget, $start, $end); @@ -134,14 +135,14 @@ class CreateAutoBudgetLimits implements ShouldQueue return; } - if (!$budgetLimit instanceof BudgetLimit && AutoBudgetType::AUTO_BUDGET_ROLLOVER->value === (int) $autoBudget->auto_budget_type) { + if (!$budgetLimit instanceof BudgetLimit && AutoBudgetType::AUTO_BUDGET_ROLLOVER->value === (int)$autoBudget->auto_budget_type) { // budget limit exists already, $this->createRollover($autoBudget); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id)); return; } - if (!$budgetLimit instanceof BudgetLimit && AutoBudgetType::AUTO_BUDGET_ADJUSTED->value === (int) $autoBudget->auto_budget_type) { + if (!$budgetLimit instanceof BudgetLimit && AutoBudgetType::AUTO_BUDGET_ADJUSTED->value === (int)$autoBudget->auto_budget_type) { // budget limit exists already, $this->createAdjustedLimit($autoBudget); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id)); @@ -192,12 +193,12 @@ class CreateAutoBudgetLimits implements ShouldQueue private function findBudgetLimit(Budget $budget, Carbon $start, Carbon $end): ?BudgetLimit { Log::debug(sprintf( - 'Going to find a budget limit for budget #%d ("%s") between %s and %s', - $budget->id, - $budget->name, - $start->format('Y-m-d'), - $end->format('Y-m-d') - )); + 'Going to find a budget limit for budget #%d ("%s") between %s and %s', + $budget->id, + $budget->name, + $start->format('Y-m-d'), + $end->format('Y-m-d') + )); /** @var null|BudgetLimit */ return $budget->budgetlimits()->where('start_date', $start->format('Y-m-d'))->where('end_date', $end->format('Y-m-d'))->first(); @@ -209,16 +210,22 @@ class CreateAutoBudgetLimits implements ShouldQueue if (null !== $amount) { Log::debug(sprintf('Amount is overruled and will be set to %s', $amount)); } - $budgetLimit = new BudgetLimit(); - $budgetLimit->budget()->associate($autoBudget->budget); - $budgetLimit->transactionCurrency()->associate($autoBudget->transactionCurrency); - $budgetLimit->start_date = clone $start; - $budgetLimit->end_date = clone $end; - $budgetLimit->amount = $amount ?? $autoBudget->amount; - $budgetLimit->period = $autoBudget->period; - $budgetLimit->generated = 1; - $budgetLimit->save(); + /** @var BudgetLimitRepositoryInterface $repository */ + $repository = app(BudgetLimitRepositoryInterface::class); + $repository->setUserGroup($autoBudget->budget->user->userGroup); + $budgetLimit = $repository->store( + [ + 'currency_id' => $autoBudget->transaction_currency_id, + 'budget_id' => $autoBudget->budget->id, + 'start_date' => clone $start, + 'end_date' => clone $end, + 'amount' => $amount ?? $autoBudget->amount, + 'period' => $autoBudget->period, + 'generated' => true, + + ] + ); Log::debug(sprintf('Created budget limit #%d.', $budgetLimit->id)); } @@ -229,23 +236,23 @@ class CreateAutoBudgetLimits implements ShouldQueue { Log::debug(sprintf('Will now manage rollover for auto budget #%d', $autoBudget->id)); // current period: - $start = Navigation::startOfPeriod($this->date, $autoBudget->period); - $end = Navigation::endOfPeriod($start, $autoBudget->period); + $start = Navigation::startOfPeriod($this->date, $autoBudget->period); + $end = Navigation::endOfPeriod($start, $autoBudget->period); // which means previous period: $previousStart = Navigation::subtractPeriod($start, $autoBudget->period); $previousEnd = Navigation::endOfPeriod($previousStart, $autoBudget->period); Log::debug(sprintf( - 'Current period is %s-%s, so previous period is %s-%s', - $start->format('Y-m-d'), - $end->format('Y-m-d'), - $previousStart->format('Y-m-d'), - $previousEnd->format('Y-m-d') - )); + 'Current period is %s-%s, so previous period is %s-%s', + $start->format('Y-m-d'), + $end->format('Y-m-d'), + $previousStart->format('Y-m-d'), + $previousEnd->format('Y-m-d') + )); // has budget limit in previous period? - $budgetLimit = $this->findBudgetLimit($autoBudget->budget, $previousStart, $previousEnd); + $budgetLimit = $this->findBudgetLimit($autoBudget->budget, $previousStart, $previousEnd); if (!$budgetLimit instanceof BudgetLimit) { Log::debug('No budget limit exists in previous period, so create one.'); @@ -257,23 +264,23 @@ class CreateAutoBudgetLimits implements ShouldQueue } Log::debug('Budget limit exists for previous period.'); // if has one, calculate expenses and use that as a base. - $repository = app(OperationsRepositoryInterface::class); + $repository = app(OperationsRepositoryInterface::class); $repository->setUser($autoBudget->budget->user); - $spent = $repository->sumExpenses( + $spent = $repository->sumExpenses( $previousStart, $previousEnd, null, new Collection()->push($autoBudget->budget), $autoBudget->transactionCurrency ); - $currencyId = $autoBudget->transaction_currency_id; - $spentAmount = $spent[$currencyId]['sum'] ?? '0'; + $currencyId = $autoBudget->transaction_currency_id; + $spentAmount = $spent[$currencyId]['sum'] ?? '0'; Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); // if you spent more in previous budget period, than whatever you had previous budget period, the amount resets // previous budget limit + spent - $budgetLeft = bcadd($budgetLimit->amount, $spentAmount); - $totalAmount = $autoBudget->amount; + $budgetLeft = bcadd($budgetLimit->amount, $spentAmount); + $totalAmount = $autoBudget->amount; Log::debug(sprintf('Total amount left for previous budget period is %s', $budgetLeft)); if (-1 !== bccomp('0', $budgetLeft)) { @@ -293,23 +300,23 @@ class CreateAutoBudgetLimits implements ShouldQueue { Log::debug(sprintf('Will now manage rollover for auto budget #%d', $autoBudget->id)); // current period: - $start = Navigation::startOfPeriod($this->date, $autoBudget->period); - $end = Navigation::endOfPeriod($start, $autoBudget->period); + $start = Navigation::startOfPeriod($this->date, $autoBudget->period); + $end = Navigation::endOfPeriod($start, $autoBudget->period); // which means previous period: - $previousStart = Navigation::subtractPeriod($start, $autoBudget->period); - $previousEnd = Navigation::endOfPeriod($previousStart, $autoBudget->period); + $previousStart = Navigation::subtractPeriod($start, $autoBudget->period); + $previousEnd = Navigation::endOfPeriod($previousStart, $autoBudget->period); Log::debug(sprintf( - 'Current period is %s-%s, so previous period is %s-%s', - $start->format('Y-m-d'), - $end->format('Y-m-d'), - $previousStart->format('Y-m-d'), - $previousEnd->format('Y-m-d') - )); + 'Current period is %s-%s, so previous period is %s-%s', + $start->format('Y-m-d'), + $end->format('Y-m-d'), + $previousStart->format('Y-m-d'), + $previousEnd->format('Y-m-d') + )); // has budget limit in previous period? - $budgetLimit = $this->findBudgetLimit($autoBudget->budget, $previousStart, $previousEnd); + $budgetLimit = $this->findBudgetLimit($autoBudget->budget, $previousStart, $previousEnd); if (!$budgetLimit instanceof BudgetLimit) { Log::debug('No budget limit exists in previous period, so create one.'); @@ -321,17 +328,17 @@ class CreateAutoBudgetLimits implements ShouldQueue Log::debug('Budget limit exists for previous period.'); // if has one, calculate expenses and use that as a base. - $repository = app(OperationsRepositoryInterface::class); + $repository = app(OperationsRepositoryInterface::class); $repository->setUser($autoBudget->budget->user); - $spent = $repository->sumExpenses( + $spent = $repository->sumExpenses( $previousStart, $previousEnd, null, new Collection()->push($autoBudget->budget), $autoBudget->transactionCurrency ); - $currencyId = $autoBudget->transaction_currency_id; - $spentAmount = $spent[$currencyId]['sum'] ?? '0'; + $currencyId = $autoBudget->transaction_currency_id; + $spentAmount = $spent[$currencyId]['sum'] ?? '0'; Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); // what you spent in previous period PLUS the amount for the current period, @@ -361,7 +368,7 @@ class CreateAutoBudgetLimits implements ShouldQueue public function setDate(Carbon $date): void { - $newDate = clone $date; + $newDate = clone $date; $newDate->startOfDay(); $this->date = $newDate; } diff --git a/app/Listeners/Model/BudgetLimit/RecalculatesAvailableBudgets.php b/app/Listeners/Model/BudgetLimit/RecalculatesAvailableBudgets.php new file mode 100644 index 0000000000..6490666c91 --- /dev/null +++ b/app/Listeners/Model/BudgetLimit/RecalculatesAvailableBudgets.php @@ -0,0 +1,35 @@ +. + */ + +namespace FireflyIII\Listeners\Model\BudgetLimit; + +use FireflyIII\Events\Model\BudgetLimit\DestroyedBudgetLimit; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Support\Facades\Log; + +class RecalculatesAvailableBudgets implements ShouldQueue +{ + public function handle(DestroyedBudgetLimit $event): void + { + Log::debug(sprintf('Noticed event %s. Now what?', get_class($event))); + } + +} diff --git a/app/Repositories/Budget/BudgetLimitRepository.php b/app/Repositories/Budget/BudgetLimitRepository.php index 3d776cdaee..ce07867f43 100644 --- a/app/Repositories/Budget/BudgetLimitRepository.php +++ b/app/Repositories/Budget/BudgetLimitRepository.php @@ -25,6 +25,7 @@ declare(strict_types=1); namespace FireflyIII\Repositories\Budget; use Carbon\Carbon; +use FireflyIII\Events\Model\BudgetLimit\DestroyedBudgetLimit; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Factory\TransactionCurrencyFactory; use FireflyIII\Models\Budget; @@ -53,9 +54,9 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup */ public function budgeted(Carbon $start, Carbon $end, TransactionCurrency $currency, ?Collection $budgets = null): string { - $query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') + $query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') // same complex where query as below. - ->where(static function (Builder $q5) use ($start, $end): void { + ->where(static function (Builder $q5) use ($start, $end): void { $q5->where(static function (Builder $q1) use ($start, $end): void { $q1->where(static function (Builder $q2) use ($start, $end): void { $q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d')); @@ -70,11 +71,10 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d')); }); }) - ->where('budget_limits.transaction_currency_id', $currency->id) - ->whereNull('budgets.deleted_at') - ->where('budgets.active', true) - ->where('budgets.user_id', $this->user->id) - ; + ->where('budget_limits.transaction_currency_id', $currency->id) + ->whereNull('budgets.deleted_at') + ->where('budgets.active', true) + ->where('budgets.user_id', $this->user->id); if ($budgets instanceof Collection && $budgets->count() > 0) { $query->whereIn('budget_limits.budget_id', $budgets->pluck('id')->toArray()); } @@ -84,7 +84,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup /** @var BudgetLimit $budgetLimit */ foreach ($set as $budgetLimit) { - $result = bcadd((string) $budgetLimit->amount, $result); + $result = bcadd((string)$budgetLimit->amount, $result); } return $result; @@ -109,13 +109,15 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup */ public function destroyBudgetLimit(BudgetLimit $budgetLimit): void { + $user = $budgetLimit->budget->user; $budgetLimit->delete(); + event(new DestroyedBudgetLimit($user)); } public function getAllBudgetLimitsByCurrency(TransactionCurrency $currency, ?Carbon $start = null, ?Carbon $end = null): Collection { return $this->getAllBudgetLimits($start, $end)->filter( - static fn (BudgetLimit $budgetLimit): bool => $budgetLimit->transaction_currency_id === $currency->id + static fn(BudgetLimit $budgetLimit): bool => $budgetLimit->transaction_currency_id === $currency->id ); } @@ -124,19 +126,17 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup // both are NULL: if (!$start instanceof Carbon && !$end instanceof Carbon) { return BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') - ->with(['budget']) - ->where('budgets.user_id', $this->user->id) - ->whereNull('budgets.deleted_at') - ->get(['budget_limits.*']) - ; + ->with(['budget']) + ->where('budgets.user_id', $this->user->id) + ->whereNull('budgets.deleted_at') + ->get(['budget_limits.*']); } // one of the two is NULL. if (!$start instanceof Carbon xor !$end instanceof Carbon) { $query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') - ->with(['budget']) - ->whereNull('budgets.deleted_at') - ->where('budgets.user_id', $this->user->id) - ; + ->with(['budget']) + ->whereNull('budgets.deleted_at') + ->where('budgets.user_id', $this->user->id); if ($end instanceof Carbon) { // end date must be before $end. $query->where('end_date', '<=', $end->format('Y-m-d 00:00:00')); @@ -151,26 +151,25 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup // neither are NULL: return BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') - ->with(['budget']) - ->where('budgets.user_id', $this->user->id) - ->whereNull('budgets.deleted_at') - ->where(static function (Builder $q5) use ($start, $end): void { - $q5->where(static function (Builder $q1) use ($start, $end): void { - $q1->where(static function (Builder $q2) use ($start, $end): void { - $q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d')); - $q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d')); - })->orWhere(static function (Builder $q3) use ($start, $end): void { - $q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d')); - $q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d')); - }); - })->orWhere(static function (Builder $q4) use ($start, $end): void { - // or start is before start AND end is after end. - $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d')); - $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d')); - }); - }) - ->get(['budget_limits.*']) - ; + ->with(['budget']) + ->where('budgets.user_id', $this->user->id) + ->whereNull('budgets.deleted_at') + ->where(static function (Builder $q5) use ($start, $end): void { + $q5->where(static function (Builder $q1) use ($start, $end): void { + $q1->where(static function (Builder $q2) use ($start, $end): void { + $q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d')); + $q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d')); + })->orWhere(static function (Builder $q3) use ($start, $end): void { + $q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d')); + $q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d')); + }); + })->orWhere(static function (Builder $q4) use ($start, $end): void { + // or start is before start AND end is after end. + $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d')); + $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d')); + }); + }) + ->get(['budget_limits.*']); } public function getBudgetLimits(Budget $budget, ?Carbon $start = null, ?Carbon $end = null): Collection @@ -208,8 +207,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup ->orWhere(static function (Builder $q3) use ($start, $end): void { $q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d 00:00:00')); $q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d 23:59:59')); - }) - ; + }); })->orWhere(static function (Builder $q4) use ($start, $end): void { // or start is before start AND end is after end. $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d 23:59:59')); @@ -217,14 +215,13 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup }); }) ->orderBy('budget_limits.start_date', 'DESC') - ->get(['budget_limits.*']) - ; + ->get(['budget_limits.*']); } #[Override] public function getNoteText(BudgetLimit $budgetLimit): string { - return (string) $budgetLimit->notes()->first()?->text; + return (string)$budgetLimit->notes()->first()?->text; } /** @@ -234,48 +231,49 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup { // if no currency has been provided, use the user's default currency: /** @var TransactionCurrencyFactory $factory */ - $factory = app(TransactionCurrencyFactory::class); - $currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null); + $factory = app(TransactionCurrencyFactory::class); + $currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($this->user->userGroup); } - $currency->enabled = true; + $currency->enabled = true; $currency->save(); // find the budget: /** @var null|Budget $budget */ - $budget = $this->user->budgets()->find((int) $data['budget_id']); + $budget = $this->user->budgets()->find((int)$data['budget_id']); if (null === $budget) { throw new FireflyException('200004: Budget does not exist.'); } // find limit with same date range and currency. - $limit = $budget + $limit = $budget ->budgetlimits() ->where('budget_limits.start_date', $data['start_date']->format('Y-m-d')) ->where('budget_limits.end_date', $data['end_date']->format('Y-m-d')) ->where('budget_limits.transaction_currency_id', $currency->id) - ->first(['budget_limits.*']) - ; + ->first(['budget_limits.*']); if (null !== $limit) { throw new FireflyException('200027: Budget limit already exists.'); } Log::debug('No existing budget limit, create a new one'); // this is a lame trick to communicate with the observer. - $singleton = PreferencesSingleton::getInstance(); + $singleton = PreferencesSingleton::getInstance(); $singleton->setPreference('fire_webhooks_bl_store', $data['fire_webhooks'] ?? true); // or create one and return it. - $limit = new BudgetLimit(); + $limit = new BudgetLimit(); $limit->budget()->associate($budget); $limit->start_date = $data['start_date']->format('Y-m-d'); $limit->end_date = $data['end_date']->format('Y-m-d'); $limit->amount = $data['amount']; + $limit->generated = $data['generated'] ?? false; + $limit->period = $data['period'] ?? ''; $limit->transaction_currency_id = $currency->id; $limit->save(); - $noteText = (string) ($data['notes'] ?? ''); + $noteText = (string)($data['notes'] ?? ''); if ('' !== $noteText) { $this->setNoteText($limit, $noteText); } @@ -293,8 +291,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup ->where('transaction_currency_id', $currency->id) ->where('start_date', $start->format('Y-m-d')) ->where('end_date', $end->format('Y-m-d')) - ->first() - ; + ->first(); } #[Override] @@ -319,8 +316,8 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup */ public function update(BudgetLimit $budgetLimit, array $data): BudgetLimit { - $budgetLimit->amount = array_key_exists('amount', $data) ? $data['amount'] : $budgetLimit->amount; - $budgetLimit->budget_id = array_key_exists('budget_id', $data) ? $data['budget_id'] : $budgetLimit->budget_id; + $budgetLimit->amount = array_key_exists('amount', $data) ? $data['amount'] : $budgetLimit->amount; + $budgetLimit->budget_id = array_key_exists('budget_id', $data) ? $data['budget_id'] : $budgetLimit->budget_id; if (array_key_exists('start', $data)) { $budgetLimit->start_date = $data['start']->startOfDay(); @@ -332,7 +329,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup } // if no currency has been provided, use the user's default currency: - $currency = null; + $currency = null; // update if relevant: if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) { @@ -344,11 +341,12 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup if (null === $currency) { $currency = $budgetLimit->transactionCurrency ?? Amount::getPrimaryCurrencyByUserGroup($this->user->userGroup); } - $currency->enabled = true; + $currency->enabled = true; $currency->save(); // this is a lame trick to communicate with the observer. - $singleton = PreferencesSingleton::getInstance(); + // FIXME so don't do that lol. + $singleton = PreferencesSingleton::getInstance(); $singleton->setPreference('fire_webhooks_bl_update', $data['fire_webhooks'] ?? true); $budgetLimit->transaction_currency_id = $currency->id; @@ -356,69 +354,10 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup // update notes if they exist. if (array_key_exists('notes', $data)) { - $this->setNoteText($budgetLimit, (string) $data['notes']); + $this->setNoteText($budgetLimit, (string)$data['notes']); } return $budgetLimit; } - // public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $amount): ?BudgetLimit - // { - // // count the limits: - // $limits = $budget->budgetlimits() - // ->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00')) - // ->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00')) - // ->count('budget_limits.*') - // ; - // Log::debug(sprintf('Found %d budget limits.', $limits)); - // - // // there might be a budget limit for these dates: - // /** @var null|BudgetLimit $limit */ - // $limit = $budget->budgetlimits() - // ->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00')) - // ->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00')) - // ->first(['budget_limits.*']) - // ; - // - // // if more than 1 limit found, delete the others: - // if ($limits > 1 && null !== $limit) { - // Log::debug(sprintf('Found more than 1, delete all except #%d', $limit->id)); - // $budget->budgetlimits() - // ->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00')) - // ->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00')) - // ->where('budget_limits.id', '!=', $limit->id)->delete() - // ; - // } - // - // // delete if amount is zero. - // // Returns 0 if the two operands are equal, - // // 1 if the left_operand is larger than the right_operand, -1 otherwise. - // if (null !== $limit && bccomp($amount, '0') <= 0) { - // Log::debug(sprintf('%s is zero, delete budget limit #%d', $amount, $limit->id)); - // $limit->delete(); - // - // return null; - // } - // // update if exists: - // if (null !== $limit) { - // Log::debug(sprintf('Existing budget limit is #%d, update this to amount %s', $limit->id, $amount)); - // $limit->amount = $amount; - // $limit->save(); - // - // return $limit; - // } - // Log::debug('No existing budget limit, create a new one'); - // // or create one and return it. - // $limit = new BudgetLimit(); - // $limit->budget()->associate($budget); - // $limit->start_date = $start->startOfDay(); - // $limit->start_date_tz = $start->format('e'); - // $limit->end_date = $end->startOfDay(); - // $limit->end_date_tz = $end->format('e'); - // $limit->amount = $amount; - // $limit->save(); - // Log::debug(sprintf('Created new budget limit with ID #%d and amount %s', $limit->id, $amount)); - // - // return $limit; - // } } diff --git a/app/Support/Observers/RecalculatesAvailableBudgetsTrait.php b/app/Support/Observers/RecalculatesAvailableBudgetsTrait.php index 9bca8324ca..40cac2373c 100644 --- a/app/Support/Observers/RecalculatesAvailableBudgetsTrait.php +++ b/app/Support/Observers/RecalculatesAvailableBudgetsTrait.php @@ -169,7 +169,7 @@ trait RecalculatesAvailableBudgetsTrait [$start, $end] = [$end, $start]; $budgetLimit->start_date = $start; $budgetLimit->end_date = $end; - $budgetLimit->saveQuietly(); + $budgetLimit->saveQuietly(); // FIXME needs to be removed here, put in repository. } // limit period in total is: