* fix(skatteverket): skip skattekonto rows without belopp instead of failing the whole sync
SKV's transaktioner response can contain a row without beloppSkatteverket
despite the spec typing it as required. The row mapped to a NULL in the
NOT NULL belopp_skatteverket column, so the batch upsert failed with
23502 and every sync for the company (post-connect, manual, nightly
cron) died permanently on the same row.
Filter out rows that cannot satisfy the table's NOT NULL columns before
mapping, sync the rest, log one structured warn with the offending row
as diagnostic, and report the count as skipped in the sync result.
Skipping over coalescing to 0 kr is deliberate: an invented amount would
be renderable, matchable and bookable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(skatteverket): durable skipped-row trace in extension_data, minimized log
Review batch for PR #1837:
- Compliance swarm (GDPR Art.5(1)(c) high, ISO A.8.11 medium): the warn
log no longer carries the raw SKV row; it logs status, missing fields,
transaktionsidentitet and transaktionsdatum only.
- Swedish accounting review (BFL 5 kap fullstandighet, BFNAR 2013:2
kap 8): skipped rows are now retained durably and queryably in the
company-scoped extension_data key skattekonto_skipped_rows, raw
payload included, overwritten each sync so a completed row
self-clears the trace.
- CodeRabbit: eventBus.clear() in beforeEach; new test case covering
rows missing transaktionsdatum and transaktionstext; warn assertion
retargeted to the minimized shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(skatteverket): uncapped skipped count, merge-history trace with truncation flag
Second review cycle for PR #1837 (Swedish accounting review):
- skipped now counts the full payload before the trace cap, and the
trace record carries truncated: true (plus traceTruncated in the log)
when entries had to be dropped past MAX_SKIPPED_ROWS_RETAINED.
- The extension_data trace merges with the previous record instead of
overwriting it: entries keep firstSeenAt/lastSeenAt, survive aging out
of SKV's ~555-day window, and leave the trace only when their
transaktionsidentitet arrives complete and lands in
skattekonto_transactions (BFNAR 2013:2 kap 8 behandlingshistorik).
- Tests: aged-out retention + id resolution, 60-row truncation case.
Saldo-reconciliation finding dispositioned without code change: the
existing drift detector already compares the unfiltered SKV saldo
against GL 1630 and alerts, which covers a skipped row's balance effect.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>