mega-plant/lib/purchase-invoice-status.ts

28 lines
1.5 KiB
TypeScript
Raw Normal View History

/** How far a purchase order has been invoiced. Pure — client-safe. Shared by Purchases and Suppliers 2. */
/** Invoiced within this many rand of the PO total counts as fully invoiced (rounding). */
export const CLOSE_TOLERANCE = 1;
export type InvoiceStatus = "none" | "partial" | "complete" | "over";
/**
* red = no invoice; amber = some invoiced but the money does not cover the PO (an invoice with
* no amount typed in also lands here, since its value is unknown); teal = invoiced to within R1
* of the PO total, so it can be closed; purple = invoiced MORE than the PO by over R1. That is
* never "closed": it is a typo, a duplicate or a changed order, and a person has to look.
*/
export function invoiceStatusOf(total: number, amounts: (number | null)[]): { status: InvoiceStatus; invoiced: number } {
const invoiced = amounts.reduce<number>((s, a) => s + (a ?? 0), 0);
if (amounts.length === 0) return { status: "none", invoiced };
if (invoiced - total > CLOSE_TOLERANCE) return { status: "over", invoiced };
if (invoiced > 0 && total - invoiced <= CLOSE_TOLERANCE) return { status: "complete", invoiced };
return { status: "partial", invoiced };
}
export const STATUS_STYLE: Record<InvoiceStatus, { color: string; label: string }> = {
none: { color: "#D1495B", label: "No invoice yet" },
partial: { color: "#EDAE49", label: "Partly invoiced" },
complete: { color: "#00798C", label: "Fully invoiced — can be closed" },
over: { color: "#8B5CF6", label: "Invoiced MORE than the PO — check" },
};