fix(collection-ai): findings fallback tests, rounding

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dave 2026-10-17 01:37:29 +02:00
parent 122eb9862e
commit 7bcd92f999
2 changed files with 46 additions and 11 deletions

View file

@ -182,15 +182,50 @@ describe("buildDocFindings", () => {
{ doc_line_no: 2, po_line_id: null },
],
});
expect(out.map((s) => s.split(" ")[0])).toEqual([
"Document", // covers
"Alpha", // not collected
"Document", // no PO line
"Beta", // collected not on doc
"Supplier",
"Alpha:", // to follow
"Alpha:", // qty
"No",
expect(out).toEqual([
"Document 5028256 covers 2 POs: PO1, PO2.",
"Alpha × 40 is on the document but not marked collected.",
'Document line "Orphan" doesn\'t match any PO line.',
"Beta was marked collected but isn't on the document.",
"Supplier on the document (Other Co) differs from the PO supplier (Acme).",
"Alpha: supplier shows nothing to follow, but 4 are still outstanding.",
"Alpha: order line says 40 but the PO quantity is 4.",
"No PO number on the document matched; checked against PO1.",
]);
});
const toFollow = (po: Partial<PoLineLite>) =>
buildDocFindings({
...base,
read: read([dl({ line_no: 1, quantity: 30, to_follow: 0 })]),
poLines: [pl(po)],
pairs: [{ doc_line_no: 1, po_line_id: "p1" }],
});
it("to-follow uses quantity when order_qty is 0", () => {
expect(toFollow({ order_qty: 0, quantity: 40, qty_collected: 30 })).toEqual([
"M8x25 stainless steel: supplier shows nothing to follow, but 10 are still outstanding.",
]);
});
it("to-follow does not fire when fallback ordered is fully collected", () => {
expect(toFollow({ order_qty: 0, quantity: 30, qty_collected: 30 })).toEqual([]);
});
it("rounds float noise in outstanding quantity", () => {
expect(toFollow({ order_qty: 0, quantity: 0.3, qty_collected: 0.1 })).toEqual([
"M8x25 stainless steel: supplier shows nothing to follow, but 0.2 are still outstanding.",
]);
});
it("prints a single-spaced placeholder for a null document quantity", () => {
expect(
buildDocFindings({
...base,
read: read([dl({ line_no: 1, quantity: null })]),
poLines: [pl({ collected: false, qty_collected: 0 })],
pairs: [{ doc_line_no: 1, po_line_id: "p1" }],
}),
).toEqual(["M8x25 stainless steel × ? is on the document but not marked collected."]);
});
});

View file

@ -13,9 +13,9 @@ export type PoLineLite = {
export type LinePair = { doc_line_no: number; po_line_id: string | null };
/** 40 not 40.0; other values as-is. */
/** 40 not 40.0; at most 3 decimals so float noise never prints. */
function fmt(n: number): string {
return String(n);
return String(Math.round(n * 1000) / 1000);
}
/** Ordered = order_qty, falling back to quantity when order_qty is 0. */