whisper-money/app
Víctor Falcón f2a7f955e6
fix(budgets): handle refunds correctly in budget spending calculations (#152)
## Why

### Problem

When a refund (positive transaction amount) is assigned to a budget, it
incorrectly **increases** the cumulative spending instead of
**reducing** it. This causes:

- The spending chart line to go **up** on refunds instead of down
- The "Spent" amount to be inflated
- The "Remaining" amount to be understated
- Period rollover calculations to carry over incorrect amounts

### Root Cause

`BudgetTransactionService` uses `abs($transaction->amount)` when
creating budget transactions, which forces all amounts to be positive —
including refunds. Since expenses are stored as negative in the
`transactions` table and refunds as positive, `abs()` treats both as
spending.

## What

### Changes

- Replace `abs($transaction->amount)` with `-$transaction->amount` in
both `assignTransaction()` and `assignHistoricalTransactionsToPeriod()`
— expenses (`-5000`) become positive spending (`5000`), refunds
(`+1000`) become negative spending (`-1000`)
- Remove redundant `abs()` in `BudgetPeriodService::closePeriod()`
rollover calculation
- Add data migration to fix existing `budget_transactions` rows where
the original transaction was a refund
- No frontend changes needed — the chart and budget card already sum
`t.amount` directly

## Verification

### Tests

- Updated `assignHistoricalTransactionsToPeriod stores negated
transaction amount for expenses` — verifies expense sign is preserved
- Added `assignHistoricalTransactionsToPeriod stores refund as negative
amount` — verifies refunds reduce spending
- Added `budget spending correctly reflects mix of expenses and refunds`
— verifies net spending (expense - refund)
- Added `assignTransaction stores refund as negative budget transaction
amount` — verifies real-time assignment handles refunds
2026-02-24 21:12:36 +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 refactor: extract AccountMetricsService to deduplicate balance computation logic (#147) 2026-02-24 09:07:42 +01:00
Jobs perf: make banking syncs incremental on subsequent runs (#141) 2026-02-23 15:10:40 +01:00
Listeners feat: Apply automation rules to bank-synced transactions (#112) 2026-02-12 14:20:55 +01:00
Mail Email notification for bank-synced transactions (#113) 2026-02-12 14:05:02 +01:00
Models feat: investment benefits — show gains/losses on investment accounts (#140) 2026-02-23 13:59:10 +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(budgets): handle refunds correctly in budget spending calculations (#152) 2026-02-24 21:12:36 +01:00