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