From 333004c4d9adb975c1378a712d999741e3da5c31 Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 30 Jul 2025 06:59:58 +0200 Subject: [PATCH] Upgrade to font awesome 7, make sure chart includes currencies outside of limits. --- .../V1/Controllers/Chart/BudgetController.php | 81 +++++++++++++++---- package-lock.json | 2 +- resources/assets/v2/package.json | 2 +- resources/assets/v2/src/sass/app.scss | 46 +++++++---- 4 files changed, 95 insertions(+), 36 deletions(-) diff --git a/app/Api/V1/Controllers/Chart/BudgetController.php b/app/Api/V1/Controllers/Chart/BudgetController.php index b680a233c4..7c0f557d78 100644 --- a/app/Api/V1/Controllers/Chart/BudgetController.php +++ b/app/Api/V1/Controllers/Chart/BudgetController.php @@ -49,7 +49,7 @@ class BudgetController extends Controller use CleansChartData; use ValidatesUserGroupTrait; - protected array $acceptedRoles = [UserRoleEnum::READ_ONLY]; + protected array $acceptedRoles = [UserRoleEnum::READ_ONLY]; protected OperationsRepositoryInterface $opsRepository; private BudgetLimitRepositoryInterface $blRepository; @@ -77,16 +77,17 @@ class BudgetController extends Controller /** * TODO see autocomplete/accountcontroller + * @throws FireflyException */ public function dashboard(DateRequest $request): JsonResponse { - $params = $request->getAll(); + $params = $request->getAll(); /** @var Carbon $start */ - $start = $params['start']; + $start = $params['start']; /** @var Carbon $end */ - $end = $params['end']; + $end = $params['end']; // code from FrontpageChartGenerator, but not in separate class $budgets = $this->repository->getActiveBudgets(); @@ -108,16 +109,52 @@ class BudgetController extends Controller { // get all limits: $limits = $this->blRepository->getBudgetLimits($budget, $start, $end); - $rows = []; + + // 'currency_id' => string '1' (length=1) + // 'currency_code' => string 'EUR' (length=3) + // 'currency_name' => string 'Euro' (length=4) + // 'currency_symbol' => string '€' (length=3) + // 'currency_decimal_places' => int 2 + // 'start' => string '2025-07-01T00:00:00+02:00' (length=25) + // 'end' => string '2025-07-31T23:59:59+02:00' (length=25) + // 'budgeted' => string '100.000000000000' (length=16) + // 'spent' => string '-421.230000000000' (length=17) + // 'left' => string '0' (length=1) + // 'overspent' => string '321.230000000000' (length=16) + + + $rows = []; + + // instead of using the budget limits as a thing to collect all expenses, + // use the budget range itself to collect and group them, + // AND THEN add budgeted amounts from the limits to the rows. + $spent = $this->opsRepository->listExpenses($start, $end, null, new Collection([$budget])); + $expenses = $this->processExpenses($budget->id, $spent, $start, $end); + + /** + * @var int $currencyId + * @var array $row + */ + foreach ($expenses as $currencyId => $row) { + // budgeted, left and overspent are now 0. + $limit = $this->filterLimit($currencyId, $limits); + if (null !== $limit) { + $row['budgeted'] = $limit->amount; + $row['left'] = bcsub($row['budgeted'], bcmul($row['spent'], '-1')); + $row['overspent'] = bcmul($row['left'], '-1'); + $row['left'] = 1 === bccomp($row['left'], '0') ? $row['left'] : '0'; + $row['overspent'] = 1 === bccomp($row['overspent'], '0') ? $row['overspent'] : '0'; + } + $rows[] = $row; + } + // if no limits - if (0 === $limits->count()) { - // return as a single item in an array - $rows = $this->noBudgetLimits($budget, $start, $end); - } - if ($limits->count() > 0) { - $rows = $this->budgetLimits($budget, $limits); - } +// if (0 === $limits->count()) { +// return as a single item in an array +// $rows = $this->noBudgetLimits($budget, $start, $end); +// } + // is always an array $return = []; foreach ($rows as $row) { @@ -170,7 +207,7 @@ class BudgetController extends Controller * This array contains the expenses in this budget. Grouped per currency. * The grouping is on the main currency only. * - * @var int $currencyId + * @var int $currencyId * @var array $block */ foreach ($spent as $currencyId => $block) { @@ -188,7 +225,7 @@ class BudgetController extends Controller 'left' => '0', 'overspent' => '0', ]; - $currentBudgetArray = $block['budgets'][$budgetId]; + $currentBudgetArray = $block['budgets'][$budgetId]; // var_dump($return); /** @var array $journal */ @@ -229,7 +266,7 @@ class BudgetController extends Controller private function processLimit(Budget $budget, BudgetLimit $limit): array { Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__)); - $end = clone $limit->end_date; + $end = clone $limit->end_date; $end->endOfDay(); $spent = $this->opsRepository->listExpenses($limit->start_date, $end, null, new Collection([$budget])); $limitCurrencyId = $limit->transaction_currency_id; @@ -237,8 +274,8 @@ class BudgetController extends Controller /** @var array $entry */ // only spent the entry where the entry's currency matches the budget limit's currency // so $filtered will only have 1 or 0 entries - $filtered = array_filter($spent, fn ($entry) => $entry['currency_id'] === $limitCurrencyId); - $result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end); + $filtered = array_filter($spent, fn($entry) => $entry['currency_id'] === $limitCurrencyId); + $result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end); if (1 === count($result)) { $compare = bccomp($limit->amount, (string)app('steam')->positive($result[$limitCurrencyId]['spent'])); $result[$limitCurrencyId]['budgeted'] = $limit->amount; @@ -253,4 +290,14 @@ class BudgetController extends Controller return $result; } + + private function filterLimit(int $currencyId, Collection $limits): ?BudgetLimit + { + foreach ($limits as $limit) { + if ($limit->transaction_currency_id === $currencyId) { + return $limit; + } + } + return null; + } } diff --git a/package-lock.json b/package-lock.json index d501fcf28d..f07a1c8c18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12525,7 +12525,7 @@ "resources/assets/v2": { "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-free": "^7.0.0", + "@fortawesome/fontawesome-free": "^7", "@popperjs/core": "^2.11.8", "admin-lte": "^4.0.0-rc4", "alpinejs": "^3.13.7", diff --git a/resources/assets/v2/package.json b/resources/assets/v2/package.json index 2a2578e303..d37480fa7a 100644 --- a/resources/assets/v2/package.json +++ b/resources/assets/v2/package.json @@ -16,7 +16,7 @@ "vite-plugin-manifest-sri": "^0.2.0" }, "dependencies": { - "@fortawesome/fontawesome-free": "^7.0.0", + "@fortawesome/fontawesome-free": "^7", "@popperjs/core": "^2.11.8", "admin-lte": "^4.0.0-rc4", "alpinejs": "^3.13.7", diff --git a/resources/assets/v2/src/sass/app.scss b/resources/assets/v2/src/sass/app.scss index 641ee0cd29..872e5bda2d 100644 --- a/resources/assets/v2/src/sass/app.scss +++ b/resources/assets/v2/src/sass/app.scss @@ -26,7 +26,28 @@ $danger: #CD5029 !default; $primary: #1E6581 !default; $success: #64B624 !default; +// admin LTE +@use "admin-lte/src/scss/adminlte" with ( + $color-mode-type: $color-mode-type, + $link-decoration: $link-decoration, + $font-family-sans-serif: $font-family-sans-serif, + $danger: $danger, + $primary: $primary, + $success: $success +); +@use '@fortawesome/fontawesome-free/scss/variables' with ( + $font-path: "@fortawesome/fontawesome-free/webfonts" +); + +@use '@fortawesome/fontawesome-free/scss/fontawesome'; +@use '@fortawesome/fontawesome-free/scss/fa' as fa; +@use '@fortawesome/fontawesome-free/scss/solid.scss' as fa-solid; +@use '@fortawesome/fontawesome-free/scss/brands.scss' as fa-brands; +@use '@fortawesome/fontawesome-free/scss/regular.scss' as fa-regular; + + +// some local CSS .skip-links {display: none;} /* @@ -59,16 +80,7 @@ h3.hover-expand:hover { appearance: auto; } -// Bootstrap -// @import "bootstrap/scss/bootstrap"; - -// admin LTE -@import "adminlte-filtered"; - - -// @import "~bootstrap-sass/assets/stylesheets/bootstrap"; - -// hover buttons +// edit buttons .hidden-edit-button { cursor: pointer; } @@ -76,12 +88,12 @@ td:not(:hover) .hidden-edit-button { visibility: hidden; } +// Bootstrap +// @import "bootstrap/scss/bootstrap"; + + +// @import "~bootstrap-sass/assets/stylesheets/bootstrap"; + +// hover buttons -// Font awesome -//@import "~font-awesome/css/font-awesome"; -$fa-font-path: "@fortawesome/fontawesome-free/webfonts"; -@import "@fortawesome/fontawesome-free/scss/fontawesome.scss"; -@import "@fortawesome/fontawesome-free/scss/solid.scss"; -@import "@fortawesome/fontawesome-free/scss/brands.scss"; -@import "@fortawesome/fontawesome-free/scss/regular.scss";