/* eslint-disable */ /* © 2026 K2B NETWORK SOLUTIONS LLC. All rights reserved. */ // RC26 (inv) — the screens for the parts & inventory money commands (src/routes/parts.js): // PartsReceivePODialog Parts Dept › Purchase Orders › Receive: the lines that arrived (partial receipts allowed), the unit cost, the vendor's // invoice #. The preview is PartsCalc.poReceipt (the server's own calculation); over-receiving is shown before it is sent // and refused by the server with the exact quantity still open. ONE vendor bill per receipt (A/P 300). // PartsReturnDialog Parts Ticket › Recent tickets › Return: a counter return against the STORED invoice — never more than sold minus already // returned (the dialog shows how many are left), restock / defective / core, refund cash / card / back to the A/R account / // a check (the office). The invoice itself never changes and reprints the same; the return is its own document. // Global names are prefixed Parts* (one shared Babel scope). Every money figure the preview shows is integer cents from window.PartsCalc. const partsUiMoney = (c) => (window.PartsCalc ? window.PartsCalc.fmt(Number(c) || 0) : "$" + ((Number(c) || 0) / 100).toFixed(2)); const partsUiInp = { fontSize: 12.5, padding: "4px 6px", fontFamily: "var(--jb-mono, monospace)", border: "1px solid #9AA4B1", borderRadius: 3 }; const partsUiTh = { textAlign: "left", fontSize: 10.5, textTransform: "uppercase", letterSpacing: "0.04em", color: "var(--jb-text-muted, #666)", padding: "5px 8px", background: "var(--jb-surface-2, #EEF1F5)" }; const partsUiTd = { padding: "5px 8px", borderTop: "1px solid var(--jb-border, #DDD)", fontSize: 12.5 }; const PartsReceivePODialog = ({ po: poNo, onClose, act }) => { const po = (DMS.partsOrders() || []).find((o) => o.po === poNo) || { lines: [] }; const [rows, setRows] = React.useState(() => (po.lines || []).map((l) => { const open = Math.max(0, (+l.qty || 0) - (+l.received || 0)); return { part: l.part, desc: l.desc || "", ordered: +l.qty || 0, received: +l.received || 0, open, qty: open ? String(open) : "", unitCost: String(l.cost != null ? l.cost : "") }; })); const [inv, setInv] = React.useState(""); const [busy, setBusy] = React.useState(false); const [msg, setMsg] = React.useState(null); const set = (i, k, v) => setRows((rs) => rs.map((r, j) => (j === i ? Object.assign({}, r, { [k]: v }) : r))); const PC = window.PartsCalc; const picked = rows.filter((r) => r.qty !== "" && r.qty !== "0"); const pv = PC ? PC.poReceipt(picked.map((r) => ({ part: r.part, desc: r.desc, qty: r.qty, unitCost: r.unitCost, ordered: r.ordered, received: r.received }))) : null; const submit = async () => { if (!picked.length) { setMsg({ ok: false, msg: "Enter the quantity that arrived on at least one line." }); return; } if (pv && pv.problems.length) { setMsg({ ok: false, msg: pv.problems[0].msg }); return; } setBusy(true); setMsg(null); const r = await act(DMS.receivePO(poNo, { lines: picked.map((x) => ({ partNo: x.part, qtyReceived: x.qty, unitCost: x.unitCost })), vendorInvoice: inv })); setBusy(false); setMsg(r); if (r && r.ok) setTimeout(onClose, 600); }; return ( Cancel{busy ? "Receiving on the server…" : "Receive"}}>
{["Part #", "Description", "Ordered", "Received", "Open", "Arrived now", "Unit cost $", "Line"].map((h) => )}{rows.map((r, i) => { const over = r.qty !== "" && +r.qty > r.open; const line = pv && pv.lines.find((x) => x.part === r.part); return ( ); })}
{h}
{r.part} {r.desc} {r.ordered} {r.received} {r.open} set(i, "qty", e.target.value.replace(/[^0-9]/g, ""))} style={{ ...partsUiInp, width: 60, background: over ? "#FDECEA" : "#FFFFE1" }} />{over &&
only {r.open} open
}
set(i, "unitCost", e.target.value.replace(/[^0-9.,$]/g, ""))} style={{ ...partsUiInp, width: 80 }} /> {line ? partsUiMoney(line.extCents) : ""}
This receipt: {pv ? partsUiMoney(pv.totalCents) : "—"} → parts inventory 242 at cost · ONE vendor bill for {po.vendor || "the vendor"} on A/P 300 (pay it in Check Writing){pv && pv.problems.length ?
{pv.problems[0].msg}
: null}
{Array.isArray(po.receipts) && po.receipts.length > 0 &&
Earlier receipts: {po.receipts.map((x) => `#${x.n} ${x.vendorInvoice || x.id} ${partsUiMoney(x.totalCents)}`).join(" · ")}
} {msg &&
{msg.msg}
}
); }; const PartsReturnDialog = ({ sale, onClose, onPrint }) => { const inv = sale || { lines: [] }; const [prior, setPrior] = React.useState(null); const [cfg, setCfg] = React.useState(null); const [rows, setRows] = React.useState(() => (inv.lines || []).map((l, i) => ({ i, part: l.part, desc: l.desc || "", sold: +l.qty || 0, unitCents: +l.unitCents || 0, coreCents: +l.coreCents || 0, qty: "", disposition: "restock" }))); const [method, setMethod] = React.useState(inv.tender && inv.tender.method === "charge" ? "ar" : inv.tender && inv.tender.method === "card" ? "card" : "cash"); const [ref, setRef] = React.useState(""); const [reason, setReason] = React.useState(""); const [busy, setBusy] = React.useState(false); const [msg, setMsg] = React.useState(null); const load = React.useCallback(() => { DMS.partsReturns(inv.saleId).then((r) => setPrior(r.returns || [])); }, [inv.saleId]); React.useEffect(() => { load(); DMS.partsConfig().then((c) => setCfg(c)); }, [load]); const returned = {}; let extBack = 0, taxBack = 0; (prior || []).forEach((p) => { extBack += +p.subtotalCents || 0; taxBack += +p.taxCents || 0; (p.lines || []).forEach((l) => { returned[l.lineIndex] = (returned[l.lineIndex] || 0) + (+l.qty || 0); }); }); const set = (i, k, v) => setRows((rs) => rs.map((r) => (r.i === i ? Object.assign({}, r, { [k]: v }) : r))); const picked = rows.filter((r) => r.qty !== "" && r.qty !== "0"); const PC = window.PartsCalc; const pv = PC ? PC.partsReturn({ invoice: inv, returned, extBackSoFarCents: extBack, taxBackSoFarCents: taxBack, lines: picked.map((r) => ({ lineIndex: r.i, qty: r.qty, disposition: r.disposition, costCents: 0 })), refundMethod: method }) : null; const office = !!(cfg && cfg.may && cfg.may.refundCheck); const submit = async () => { if (!picked.length) { setMsg({ ok: false, msg: "Enter how many come back on at least one line." }); return; } if (pv && pv.problems.length) { setMsg({ ok: false, msg: pv.problems[0].msg }); return; } if (reason.trim().length < 3) { setMsg({ ok: false, msg: "Give the reason for the return (a few words — it goes on the journal entry)." }); return; } setBusy(true); setMsg(null); const refund = { method }; if (method === "card") refund.ref = ref; const r = await DMS.partsReturn(inv.saleId, picked.map((x) => ({ lineId: x.i, qty: x.qty, disposition: x.disposition })), refund, reason.trim()); setBusy(false); setMsg(r); window.k2bToast && window.k2bToast(r.msg, r.ok ? "ok" : "warn", r.ok ? 5000 : 9000); if (r.ok) { setRows((rs) => rs.map((x) => Object.assign({}, x, { qty: "" }))); load(); } }; return ( Close{onPrint && onPrint(inv)}>🖨 Reprint the invoice}{busy ? "Returning on the server…" : "Post the return"}}>
{["Part #", "Description", "Sold", "Returned", "Left", "Return now", "What happens", "Back"].map((h) => )}{rows.map((r) => { const done = returned[r.i] || 0; const left = r.sold - done; const over = r.qty !== "" && +r.qty > left; const line = pv && pv.lines.find((x) => x.lineIndex === r.i); return ( ); })}
{h}
{r.part} {r.desc} {r.sold} {prior ? done : "…"} {prior ? left : "…"} set(r.i, "qty", e.target.value.replace(/[^0-9]/g, ""))} style={{ ...partsUiInp, width: 54, background: over ? "#FDECEA" : "#FFFFE1" }} />{over &&
only {Math.max(0, left)} left
}
{line ? partsUiMoney(line.extCents) : ""}
{method === "card" && }
Refund: {pv ? partsUiMoney(pv.refundCents) : "—"} ({pv ? partsUiMoney(pv.subtotalCents) : "—"} parts{pv && pv.taxCents ? " + " + partsUiMoney(pv.taxCents) + " tax" : ""}) · the sale, its tax and its cost are reversed in proportion; restocked parts go back into 242 at the cost of the sale{pv && pv.problems.length ?
{pv.problems[0].msg}
: null}
{!office &&
A refund back to an A/R account or by check is done by the office.
} {prior && prior.length > 0 &&
Returns on this ticket: {prior.map((p) => `${p.returnId} ${partsUiMoney(p.refundCents)} (${(p.refund && p.refund.method) || ""}${p.refund && p.refund.checkNum ? " #" + p.refund.checkNum : ""}${p.refund && p.refund.checkVoided ? " — check VOID, still owed" : ""})`).join(" · ")}
} {msg &&
{msg.msg}
}
); }; Object.assign(window, { PartsReceivePODialog, PartsReturnDialog });