From 607d0115f00e43734ccd8ff9a17d472f5d62d763 Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 25 Apr 2016 13:20:42 +0200 Subject: [PATCH] Code improvements for budgets. --- app/Http/Controllers/BudgetController.php | 33 +++++++---- app/Repositories/Budget/BudgetRepository.php | 44 +++++++++++++- .../Budget/BudgetRepositoryInterface.php | 15 ++++- resources/lang/en_US/firefly.php | 3 + resources/views/budgets/index.twig | 57 +++++++++++-------- 5 files changed, 114 insertions(+), 38 deletions(-) diff --git a/app/Http/Controllers/BudgetController.php b/app/Http/Controllers/BudgetController.php index 7b0942d0ba..fe7e001209 100644 --- a/app/Http/Controllers/BudgetController.php +++ b/app/Http/Controllers/BudgetController.php @@ -3,6 +3,7 @@ use Amount; use Auth; use Carbon\Carbon; +use Config; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Http\Requests\BudgetFormRequest; use FireflyIII\Models\Budget; @@ -142,18 +143,22 @@ class BudgetController extends Controller */ public function index(BudgetRepositoryInterface $repository, ARI $accountRepository) { - $budgets = $repository->getActiveBudgets(); - $inactive = $repository->getInactiveBudgets(); - $spent = '0'; - $budgeted = '0'; - $range = Preferences::get('viewRange', '1M')->data; + $budgets = $repository->getActiveBudgets(); + $inactive = $repository->getInactiveBudgets(); + $spent = '0'; + $budgeted = '0'; + $range = Preferences::get('viewRange', '1M')->data; + $repeatFreq = Config::get('firefly.range_to_repeat_freq.' . $range); /** @var Carbon $date */ - $date = session('start', new Carbon); - $start = Navigation::startOfPeriod($date, $range); - $end = Navigation::endOfPeriod($start, $range); + /** @var Carbon $start */ + $start = session('start', new Carbon); + /** @var Carbon $end */ + $end = session('end', new Carbon); $key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd'); $budgetIncomeTotal = Preferences::get($key, 1000)->data; $period = Navigation::periodShow($start, $range); + $periodStart = $start->formatLocalized($this->monthAndDayFormat); + $periodEnd = $end->formatLocalized($this->monthAndDayFormat); $accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']); /** @@ -164,8 +169,9 @@ class BudgetController extends Controller // loop the budgets: /** @var Budget $budget */ foreach ($budgets as $budget) { - $budget->spent = $repository->balanceInPeriod($budget, $start, $end, $accounts); - $budget->currentRep = $repository->getCurrentRepetition($budget, $start, $end); + $budget->spent = $repository->balanceInPeriod($budget, $start, $end, $accounts); + $budget->currentRep = $repository->getCurrentRepetition($budget, $repeatFreq, $start, $end); + $budget->otherRepetitions = $repository->getValidRepetitions($budget, $start, $end, $budget->currentRep); if (!is_null($budget->currentRep->id)) { $budgeted = bcadd($budgeted, $budget->currentRep->amount); } @@ -178,7 +184,12 @@ class BudgetController extends Controller $defaultCurrency = Amount::getDefaultCurrency(); return view( - 'budgets.index', compact('budgetMaximum', 'period', 'range', 'budgetIncomeTotal', 'defaultCurrency', 'inactive', 'budgets', 'spent', 'budgeted') + 'budgets.index', compact( + 'budgetMaximum', 'periodStart', 'periodEnd', + 'period', 'range', 'budgetIncomeTotal', + 'defaultCurrency', 'inactive', 'budgets', + 'spent', 'budgeted' + ) ); } diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index f90d15065e..232cba03de 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -408,14 +408,16 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn /** * @param Budget $budget + * @param string $repeatFreq * @param Carbon $start * @param Carbon $end * * @return LimitRepetition */ - public function getCurrentRepetition(Budget $budget, Carbon $start, Carbon $end): LimitRepetition + public function getCurrentRepetition(Budget $budget, string $repeatFreq, Carbon $start, Carbon $end): LimitRepetition { $data = $budget->limitrepetitions() + ->where('budget_limits.repeat_freq', $repeatFreq) ->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00')) ->where('limit_repetitions.enddate', $end->format('Y-m-d 00:00:00')) ->first(['limit_repetitions.*']); @@ -844,4 +846,44 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn return $limit; } + + /** + * Returns a list of budget limits that are valid in the current given range. + * $ignore is optional. Send an empty limit rep. + * + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * @param LimitRepetition $ignore + * + * @return Collection + */ + public function getValidRepetitions(Budget $budget, Carbon $start, Carbon $end, LimitRepetition $ignore) : Collection + { + $query = $budget->limitrepetitions() + ->where( // valid when either of these are true: + function ($q) use ($start, $end) { + $q->where( + function ($query) use ($start, $end) { + // starts before start time, and the end also after start time. + $query->where('limit_repetitions.startdate', '<=', $start->format('Y-m-d 00:00:00')); + $query->where('limit_repetitions.enddate', '>=', $start->format('Y-m-d 00:00:00')); + } + ); + $q->orWhere( + function ($query) use ($start, $end) { + // end after end time, and start is before end time + $query->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00')); + $query->where('limit_repetitions.enddate', '>=', $end->format('Y-m-d 00:00:00')); + } + ); + } + ); + if (!is_null($ignore->id)) { + $query->where('limit_repetitions.id', '!=', $ignore->id); + } + $data = $query->get(['limit_repetitions.*']); + + return $data; + } } diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index 51b252ad8e..5671c6860b 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -146,14 +146,27 @@ interface BudgetRepositoryInterface */ public function getBudgetsAndLimitsInRange(Carbon $start, Carbon $end): Collection; + /** + * Returns a list of budget limits that are valid in the current given range. + * + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * @param LimitRepetition $ignore + * + * @return Collection + */ + public function getValidRepetitions(Budget $budget, Carbon $start, Carbon $end, LimitRepetition $ignore) : Collection; + /** * @param Budget $budget + * @param string $repeatFreq * @param Carbon $start * @param Carbon $end * * @return LimitRepetition */ - public function getCurrentRepetition(Budget $budget, Carbon $start, Carbon $end): LimitRepetition; + public function getCurrentRepetition(Budget $budget, string $repeatFreq, Carbon $start, Carbon $end): LimitRepetition; /** * Returns all expenses for the given budget and the given accounts, in the given period. diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index fc3d38f165..4fd6ca302f 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -459,8 +459,11 @@ return [ 'store_new_budget' => 'Store new budget', 'stored_new_budget' => 'Stored new budget ":name"', 'availableIn' => 'Available in :date', + 'available_between' => 'Available between :start and :end', 'transactionsWithoutBudget' => 'Expenses without budget', 'transactionsWithoutBudgetDate' => 'Expenses without budget in :date', + 'transactions_no_budget' => 'Expenses without budget between :start and :end', + 'spent_between' => 'Spent between :start and :end', 'createBudget' => 'New budget', 'inactiveBudgets' => 'Inactive budgets', 'without_budget_between' => 'Transactions without a budget between :start and :end', diff --git a/resources/views/budgets/index.twig b/resources/views/budgets/index.twig index dfa90e0f6e..cfc1363153 100644 --- a/resources/views/budgets/index.twig +++ b/resources/views/budgets/index.twig @@ -9,7 +9,7 @@
-

{{ Session.get('start').formatLocalized(monthFormat) }}

+

{{ periodStart }} — {{ periodEnd }}

@@ -23,7 +23,7 @@ {{ 'budgeted'|_ }}: {{ budgeted|formatAmountPlain }}
- {{ trans('firefly.availableIn',{date : period }) }}: + {{ trans('firefly.available_between',{start : periodStart, end: periodEnd }) }}: {{ budgetIncomeTotal|formatAmount }} @@ -44,7 +44,7 @@
- {{ 'spent'|_ }}: {{ spent|formatAmount }} + {{ trans('firefly.spent_between', {start: periodStart, end: periodEnd}) }}: {{ spent|formatAmount }}
-

Bla bla bla

{% for budget in budgets %}
@@ -132,7 +131,7 @@ {{ 'budgeted'|_ }} -
+
{{ session('start').formatLocalized(monthAndDayFormat) }} - {{ session('end').formatLocalized(monthAndDayFormat) }}
@@ -160,35 +159,43 @@ {{ 'spent'|_ }} -
+
{{ session('start').formatLocalized(monthAndDayFormat) }} - {{ session('end').formatLocalized(monthAndDayFormat) }}
{{ budget.spent|formatAmount }} - + {% if budget.otherRepetitions.count > 0 %} + + +
    + {% for other in budget.otherRepetitions %} + {% if other.id != budget.currentRep.id %} +
  • Budgeted + {{ other.amount|formatAmountPlain }} + between + {{ other.startdate.formatLocalized(monthAndDayFormat) }} + and {{ other.enddate.formatLocalized(monthAndDayFormat) }}. +
  • + {% endif %} + {% endfor %} +
+ + + {% endif %}
+ {% if loop.index % 3 == 0 %} +
+ {% endif %} {% endfor %} +
- {% if inactive|length > 0 %} + {% if inactive|length > 0 %} +
@@ -209,8 +216,8 @@
- {% endif %} -
+ + {% endif %} {% endblock %} {% block scripts %}