whisper-money/app/Http/Controllers/Api
Víctor Falcón 952ca41eb1
refactor(analytics): dedupe the two account balance evolution endpoints (#766)
## Why

We just landed the CRAP and DRY checks. `DashboardAnalyticsController`
was the worst offender after the trial-experiment code (which #762
deletes anyway):

- `accountBalanceEvolution` — cyclomatic complexity **30**
- `accountDailyBalanceEvolution` — cyclomatic complexity **12**

And the two were near-identical copies of each other, so it was a
duplication problem wearing a complexity costume.

## What changed

The monthly and daily series shared everything except the dates they
iterate and the projections the monthly one appends: authorization,
range validation, per-point assembly (balance, invested amount, linked
mortgage, display-currency equivalents) and the response envelope. Those
are now shared methods:

| new method | what it owns |
|---|---|
| `authorizedDateRange` | 403 guard + `from`/`to` validation + parsing |
| `displayCurrencyFor` | the user currency, or null when it matches the
account |
| `balanceLookupFor` | the `BalanceLookup` over the account and its
linked loan |
| `balancePointAt` | one point: value, invested amount, mortgage,
display fields |
| `projectedPoints` → `loanProjection` / `realEstateProjection` /
`projectedPoint` | the future months |
| `evolutionResponse` | the `data` + `account` + `display_currency_code`
envelope |

Also collapsed the three byte-identical "sum transactions joined to a
category of type X" queries in `calculateSpending`/`calculateCashFlow`
behind `sumByCategoryType`.

## Behaviour

No change. One thing worth naming: the daily series used to read the
balance at **start** of day and the invested amount at **end** of day
(`endOfDay()` mutates the Carbon instance mid-method). It now reads both
at end of day — same result, because `BalanceLookup` compares
`toDateString()`, i.e. by day.

## Metrics

| | before | after |
|---|---|---|
| methods over complexity 10 | 35 | 33 |
| `accountBalanceEvolution` | 30 | 4 |
| `accountDailyBalanceEvolution` | 12 | 4 |
| duplicated lines (php) | 5.92% | 5.68% |
| duplicated lines (total) | 5.34% | 5.25% |

## Testing

`DashboardAnalyticsTest` (41), `LoanTest` + `AccountControllerTest` (68)
— all green, unchanged. Between them they cover both projection paths,
both currency-conversion paths and the mortgage overlay, so the refactor
is verified by the existing suite; no new tests were needed.

## Noticed, not changed

`display_invested_amount` converts **from** the user currency **to** the
account currency, while every sibling field converts the other way.
Looks like an inverted argument pair, but fixing it changes numbers on
the invested-amount chart, so it stays out of a no-behaviour-change PR.
Worth a follow-up.
2026-08-11 14:36:52 +02:00
..
Concerns fix(analysis): respect category types like the cashflow screen (#612) 2026-06-29 21:04:18 +02:00
AccountController.php refactor(api): standardize serialization via model $hidden (#492) 2026-06-05 13:57:34 +02:00
AccountImportConfigController.php feat(import): persist per-account import configuration on the backend (#698) 2026-07-18 16:10:40 +02:00
CashflowAnalyticsController.php refactor: consolidate duplicated financial calculations (#643) 2026-07-04 22:26:44 +02:00
CategoryMonthlyBreakdownController.php fix(analysis): respect category types like the cashflow screen (#612) 2026-06-29 21:04:18 +02:00
DashboardAnalyticsController.php refactor(analytics): dedupe the two account balance evolution endpoints (#766) 2026-08-11 14:36:52 +02:00
ImportDataController.php refactor(api): standardize serialization via model $hidden (#492) 2026-06-05 13:57:34 +02:00
SavedFilterController.php feat(analysis): project-aware transaction analysis (#513) 2026-06-09 15:32:07 +02:00
TransactionAnalysisController.php feat(transactions): add a monthly trend view to the analysis drawer (#736) 2026-07-26 17:03:52 +02:00
TransactionController.php fix: address remaining security audit findings (round 2) (#628) 2026-07-03 15:04:03 +00:00