/* eslint-disable */
/* © 2026 K2B NETWORK SOLUTIONS LLC. All rights reserved.
Proprietary and confidential. Unauthorized copying, distribution, or use of
this file, via any medium, is strictly prohibited. Original work product. */
// JBREWS DMS — A/R Defaults (legacy "ARDFT" screen, scan 5).
// Left: the dealership's default A/R posting config. Right: Setup Files —
// Account Types, Dunning Messages, Price Matrix, Letters, Tax Codes.
// Saves through DMSCore so every other A/R screen picks up the new config.
// Module-scope row + input (defined OUTSIDE the component so they are not
// recreated each keystroke — that recreation remounted the and limited
// typing to one character at a time).
const ARDRow = ({ label, children, hint }) => (
{label}
{children}{hint ? {hint} : null}
);
const ARDInp = (props) => ;
// Numeric input (audit A-06): keeps a TEXT draft while focused so a decimal
// point can be typed and the box can be cleared; parses and commits on blur
// (or Enter). `int` → whole numbers only.
const ARDNum = ({ value, onCommit, int, style }) => {
const fmt = (v) => (v === undefined || v === null || v === "" ? "" : String(v));
const [text, setText] = React.useState(() => fmt(value));
const [focused, setFocused] = React.useState(false);
React.useEffect(() => { if (!focused) setText(fmt(value)); }, [value, focused]);
const parse = (s) => {
const c = String(s || "").replace(int ? /[^0-9\-]/g : /[^0-9.\-]/g, "");
const n = int ? parseInt(c, 10) : parseFloat(c);
return isNaN(n) ? 0 : n;
};
return (
{ setFocused(true); window.jbFocusSelect && window.jbFocusSelect(e); }}
onChange={(e) => setText(e.target.value)}
onBlur={() => { setFocused(false); const n = parse(text); setText(fmt(n)); onCommit(n); }}
onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); e.currentTarget.blur(); } }}
style={style} />
);
};
const ARDefaults = ({ onClose, go }) => {
const [, force] = React.useReducer(n => n + 1, 0);
React.useEffect(() => DMS.subscribe(force), []);
const saved = DMS.arDefaults();
const [d, setD] = React.useState(saved);
const [dirty, setDirty] = React.useState(false);
const [file, setFile] = React.useState(null); // open setup-file dialog
const set = (k, v) => { setD(s => ({ ...s, [k]: v })); setDirty(true); };
const taxName = (DMS.arTaxCodes().find(t => t.code === d.defaultTaxCode) || {}).name || "";
const Row = ARDRow;
const Inp = ARDInp;
const setupFiles = [
{ key: "types", label: "Account Types", desc: `${DMS.arAccountTypes().length} types` },
{ key: "dunning", label: "Dunning Messages",desc: `${DMS.arDunningMessages().length} messages` },
{ key: "matrix", label: "Price Matrix", desc: "5 markup tiers" },
{ key: "letters", label: "Letters", desc: `${DMS.arLetterTemplates().length} templates` },
{ key: "tax", label: "Tax Codes", desc: `${DMS.arTaxCodes().length} codes` },
];
return (
{/* Defaults */}
Defaults
set("arAccount", e.target.value)} style={{ width: 70, fontFamily: "var(--jb-mono)" }} />
{d.arAccountName}
set("financeChargeAcct", e.target.value)} style={{ width: 70, fontFamily: "var(--jb-mono)" }} />
{d.financeChargeAcctName}
set("financeChargeJournal", e.target.value)} style={{ width: 50, fontFamily: "var(--jb-mono)" }} />
{d.financeChargeJournalName}
set("monthlyFinanceChargePct", n)} style={{ width: 70, textAlign: "right", fontFamily: "var(--jb-mono)" }} />
%
set("graceDays", n)} style={{ width: 50, textAlign: "right", fontFamily: "var(--jb-mono)" }} />
days
{taxName}
set("depositJournal", e.target.value)} style={{ width: 50, fontFamily: "var(--jb-mono)" }} />
{d.depositJournalName}
Credit Card
set("creditCardFeePct", n)} style={{ width: 70, textAlign: "right", fontFamily: "var(--jb-mono)" }} />
%
set("creditCardJournal", e.target.value)} style={{ width: 50, fontFamily: "var(--jb-mono)" }} />
{d.creditCardJournalName}
set("creditCardDepositAcct", e.target.value)} style={{ width: 70, fontFamily: "var(--jb-mono)" }} />
set("creditCardFeeAcct", e.target.value)} style={{ width: 70, fontFamily: "var(--jb-mono)" }} />
{/* Setup Files */}
Setup Files
{setupFiles.map(s => (
))}
ESC-Close
{ _arToast(DMS.arUpdateDefaults(d)); setDirty(false); }}>F9-Save
{dirty ?
Unsaved changes : null}
go && go("arproc")}>Processing →
{file === "types" &&
setFile(null)} />}
{file === "tax" && setFile(null)} />}
{file === "dunning" && setFile(null)} />}
{file === "letters" && setFile(null)} />}
{file === "matrix" && setFile(null)} />}
);
};
/* Account Types */
const ARTypesDialog = ({ onClose }) => {
const [rows, setRows] = React.useState(DMS.arAccountTypes().map(r => ({ ...r })));
const upd = (i, k, v) => setRows(rs => rs.map((r, j) => j === i ? { ...r, [k]: v } : r));
return (
Cancel
{ _arToast(DMS.arSetTable("arAccountTypes", rows)); onClose(); }}>Save>}>
| Code | Name | Terms | Grace | FC Exempt |
{rows.map((r, i) => (
| {r.code} |
upd(i, "name", e.target.value)} style={{ width: "100%" }} /> |
upd(i, "terms", e.target.value)} style={{ width: "100%" }} /> |
upd(i, "graceDays", n)} style={{ width: 50, textAlign: "right" }} /> |
upd(i, "fcExempt", e.target.checked)} /> |
))}
);
};
/* Tax Codes */
const ARTaxDialog = ({ onClose }) => {
const [rows, setRows] = React.useState(DMS.arTaxCodes().map(r => ({ ...r })));
const upd = (i, k, v) => setRows(rs => rs.map((r, j) => j === i ? { ...r, [k]: v } : r));
const add = () => setRows(rs => [...rs, { code: "", name: "", rate: 0, desc: "" }]);
return (
+ AddCancel
{ _arToast(DMS.arSetTable("arTaxCodes", rows.filter(r => r.code))); onClose(); }}>Save>}>
| Code | Name | Rate % | Description |
{rows.map((r, i) => (
| upd(i, "code", e.target.value)} style={{ width: 70 }} /> |
upd(i, "name", e.target.value)} style={{ width: 90 }} /> |
upd(i, "rate", n)} style={{ width: 70, textAlign: "right" }} /> |
upd(i, "desc", e.target.value)} style={{ width: "100%" }} /> |
))}
);
};
/* Dunning Messages */
const ARDunningDialog = ({ onClose }) => {
const [rows, setRows] = React.useState(DMS.arDunningMessages().map(r => ({ ...r })));
const upd = (i, v) => setRows(rs => rs.map((r, j) => j === i ? { ...r, message: v } : r));
return (
Cancel
{ _arToast(DMS.arSetTable("arDunningMessages", rows)); onClose(); }}>Save>}>
{rows.map((r, i) => (
Oldest item {r.bucket} days
))}
);
};
/* Letters */
const ARLettersDialog = ({ onClose }) => {
const [rows, setRows] = React.useState(DMS.arLetterTemplates().map(r => ({ ...r })));
const upd = (i, k, v) => setRows(rs => rs.map((r, j) => j === i ? { ...r, [k]: v } : r));
return (
Cancel
{ _arToast(DMS.arSetTable("arLetterTemplates", rows)); onClose(); }}>Save>}>
Letters are generated from A/R › Processing or Reports › Send Letters and logged to the letter history.
);
};
/* Price Matrix (parts markup tiers, referenced from the legacy AR setup) */
const ARMatrixDialog = ({ onClose }) => {
const tiers = [
{ lo: "$0.00", hi: "$5.00", markup: "200%" },
{ lo: "$5.01", hi: "$25.00", markup: "150%" },
{ lo: "$25.01", hi: "$100.00", markup: "100%" },
{ lo: "$100.01", hi: "$500.00", markup: "60%" },
{ lo: "$500.01", hi: "and up", markup: "40%" },
];
return (
Close}>
Cost-based markup tiers used when charging parts to an A/R account.
| Cost From | Cost To | Markup |
{tiers.map((t, i) => (
| {t.lo} | {t.hi} | {t.markup} |
))}
);
};
Object.assign(window, { ARDefaults });