whisper-money/app/Http/Controllers/OpenBanking
Víctor Falcón 845f51abb5
refactor(open-banking): extract shared connect-controller flow into a base class (#639)
## Why

The five API-key OpenBanking "connect" controllers — Binance, Bitpanda,
Coinbase, Indexa Capital and Interactive Brokers — each carried a
~60-line `store()` that was near-identical: subscription gate →
credential validation → `Bank::firstOrCreate` → create the
`BankingConnection` (Pending) → update it to `AwaitingMapping` with
pending accounts → auto-map during onboarding or redirect to mapping.
Any change to that flow, or a bug in it, had to be made five times.

## What

Extract the shared flow into a small class hierarchy, so each controller
declares only what actually varies per provider.

- **`OpenBankingConnectController`** (abstract) owns the whole flow in a
`connect()` template method, with per-provider extension points:
`provider()`, `providerName()`, `bankLogo()`, `aspspCountry()`,
`fetchProviderData()`, `credentialErrorMessage()`,
`buildPendingAccounts()`, and an optional `emptyProviderDataMessage()`
guard.
- **`CryptoPortfolioConnectController`** (abstract, extends the above)
implements the two hooks the crypto providers share: `aspspCountry()`
(from the request) and the single "Crypto Portfolio"
`buildPendingAccounts()` (uid derived from the provider enum value, so
the generated uids are unchanged).
- The five controllers shrink to their genuine differences (client,
names, logo, error copy, and — for IB — the Flex error mapping and
empty-statement guard).

Net **−110 lines** across the five `store()` methods, and the connection
lifecycle now lives in one place.

## Behavior

No functional change. The credential-failure warning log is now a single
structured message with a `provider` key instead of five free-text
variants (the only observable difference; HTTP responses are
byte-for-byte identical). Verified by the full suite: **1869 passing, 0
failing** (`--exclude-testsuite=Browser`); `pint --test`, `format` and
`lint` clean.

## Review-driven follow-up commits

Two review agents (architecture/duplication/coverage, and
behavior/regressions) ran against the first commit. Applied, each as its
own commit:

- Finished the crypto dedup via the intermediate base (the reviewers
flagged the still-duplicated crypto hooks).
- Dropped the over-engineered per-provider
`validationFailureLogMessage()` hook in favor of a structured base log.
- Added the missing test for the Interactive Brokers empty-statement
guard (the only conditional hook, previously unexercised): asserts 422 +
NAV-section message, no connection row, and no warning logged.

## Deliberately out of scope

- **Wise** is left as-is: it builds pending accounts mid-flow (needs the
client), creates the connection in one step, and has its own
empty-portfolio guard — it does not fit this template.
- **Pre-existing** (not introduced here, noted by review):
`Bank::firstOrCreate` returns an existing bank without refreshing its
logo, so `aspsp_logo` can copy a stale/null value. Worth a separate fix.
2026-07-04 20:24:54 +02:00
..
Concerns fix(open-banking): stop storing the XXX no-currency placeholder on accounts (#602) 2026-06-27 16:01:21 +00:00
AccountMappingController.php fix(open-banking): stop storing the XXX no-currency placeholder on accounts (#602) 2026-06-27 16:01:21 +00:00
AuthorizationController.php fix: address remaining security audit findings (round 2) (#628) 2026-07-03 15:04:03 +00:00
BinanceController.php refactor(open-banking): extract shared connect-controller flow into a base class (#639) 2026-07-04 20:24:54 +02:00
BitpandaController.php refactor(open-banking): extract shared connect-controller flow into a base class (#639) 2026-07-04 20:24:54 +02:00
CoinbaseController.php refactor(open-banking): extract shared connect-controller flow into a base class (#639) 2026-07-04 20:24:54 +02:00
ConnectionAccountController.php feat(open-banking): enable manage bank accounts for everyone (#572) 2026-06-20 17:35:43 +00:00
ConnectionController.php feat(banking): let Wise credentials be updated (#588) 2026-06-23 09:54:31 +00:00
CryptoPortfolioConnectController.php refactor(open-banking): extract shared connect-controller flow into a base class (#639) 2026-07-04 20:24:54 +02:00
IndexaCapitalController.php refactor(open-banking): extract shared connect-controller flow into a base class (#639) 2026-07-04 20:24:54 +02:00
InstitutionController.php feat: Integrate EnableBanking as open banking provider (#106) 2026-02-12 09:09:28 +01:00
InteractiveBrokersController.php refactor(open-banking): extract shared connect-controller flow into a base class (#639) 2026-07-04 20:24:54 +02:00
OpenBankingConnectController.php refactor(open-banking): extract shared connect-controller flow into a base class (#639) 2026-07-04 20:24:54 +02:00
WiseController.php feat(banking): add Interactive Brokers sync via Flex Web Service (#581) 2026-06-23 11:39:24 +02:00