whisper-money/app/Services
Víctor Falcón 271b659260 fix(banking): give every account its turn when the bank refuses one of them
`EnableBankingSyncer::sync` wrapped the transaction call but only caught
`InaccessibleBankAccountException` and `WrongTransactionsPeriodException`. A
`TransientBankingProviderException` — what EnableBanking's HTTP 400
`{"error":"ASPSP_ERROR"}` becomes, i.e. "the bank's connector failed" — propagated
out and abandoned the loop, so every account behind the failing one was skipped
along with its balance, cycle after cycle.

Verified in production on a CaixaBank connection with three accounts: account 1
kept importing transactions until 2026-07-18 (618 rows, 231 balance days), while
accounts 2 and 3 sat at zero transactions with their balances frozen at
2026-06-12 — the date of the last complete run. Five weeks of it. That user has
since deleted their account, so this ships as a latent fix rather than a rescue;
84 of the 260 live EnableBanking connections have two or more accounts.

Deliberately conservative about everything else. The failure is still raised once
every account has had its turn, so the connection keeps its Error state, its
retries and its unset `last_synced_at` exactly as before. Recording a partial run
as a success would have shown an Active badge and a fresh timestamp over an
account that had stopped updating, and nothing in the product distinguishes a
stale account from a fresh one — a quieter dead end than the one being fixed. It
would also have stamped `bank_transactions_email_cutoff_at` and consumed the
connection-level first sync, permanently losing the failing account's derived
balance history and reporting its eventual backfill as "new transactions today".

A provider that never answered is rethrown immediately instead: `statusCode` is
null only on the `ConnectionException` path, and carrying on there would spend the
client's timeout per account against the job's 120s — a 26-account connection
already takes 62s when everything works.
2026-08-13 10:13:56 +02:00
..
Ai feat(stats): post the Discord stats reports in Spanish, opened by an AI summary (#752) 2026-08-10 10:13:40 +02:00
Banking fix(banking): give every account its turn when the bank refuses one of them 2026-08-13 10:13:56 +02:00
Demo Remove encryption from browser tests and demo user (#129) 2026-02-17 11:45:27 +01:00
Discord feat(stats): post the Discord stats reports in Spanish, opened by an AI summary (#752) 2026-08-10 10:13:40 +02:00
Stats feat(subscriptions): end the trial experiment and make the trial length per plan (#762) 2026-08-12 10:59:55 +02:00
Stripe feat(discord): enrich Stripe event messages and dedupe deliveries (#460) 2026-05-31 12:50:37 +02:00
Subscriptions feat(subscriptions): add an A/B price experiment (€3.99 control vs €8.99 high) (#700) 2026-08-12 13:36:49 +02:00
AccountMetricsService.php feat(dashboard): add accounts manager dialog with visibility toggle and reorder (#604) 2026-06-27 16:11:25 +00:00
AccountUserCurrencyService.php fix(open-banking): stop storing the XXX no-currency placeholder on accounts (#602) 2026-06-27 16:01:21 +00:00
AuthEntryPointService.php fix(auth): make build deterministic when REGISTRATION_ENABLED=false (#720) 2026-07-22 07:04:20 +00:00
AutomationRuleService.php fix(budgets): re-derive budget membership when labels are attached without a model event (#787) 2026-08-12 12:48:47 +02:00
BalanceLookup.php feat(accounts): count shared accounts at the owner's percentage (#750) 2026-08-11 13:26:54 +00:00
BudgetNotificationService.php feat(budgets): enable email notifications by default and coalesce alerts per transaction (#733) 2026-07-24 15:33:14 +02:00
BudgetPeriodService.php feat(mcp): budget tools — read, create, edit and delete (#779) 2026-08-11 14:28:53 +00:00
BudgetService.php feat(mcp): budget tools — read, create, edit and delete (#779) 2026-08-11 14:28:53 +00:00
BudgetTransactionService.php feat(budgets): count shared accounts at the owner's percentage (#786) 2026-08-12 12:47:43 +02:00
CashflowSummaryService.php refactor: consolidate duplicated financial calculations (#643) 2026-07-04 22:26:44 +02:00
CategorySpendingService.php feat(accounts): count shared accounts at the owner's percentage (#750) 2026-08-11 13:26:54 +00:00
CategoryTree.php feat(analysis): break down spending by sub-category (#508) 2026-06-08 14:53:36 +02:00
CurrencyConversionService.php fix(currency): make rate fetching resilient to slow CDN (#502) 2026-06-08 09:10:38 +02:00
CurrencyOptions.php feat(settings): centralize currency options and split profile/account support (#256) 2026-04-02 19:23:10 +02:00
ExchangeRateService.php Fix PHP-LARAVEL-1V exchange rate cache race (#383) 2026-05-12 12:45:45 +02:00
LoanAmortizationService.php fix(dashboard): avoid month overflow in real estate projection (#340) 2026-04-30 13:53:01 +00:00
LoanBalanceGeneratorService.php fix(balances): stop historical-balance generator OOM on ancient purchase/loan dates (PHP-LARAVEL-49) (#661) 2026-07-08 21:34:43 +00:00
ManualBalanceAdjuster.php feat(transactions): allow manual transactions on bank-connected accounts (#747) 2026-08-10 05:32:40 +02:00
PeriodComparator.php feat(cashflow): add savings and period views (#424) 2026-05-25 16:41:00 +02:00
RealEstateBalanceGeneratorService.php fix(balances): stop historical-balance generator OOM on ancient purchase/loan dates (PHP-LARAVEL-49) (#661) 2026-07-08 21:34:43 +00:00
ResendService.php refactor: remove HIDE_AUTH_BUTTONS launch gate and waitlist apparatus (#717) 2026-07-22 08:51:48 +02:00