39 lines
1.6 KiB
TypeScript
39 lines
1.6 KiB
TypeScript
|
|
/** Supplier list rules: folding names into one key, payment terms and due dates. Pure — client-safe. */
|
||
|
|
|
||
|
|
export type Terms = "" | "cash" | "30" | "60";
|
||
|
|
export const TERMS: { id: Terms; label: string }[] = [
|
||
|
|
{ id: "cash", label: "Cash" },
|
||
|
|
{ id: "30", label: "30 days" },
|
||
|
|
{ id: "60", label: "60 days" },
|
||
|
|
];
|
||
|
|
export const termsLabel = (t: string) => TERMS.find((x) => x.id === t)?.label ?? "Not set";
|
||
|
|
export const parseTerms = (v: unknown): Terms => (v === "cash" || v === "30" || v === "60" ? v : "");
|
||
|
|
export const isAccount = (t: string) => t === "30" || t === "60";
|
||
|
|
|
||
|
|
// Company-form words that change between a PO and a till slip but never name a different supplier.
|
||
|
|
const NOISE = new Set(["PTY", "LTD", "LIMITED", "CC", "INC", "THE", "AND"]);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* "Lube Force Traders cc" → "LUBEFORCETRADERS". Upper-case, punctuation gone, company-form words
|
||
|
|
* dropped. This is the same name typed two ways — it is NOT a fuzzy match: "Your Tyre Shop" and
|
||
|
|
* "Tyre Shop" stay different suppliers.
|
||
|
|
*/
|
||
|
|
export function supplierKey(name: string): string {
|
||
|
|
return (name || "")
|
||
|
|
.toUpperCase()
|
||
|
|
.replace(/&/g, " AND ")
|
||
|
|
.replace(/[^A-Z0-9]+/g, " ")
|
||
|
|
.split(" ")
|
||
|
|
.filter((w) => w && !NOISE.has(w))
|
||
|
|
.join("");
|
||
|
|
}
|
||
|
|
|
||
|
|
/** The day an account purchase falls due: PO date + terms. "" when there are no account terms or no valid date. */
|
||
|
|
export function dueDate(poDate: string, terms: string): string {
|
||
|
|
if (!isAccount(terms)) return "";
|
||
|
|
const d = new Date(`${(poDate || "").slice(0, 10)}T00:00:00Z`);
|
||
|
|
if (Number.isNaN(d.getTime())) return "";
|
||
|
|
d.setUTCDate(d.getUTCDate() + Number(terms));
|
||
|
|
return d.toISOString().slice(0, 10);
|
||
|
|
}
|