mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
The receivable/payable split contradicted how money actually moves, in three ways that each changed a headline number: - The wagon-cancellation FEE was booked as a payable. It is money the customer owes EDR (raised ISSUED and unpaid at request time), so it belongs on the receivable side while open. The sign was inverted. - A whole-booking wagon cancellation was booked at the source invoice's full paid_amount, and never cleared: the booking stays CANCELLED and the invoice stays PAID even after the credit is rebooked. The real liability is the ledger row's credit_amount, and only while it sits in CREDIT_AVAILABLE — cancellation refunds no cash, it hands back bookable credit redeemed by creating another booking. - Shipping-line debt in UNBILLED has no invoice row at all, so an invoice-only fact table could not see it. That is the un-batched half of the debt, in the report whose stated purpose is shipping-line credit. The report is now a UNION of the three tables that hold the answer: invoices with a balance (plus prepayments against dead bookings), UNBILLED shipping_line_credits, and CREDIT_AVAILABLE booking_wagon_cancellations. A booking already carried by the cancellation ledger is excluded from the invoice branch so its money is counted once. Fully settled invoices are dropped — zero exposure is neither a receivable nor a payable. Branches are re-projected through an explicit column list before being unioned: UNION matches by position and TypeORM does not preserve addSelect order, which silently reordered one branch into "gross, exposure, side_key, ..." and failed with "UNION types text and numeric cannot be matched". Verified against Postgres with a rollback-only fixture covering every side, plus EXPLAIN over each filter combination and every sortable column.