whisper-money/tests/Feature
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
Api feat(transactions): serve import dedup and account ledger from the backend (#631) 2026-07-03 16:49:59 +02:00
Auth fix(auth): make build deterministic when REGISTRATION_ENABLED=false (#720) 2026-07-22 07:04:20 +00:00
Console feat(reports): email a monthly CSV of active user emails to the owners (#783) 2026-08-12 11:29:28 +02:00
Events fix: stop double-dispatching transaction listeners (N+1 insert into jobs) (#620) 2026-07-02 13:26:45 +00:00
Jobs feat(drip): email users stuck on the paywall a day after onboarding (#562) 2026-06-19 14:11:12 +00:00
Listeners feat(budgets): track multiple categories and labels per budget (#466) 2026-06-01 12:32:23 +02:00
Mcp feat(mcp): budget tools — read, create, edit and delete (#779) 2026-08-11 14:28:53 +00:00
Onboarding fix(onboarding): don't trap users on the syncing step when a bank sync fails (#745) 2026-08-09 18:40:49 +02:00
OpenBanking fix(banking): give every account its turn when the bank refuses one of them 2026-08-13 10:13:56 +02:00
Services refactor: remove HIDE_AUTH_BUTTONS launch gate and waitlist apparatus (#717) 2026-07-22 08:51:48 +02:00
Settings fix(budgets): keep per-transaction email notifications opt-in (#735) 2026-07-25 12:36:13 +02:00
Spaces feat(spaces): phase 0 — multi-tenant Space foundation (no behaviour change) (#650) 2026-07-09 14:26:07 +02:00
Sync refactor: Simplify transaction endpoints architecture (#76) 2026-01-25 16:15:17 +01:00
AccountBalanceControllerTest.php fix(balances): allow saving a zero balance (#664) 2026-07-10 15:02:38 +02:00
AccountControllerTest.php feat(accounts): count shared accounts at the owner's percentage (#750) 2026-08-11 13:26:54 +00:00
AccountImportConfigTest.php feat(import): persist per-account import configuration on the backend (#698) 2026-07-18 16:10:40 +02:00
AccountUserCurrencyServiceTest.php fix(open-banking): stop storing the XXX no-currency placeholder on accounts (#602) 2026-06-27 16:01:21 +00:00
AiConsentSettingsTest.php refactor(ai): remove AiConsentSettings feature flag (#619) 2026-07-01 09:47:55 +02:00
AiConsentTest.php feat(ai): dismissable AI consent banner that stops after the first decision (#617) 2026-07-01 07:26:36 +00:00
AlignAccountsEncryptedFlagMigrationTest.php refactor(encryption): strip client-side transaction encryption (#514) 2026-06-20 16:13:26 +00:00
ApplyRealEstateRevaluationTest.php fix(real-estate): compound annual revaluation monthly (#337) 2026-04-27 07:35:51 +01:00
AuthenticatedLayoutSafeAreaTest.php fix(layout): keep bottom padding while floating nav is visible (#537) 2026-06-15 18:23:26 +02:00
AutomationRuleApplicationTest.php fix(budgets): re-derive budget membership when labels are attached without a model event (#787) 2026-08-12 12:48:47 +02:00
AutomationRuleEvaluationTest.php feat(transactions): add counterparty fields (#440) 2026-05-27 16:20:55 +02:00
AutomationRuleTest.php fix(ai): stop a learned rule title from 500-ing the user's category change (#741) 2026-08-09 15:39:14 +00:00
BackfillAccountIbansCommandTest.php chore: upgrade Laravel 12 to 13 (#242) 2026-03-25 12:56:33 +00:00
BackfillXxxAccountCurrenciesTest.php fix(open-banking): stop storing the XXX no-currency placeholder on accounts (#602) 2026-06-27 16:01:21 +00:00
BalanceLookupTest.php feat: investment benefits — show gains/losses on investment accounts (#140) 2026-02-23 13:59:10 +01:00
BudgetHistoricalAssignmentTest.php feat(budgets): track multiple categories and labels per budget (#466) 2026-06-01 12:32:23 +02:00
BudgetNotificationTest.php feat(budgets): enable email notifications by default and coalesce alerts per transaction (#733) 2026-07-24 15:33:14 +02:00
BudgetPeriodDateTest.php Remove budgets feature flag (#108) 2026-02-12 09:58:01 +01:00
BudgetPeriodServiceTest.php fix(budgets): make period generation idempotent (#533) 2026-06-15 12:44:44 +02:00
BudgetTest.php feat(mcp): budget tools — read, create, edit and delete (#779) 2026-08-11 14:28:53 +00:00
BudgetTransactionServiceTest.php feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
BulkUpdateTransactionsTest.php refactor(transactions): build the bulk selection once in bulkUpdate (#774) 2026-08-11 13:14:19 +00:00
CancelFreeEnableBankingConnectionsCommandTest.php Cancel Enable Banking connections for free users (#289) 2026-04-15 16:23:03 +02:00
CashflowAnalyticsTest.php fix(cashflow): bound trend window to prevent request timeout (#534) 2026-06-15 12:47:27 +02:00
CashflowPageTest.php refactor: remove HIDE_AUTH_BUTTONS launch gate and waitlist apparatus (#717) 2026-07-22 08:51:48 +02:00
CatchAllBudgetTest.php fix(budgets): keep labeled expenses out of the catch-all budget (#781) 2026-08-11 15:45:19 +00:00
CategoryMonthlyBreakdownTest.php feat(analysis): per-category 12-month spending drawer (#519) 2026-06-11 09:52:53 +02:00
CrapCommandTest.php ci: add duplication and complexity quality checks (#765) 2026-08-11 13:29:37 +02:00
CurrencyConversionServiceTest.php fix(currency): make rate fetching resilient to slow CDN (#502) 2026-06-08 09:10:38 +02:00
DashboardAnalyticsTest.php fix(accounts): show credit cards as positive and exclude them from net worth (#673) 2026-07-13 07:27:52 +00:00
DashboardTest.php fix(auth): make build deterministic when REGISTRATION_ENABLED=false (#720) 2026-07-22 07:04:20 +00:00
DecryptTransactionsTest.php refactor(encryption): strip client-side transaction encryption (#514) 2026-06-20 16:13:26 +00:00
DeleteUserCommandTest.php Support soft-deleted users with reusable emails (#316) 2026-04-22 11:41:41 +01:00
DemoAccountRestrictionsTest.php fix(demo): stop demo:reset from colliding on the fake Stripe subscription id (#756) 2026-08-10 12:48:13 +00:00
DisconnectBankingConnectionsCommandTest.php feat(banking): add command to disconnect connections by id (#497) 2026-06-06 11:16:01 +02:00
DiscordReportEmbedLimitsTest.php feat(subscriptions): end the trial experiment and make the trial length per plan (#762) 2026-08-12 10:59:55 +02:00
DiscordWebhookTest.php feat: add Discord admin feed for daily stats and Stripe events (#458) 2026-05-30 18:14:46 +02:00
EncryptionTest.php refactor(encryption): strip client-side transaction encryption (#514) 2026-06-20 16:13:26 +00:00
ExampleTest.php Install Pest 2025-11-07 12:01:58 +00:00
ExchangeRateServiceTest.php Fix PHP-LARAVEL-1V exchange rate cache race (#383) 2026-05-12 12:45:45 +02:00
GenerateStripePromotionCodesCommandTest.php chore(deps): update composer dependencies to latest (#764) 2026-08-11 11:15:27 +00:00
IdorVulnerabilityTest.php refactor: Simplify transaction endpoints architecture (#76) 2026-01-25 16:15:17 +01:00
ImportDataTest.php fix: Apply automation rule labels on transaction creation and import (#79) 2026-01-27 11:11:29 +01:00
InertiaSharedDataTest.php feat(mcp): read-only MCP server for Pro accounts (#689) 2026-07-17 16:54:15 +02:00
IntegrationRequestTest.php feat(integration-requests): add done status and fix review command crash on orphaned author (#601) 2026-06-27 14:42:09 +00:00
LabelBudgetReassignmentTest.php fix(budgets): re-derive budget membership when labels are attached without a model event (#787) 2026-08-12 12:48:47 +02:00
LabelTest.php refactor(api): standardize serialization via model $hidden (#492) 2026-06-05 13:57:34 +02:00
LoanTest.php refactor(accounts): split store/update in the account controller (#776) 2026-08-11 13:58:47 +00:00
LocalizationTest.php feat(currencies): add the Danish Krone (DKK) (#754) 2026-08-10 12:08:56 +02:00
LoggingConfigTest.php fix(logging): keep laravel.log writable across container UIDs (#451) 2026-05-29 15:10:50 +02:00
MailSenderTest.php feat(reports): email a monthly CSV of active user emails to the owners (#783) 2026-08-12 11:29:28 +02:00
NewTransactionsMarkerTest.php feat(transactions): make new-transaction marker cross-device (#611) 2026-06-29 19:11:37 +02:00
OpenAiAppsChallengeTest.php feat(mcp): serve the ChatGPT app directory domain challenge (#749) 2026-08-10 07:46:49 +00:00
PersistUpsellSourceFromStripeTest.php feat: reuse the upgrade modal at more upsell points and attribute revenue (#699) 2026-07-18 12:53:20 +00:00
PlaintextTransactionsTest.php Remove plaintext-transactions feature flag & E2E references (#116) 2026-02-13 11:10:21 +01:00
PlanFeatureTest.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
PopoverSafeAreaTest.php fix: keep iOS popovers below the notch (#282) 2026-04-13 15:19:56 +01:00
PostStripeEventToDiscordTest.php fix(discord): show old → new plan on plan change notification (#637) 2026-07-04 15:49:09 +00:00
PriceExperimentTest.php feat(subscriptions): add an A/B price experiment (€3.99 control vs €8.99 high) (#700) 2026-08-12 13:36:49 +02:00
PurgeResidualEncryptionArtifactsJobTest.php chore: harden Inertia boundary, CI type-check, and test isolation (#640) 2026-07-04 18:57:58 +00:00
PwaTest.php Harden browser storage and PostHog recording (#402) 2026-05-14 15:57:48 +02:00
QueueConfigTest.php fix(queue): raise retry_after above the longest job timeout (PHP-LARAVEL-2D) (#645) 2026-07-05 09:31:23 +00:00
ReEvaluateTransactionRulesTest.php fix(security): scope job-status endpoints to owner + feature-area fixes (#627) 2026-07-03 14:49:32 +02:00
RealEstateAvailabilityTest.php refactor(real-estate): remove Pennant gating (#308) 2026-04-20 13:31:49 +01:00
RealEstateTest.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
ResendSyncCommandTest.php feat: Sync new users to Resend contacts (#85) 2026-01-28 21:25:58 +01:00
RoadmapTest.php feat(roadmap): add a public roadmap page mirrored from UserJot (#778) 2026-08-11 14:14:59 +00:00
RouteNotificationForMailTest.php refactor: remove HIDE_AUTH_BUTTONS launch gate and waitlist apparatus (#717) 2026-07-22 08:51:48 +02:00
RuleEngineParityTest.php refactor: consolidate duplicated financial calculations (#643) 2026-07-04 22:26:44 +02:00
SavedFilterTest.php feat(transactions): add a monthly trend view to the analysis drawer (#736) 2026-07-26 17:03:52 +02:00
SendAiCohortReportCommandTest.php feat(stats): post the Discord stats reports in Spanish, opened by an AI summary (#752) 2026-08-10 10:13:40 +02:00
SendAiConsentFollowUpEmailsCommandTest.php test(drip): deflake AI consent onboarding-grace boundary test (#625) 2026-07-03 07:06:20 +00:00
SendDailyStatsReportCommandTest.php feat(stats): post the Discord stats reports in Spanish, opened by an AI summary (#752) 2026-08-10 10:13:40 +02:00
SendStuckCohortReportCommandTest.php feat(stats): add --no-discord to the remaining report commands (#607) 2026-06-29 15:32:31 +02:00
SendSubscriptionFunnelReportCommandTest.php feat(subscriptions): end the trial experiment and make the trial length per plan (#762) 2026-08-12 10:59:55 +02:00
SentryConfigTest.php ci: remove production deploy job (#574) 2026-06-20 18:17:14 +00:00
SentryUserMiddlewareTest.php Add Sentry user context (#348) 2026-05-04 13:26:50 +01:00
SetLocaleTest.php feat(i18n): add French translation support (#532) 2026-06-15 19:15:43 +02:00
SharedAccountOwnershipTest.php feat(budgets): count shared accounts at the owner's percentage (#786) 2026-08-12 12:47:43 +02:00
SitemapTest.php User Onboarding Flow (#23) 2025-12-12 13:06:08 +01:00
StrayHttpRequestGuardTest.php chore: harden Inertia boundary, CI type-check, and test isolation (#640) 2026-07-04 18:57:58 +00:00
StripeSubscriptionStatsCommandTest.php feat: add Discord admin feed for daily stats and Stripe events (#458) 2026-05-30 18:14:46 +02:00
SubscriptionTest.php feat(subscriptions): end the trial experiment and make the trial length per plan (#762) 2026-08-12 10:59:55 +02:00
SuggestionPersistenceTest.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
SyncBankingConnectionsCommandTest.php chore: Remove account-mapping feature flag (#252) 2026-04-01 12:09:22 +02:00
SyncStripePricesCommandTest.php feat(subscriptions): add an A/B price experiment (€3.99 control vs €8.99 high) (#700) 2026-08-12 13:36:49 +02:00
TrackLastActiveAtTest.php feat(users): track last login and last active timestamps (#516) 2026-06-10 11:01:30 +02:00
TransactionAnalysisTest.php feat(transactions): add a monthly trend view to the analysis drawer (#736) 2026-07-26 17:03:52 +02:00
TransactionFilterTest.php fix(transactions): prevent crash when sorting by nullable column (#501) 2026-06-06 17:23:21 +02:00
TransactionSideClassificationTest.php refactor: consolidate duplicated financial calculations (#643) 2026-07-04 22:26:44 +02:00
TransactionTest.php refactor: remove HIDE_AUTH_BUTTONS launch gate and waitlist apparatus (#717) 2026-07-22 08:51:48 +02:00
WeighBudgetTransactionsMigrationTest.php feat(budgets): count shared accounts at the owner's percentage (#786) 2026-08-12 12:47:43 +02:00
WelcomeBanksOrderingTest.php feat(open-banking): remove feature flag gating (#297) 2026-04-17 10:20:05 +02:00