c90ccc9c429277299fd4ecec0652cd8b6fa080be
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
477b59453f |
fix(enable-banking): flatten Enable Banking's bank_transaction_code object to a string (#2398)
* fix(enable-banking): flatten Enable Banking's bank_transaction_code object to a string
Enable Banking serializes bank_transaction_code as {description, code,
sub_code}; three places declared it a string. The direct path passed the
object through, so PostgREST wrote its JSON text into
transactions.bank_transaction_code for every Enable Banking row since
2026-08-09 (6,356 rows, 78 companies) and the label/method derivation never
matched. The Connect service forwarded the same object and the wire contract
rejected it, so every connector-canary sync failed from 2026-09-03 (Capstone
support case 2026-09-07, "banksynken mot Nordea").
One rule, one place: normalizeBankTransactionCode in the connect-contract
file (code, code/sub_code, else description, else null), applied by
convertTransaction here and by Connect's normalizeBookedTransaction in the
mirrored contract. The wire schema stays z.string().nullable();
CONTRACT_VERSION bumps to 2026-09-08. A repair migration rewrites the stored
JSON text with the same rule and touches nothing else.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RnbRMhwvUigizrPar5hW47
* fix(enable-banking): skip reset-source rows in the repair and read "Kortköp/uttag" as card
Skeptic findings on 4a30bb3f3:
- The repair migration would have aborted on prod: 110 of the 6,356 rows
belong to a migration-reset source company, whose transactions are
immutable by trigger (transactions_block_migration_reset_source_mutation).
Same failure as 20260903170000. Those rows are now excluded; nothing reads
the column back for an archived company.
- With the code description reaching the keyword tables as a string,
"Kortköp/uttag" (SEB/Swedbank wording for an ordinary card purchase)
matched UTTAG before KORT in both CODE_KEYWORD_METHODS and KEYWORD_LABELS,
so 256 card rows a month would have shown "Betalsätt: Uttag". Card now
precedes withdrawal in both tables (and in the Connect mirror), matching
what TRAILING_PHRASES already says about the same phrase.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RnbRMhwvUigizrPar5hW47
* chore(migrations): annotate the repair as pg-test skip and state why no rattelse log is owed
coverage-gate flagged the migration because it creates a function; the only
function is a pg_temp helper dropped in the same statement batch, and a
one-shot UPDATE cannot be re-exercised after apply, so the annotation is the
honest disposition. The header also answers the Swedish compliance review:
the column is a write-once ingest projection with no reader, the underlag is
the archived raw PSD2 page (untouched), and the verifikat lives in
journal_entries, which the statement never reads or writes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RnbRMhwvUigizrPar5hW47
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
4c6feea64d |
feat(connect): bank sync through the connector operation, with a per-company canary (#2205)
* feat(connect): bank sync through the connector operation, with a per-company canary In connector mode the enable-banking sync no longer pages Enable Banking on the instance: it calls POST /api/connect/bank/sync on the hosted service with the session id it holds and the account, and receives booked, normalized rows plus the raw provider pages to archive. Everything downstream is shared with the direct path (stored external ids computed here from booking_date, amount and the account scope; ingest; archive; balance refresh), so a company that moves to the connector produces byte-identical keys. A 410 from the service maps onto the same SessionExpiredError the direct path throws. bankConnectorMode(companyId) gains CONNECT_BANK_CANARY_COMPANIES: listed companies use the connector even while the installation has its own Enable Banking credentials, which is how hosted Accounted moves its bank sync to Connect a few companies at a time before dropping its keys. The contract package gains the bank sync request/response schemas (2026-09-03). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> * fix(connect): calendar-valid dates, body read inside the timeout, service origin as the default Review follow-ups on #2205. The contract validates date_from, date_to and booking_date with z.iso.date() (2026-02-30 and an empty booking date are refused; the installation derives its stored keys from booking_date). The connector sync reads the response body inside the timeout window so a service that stalls the body cannot hold the sync open. DEFAULT_CONNECT_BASE_URL now names the connector service (connect.accounted.se), which is where the sync operation exists; the hosted app's copy of the connector routes is legacy and hosted Accounted itself sets GNUBOK_CONNECT_URL explicitly. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> --------- Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
fcfa1ba974 |
feat(connect): extract the connector wire contract into packages/connect-contract (#2179)
* feat(connect): extract the connector wire contract into packages/connect-contract The definitions in lib/connect/contract.ts (key prefix, headers, entitlements path, entitlement and sync-report shapes) move into a standalone MIT package, packages/connect-contract (published as @accounted/connect-contract), joined by the error envelope, the stable error codes, and Zod schemas for every Peppol connector operation (lookup, submit, status, evidence, register, unregister, inbound list and xml) with an operation table. Shape only: no behaviour, no provider code. In-repo callers import through the tsconfig and vitest alias; lib/connect/contract.ts re-exports so nothing else changes. The point of the package is that either side of the connection can be built outside this repository: a self-hosted ledger talking to Accounted Connect, or another connector service talking to the open ledger. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> * docs(decisions): record the Connect direction, the Peppol proxy shape, and the contract package Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> --------- Signed-off-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |