/* 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 — Deal Pipeline (CUSDISP). // Every deal in the store, by stage: Desked · Cash · F&I · Posted · Funded. // ONE PATH: deals are created in the CRM (+ New Lead → Desk It) — this screen // never creates one. It reviews, hands off to the desk / Cash Deal / Finance // Deal, posts to accounting (window.jbPostDeal) and marks funded (window.jbFundDeal). const PRINT_FORMS = [ { code: "BO-01", name: "Buyer's Order", action: "buyersorder" }, { code: "FW-01", name: "Finance Worksheet", action: "finance" }, { code: "DOR-108", name: "Missouri Title Application (DOR-108)", action: "titlemo" }, { code: "DOR-100", name: "Missouri Sales Tax Receipt (DOR-100)" }, { code: "ODM-01", name: "Federal Odometer Disclosure" }, { code: "WEOWE-1", name: "We Owe / Due Bill" }, { code: "PRIV-1", name: "Privacy Notice (GLBA)" }, { code: "RFC-1", name: "Retail Installment Contract" }, { code: "POA-1", name: "Power of Attorney — Title" }, { code: "CREDIT", name: "Credit Application (Reg-B)", action: "creditapp" }, ]; // Stage helpers — DMSCore owns the list + reconciliation of legacy records. const drStages = () => (window.DMS && window.DMS.DEAL_STAGES) || ["Desked", "Cash", "F&I", "Posted", "Funded"]; const drStage = (d) => (window.DMS && window.DMS.dealStage) ? window.DMS.dealStage(d) : (d.stage || "Desked"); const drStageTone = { Desked: { bg: "var(--jb-amber-tint, #FBF3E0)", fg: "#9A6700" }, Cash: { bg: "var(--jb-green-tint, #E6F7EC)", fg: "var(--jb-green, #0E7A37)" }, "F&I": { bg: "var(--jb-blue-tint, #E5EFFA)", fg: "var(--jb-blue, #1B66A8)" }, Posted: { bg: "#EAE6F7", fg: "#5B3FA0" }, Funded: { bg: "var(--jb-green, #16A34A)", fg: "#FFF" }, }; const DrStageBadge = ({ d, small }) => { const s = drStage(d); const t = drStageTone[s] || drStageTone.Desked; return ( {s === "Funded" ? "DONE ✓" : s} ); }; // Hand the deal to the Desking Tool: link its customer AND its unit (from // live inventory when the stock # matches). Writes the full pointer set. const drOpenInDesking = (d, go) => { if (!d) return; const unit = (DMS.inventory() || []).find(u => u.stock === d.stock); if (unit) { window.jbDeskUnit = { stock: unit.stock, vin: unit.vin, yr: unit.yr, mk: unit.mk, mdl: unit.mdl, list: unit.asking, cost: unit.cost, type: unit.type, miles: unit.miles }; try { localStorage.setItem("jb_desk_unit", JSON.stringify(window.jbDeskUnit)); } catch (e) {} } window.jbDeskDeal = { id: d.id, buyer: d.buyer }; try { localStorage.setItem("jb_desk_deal", JSON.stringify(window.jbDeskDeal)); } catch (e) {} try { localStorage.setItem("jb_fw_deal", d.id); } catch (e) {} go && go("desking"); }; const drOpenClosing = (d, go) => { if (!d) return; try { localStorage.setItem("jb_fw_deal", d.id); } catch (e) {} go && go(drStage(d) === "Cash" ? "cashworksheet" : "finance"); }; const DealReview = ({ onClose, go }) => { // Deals live in the shared ledger so they appear everywhere (MO Forms, // Trade Appraisal, Accounting) — one source of truth. const [, force] = React.useReducer(n => n + 1, 0); React.useEffect(() => DMS.subscribe(force), []); const deals = DMS.deals(); const [selectedId, setSelectedId] = React.useState(null); const [help, setHelp] = React.useState(false); const [stageFilter, setStageFilter] = React.useState("All"); // Recap — opened by clicking a row or a jb_deal_focus hand-off (read once). const [recapId, setRecapId] = React.useState(() => { try { const id = localStorage.getItem("jb_deal_focus"); if (id) { localStorage.removeItem("jb_deal_focus"); return id; } } catch (e) {} return null; }); const selected = deals.find(d => d.id === selectedId); const needSel = () => window.k2bToast && window.k2bToast("Select a deal first.", "warn", 2600); React.useEffect(() => { const fire = (e) => { // Audit A-07 guards: // • never intercept F5 (browser refresh) or modified keys // • while a dialog is open, Esc closes ONLY that dialog; other keys pass // • keys typed into an input / textarea / select never trigger actions if (e.key === "F5" || e.altKey || e.ctrlKey || e.metaKey) return; const dialogOpen = help || (window.jbAnyModalOpen && window.jbAnyModalOpen()); if (dialogOpen) { if (e.key === "Escape") { e.preventDefault(); if (help) setHelp(false); } return; } if (window.jbKeyFromField && window.jbKeyFromField(e)) return; const map = { // Esc backs out one level: recap → list → previous screen. "Escape": () => (recapId ? (setRecapId(null), setBackendView(false)) : onClose()), "F1": () => setHelp(true), // ONE PATH: F2 = start in the CRM (deals are never created here). "F2": () => go && go("crm"), "F3": () => go && go("creditapp"), "F4": () => go && go("inventory"), "F6": () => selected ? drOpenInDesking(selected, go) : needSel(), "F7": () => selected ? drOpenInDesking(selected, go) : needSel(), "F9": () => selected ? drOpenClosing(selected, go) : needSel(), "F10": () => onClose(), }; const fn = map[e.key]; if (fn) { e.preventDefault(); fn(); } }; window.addEventListener("keydown", fire); return () => window.removeEventListener("keydown", fire); }, [go, onClose, selected, help, recapId]); const recapDeal = recapId ? deals.find(d => d.id === recapId) : null; const [backendView, setBackendView] = React.useState(false); // RC19: one search box over the list (DealSearch.jsx.txt) — searches the stage the chips show; an empty box = the list as before. // ↑ ↓ move the highlighted row, Enter opens its review (same as a click). Called before the early returns below (hook order). const drSearchBase = stageFilter === "All" ? deals : deals.filter(d => drStage(d) === stageFilter); const ds = dsUseDealSearch({ deals: drSearchBase, selectedId, onSelect: setSelectedId, onOpen: (d) => { setSelectedId(d.id); setRecapId(d.id); } }); if (recapDeal && backendView) { return setBackendView(false)} />; } if (recapDeal) { return { setRecapId(null); setBackendView(false); }} onBackend={() => setBackendView(true)} onDesk={() => drOpenInDesking(recapDeal, go)} />; } const counts = drStages().reduce((m, s) => { m[s] = deals.filter(d => drStage(d) === s).length; return m; }, {}); const shown = ds.list; return (
{/* Page header */}
Deal Pipeline
{deals.length === 0 ? "No deals yet. Deals start in the CRM: + New Lead → Desk It." : `${deals.length} deal${deals.length === 1 ? "" : "s"} · Desked → Cash / F&I → Posted → Funded`}
setHelp(true)}>? Help go && go("uploadtool")}>Import Deals go && go("crm")}> Start in CRM ▸
{deals.length === 0 ? go && go("uploadtool")} /> : ( <> {/* Stage filter chips */}
{["All", ...drStages()].map(s => { const on = stageFilter === s; const t = drStageTone[s]; const n = s === "All" ? deals.length : (counts[s] || 0); return ( ); })} Click a row to review · F6/F7 Desk · F9 Cash / Finance Deal
drOpenInDesking(d, go)} onReview={setRecapId} ds={ds} /> ) } {help && setHelp(false)} />}
); }; /* ─── Empty state ──────────────────────────────────────────── */ const EmptyDealsState = ({ go, onImport }) => (
{/* Big CTA card */}
📑
No deals yet
Deals start in the CRM: + New Lead → Desk It. The desk works the numbers, then pushes the deal to Cash Deal or Finance Deal, which posts it to accounting.
go && go("crm")}>Open CRM ▸ Import from old DMS
{/* Step-by-step */}
The one path — every deal follows it
  1. CRM — find the customer (or add them), then + New Lead.
  2. Desk It ▸ creates the deal and opens Desking — price, trade, down, payment.
  3. Push to Cash Deal or Push to Finance hands it to the closing screen.
  4. Post to Accounting books the deal (one shared gate).
  5. Accounting marks it Funded — done.
Tip: Already have deals in your old DMS? Use Import / Export in the top toolbar to bring them all over in one pass — no manual re-entry.
); /* ─── Deals table ──────────────────────────────────────────── */ const DealsTable = ({ deals, selectedId, onSelect, go, onOpen, onReview, ds }) => (
{deals.length === 0 && ( )} {deals.map(d => { const st = drStage(d); return ( { onSelect && onSelect(d.id); onReview && onReview(d.id); }} title="Click to review this deal" style={{ background: d.id === selectedId ? "var(--jb-blue-tint)" : "transparent", cursor: "pointer", borderBottom: "1px solid var(--jb-border)", opacity: st === "Funded" ? 0.75 : 1, }}> ); })}
Deal # Buyer Vehicle Stage Created
{ds && ds.filtering ? "No deals match the search." : "No deals at this stage."}
{d.id} {d.buyer || "—"}{ds ? : null} {d.vehicle || "—"} {d.created ? new Date(d.created).toLocaleDateString() : "—"} { e.stopPropagation(); onReview && onReview(d.id); }}>Review {!d.postedToGL && { e.stopPropagation(); onOpen && onOpen(d); }}>Desk ▸} {(st === "Cash" || st === "F&I") && ( { e.stopPropagation(); drOpenClosing(d, go); }}>{st === "Cash" ? "Cash Deal ▸" : "Finance Deal ▸"} )}
); const dealsTh = { padding: "10px 14px", textAlign: "left", fontSize: 11, textTransform: "uppercase", letterSpacing: "0.04em", color: "var(--jb-text-dim)", borderBottom: "1px solid var(--jb-border)", background: "var(--jb-surface-2)" }; const dealsTd = { padding: "10px 14px", fontSize: 13, color: "var(--jb-text)" }; /* ─── Help dialog ──────────────────────────────────────────── */ const HelpDialog = ({ onClose }) => (

Deal Pipeline lists every deal at the dealership by stage (Desked · Cash · F&I · Posted · Funded) and lets you open any one to work it through to funding. Deals are created in the CRM (+ New Lead → Desk It) — never here.

F1 This help screen F2 Start in the CRM (new customer / lead → Desk It) F3 Open the buyer's Credit Application F4 Open Vehicle Inventory F6 / F7 Open the selected deal in Desking (carries the unit) F9 Open the selected deal's closing screen (Cash Deal / Finance Deal) F10 / ESC Close Ctrl+S Save (anywhere)
); Object.assign(window, { DealReview }); /* ═══ Deal recap — the per-deal screen ═══════════════════════ The full picture of one deal: pipeline stage, buyer, vehicle, trade, figures, gross recap, and every next action. */ const dr$ = (n) => "$" + (+n || 0).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); const DealRecap = ({ deal: d, go, onBack, onDesk, onBackend }) => { const stage = drStage(d); const stageIdx = (window.DMS && window.DMS.dealStageIndex) ? window.DMS.dealStageIndex(d) : Math.max(0, drStages().indexOf(stage)); const cust = (window.DMS && d.custNum) ? ((window.DMS.findCustomer ? window.DMS.findCustomer(d.custNum) : window.DMS.customers()[d.custNum]) || null) : null; // RC30 (cn): an old number still finds the account const unit = window.DMS ? (window.DMS.inventory() || []).find(u => u.stock === d.stock) : null; const unitCheck = (window.DMS && window.DMS.unitOpenItems && d.stock) ? window.DMS.unitOpenItems(d.stock, { exceptDeal: d.id }) : { clean: true, items: [] }; // RC28 (fx, the reviewer's gate 2b): the gross recap is the desk's / the posting's (DMSCore.dealGross = DealCalc.profitPlan): the pack and the // deal's cost lines (Profit panel) come off exactly as they do there — before RC28 this screen showed price − cost and the F&I gross only const g = window.DMS && window.DMS.dealGross ? window.DMS.dealGross(d) : null; const front = g ? g.frontGrossCents / 100 : (+d.salePrice || 0) - (+d.cost || 0) - ((+d.tradeAllow || 0) - (+d.tradeACV || +d.tradeAllow || 0)); const fi = g ? g.fiGrossCents / 100 : (+d.fiGross || 0); const isCash = stage === "Cash" || (d.postedToGL && /cash/i.test(String(d.dealType || ""))); const toClosing = (which) => { try { localStorage.setItem("jb_fw_deal", d.id); } catch (e) {} go && go(which === "cash" ? "cashworksheet" : "finance"); }; // ONE PATH: post + fund only through the shared helpers (one gate, one confirm). const post = () => { if (window.jbPostDeal) window.jbPostDeal(d.id); else window.k2bToast && window.k2bToast("Ledger offline.", "warn"); }; const fund = () => { if (window.jbFundDeal) window.jbFundDeal(d.id); else window.k2bToast && window.k2bToast("Ledger offline.", "warn"); }; const card = { background: "var(--jb-surface)", border: "1px solid var(--jb-border)", borderRadius: "var(--jb-r-lg)", padding: "14px 16px" }; const cardHead = { fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--jb-text-dim)", fontWeight: 700, marginBottom: 8 }; const fig = (label, val, strong) => (
{label} {val}
); // Stage strip: Desked · (Cash / F&I) · Posted · Funded. Cash and F&I are // alternatives — whichever leg the deal took is lit, the other greyed. const stripNode = (s, i, lit, done, ghost) => (
{done ? "✓" : i} {s}
); const line = (on) =>
; const legTaken = stageIdx >= 3 ? (isCash ? "Cash" : "F&I") : (stage === "Cash" || stage === "F&I" ? stage : null); return (
{/* Header */}
‹ Pipeline
{d.id} — {d.buyer}
{d.vehicle || "no vehicle yet"}{d.stock ? ` · Stk ${d.stock}` : ""}{d.created ? ` · created ${new Date(d.created).toLocaleDateString()}` : ""} {d.salesperson ? ` · ${d.salesperson}` : ""}{d.dealType ? ` · ${d.dealType}` : ""}
{/* Stage-driven next actions */} {!d.postedToGL && ▭ Desk ▸} {stage === "Cash" && toClosing("cash")} style={{ fontWeight: 700, color: "var(--jb-green)" }}>Cash Deal ▸} {stage === "F&I" && toClosing("finance")} style={{ fontWeight: 700, color: "var(--jb-blue)" }}>Finance Deal ▸} 🔒 Backend ▸ {/* Posted deals: post-sale adjustments (charges, fees, products, payoff, terms) post one adjusting entry. Unposted deals are still live on the Cash Deal / Finance Deal screen (buttons above). */} {d.postedToGL && window.DealAdjustButton && } {window.DealCorrectButtons && } go && go("creditapp")}>✍ Credit App go && go("buyersorder")}>📋 Buyer's Order {!d.postedToGL && ( Post to Accounting )} {stage === "Posted" && ( ✓ Mark Funded )} {stage === "Funded" && ( DONE ✓ )}
{/* Pipeline strip */}
{stripNode("Desked", 1, stageIdx === 0, stageIdx > 0, false)} {line(stageIdx >= 1)}
{stripNode("Cash", 2, stage === "Cash", stageIdx >= 3 && legTaken === "Cash", legTaken != null && legTaken !== "Cash")} / {stripNode("F&I", 2, stage === "F&I", stageIdx >= 3 && legTaken === "F&I", legTaken != null && legTaken !== "F&I")}
{line(stageIdx >= 3)} {stripNode("Posted", 3, stage === "Posted", stageIdx > 3, false)} {line(stageIdx >= 4)} {stripNode("Funded", 4, stage === "Funded", false, false)}
{/* Issues / pending notes */} {!unitCheck.clean && (
⚠ Unit not clean — Stk {d.stock}:{" "} {unitCheck.items.map(x => x.label).join(" · ")} go && go("servicedept")}>Service ▸
)} {(d.fundingIssue || d.pending) && (
⚠ {d.fundingIssue || d.pending}
)} {/* RC23 (corr): the deal's correction history (unwinds, cancelled products, refunds, funding reversals) */} {window.DealCorrectionHistory && } {/* Body grid */}
{/* Buyer */}
Buyer
{d.buyer}
{cust ? (
{cust.phone || cust.cell || "no phone"} · Customer # {cust.custNum}
{[cust.street, [cust.city, cust.state, cust.postal || cust.zip].filter(Boolean).join(" ")].filter(Boolean).join(" · ") || ""} {cust.dlNumber ? <>
DL {cust.dlNumber} : null}
) : (
Not linked to a customer file — this deal was not started from the CRM.{d.custNum ? ` (Customer # ${d.custNum})` : ""}
)}
go && go("customers")}>Customer File ▸ go && go("crm")}>CRM ▸
{/* Vehicle + trade */}
Vehicle
{d.vehicle || "—"}
{d.stock ? `Stock ${d.stock}` : "no stock # yet"}{d.type ? ` · ${d.type}` : ""} {unit ? ` · ${unit.status}` : d.stock ? " · not in inventory" : ""}
{unit && (
Cost {dr$(unit.cost)} · Asking {dr$(unit.asking || unit.list || 0)}
)} {(+d.tradeAllow || 0) > 0 && ( <>
Trade
{fig("Allowance", dr$(d.tradeAllow))} {fig("Payoff", dr$(d.tradePayoff))} {fig("Net equity", dr$((+d.tradeAllow || 0) - (+d.tradePayoff || 0)), true)} )}
go && go("inventory")}>Inventory ▸
{/* Figures */}
Deal Figures{isCash ? " — Cash" : d.dealType ? ` — ${d.dealType}` : ""}
{fig("Sale price", dr$(d.salePrice))} {/* K2B-003 (RC18): a cash deal shows owed / received (recorded payments only) / balance — cashDown is never "owed" */} {isCash && window.DMS && window.DMS.cashDealFigures ? (() => { const cf = window.DMS.cashDealFigures(d); return (<> {fig("Total due", dr$(cf.totalDue))} {fig("Received", cf.legacy ? "not recorded (saved before RC18)" : dr$(cf.received))} {fig("Balance due", dr$(cf.balanceDue), true)}); })() : fig(isCash ? "Cash due at delivery" : "Cash down", dr$(d.cashDown))} {(+d.rebate || 0) > 0 && fig("Rebate", dr$(d.rebate))} {fig("Sales tax", dr$(d.tax))} {fig("Doc fee", dr$(d.docFee))} {(+d.titleFee || 0) > 0 && fig("Title fee", dr$(d.titleFee))} {(+d.vscSale || 0) > 0 && fig("Service contract", dr$(d.vscSale))} {(+d.gapSale || 0) > 0 && fig("GAP", dr$(d.gapSale))} {(+d.tradePayoff || 0) > 0 && !((+d.tradeAllow || 0) > 0) && fig("Trade payoff", dr$(d.tradePayoff))} {Array.isArray(d.charges) && d.charges.map((c, i) => {fig("+ " + (c.desc || "Charge"), dr$(c.amount))})} {!isCash && fig("Amount financed", dr$(d.amtFinanced), true)} {!isCash && d.lender ? fig("Lender", d.lender) : null} {!isCash && ((+d.apr || 0) > 0 || +d.term > 0) && fig("APR / Term", `${(+d.apr || 0).toFixed(2)}% / ${d.term || "—"} mo`)} {!isCash && (+d.payment || 0) > 0 && fig("Payment", dr$(d.payment) + " /mo")} {isCash && fig("Lender", "None — cash deal", true)}
Gross Recap
{fig("Front gross", dr$(front))} {g && g.packCents ? fig("− Pack", dr$(g.packCents / 100)) : null} {g && g.frontAddsCents ? fig("− Front cost lines", dr$(g.frontAddsCents / 100)) : null} {g ? {fig("Net front", dr$(g.netFrontCents / 100))} : null} {fig("F&I gross", dr$(fi))} {g && g.backAddsCents ? fig("− Back cost lines", dr$(g.backAddsCents / 100)) : null} {fig("Total gross", dr$(g ? g.totalGrossCents / 100 : front + fi), true)}
{Array.isArray(d.products) && d.products.length > 0 && (
{d.products.length} backend product{d.products.length !== 1 ? "s" : ""} on deal — see 🔒 Backend.
)}
{Array.isArray(d.adjustments) && d.adjustments.length > 0 && window.DealAdjustHistory && } {/* Status footer */}
Stage: {stage} {d.status ? ` · ${d.status}` : ""} {d.postedToGL ? " · posted to accounting" : " · not posted"} {d.postedToGL && !/^funded/i.test(String(d.status || "")) && d.fundingStatus ? ` · ${d.fundingStatus}${d.sentForFundingAt ? " " + new Date(d.sentForFundingAt).toLocaleDateString() : ""}` : ""} {d.delivered ? ` · delivered ${new Date(d.delivered).toLocaleDateString()}` : ""} {d.fundedDate ? ` · funded ${new Date(d.fundedDate).toLocaleDateString()}` : ""}
); }; Object.assign(window, { DealRecap });