whisper-money/app/Http/Controllers
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
..
Ai fix(security): scope job-status endpoints to owner + feature-area fixes (#627) 2026-07-03 14:49:32 +02:00
Api refactor(analytics): dedupe the two account balance evolution endpoints (#766) 2026-08-11 14:36:52 +02:00
Auth fix: verify email via signed link without requiring login (#490) 2026-06-05 10:01:32 +02:00
OpenBanking fix(open-banking): unblock account mapping when the bank reports accounts without a uid (#746) 2026-08-09 18:41:35 +02:00
Settings fix(budgets): keep per-transaction email notifications opt-in (#735) 2026-07-25 12:36:13 +02:00
Sync refactor(api): standardize serialization via model $hidden (#492) 2026-06-05 13:57:34 +02:00
AccountBalanceController.php feat: investment benefits — show gains/losses on investment accounts (#140) 2026-02-23 13:59:10 +01:00
AccountController.php perf(accounts): defer the account ledger prop on show (#632) 2026-07-03 17:40:08 +02:00
BudgetController.php fix(budgets): keep per-transaction email notifications opt-in (#735) 2026-07-25 12:36:13 +02:00
CashflowController.php refactor(api): standardize serialization via model $hidden (#492) 2026-06-05 13:57:34 +02:00
Controller.php Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
DashboardController.php refactor: consolidate duplicated financial calculations (#643) 2026-07-04 22:26:44 +02:00
EncryptionController.php refactor(encryption): strip client-side transaction encryption (#514) 2026-06-20 16:13:26 +00:00
IntegrationRequestController.php feat(integration-requests): add done status and fix review command crash on orphaned author (#601) 2026-06-27 14:42:09 +00:00
LoanDetailController.php feat(loans): backfill historical balances on loan creation (#322) 2026-04-24 13:09:34 +01:00
OnboardingController.php fix(onboarding): don't trap users on the syncing step when a bank sync fails (#745) 2026-08-09 18:40:49 +02:00
ReEvaluateTransactionRulesController.php fix(security): scope job-status endpoints to owner + feature-area fixes (#627) 2026-07-03 14:49:32 +02:00
RealEstateDetailController.php feat(accounts): add real estate asset tracking (#241) 2026-03-24 10:21:32 +00:00
RobotsController.php User Onboarding Flow (#23) 2025-12-12 13:06:08 +01:00
SitemapController.php SEO landing page 2025-11-25 11:33:11 +01:00
SubscriptionController.php fix(demo): stop demo:reset from colliding on the fake Stripe subscription id (#756) 2026-08-10 12:48:13 +00:00
TransactionController.php feat(transactions): allow editing all fields of manual transactions (#683) 2026-07-16 08:59:10 +02:00