whisper-money/tests
Víctor Falcón cd323bbe52
fix(budgets): make period generation idempotent (#533)
## Sentry
Fixes
**[PHP-LARAVEL-39](https://whisper-money.sentry.io/issues/PHP-LARAVEL-39)**
— `UniqueConstraintViolationException` (1062) on
`budget_periods_budget_id_start_date_unique`. 7 events over 6 days, 0
users (background command), regressed.

## Root cause
`BudgetPeriodService::generatePeriod()` did a blind
`BudgetPeriod::create()`. The scheduled `budgets:generate-periods`
command reaches `generatePeriod()` from three paths (`handle()` +
`closePeriod()`), each computing the next start date as `max(end_date) +
1 day`. Across **overlapping or repeated runs** two paths compute the
same `start_date`, and the second insert collides with the unique key:

```
insert into budget_periods (budget_id, start_date, ...) values (019ea713..., 2026-06-30 00:00:00, ...)
-> 1062 Duplicate entry '019ea713...-2026-06-30'
```

## Fix
Make creation idempotent on the `(budget_id, start_date)` unique key via
`firstOrCreate()`. It delegates to Laravel's `createOrFirst()`, which
catches the unique violation and re-queries — so the call is
**concurrency-safe** and the command is safe to re-run. Period dates are
normalized to start-of-day so the lookup matches the stored date key.

## Test
`generatePeriod is idempotent when a period already exists for the start
date` — reproduces the 1062 (verified failing against the pre-fix code
with the exact `BudgetPeriodService.php:26` stack), passes after the
fix. Returns the existing period, no duplicate row.

## Notes
Behavior change: when the next period already exists, `generatePeriod()`
now returns it unchanged instead of throwing. `closePeriod()` still
updates `carried_over_amount` on the returned period.
2026-06-15 12:44:44 +02:00
..
.pest Speed up PR CI browser path (#365) 2026-05-07 20:40:13 +01:00
Browser feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
Feature fix(budgets): make period generation idempotent (#533) 2026-06-15 12:44:44 +02:00
Performance feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
Support test(open-banking): e2e coverage for Enable Banking connection flows (#509) 2026-06-09 11:58:50 +02:00
Unit feat(transactions): add counterparty fields (#440) 2026-05-27 16:20:55 +02:00
Pest.php feat: add Discord admin feed for daily stats and Stripe events (#458) 2026-05-30 18:14:46 +02:00
TestCase.php Remove encryption from browser tests and demo user (#129) 2026-02-17 11:45:27 +01:00
bootstrap.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00