diff --git a/app/Http/Controllers/Budget/IndexController.php b/app/Http/Controllers/Budget/IndexController.php index 8889a9677e..5d80e1432b 100644 --- a/app/Http/Controllers/Budget/IndexController.php +++ b/app/Http/Controllers/Budget/IndexController.php @@ -98,138 +98,56 @@ class IndexController extends Controller public function index(Request $request, Carbon $start = null, Carbon $end = null) { Log::debug('Start of IndexController::index()'); + // collect some basic vars: $range = app('preferences')->get('viewRange', '1M')->data; $start = $start ?? session('start', Carbon::now()->startOfMonth()); $end = $end ?? app('navigation')->endOfPeriod($start, $range); $defaultCurrency = app('amount')->getDefaultCurrency(); + $currencies = $this->currencyRepository->getEnabled(); $budgeted = '0'; $spent = '0'; - Log::debug(sprintf('1) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); // new period stuff: $periodTitle = app('navigation')->periodShow($start, $range); $prevLoop = $this->getPreviousPeriods($start, $range); $nextLoop = $this->getNextPeriods($start, $range); - Log::debug(sprintf('2) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); - // get all available budgets. - $ab = $this->abRepository->get($start, $end); - $availableBudgets = []; - Log::debug(sprintf('3) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); - // for each, complement with spent amount: - /** @var AvailableBudget $entry */ - foreach ($ab as $entry) { - $array = $entry->toArray(); - $array['start_date'] = $entry->start_date; - $array['end_date'] = $entry->end_date; + // get all available budgets: + $availableBudgets = $this->getAllAvailableBudgets($start, $end); - // spent in period: - $spentArr = $this->opsRepository->sumExpenses($entry->start_date, $entry->end_date, null, null, $entry->transactionCurrency); - $array['spent'] = $spentArr[$entry->transaction_currency_id]['sum'] ?? '0'; - - // budgeted in period: - $budgeted = $this->blRepository->budgeted($entry->start_date, $entry->end_date, $entry->transactionCurrency, ); - $array['budgeted'] = $budgeted; - $availableBudgets[] = $array; - unset($spentArr); - Log::debug(sprintf('4) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); - } + // get all active budgets: + $budgets = $this->getAllBudgets($start, $end, $currencies, $defaultCurrency); + $sums = $this->getSums($budgets); + // get budgeted for default currency: if (0 === count($availableBudgets)) { - // get budgeted for default currency: - $budgeted = $this->blRepository->budgeted($start, $end, $defaultCurrency, ); + $budgeted = $this->blRepository->budgeted($start, $end, $defaultCurrency,); $spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $defaultCurrency); $spent = $spentArr[$defaultCurrency->id]['sum'] ?? '0'; unset($spentArr); - Log::debug(sprintf('5) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); } // count the number of enabled currencies. This determines if we display a "+" button. - $currencies = $this->currencyRepository->getEnabled(); $enableAddButton = $currencies->count() > count($availableBudgets); // number of days for consistent budgeting. $activeDaysPassed = $this->activeDaysPassed($start, $end); // see method description. $activeDaysLeft = $this->activeDaysLeft($start, $end); // see method description. - Log::debug(sprintf('6) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); - - // get all budgets, and paginate them into $budgets. - $collection = $this->repository->getActiveBudgets(); - $budgets = []; - Log::debug(sprintf('7) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); - - // complement budget with budget limits in range, and expenses in currency X in range. - /** @var Budget $current */ - foreach ($collection as $current) { - $array = $current->toArray(); - $array['spent'] = []; - $array['budgeted'] = []; - $array['attachments'] = $this->repository->getAttachments($current); - $array['auto_budget'] = $this->repository->getAutoBudget($current); - $budgetLimits = $this->blRepository->getBudgetLimits($current, $start, $end); - Log::debug(sprintf('8) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); - /** @var BudgetLimit $limit */ - foreach ($budgetLimits as $limit) { - $currency = $limit->transactionCurrency ?? $defaultCurrency; - $array['budgeted'][] = [ - 'id' => $limit->id, - 'amount' => number_format((float) $limit->amount, $currency->decimal_places, '.', ''), - 'start_date' => $limit->start_date->formatLocalized($this->monthAndDayFormat), - 'end_date' => $limit->end_date->formatLocalized($this->monthAndDayFormat), - 'in_range' => $limit->start_date->isSameDay($start) && $limit->end_date->isSameDay($end), - 'currency_id' => $currency->id, - 'currency_symbol' => $currency->symbol, - 'currency_name' => $currency->name, - 'currency_decimal_places' => $currency->decimal_places, - ]; - Log::debug(sprintf('9) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); - } - - /** @var TransactionCurrency $currency */ - foreach ($currencies as $currency) { - $spentArr = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$current]), $currency); - if (isset($spentArr[$currency->id]['sum'])) { - $array['spent'][$currency->id]['spent'] = $spentArr[$currency->id]['sum']; - $array['spent'][$currency->id]['currency_id'] = $currency->id; - $array['spent'][$currency->id]['currency_symbol'] = $currency->symbol; - $array['spent'][$currency->id]['currency_decimal_places'] = $currency->decimal_places; - Log::debug(sprintf('10) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); - } - } - $budgets[] = $array; - } // get all inactive budgets, and simply list them: $inactive = $this->repository->getInactiveBudgets(); - Log::debug(sprintf('11) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); return view( - 'budgets.index', - compact( - 'availableBudgets', - 'budgeted', - 'spent', - 'prevLoop', - 'nextLoop', - 'budgets', - 'currencies', - 'enableAddButton', - 'periodTitle', - 'defaultCurrency', - 'activeDaysPassed', - 'activeDaysLeft', - 'inactive', - 'budgets', - 'start', - 'end' - ) + 'budgets.index', compact( + 'availableBudgets', 'budgeted', 'spent', 'prevLoop', 'nextLoop', 'budgets', 'currencies', 'enableAddButton', 'periodTitle', + 'defaultCurrency', 'activeDaysPassed', 'activeDaysLeft', 'inactive', 'budgets', 'start', 'end', 'sums' + ) ); } /** * @param Request $request - * * @param BudgetRepositoryInterface $repository * * @return JsonResponse @@ -250,4 +168,154 @@ class IndexController extends Controller return response()->json(['OK']); } + + /** + * @param array $budgets + * + * @return array + */ + private function getSums(array $budgets): array + { + $sums = [ + 'budgeted' => [], + 'spent' => [], + 'left' => [], + ]; + + /** @var array $budget */ + foreach ($budgets as $budget) { + /** @var array $spent */ + foreach ($budget['spent'] as $spent) { + $currencyId = $spent['currency_id']; + $sums['spent'][$currencyId] + = $sums['spent'][$currencyId] + ?? [ + 'amount' => '0', + 'currency_id' => $spent['currency_id'], + 'currency_symbol' => $spent['currency_symbol'], + 'currency_decimal_places' => $spent['currency_decimal_places'], + ]; + $sums['spent'][$currencyId]['amount'] = bcadd($sums['spent'][$currencyId]['amount'], $spent['spent']); + } + + /** @var array $budgeted */ + foreach ($budget['budgeted'] as $budgeted) { + $currencyId = $budgeted['currency_id']; + $sums['budgeted'][$currencyId] + = $sums['budgeted'][$currencyId] + ?? [ + 'amount' => '0', + 'currency_id' => $budgeted['currency_id'], + 'currency_symbol' => $budgeted['currency_symbol'], + 'currency_decimal_places' => $budgeted['currency_decimal_places'], + ]; + $sums['budgeted'][$currencyId]['amount'] = bcadd($sums['budgeted'][$currencyId]['amount'], $budgeted['amount']); + + // also calculate how much left from budgeted: + $sums['left'][$currencyId] = $sums['left'][$currencyId] + ?? [ + 'amount' => '0', + 'currency_id' => $budgeted['currency_id'], + 'currency_symbol' => $budgeted['currency_symbol'], + 'currency_decimal_places' => $budgeted['currency_decimal_places'], + ]; + } + } + // final calculation for 'left': + foreach ($sums['budgeted'] as $currencyId => $info) { + $spent = $sums['spent'][$currencyId]['amount'] ?? '0'; + $budgeted = $sums['budgeted'][$currencyId]['amount'] ?? '0'; + $sums['left'][$currencyId]['amount'] = bcadd($spent, $budgeted); + } + + return $sums; + } + + /** + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + private function getAllAvailableBudgets(Carbon $start, Carbon $end): array + { + // get all available budgets. + $ab = $this->abRepository->get($start, $end); + $availableBudgets = []; + // for each, complement with spent amount: + /** @var AvailableBudget $entry */ + foreach ($ab as $entry) { + $array = $entry->toArray(); + $array['start_date'] = $entry->start_date; + $array['end_date'] = $entry->end_date; + + // spent in period: + $spentArr = $this->opsRepository->sumExpenses($entry->start_date, $entry->end_date, null, null, $entry->transactionCurrency); + $array['spent'] = $spentArr[$entry->transaction_currency_id]['sum'] ?? '0'; + + // budgeted in period: + $budgeted = $this->blRepository->budgeted($entry->start_date, $entry->end_date, $entry->transactionCurrency,); + $array['budgeted'] = $budgeted; + $availableBudgets[] = $array; + unset($spentArr); + } + + return $availableBudgets; + } + + /** + * @param Carbon $start + * @param Carbon $end + * @param Collection $currencies + * @param TransactionCurrency $defaultCurrency + * + * @return array + */ + private function getAllBudgets(Carbon $start, Carbon $end, Collection $currencies, TransactionCurrency $defaultCurrency): array + { + // get all budgets, and paginate them into $budgets. + $collection = $this->repository->getActiveBudgets(); + $budgets = []; + Log::debug(sprintf('7) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); + + // complement budget with budget limits in range, and expenses in currency X in range. + /** @var Budget $current */ + foreach ($collection as $current) { + $array = $current->toArray(); + $array['spent'] = []; + $array['budgeted'] = []; + $array['attachments'] = $this->repository->getAttachments($current); + $array['auto_budget'] = $this->repository->getAutoBudget($current); + $budgetLimits = $this->blRepository->getBudgetLimits($current, $start, $end); + /** @var BudgetLimit $limit */ + foreach ($budgetLimits as $limit) { + $currency = $limit->transactionCurrency ?? $defaultCurrency; + $array['budgeted'][] = [ + 'id' => $limit->id, + 'amount' => number_format((float) $limit->amount, $currency->decimal_places, '.', ''), + 'start_date' => $limit->start_date->formatLocalized($this->monthAndDayFormat), + 'end_date' => $limit->end_date->formatLocalized($this->monthAndDayFormat), + 'in_range' => $limit->start_date->isSameDay($start) && $limit->end_date->isSameDay($end), + 'currency_id' => $currency->id, + 'currency_symbol' => $currency->symbol, + 'currency_name' => $currency->name, + 'currency_decimal_places' => $currency->decimal_places, + ]; + } + + /** @var TransactionCurrency $currency */ + foreach ($currencies as $currency) { + $spentArr = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$current]), $currency); + if (isset($spentArr[$currency->id]['sum'])) { + $array['spent'][$currency->id]['spent'] = $spentArr[$currency->id]['sum']; + $array['spent'][$currency->id]['currency_id'] = $currency->id; + $array['spent'][$currency->id]['currency_symbol'] = $currency->symbol; + $array['spent'][$currency->id]['currency_decimal_places'] = $currency->decimal_places; + } + } + $budgets[] = $array; + } + + return $budgets; + } } diff --git a/resources/views/v1/budgets/index.twig b/resources/views/v1/budgets/index.twig index b35bff25ca..3254769f9d 100644 --- a/resources/views/v1/budgets/index.twig +++ b/resources/views/v1/budgets/index.twig @@ -216,11 +216,11 @@ - - - - - + + + + + @@ -228,12 +228,12 @@ - - - - {% endfor %} + + + + + + + + +
{{ 'budget'|_ }}{{ 'budgeted'|_ }}{{ 'left'|_ }} ({{ 'per_day'|_|lower }}){{ 'budget'|_ }}{{ 'budgeted'|_ }}{{ 'left'|_ }} ({{ 'per_day'|_|lower }})
+ {{ budget.name }} {% if budget.auto_budget %} {% if 1 == budget.auto_budget.auto_budget_type %} @@ -247,7 +247,7 @@ {% endif %} + {% if 0==budget.budgeted|length %}
{{ defaultCurrency.symbol }}
@@ -287,18 +287,22 @@ {% if budget.budgeted|length < currencies.count %} - + {% endif %}
+ {% for spentInfo in budget.spent %} {% set countLimit = 0 %} {% for budgetLimit in budget.budgeted %} @@ -324,41 +328,45 @@
{% endif %} {% endfor %} - - - - - - {#{{ "-1"|formatAmount }}#} - {#{{ (repAmount + budgetInformation[budget.id]['spent'])|formatAmount }}#} - {#{% if repAmount + budgetInformation[budget.id]['spent'] > 0 %}#} - {#({{ "-1"|formatAmount }})#} - {#({{ ((repAmount + budgetInformation[budget.id]['spent']) / activeDaysLeft)|formatAmount }})#} - {#{% endif %}#} + {% for budgetLimit in budget.budgeted %} + {% if null == budget.spent[budgetLimit.currency_id] %} + + {{ formatAmountBySymbol(budgetLimit.amount, budgetLimit.currency_symbol, budgetLimit.currency_decimal_places) }} + ({{ formatAmountBySymbol(budgetLimit.amount / activeDaysLeft, budgetLimit.currency_symbol, budgetLimit.currency_decimal_places) }}) + +
+ {% endif %} + {% endfor %}
 {{ 'sum'|_ }} + {% for arr in sums.budgeted %} + {{ formatAmountBySymbol(arr.amount, arr.currency_symbol, arr.currency_decimal_places) }}
+ {% endfor %} +
+ {% for arr in sums.spent %} + {{ formatAmountBySymbol(arr.amount, arr.currency_symbol, arr.currency_decimal_places) }} + ({{ formatAmountBySymbol(arr.amount / activeDaysPassed, arr.currency_symbol, arr.currency_decimal_places) }}) +
+ {% endfor %} +
+ {% for arr in sums.left %} + {{ formatAmountBySymbol(arr.amount, arr.currency_symbol, arr.currency_decimal_places) }} + ({{ formatAmountBySymbol(arr.amount / activeDaysLeft, arr.currency_symbol, arr.currency_decimal_places) }}) +
+ {% endfor %} +