diff --git a/app/Helpers/Collection/BalanceLine.php b/app/Helpers/Collection/BalanceLine.php index f82a5ee3db..594f26c6d8 100644 --- a/app/Helpers/Collection/BalanceLine.php +++ b/app/Helpers/Collection/BalanceLine.php @@ -14,6 +14,7 @@ namespace FireflyIII\Helpers\Collection; use Carbon\Carbon; use FireflyIII\Models\Budget as BudgetModel; +use FireflyIII\Models\BudgetLimit; use Illuminate\Support\Collection; /** @@ -34,12 +35,27 @@ class BalanceLine /** @var BudgetModel */ protected $budget; - /** @var Carbon */ - protected $endDate; /** @var int */ protected $role = self::ROLE_DEFAULTROLE; - /** @var Carbon */ - protected $startDate; + + /** @var BudgetLimit */ + protected $budgetLimit; + + /** + * @return BudgetLimit + */ + public function getBudgetLimit(): BudgetLimit + { + return $this->budgetLimit; + } + + /** + * @param BudgetLimit $budgetLimit + */ + public function setBudgetLimit(BudgetLimit $budgetLimit) + { + $this->budgetLimit = $budgetLimit; + } /** * @@ -95,15 +111,7 @@ class BalanceLine */ public function getEndDate() { - return $this->endDate; - } - - /** - * @param Carbon $endDate - */ - public function setEndDate($endDate) - { - $this->endDate = $endDate; + return $this->budgetLimit->end_date ?? new Carbon; } /** @@ -127,15 +135,7 @@ class BalanceLine */ public function getStartDate() { - return $this->startDate; - } - - /** - * @param Carbon $startDate - */ - public function setStartDate($startDate) - { - $this->startDate = $startDate; + return $this->budgetLimit->start_date ?? new Carbon; } /** @@ -170,7 +170,7 @@ class BalanceLine */ public function leftOfRepetition(): string { - $start = $this->budget->amount ?? '0'; + $start = $this->budgetLimit->amount ?? '0'; /** @var BalanceEntry $balanceEntry */ foreach ($this->getBalanceEntries() as $balanceEntry) { $start = bcadd($balanceEntry->getSpent(), $start); diff --git a/app/Helpers/Collection/BudgetLine.php b/app/Helpers/Collection/BudgetLine.php index 5538c9e8f1..03bf59f8ff 100644 --- a/app/Helpers/Collection/BudgetLine.php +++ b/app/Helpers/Collection/BudgetLine.php @@ -13,7 +13,7 @@ declare(strict_types = 1); namespace FireflyIII\Helpers\Collection; use FireflyIII\Models\Budget as BudgetModel; -use FireflyIII\Models\LimitRepetition; +use FireflyIII\Models\BudgetLimit; /** * @@ -26,14 +26,14 @@ class BudgetLine /** @var BudgetModel */ protected $budget; + /** @var BudgetLimit */ + protected $budgetLimit; /** @var string */ protected $budgeted = '0'; /** @var string */ protected $left = '0'; /** @var string */ protected $overspent = '0'; - /** @var LimitRepetition */ - protected $repetition; /** @var string */ protected $spent = '0'; @@ -57,6 +57,26 @@ class BudgetLine return $this; } + /** + * @return BudgetLimit + */ + public function getBudgetLimit(): BudgetLimit + { + return $this->budgetLimit ?? new BudgetLimit; + } + + /** + * @param BudgetLimit $budgetLimit + * + * @return BudgetLimit + */ + public function setBudgetLimit(BudgetLimit $budgetLimit): BudgetLine + { + $this->budgetLimit = $budgetLimit; + + return $this; + } + /** * @return string */ @@ -117,26 +137,6 @@ class BudgetLine return $this; } - /** - * @return LimitRepetition - */ - public function getRepetition(): LimitRepetition - { - return $this->repetition ?? new LimitRepetition; - } - - /** - * @param LimitRepetition $repetition - * - * @return BudgetLine - */ - public function setRepetition(LimitRepetition $repetition): BudgetLine - { - $this->repetition = $repetition; - - return $this; - } - /** * @return string */ diff --git a/app/Helpers/Report/BalanceReportHelper.php b/app/Helpers/Report/BalanceReportHelper.php index 55896229f9..b1d53731e7 100644 --- a/app/Helpers/Report/BalanceReportHelper.php +++ b/app/Helpers/Report/BalanceReportHelper.php @@ -19,8 +19,7 @@ use FireflyIII\Helpers\Collection\Balance; use FireflyIII\Helpers\Collection\BalanceEntry; use FireflyIII\Helpers\Collection\BalanceHeader; use FireflyIII\Helpers\Collection\BalanceLine; -use FireflyIII\Models\Budget; -use FireflyIII\Models\LimitRepetition; +use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\Tag; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; @@ -62,19 +61,17 @@ class BalanceReportHelper implements BalanceReportHelperInterface public function getBalanceReport(Collection $accounts, Carbon $start, Carbon $end): Balance { Log::debug('Start of balance report'); - $balance = new Balance; - $header = new BalanceHeader; - $limitRepetitions = $this->budgetRepository->getAllBudgetLimitRepetitions($start, $end); + $balance = new Balance; + $header = new BalanceHeader; + $budgetLimits = $this->budgetRepository->getAllBudgetLimits($start, $end); foreach ($accounts as $account) { Log::debug(sprintf('Add account %s to headers.', $account->name)); $header->addAccount($account); } - /** @var LimitRepetition $repetition */ - foreach ($limitRepetitions as $repetition) { - $budget = $this->budgetRepository->find($repetition->budget_id); - Log::debug(sprintf('Create balance line for budget #%d ("%s") and repetition #%d', $budget->id, $budget->name, $repetition->id)); - $line = $this->createBalanceLine($budget, $repetition, $accounts); + /** @var BudgetLimit $budgetLimit */ + foreach ($budgetLimits as $budgetLimit) { + $line = $this->createBalanceLine($budgetLimit, $accounts); $balance->addBalanceLine($line); } Log::debug('Create rest of the things.'); @@ -146,26 +143,23 @@ class BalanceReportHelper implements BalanceReportHelperInterface /** - * @param Budget $budget - * @param LimitRepetition $repetition - * @param Collection $accounts + * @param BudgetLimit $budgetLimit + * @param Collection $accounts * * @return BalanceLine */ - private function createBalanceLine(Budget $budget, LimitRepetition $repetition, Collection $accounts): BalanceLine + private function createBalanceLine(BudgetLimit $budgetLimit, Collection $accounts): BalanceLine { - $line = new BalanceLine; - $budget->amount = $repetition->amount; - $line->setBudget($budget); - $line->setStartDate($repetition->startdate); - $line->setEndDate($repetition->enddate); + $line = new BalanceLine; + $line->setBudget($budgetLimit->budget); + $line->setBudgetLimit($budgetLimit); // loop accounts: foreach ($accounts as $account) { $balanceEntry = new BalanceEntry; $balanceEntry->setAccount($account); $spent = $this->budgetRepository->spentInPeriod( - new Collection([$budget]), new Collection([$account]), $repetition->startdate, $repetition->enddate + new Collection([$budgetLimit->budget]), new Collection([$account]), $budgetLimit->start_date, $budgetLimit->end_date ); $balanceEntry->setSpent($spent); $line->addBalanceEntry($balanceEntry); diff --git a/app/Helpers/Report/BudgetReportHelper.php b/app/Helpers/Report/BudgetReportHelper.php index 18f9e4016f..cf6836ce96 100644 --- a/app/Helpers/Report/BudgetReportHelper.php +++ b/app/Helpers/Report/BudgetReportHelper.php @@ -18,7 +18,7 @@ use Carbon\Carbon; use FireflyIII\Helpers\Collection\Budget as BudgetCollection; use FireflyIII\Helpers\Collection\BudgetLine; use FireflyIII\Models\Budget; -use FireflyIII\Models\LimitRepetition; +use FireflyIII\Models\BudgetLimit; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use Illuminate\Support\Collection; @@ -57,8 +57,8 @@ class BudgetReportHelper implements BudgetReportHelperInterface /** @var Budget $budget */ foreach ($set as $budget) { - $repetitions = $budget->limitrepetitions()->before($end)->after($start)->get(); - if ($repetitions->count() == 0) { // no repetition(s) for this budget + $budgetLimits = $this->repository->getBudgetLimits($budget, $start, $end); + if ($budgetLimits->count() == 0) { // no budget limit(s) for this budget $spent = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end);// spent for budget in time range if ($spent > 0) { $budgetLine = new BudgetLine; @@ -67,15 +67,15 @@ class BudgetReportHelper implements BudgetReportHelperInterface } continue; } - /** @var LimitRepetition $repetition */ - foreach ($repetitions as $repetition) { // one or more repetitions for budget - $data = $this->calculateExpenses($budget, $repetition, $accounts); + /** @var BudgetLimit $budgetLimit */ + foreach ($budgetLimits as $budgetLimit) { // one or more repetitions for budget + $data = $this->calculateExpenses($budget, $budgetLimit, $accounts); $budgetLine = new BudgetLine; - $budgetLine->setBudget($budget)->setRepetition($repetition) + $budgetLine->setBudget($budget)->setBudgetLimit($budgetLimit) ->setLeft($data['left'])->setSpent($data['expenses'])->setOverspent($data['overspent']) - ->setBudgeted(strval($repetition->amount)); + ->setBudgeted(strval($budgetLimit->amount)); - $object->addBudgeted(strval($repetition->amount))->addSpent($data['spent']) + $object->addBudgeted(strval($budgetLimit->amount))->addSpent($data['spent']) ->addLeft($data['left'])->addOverspent($data['overspent'])->addBudgetLine($budgetLine); } @@ -119,19 +119,19 @@ class BudgetReportHelper implements BudgetReportHelperInterface } /** - * @param Budget $budget - * @param LimitRepetition $repetition - * @param Collection $accounts + * @param Budget $budget + * @param BudgetLimit $budgetLimit + * @param Collection $accounts * * @return array */ - private function calculateExpenses(Budget $budget, LimitRepetition $repetition, Collection $accounts): array + private function calculateExpenses(Budget $budget, BudgetLimit $budgetLimit, Collection $accounts): array { $array = []; - $expenses = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $repetition->startdate, $repetition->enddate); - $array['left'] = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? bcadd($repetition->amount, $expenses) : '0'; - $array['spent'] = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? $expenses : '0'; - $array['overspent'] = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? '0' : bcadd($expenses, $repetition->amount); + $expenses = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $budgetLimit->start_date, $budgetLimit->end_date); + $array['left'] = bccomp(bcadd($budgetLimit->amount, $expenses), '0') === 1 ? bcadd($budgetLimit->amount, $expenses) : '0'; + $array['spent'] = bccomp(bcadd($budgetLimit->amount, $expenses), '0') === 1 ? $expenses : '0'; + $array['overspent'] = bccomp(bcadd($budgetLimit->amount, $expenses), '0') === 1 ? '0' : bcadd($expenses, $budgetLimit->amount); $array['expenses'] = $expenses; return $array; diff --git a/app/Http/Controllers/BudgetController.php b/app/Http/Controllers/BudgetController.php index 82030bb7bf..591aed5075 100644 --- a/app/Http/Controllers/BudgetController.php +++ b/app/Http/Controllers/BudgetController.php @@ -285,8 +285,7 @@ class BudgetController extends Controller */ public function showByBudgetLimit(Request $request, Budget $budget, BudgetLimit $budgetLimit) { - if ($budgetLimit->budget->id - != $budget->id) { + if ($budgetLimit->budget->id != $budget->id) { throw new FireflyException('This budget limit is not part of this budget.'); } diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index 372e972edd..958cb45d36 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -14,11 +14,12 @@ declare(strict_types = 1); namespace FireflyIII\Http\Controllers\Chart; use Carbon\Carbon; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Generator\Chart\Basic\GeneratorInterface; use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Budget; -use FireflyIII\Models\LimitRepetition; +use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; @@ -104,26 +105,30 @@ class BudgetController extends Controller * @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly five. * @param BudgetRepositoryInterface $repository * @param Budget $budget - * @param LimitRepetition $repetition + * @param BudgetLimit $budgetLimit * * @return \Symfony\Component\HttpFoundation\Response */ - public function budgetLimit(BudgetRepositoryInterface $repository, Budget $budget, LimitRepetition $repetition) + public function budgetLimit(BudgetRepositoryInterface $repository, Budget $budget, BudgetLimit $budgetLimit) { - $start = clone $repetition->startdate; - $end = $repetition->enddate; + if ($budgetLimit->budget->id != $budget->id) { + throw new FireflyException('This budget limit is not part of this budget.'); + } + + $start = clone $budgetLimit->start_date; + $end = clone $budgetLimit->end_date; $cache = new CacheProperties(); $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty('chart.budget.budget.limit'); - $cache->addProperty($repetition->id); + $cache->addProperty($budgetLimit->id); if ($cache->has()) { return Response::json($cache->get()); } $entries = []; - $amount = $repetition->amount; + $amount = $budgetLimit->amount; $budgetCollection = new Collection([$budget]); while ($start <= $end) { $spent = $repository->spentInPeriod($budgetCollection, new Collection, $start, $start); @@ -160,9 +165,8 @@ class BudgetController extends Controller if ($cache->has()) { return Response::json($cache->get()); } - $budgets = $repository->getActiveBudgets(); - $repetitions = $repository->getAllBudgetLimitRepetitions($start, $end); - $chartData = [ + $budgets = $repository->getActiveBudgets(); + $chartData = [ ['label' => strval(trans('firefly.spent_in_budget')), 'entries' => [], 'type' => 'bar',], ['label' => strval(trans('firefly.left_to_spend')), 'entries' => [], 'type' => 'bar',], ['label' => strval(trans('firefly.overspent')), 'entries' => [], 'type' => 'bar',], @@ -172,8 +176,8 @@ class BudgetController extends Controller /** @var Budget $budget */ foreach ($budgets as $budget) { // get relevant repetitions: - $filtered = $this->filterRepetitions($repetitions, $budget, $start, $end); - $expenses = $this->getExpensesForBudget($filtered, $budget, $start, $end); + $limits = $repository->getBudgetLimits($budget, $start, $end); + $expenses = $this->getExpensesForBudget($limits, $budget, $start, $end); foreach ($expenses as $name => $row) { $chartData[0]['entries'][$name] = $row['spent']; $chartData[1]['entries'][$name] = $row['left']; @@ -224,25 +228,14 @@ class BudgetController extends Controller $entries = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end); $key = Navigation::preferredCarbonFormat($start, $end); $range = Navigation::preferredRangeFormat($start, $end); - - // get the budget limits (if any) - $repetitions = $repository->getAllBudgetLimitRepetitions($start, $end); - $current = clone $start; + $current = clone $start; while ($current < $end) { - $currentStart = Navigation::startOfPeriod($current, $range); - $currentEnd = Navigation::endOfPeriod($current, $range); - $reps = $repetitions->filter( - function (LimitRepetition $repetition) use ($budget, $currentStart, $currentEnd) { - if ($repetition->budget_id === $budget->id && $repetition->startdate >= $currentStart && $repetition->enddate <= $currentEnd) { - return true; - } - - return false; - } - ); + $currentStart = Navigation::startOfPeriod($current, $range); + $currentEnd = Navigation::endOfPeriod($current, $range); + $budgetLimits = $repository->getBudgetLimits($budget, $currentStart, $currentEnd); $index = $currentStart->format($key); - $budgeted[$index] = $reps->sum('amount'); + $budgeted[$index] = $budgetLimits->sum('amount'); $currentEnd->addDay(); $current = clone $currentEnd; } @@ -312,46 +305,23 @@ class BudgetController extends Controller return Response::json($data); } - /** - * @param Collection $repetitions - * @param Budget $budget - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - private function filterRepetitions(Collection $repetitions, Budget $budget, Carbon $start, Carbon $end): Collection - { - - return $repetitions->filter( - function (LimitRepetition $repetition) use ($budget, $start, $end) { - if ($repetition->startdate < $end && $repetition->enddate > $start && $repetition->budget_id === $budget->id) { - return true; - } - - return false; - } - ); - } - - /** * * @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's 6 but ok. * - * @param Collection $repetitions + * @param Collection $limits * @param Budget $budget * @param Carbon $start * @param Carbon $end * * @return array */ - private function getExpensesForBudget(Collection $repetitions, Budget $budget, Carbon $start, Carbon $end): array + private function getExpensesForBudget(Collection $limits, Budget $budget, Carbon $start, Carbon $end): array { /** @var BudgetRepositoryInterface $repository */ $repository = app(BudgetRepositoryInterface::class); $return = []; - if ($repetitions->count() === 0) { + if ($limits->count() === 0) { $spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end); if (bccomp($spent, '0') !== 0) { $return[$budget->name]['spent'] = bcmul($spent, '-1'); @@ -362,7 +332,7 @@ class BudgetController extends Controller return $return; } - $rows = $this->spentInPeriodMulti($repository, $budget, $repetitions); + $rows = $this->spentInPeriodMulti($repository, $budget, $limits); foreach ($rows as $name => $row) { if (bccomp($row['spent'], '0') !== 0 || bccomp($row['left'], '0') !== 0) { $return[$name]['spent'] = bcmul($row['spent'], '-1'); @@ -386,26 +356,29 @@ class BudgetController extends Controller * * @param BudgetRepositoryInterface $repository * @param Budget $budget - * @param Collection $repetitions + * @param Collection $limits * * @return array */ - private function spentInPeriodMulti(BudgetRepositoryInterface $repository, Budget $budget, Collection $repetitions): array + private function spentInPeriodMulti(BudgetRepositoryInterface $repository, Budget $budget, Collection $limits): array { $return = []; $format = strval(trans('config.month_and_day')); $name = $budget->name; - /** @var LimitRepetition $repetition */ - foreach ($repetitions as $repetition) { - $expenses = $repository->spentInPeriod(new Collection([$budget]), new Collection, $repetition->startdate, $repetition->enddate); + /** @var BudgetLimit $budgetLimit */ + foreach ($limits as $budgetLimit) { + $expenses = $repository->spentInPeriod(new Collection([$budget]), new Collection, $budgetLimit->start_date, $budgetLimit->end_date); - if ($repetitions->count() > 1) { + if ($limits->count() > 1) { $name = $budget->name . ' ' . trans( 'firefly.between_dates', - ['start' => $repetition->startdate->formatLocalized($format), 'end' => $repetition->enddate->formatLocalized($format)] + [ + 'start' => $budgetLimit->start_date->formatLocalized($format), + 'end' => $budgetLimit->end_date->formatLocalized($format), + ] ); } - $amount = $repetition->amount; + $amount = $budgetLimit->amount; $left = bccomp(bcadd($amount, $expenses), '0') < 1 ? '0' : bcadd($amount, $expenses); $spent = $expenses; $overspent = bccomp(bcadd($amount, $expenses), '0') < 1 ? bcadd($amount, $expenses) : '0'; diff --git a/app/Http/Controllers/Chart/BudgetReportController.php b/app/Http/Controllers/Chart/BudgetReportController.php index 5f32d04795..7dee6d99f0 100644 --- a/app/Http/Controllers/Chart/BudgetReportController.php +++ b/app/Http/Controllers/Chart/BudgetReportController.php @@ -20,14 +20,13 @@ use FireflyIII\Generator\Report\Category\MonthReportGenerator; use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Budget; -use FireflyIII\Models\LimitRepetition; +use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Support\CacheProperties; use Illuminate\Support\Collection; -use Log; use Navigation; use Response; @@ -206,7 +205,6 @@ class BudgetReportController extends Controller $function = Navigation::preferredEndOfPeriod($start, $end); $chartData = []; $currentStart = clone $start; - $limits = $repository->getAllBudgetLimitRepetitions($start, $end); // also for ALL budgets. // prep chart data: foreach ($budgets as $budget) { @@ -231,8 +229,9 @@ class BudgetReportController extends Controller 'entries' => [], ]; } - $sumOfExpenses = []; - $leftOfLimits = []; + $allBudgetLimits = $repository->getAllBudgetLimits($start, $end); + $sumOfExpenses = []; + $leftOfLimits = []; while ($currentStart < $end) { $currentEnd = clone $currentStart; $currentEnd = $currentEnd->$function(); @@ -241,20 +240,20 @@ class BudgetReportController extends Controller /** @var Budget $budget */ foreach ($budgets as $budget) { + // get budget limit(s) for this period): + $budgetLimits = $this->filterBudgetLimits($allBudgetLimits, $budget, $currentStart, $currentEnd); $currentExpenses = $expenses[$budget->id] ?? '0'; $sumOfExpenses[$budget->id] = $sumOfExpenses[$budget->id] ?? '0'; $sumOfExpenses[$budget->id] = bcadd($currentExpenses, $sumOfExpenses[$budget->id]); $chartData[$budget->id]['entries'][$label] = round(bcmul($currentExpenses, '-1'), 2); $chartData[$budget->id . '-sum']['entries'][$label] = round(bcmul($sumOfExpenses[$budget->id], '-1'), 2); - $limit = $this->filterLimits($limits, $budget, $currentStart); - if (!is_null($limit->id)) { - $leftOfLimits[$limit->id] = $leftOfLimits[$limit->id] ?? strval($limit->amount); - $leftOfLimits[$limit->id] = bcadd($leftOfLimits[$limit->id], $currentExpenses); - $chartData[$budget->id . '-left']['entries'][$label] = round($leftOfLimits[$limit->id], 2); + if (count($budgetLimits) > 0) { + $budgetLimitId = $budgetLimits->first()->id; + $leftOfLimits[$budgetLimitId] = $leftOfLimits[$budgetLimitId] ?? strval($budgetLimits->sum('amount')); + $leftOfLimits[$budgetLimitId] = bcadd($leftOfLimits[$budgetLimitId], $currentExpenses); + $chartData[$budget->id . '-left']['entries'][$label] = $leftOfLimits[$budgetLimitId]; } - - } $currentStart = clone $currentEnd; $currentStart->addDay(); @@ -267,44 +266,32 @@ class BudgetReportController extends Controller } /** - * @param $limits - * @param $budget - * @param $currentStart + * Returns the budget limits belonging to the given budget and valid on the given day. * - * @return LimitRepetition + * @param Collection $budgetLimits + * @param Carbon $start + * @param Carbon $end + * + * @return Collection */ - private function filterLimits(Collection $limits, Budget $budget, Carbon $date): LimitRepetition + private function filterBudgetLimits(Collection $budgetLimits, Budget $budget, Carbon $start, Carbon $end): Collection { - Log::debug(sprintf('Start of filterLimits with %d limits.', $limits->count())); - $filtered = $limits->filter( - function (LimitRepetition $limit) use ($budget, $date) { - if ($limit->budget_id !== $budget->id) { - Log::debug(sprintf('LimitRepetition has budget #%d but expecting #%d', $limit->budget_id, $budget->id)); - - return false; - } - if ($date < $limit->startdate || $date > $limit->enddate) { - Log::debug( - sprintf( - 'Date %s is not between %s and %s', - $date->format('Y-m-d'), $limit->startdate->format('Y-m-d'), $limit->enddate->format('Y-m-d') - ) - ); - - return false; + $set = $budgetLimits->filter( + function (BudgetLimit $budgetLimit) use ($budget, $start, $end) { + if ($budgetLimit->budget_id === $budget->id + && $budgetLimit->start_date->lte($start) // start of budget limit is on or before start + && $budgetLimit->end_date->gte($end) // end of budget limit is on or after end + ) { + return $budgetLimit; } - return $limit; + return false; } ); - if ($filtered->count() === 1) { - return $filtered->first(); - } - return new LimitRepetition; + return $set; } - /** * @param Collection $accounts * @param Collection $budgets diff --git a/app/Models/Budget.php b/app/Models/Budget.php index 6bca976677..4d5c2a61c6 100644 --- a/app/Models/Budget.php +++ b/app/Models/Budget.php @@ -118,14 +118,6 @@ class Budget extends Model return $value; } - /** - * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough - */ - public function limitrepetitions() - { - return $this->hasManyThrough('FireflyIII\Models\LimitRepetition', 'FireflyIII\Models\BudgetLimit', 'budget_id'); - } - /** * @param $value */ diff --git a/app/Models/BudgetLimit.php b/app/Models/BudgetLimit.php index c1153028d8..12728a8469 100644 --- a/app/Models/BudgetLimit.php +++ b/app/Models/BudgetLimit.php @@ -67,14 +67,6 @@ class BudgetLimit extends Model return $this->belongsTo('FireflyIII\Models\Budget'); } - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function limitrepetitions() - { - return $this->hasMany('FireflyIII\Models\LimitRepetition'); - } - /** * @param $value */ diff --git a/app/Models/LimitRepetition.php b/app/Models/LimitRepetition.php index 9c76eab93f..a1e8afe2b1 100644 --- a/app/Models/LimitRepetition.php +++ b/app/Models/LimitRepetition.php @@ -21,6 +21,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Class LimitRepetition * + * @deprecated * @package FireflyIII\Models */ class LimitRepetition extends Model diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 0188612250..69191eb2cc 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -18,7 +18,6 @@ use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Models\AvailableBudget; use FireflyIII\Models\Budget; use FireflyIII\Models\BudgetLimit; -use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionJournal; @@ -197,30 +196,35 @@ class BudgetRepository implements BudgetRepositoryInterface * * @return Collection */ - public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end): Collection + public function getAllBudgetLimits(Carbon $start, Carbon $end): Collection { - $query = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') - ->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') - ->where( - function (Builder $q1) use ($start, $end) { - $q1->where( - function (Builder $q2) use ($start, $end) { - $q2->where('limit_repetitions.enddate', '>=', $start->format('Y-m-d 00:00:00')); - $q2->where('limit_repetitions.enddate', '<=', $end->format('Y-m-d 00:00:00')); - } - ) - ->orWhere( - function (Builder $q3) use ($start, $end) { - $q3->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00')); - $q3->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00')); - } - ); - } - ) - ->where('budgets.user_id', $this->user->id) - ->whereNull('budgets.deleted_at'); - - $set = $query->get(['limit_repetitions.*', 'budget_limits.budget_id']); + $set = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') + ->with(['budget']) + ->where('budgets.user_id', $this->user->id) + ->where( + function (Builder $q1) use ($start, $end) { + $q1->where( + function (Builder $q2) use ($start, $end) { + $q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d 00:00:00')); + $q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d 00:00:00')); + } + ) + ->orWhere( + function (Builder $q3) use ($start, $end) { + $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 00:00:00')); + } + ); + } + ) + ->orWhere( + function (Builder $q4) use ($start, $end) { + // or start is before start AND end is after end. + $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d 00:00:00')); + $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d 00:00:00')); + } + ) + ->get(['budget_limits.*']); return $set; } @@ -258,20 +262,30 @@ class BudgetRepository implements BudgetRepositoryInterface $set = $budget->budgetLimits() ->where( function (Builder $q1) use ($start, $end) { + // budget limit ends within period $q1->where( function (Builder $q2) use ($start, $end) { $q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d 00:00:00')); $q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d 00:00:00')); } ) + // budget limit start within period ->orWhere( - function (Builder $q3) use ($start, $end) { - $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 00:00:00')); - } - ); + function (Builder $q3) use ($start, $end) { + $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 00:00:00')); + } + ); } - )->get(); + ) + ->orWhere( + function (Builder $q4) use ($start, $end) { + // or start is before start AND end is after end. + $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d 00:00:00')); + $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d 00:00:00')); + } + ) + ->get(); return $set; } diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index eed24b1da4..947721ea5e 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -83,16 +83,6 @@ interface BudgetRepositoryInterface */ public function getActiveBudgets(): Collection; - /** - * @deprecated - * - * @param Carbon $start - * @param Carbon $end - * - * @return Collection - */ - public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end): Collection; - /** * @param TransactionCurrency $currency * @param Carbon $start @@ -102,6 +92,14 @@ interface BudgetRepositoryInterface */ public function getAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end): string; + /** + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getAllBudgetLimits(Carbon $start, Carbon $end): Collection; + /** * @param Budget $budget * @param Carbon $start diff --git a/resources/views/reports/budget/month.twig b/resources/views/reports/budget/month.twig index 5336f0fd18..c3009fe2a0 100644 --- a/resources/views/reports/budget/month.twig +++ b/resources/views/reports/budget/month.twig @@ -75,7 +75,9 @@

{{ 'expense_per_budget'|_ }}

- +
+ +
- +
+ +