Commit Graph
2 Commits
Author SHA1 Message Date
cadf02e407 fix(migration): derive Visma invoice payment state from PaymentStatus enum (#1462)
The eAccounting /supplierinvoices LIST payload omits RemainingAmount, and
reading the absence as 0 made every migrated supplier invoice fully paid
(ElvaSmultron: 290/290 imported as paid, including two open payables).
SupplierInvoiceApi has no IsCancelled/IsBooked/IsSent either, so the shared
status derivation could never produce an open supplier invoice.

- Supplier invoices: paid = PaymentStatus in (Paid=6, PaidInBank=9); bank
  in-flight states stay open; missing RemainingAmount now falls back to the
  invoice total instead of a settled-looking 0; lifecycle from Status
  (0=Draft, 2=Deleted) + overdue from PaymentStatus (4, 7).
- Sales invoices: paid = PaymentStatus 0 (enum: 0=Paid, 1=Unpaid, 2=Overdue)
  with the old RemainingAmount check as fallback only.
- IsCreditInvoice now maps to invoiceTypeCode '381' on both sides: credit
  notes have negative totals, could never satisfy 'remaining 0 && total > 0'
  and fell through to 'draft', surfacing on the dashboard as overdue unsent
  invoices.
- PaymentDate now feeds lastPaymentDate so paid_at is the real payment date
  rather than the invoice date.

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 14:26:34 +02:00
a49d75db77 fix(migration): Visma pagination + chunk-insert resilience (the '300 misslyckades' case) (#1455)
* fix(providers): paginate Visma eAccounting with $page/$pagesize

eAccounting silently ignores OData $top/$skip, so every request returned
page 1 and getPaginated appended the first page TotalNumberOfPages times:
customers were imported in triplicate and invoice chunks hit unique
violations. Also stop on an empty page so a stale Meta can never loop or
duplicate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(migration): survive bad rows in entity imports instead of failing whole chunks

One PostgREST insert per 500-row chunk is all-or-nothing, so a single
duplicate reported every row as failed ('300 misslyckades') with no cause
shown. Now: dedupe repeats within the fetched data (paging faults, source
duplicates), fall back to per-row inserts when a chunk is rejected, store
empty invoice numbers as NULL instead of colliding '', surface the first
DB error in the result UI, and mark all-failed steps with an error icon.
Sales invoices also carry remaining_amount so open invoices no longer
land as settled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(migration): never per-row retry after a successful bulk insert with short read-back

A succeeded statement whose .select() returns fewer rows than sent means
the rows ARE in the table; retrying them one by one would duplicate every
unreturned row. Pair what came back and report the tail instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(migration): count stub-insert casualties as failed and sample enrichment errors

Review follow-ups: invoices dropped because their customer/supplier stub
insert errored are DB failures, not matching misses; classifying them as
noMatch rendered a green result row with the database error hidden.
Enrichment failures now also feed errorSample.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 10:45:02 +02:00