POST /api/v1/driver/collection-check runs the collection AI check for a PO and returns a per-line verdict (right item, right quantity) for drivers. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
69 lines
2 KiB
TypeScript
69 lines
2 KiB
TypeScript
import type { CollectionAiCheck } from "@/lib/types";
|
|
import { computeLineTicks } from "@/lib/collection-ai-ticks";
|
|
|
|
export type DriverVerdict = "green" | "amber" | "red" | "unchecked";
|
|
|
|
export interface DriverLineVerdict {
|
|
id: string;
|
|
kind: "customer" | "stock";
|
|
description: string;
|
|
qty_collected: number;
|
|
verdict: DriverVerdict;
|
|
/** One short plain sentence for the driver; empty when green. */
|
|
reason: string;
|
|
}
|
|
|
|
type Row = {
|
|
id: string;
|
|
kind: "customer" | "stock";
|
|
description?: string;
|
|
sku: string;
|
|
qty_collected: number;
|
|
order_qty: number;
|
|
cost_price: number | null;
|
|
ai_check: CollectionAiCheck | null;
|
|
};
|
|
|
|
/**
|
|
* What the driver needs to know at the supplier counter: is it the right
|
|
* product, in the right quantity? Price and SKU are the office's concern
|
|
* and never turn a driver's line amber or red.
|
|
*/
|
|
export function driverVerdict(row: Row): DriverLineVerdict {
|
|
const base = {
|
|
id: row.id,
|
|
kind: row.kind,
|
|
description: row.description ?? "",
|
|
qty_collected: row.qty_collected,
|
|
};
|
|
const check = row.ai_check;
|
|
if (!check || (check.pair_failed && !check.doc_line)) {
|
|
return { ...base, verdict: "unchecked", reason: "" };
|
|
}
|
|
const doc = check.doc_line;
|
|
if (!doc || (check.same_item !== "sure" && check.same_item !== "likely")) {
|
|
return {
|
|
...base,
|
|
verdict: "red",
|
|
reason: check.reason || "Not found on the invoice photo.",
|
|
};
|
|
}
|
|
const t = computeLineTicks(
|
|
{ sku: row.sku, qty_collected: row.qty_collected, order_qty: row.order_qty, cost_price: row.cost_price },
|
|
check,
|
|
);
|
|
if (t.qty === "red") {
|
|
return {
|
|
...base,
|
|
verdict: "red",
|
|
reason: `Invoice says ${doc.quantity}, you collected ${row.qty_collected}.`,
|
|
};
|
|
}
|
|
if (t.qty === "amber") {
|
|
return { ...base, verdict: "amber", reason: `Invoice says ${doc.quantity}, ordered ${row.order_qty}.` };
|
|
}
|
|
if (t.desc === "amber") {
|
|
return { ...base, verdict: "amber", reason: check.reason || "Looks like the same item, but not certain." };
|
|
}
|
|
return { ...base, verdict: "green", reason: "" };
|
|
}
|