whisper-money/app
Víctor Falcón ae2a8c0118
fix(open-banking): use net_amounts for Indexa Capital invested amount calculation (#156)
## Why

### Problem

The Indexa Capital dashboard shows +€11,339.01 profit for the Index
funds account, but our app shows +€9,680.43 — a €1,658.58 discrepancy.
The invested amount (and therefore the profit) is wrong.

### Root Cause

`calculateInvestedAmount()` used `instruments_cost + cash_amount` to
determine how much was invested. However, `instruments_cost` is the
**cost basis of currently held fund shares**, not the actual money
deposited. When Indexa rebalances portfolios, they sell shares
(realizing gains) and buy new ones at a higher cost basis. This inflates
`instruments_cost` over time without any new deposits, making the
"invested" figure too high and profit too low.

## What

### Changes

- Use `net_amounts` from the Indexa Capital API response instead of
`instruments_cost + cash_amount`
- `net_amounts` is an object keyed by date (`YYYYMMDD` format), where
each value is the cumulative net investment (inflows - outflows -
tax_outflows), matching Indexa Capital's own "investment" figure
- Keep `total_amount - return` as a fallback when `net_amounts` is
unavailable
- Return `null` when neither data source is available

### Concrete numbers (Index funds account, 2026-02-24)

| | Old (wrong) | New (correct) |
|---|---|---|
| Invested | €48,081.67 | €46,423.09 |
| Profit | €9,680.43 | €11,339.01 |

## Verification

### Tests

- Updated `stores invested_amount from net_amounts data` — verifies
invested_amount is sourced from `net_amounts`, not `instruments_cost +
cash_amount`
- Updated `stores null invested_amount when net_amounts is missing` —
verifies graceful null when API lacks `net_amounts`
- Updated `falls back to total_amount minus return when net_amounts is
missing` — verifies fallback path
- All 11 balance sync tests pass, all 23 SyncBankingConnectionJob tests
pass
2026-02-25 15:45:31 +01:00
..
Actions feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
Console/Commands perf: make banking syncs incremental on subsequent runs (#141) 2026-02-23 15:10:40 +01:00
Contracts feat: Integrate EnableBanking as open banking provider (#106) 2026-02-12 09:09:28 +01:00
Enums feat: enable invested amount tracking for savings accounts (#142) 2026-02-23 17:19:33 +01:00
Events Add Budgeting Feature to Track and Manage Spending (#36) 2026-01-21 15:25:50 +01:00
Http feat(open-banking): add update credentials flow for API-key connections (#154) 2026-02-25 13:41:24 +01:00
Jobs feat(open-banking): add update credentials flow for API-key connections (#154) 2026-02-25 13:41:24 +01:00
Listeners feat: Apply automation rules to bank-synced transactions (#112) 2026-02-12 14:20:55 +01:00
Mail feat(open-banking): add update credentials flow for API-key connections (#154) 2026-02-25 13:41:24 +01:00
Models feat(open-banking): add update credentials flow for API-key connections (#154) 2026-02-25 13:41:24 +01:00
Notifications feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
Policies Add Budgeting Feature to Track and Manage Spending (#36) 2026-01-21 15:25:50 +01:00
Providers Remove plaintext-transactions feature flag & E2E references (#116) 2026-02-13 11:10:21 +01:00
Services fix(open-banking): use net_amounts for Indexa Capital invested amount calculation (#156) 2026-02-25 15:45:31 +01:00