mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
test(reports): pin the receivable/payable ledger sides
Guards the two facts the report exists to get right: the cancellation fee is never a payable, and exactly one wagon-cancellation status (CREDIT_AVAILABLE) is a live liability. Adding a status to WAGON_CANCELLATION_STATUSES now fails here until someone decides which side of the ledger it lands on. Also pins the sort expressions to the union wrapper alias — a branch alias would resolve at build time and 42P01 at runtime, since the runner appends ORDER BY outside the subquery.
This commit is contained in:
@@ -0,0 +1,71 @@
|
|||||||
|
import { WAGON_CANCELLATION_STATUSES } from '../../bookings/entities/booking-wagon-cancellation.entity';
|
||||||
|
import { ShippingLineCreditStatus } from '../../shipping-lines/entities/shipping-line-credit.entity';
|
||||||
|
import {
|
||||||
|
CREDIT_LIABILITY_STATUS,
|
||||||
|
INVOICE_SIDE_EXPR,
|
||||||
|
LEDGER_SIDES,
|
||||||
|
UNINVOICED_CREDIT_STATUS,
|
||||||
|
receivablesPayablesReport,
|
||||||
|
} from './receivables-payables.report';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The report's whole point is the sign of the money: a cancellation FEE is
|
||||||
|
* owed TO EDR, and the cancelled freight is owed BACK to the customer as
|
||||||
|
* bookable credit. These tests pin the two down at the string level — the SQL
|
||||||
|
* itself is validated against the database, not here.
|
||||||
|
*/
|
||||||
|
describe('receivables-payables report', () => {
|
||||||
|
it('treats exactly one wagon-cancellation status as a liability', () => {
|
||||||
|
expect(WAGON_CANCELLATION_STATUSES).toContain(CREDIT_LIABILITY_STATUS);
|
||||||
|
// Every other status owes nothing: nothing cut yet (FEE_PENDING), redeemed
|
||||||
|
// (REBOOKED), or voided (WITHDRAWN / EXPIRED). If a new status appears,
|
||||||
|
// this fails until someone decides which side of the ledger it lands on.
|
||||||
|
expect(WAGON_CANCELLATION_STATUSES.filter((s) => s !== CREDIT_LIABILITY_STATUS).sort()).toEqual(
|
||||||
|
['EXPIRED', 'FEE_PENDING', 'REBOOKED', 'WITHDRAWN'],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('counts only the shipping-line credit status that has no invoice behind it', () => {
|
||||||
|
expect(UNINVOICED_CREDIT_STATUS).toBe(ShippingLineCreditStatus.Unbilled);
|
||||||
|
// BILLED is debt too, but it is counted through its invoice on the invoice
|
||||||
|
// branch — taking it here as well would double it.
|
||||||
|
expect(UNINVOICED_CREDIT_STATUS).not.toBe(ShippingLineCreditStatus.Billed);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('never classifies the cancellation fee as a payable', () => {
|
||||||
|
// The fee invoice rides the booking's invoice list; while it is open it is
|
||||||
|
// an ordinary receivable balance, and it must not reach a PAYABLE arm.
|
||||||
|
expect(INVOICE_SIDE_EXPR).not.toContain('WAGON_CANCEL_FEE');
|
||||||
|
expect(INVOICE_SIDE_EXPR).not.toContain('CANCELLATION_FEE');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not double-count a booking already carried by the cancellation ledger', () => {
|
||||||
|
expect(INVOICE_SIDE_EXPR).toContain('NOT EXISTS');
|
||||||
|
expect(INVOICE_SIDE_EXPR).toContain('booking_wagon_cancellations');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('emits exactly the side keys the filter offers', () => {
|
||||||
|
const declared = LEDGER_SIDES.map((s) => s.value).sort();
|
||||||
|
expect(declared).toEqual([
|
||||||
|
'PAYABLE_PREPAID',
|
||||||
|
'PAYABLE_WAGON_CREDIT',
|
||||||
|
'RECEIVABLE_OPEN',
|
||||||
|
'RECEIVABLE_SL_INVOICED',
|
||||||
|
'RECEIVABLE_SL_UNBILLED',
|
||||||
|
]);
|
||||||
|
// The summary KPIs split on these prefixes; a key matching neither would
|
||||||
|
// silently vanish from both totals.
|
||||||
|
for (const key of declared) {
|
||||||
|
expect(key.startsWith('RECEIVABLE') || key.startsWith('PAYABLE')).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sorts on the union wrapper, never on a branch-local alias', () => {
|
||||||
|
// The runner appends ORDER BY outside the union subquery, where `i.*`,
|
||||||
|
// `b.*` and `bwc.*` do not exist.
|
||||||
|
for (const col of receivablesPayablesReport.columns) {
|
||||||
|
if (!col.sortExpr) continue;
|
||||||
|
expect(col.sortExpr).toMatch(/^r\./);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user