diff --git a/app/Api/V1/Controllers/Chart/BudgetController.php b/app/Api/V1/Controllers/Chart/BudgetController.php index 1b679cb867..e39635e6c3 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; @@ -80,13 +80,13 @@ class BudgetController extends Controller */ 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(); @@ -123,7 +123,7 @@ class BudgetController extends Controller foreach ($rows as $row) { $current = [ 'label' => $budget->name, - 'currency_id' => (string) $row['currency_id'], + 'currency_id' => (string)$row['currency_id'], 'currency_code' => $row['currency_code'], 'currency_name' => $row['currency_name'], 'currency_decimal_places' => $row['currency_decimal_places'], @@ -131,6 +131,7 @@ class BudgetController extends Controller 'start' => $row['start'], 'end' => $row['end'], 'entries' => [ + 'budgeted' => $row['budgeted'], 'spent' => $row['spent'], 'left' => $row['left'], 'overspent' => $row['overspent'], @@ -163,7 +164,7 @@ class BudgetController extends Controller * * @throws FireflyException */ - private function processExpenses(int $budgetId, array $array, Carbon $start, Carbon $end): array + private function processExpenses(int $budgetId, array $spent, Carbon $start, Carbon $end): array { $return = []; @@ -171,29 +172,30 @@ 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 ($array as $currencyId => $block) { + foreach ($spent as $currencyId => $block) { $this->currencies[$currencyId] ??= TransactionCurrency::find($currencyId); $return[$currencyId] ??= [ - 'currency_id' => (string) $currencyId, + 'currency_id' => (string)$currencyId, 'currency_code' => $block['currency_code'], 'currency_name' => $block['currency_name'], 'currency_symbol' => $block['currency_symbol'], - 'currency_decimal_places' => (int) $block['currency_decimal_places'], + 'currency_decimal_places' => (int)$block['currency_decimal_places'], 'start' => $start->toAtomString(), 'end' => $end->toAtomString(), + 'budgeted' => '0', 'spent' => '0', 'left' => '0', 'overspent' => '0', ]; - $currentBudgetArray = $block['budgets'][$budgetId]; + $currentBudgetArray = $block['budgets'][$budgetId]; // var_dump($return); /** @var array $journal */ foreach ($currentBudgetArray['transaction_journals'] as $journal) { - $return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], (string) $journal['amount']); + $return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], (string)$journal['amount']); } } @@ -229,7 +231,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,16 +239,17 @@ 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'])); + $compare = bccomp($limit->amount, (string)app('steam')->positive($result[$limitCurrencyId]['spent'])); + $result[$limitCurrencyId]['budgeted'] = $limit->amount; if (1 === $compare) { // convert this amount into the native currency: - $result[$limitCurrencyId]['left'] = bcadd($limit->amount, (string) $result[$limitCurrencyId]['spent']); + $result[$limitCurrencyId]['left'] = bcadd($limit->amount, (string)$result[$limitCurrencyId]['spent']); } if ($compare <= 0) { - $result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, (string) $result[$limitCurrencyId]['spent'])); + $result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, (string)$result[$limitCurrencyId]['spent'])); } } diff --git a/config/translations.php b/config/translations.php index c9490dab6d..2b541e8ddb 100644 --- a/config/translations.php +++ b/config/translations.php @@ -65,6 +65,7 @@ return [ 'interest_calc_half-year', 'interest_calc_quarterly', 'spent', + 'budgeted', 'administration_owner', 'administration_you', 'administration_role_owner', diff --git a/resources/assets/v2/src/pages/dashboard/budgets.js b/resources/assets/v2/src/pages/dashboard/budgets.js index 5f8a4d800a..bc003535e2 100644 --- a/resources/assets/v2/src/pages/dashboard/budgets.js +++ b/resources/assets/v2/src/pages/dashboard/budgets.js @@ -60,7 +60,8 @@ export default () => ({ const start = new Date(window.store.get('start')); const end = new Date(window.store.get('end')); const cacheKey = getCacheKey('ds_bdg_chart', {start: start, end: end}); - const cacheValid = window.store.get('cacheValid'); + //const cacheValid = window.store.get('cacheValid'); + const cacheValid = false; let cachedData = window.store.get(cacheKey); if (cacheValid && typeof cachedData !== 'undefined') { @@ -80,7 +81,7 @@ export default () => ({ }, generateOptions(data) { currencies = []; - let options = getDefaultChartSettings('column'); + let options = getDefaultChartSettings('bar'); options.options.locale = window.store.get('locale').replace('_', '-'); options.options.plugins = { tooltip: { @@ -94,7 +95,7 @@ export default () => ({ if (label) { label += ': '; } - return label + ' ' + formatMoney(context.parsed.y, currencies[context.parsed.x] ?? 'EUR'); + return label + ' ' + formatMoney(context.parsed.x, currencies[context.parsed.x] ?? 'EUR'); } } } @@ -103,55 +104,40 @@ export default () => ({ labels: [], datasets: [ { + label: i18next.t('firefly.budgeted'), + data: [], + borderWidth: 1, + backgroundColor: getColors('budgeted', 'background'), + borderColor: getColors('budgeted', 'border'), + }, + { + //label: i18next.t('firefly.budgeted'), label: i18next.t('firefly.spent'), data: [], borderWidth: 1, - stack: 1, backgroundColor: getColors('spent', 'background'), borderColor: getColors('spent', 'border'), - }, - { - label: i18next.t('firefly.left'), - data: [], - borderWidth: 1, - stack: 1, - backgroundColor: getColors('left', 'background'), - borderColor: getColors('left', 'border'), - }, - { - label: i18next.t('firefly.overspent'), - data: [], - borderWidth: 1, - stack: 1, - backgroundColor: getColors('overspent', 'background'), - borderColor: getColors('overspent', 'border'), } ] }; for (const i in data) { if (data.hasOwnProperty(i)) { let current = data[i]; + console.log('Now at'); + console.log(current); // // convert to EUR yes no? let label = current.label + ' (' + current.currency_code + ')'; options.data.labels.push(label); - if (this.convertToNative) { - currencies.push(current.native_currency_code); - // series 0: spent - options.data.datasets[0].data.push(parseFloat(current.native_entries.spent) * -1); - // series 1: left - options.data.datasets[1].data.push(parseFloat(current.native_entries.left)); - // series 2: overspent - options.data.datasets[2].data.push(parseFloat(current.native_entries.overspent)); - } - if (!this.convertToNative) { - currencies.push(current.currency_code); - // series 0: spent - options.data.datasets[0].data.push(parseFloat(current.entries.spent) * -1); - // series 1: left - options.data.datasets[1].data.push(parseFloat(current.entries.left)); - // series 2: overspent - options.data.datasets[2].data.push(parseFloat(current.entries.overspent)); - } + // label = current.label + ' (' + current.currency_code + ') b'; + // options.data.labels.push(label); + + currencies.push(current.currency_code); + // series 0: budgeted + options.data.datasets[0].data.push(parseFloat(current.entries.budgeted)); + // series 1: spent + options.data.datasets[1].data.push(parseFloat(current.entries.spent) * -1); + // series 2: overspent + // options.data.datasets[2].data.push(parseFloat(current.entries.overspent)); } } // the currency format callback for the Y axis is AlWAYS based on whatever the first currency is. @@ -160,9 +146,10 @@ export default () => ({ options.options.scales = { y: { ticks: { - callback: function (context) { - return formatMoney(context, currencies[0] ?? 'EUR'); - } + // callback: function (context) { + // return 'abc'; + // return formatMoney(context, currencies[0] ?? 'EUR'); + // } } } }; diff --git a/resources/assets/v2/src/support/default-chart-settings.js b/resources/assets/v2/src/support/default-chart-settings.js index 4f6f98e935..b3096edc56 100644 --- a/resources/assets/v2/src/support/default-chart-settings.js +++ b/resources/assets/v2/src/support/default-chart-settings.js @@ -62,6 +62,36 @@ function getDefaultChartSettings(type) { }, }; } + if('bar' === type) { + return { + type: 'bar', + data: { + labels: [], + datasets: [], + }, + options: { + maintainAspectRatio: false, + indexAxis: 'y', + // Elements options apply to all the options unless overridden in a dataset + // In this case, we are setting the border of each horizontal bar to be 2px wide + elements: { + bar: { + borderWidth: 2, + } + }, + responsive: true, + plugins: { + legend: { + position: 'right', + }, + title: { + display: true, + text: 'Chart.js Horizontal Bar Chart' + } + } + }, + }; + } if ('line' === type) { return { options: { diff --git a/resources/assets/v2/src/support/get-colors.js b/resources/assets/v2/src/support/get-colors.js index 9d60317da7..7333eb0070 100644 --- a/resources/assets/v2/src/support/get-colors.js +++ b/resources/assets/v2/src/support/get-colors.js @@ -92,6 +92,14 @@ function getColors(type, field) { backgroundColor: background.rgbString(), }; break; + case 'budgeted': + background = new Color(green.rgbString()); + background.lighten(0.38); + colors = { + borderColor: green.rgbString(), + backgroundColor: background.rgbString(), + }; + break; case 'overspent': background = new Color(red.rgbString()); background.lighten(0.22); diff --git a/resources/views/v2/index.blade.php b/resources/views/v2/index.blade.php index 52f8ce6344..0ad72858b8 100644 --- a/resources/views/v2/index.blade.php +++ b/resources/views/v2/index.blade.php @@ -37,11 +37,11 @@

- TODO + List of income + sum

diff --git a/resources/views/v2/partials/dashboard/subscriptions.blade.php b/resources/views/v2/partials/dashboard/subscriptions.blade.php index d5102d6898..b8938c5360 100644 --- a/resources/views/v2/partials/dashboard/subscriptions.blade.php +++ b/resources/views/v2/partials/dashboard/subscriptions.blade.php @@ -10,6 +10,7 @@
+ + Here was chart.