/* 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. */ // K2B Network Solutions — Vehicle Stock-In (STKIN). // The receiving workflow when a new or used vehicle arrives: // 1. VIN / factory invoice / MSO / title // 2. Dealer adds (prep, fuel, freight, advertising, recon for used) // 3. Floorplan assignment & curtailment schedule // 4. Keys / fobs / accessories // 5. Post: DMS.stockInVehicle — DR 231/237/240/241 inventory · CR 310/314 // floorplan · CR 202 cash for any un-floored portion (jrn 70/71). // // The unit lands in DMS.inventory() on commit (visible immediately in // INVSTK, which reads the same ledger). const SI_BANKS = [ { id: "GMF", name: "GM FINANCIAL", rate: 7.85, curt: 30 }, { id: "ALLY", name: "ALLY", rate: 7.95, curt: 30 }, { id: "CHASE",name: "JPMORGAN CHASE", rate: 7.65, curt: 60 }, { id: "WTLK", name: "WESTLAKE FLOORPLAN", rate: 8.15, curt: 30 }, ]; const si$ = (n) => (n || 0).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); const siInt = (n) => (n || 0).toLocaleString("en-US"); // GL accounts the stock-in will post to — same rule as DMS.stockInVehicle // (new car 231 / new truck 237 / used car 240 / used truck 241; floorplan 310 new / 314 used; cash 202). const siAccts = (v) => { const isNew = String(v.type || "N").toUpperCase().startsWith("N"); const isTruck = /truck|pickup|silverado|sierra|colorado|1500|2500|3500/i.test((v.mdl || "") + " " + (v.body || "")); const inv = isNew ? (isTruck ? "237" : "231") : (isTruck ? "241" : "240"); const floor = isNew ? "310" : "314"; const nm = (a) => (window.DMS && window.DMS.acctName && window.DMS.acctName(a)) || ""; return { inv, floor, cash: "202", invName: nm(inv), floorName: nm(floor), cashName: nm("202") }; }; const siToday = () => new Date().toLocaleDateString("en-US", { month: "2-digit", day: "2-digit", year: "2-digit" }); const siNum = (x) => parseFloat(String(x == null ? "" : x).replace(/[^0-9.\-]/g, "")) || 0; // Starting values that count as "empty" for the VIN decode until a person types over them. const SI_FILL_DEFAULT = { yr: 2026, mk: "CHEV", body: "4D SUV" }; // A VIN is stored without spaces or dashes (a pasted "1gcuy-eed5nz-612345" is the same VIN): otherwise the unit never matches its market price. const siVinClean = (x) => (typeof invMcNormVin === "function" ? invMcNormVin(x) : String(x == null ? "" : x).toUpperCase().replace(/[\s-]+/g, "")); const SI_DEFAULT_ADDS = { prep: 285, fuel: 42, freight: 1395, advertising: 220, pdi: 165, recon: 0, }; const VehicleStockIn = ({ onClose, go }) => { const [step, setStep] = React.useState(0); // 0..4 const [flash, setFlash] = React.useState(""); // Fields a person has typed in (or that arrived pre-filled from VIN Decode) — a VIN decode from MarketCheck never replaces these. const touched = React.useRef(null); const [v, setV] = React.useState(() => { // VIN Decode's F5-Reserve hands off the decoded vehicle here. const pre = (typeof window !== "undefined" && window.jbStockInPrefill) || {}; if (typeof window !== "undefined") window.jbStockInPrefill = null; touched.current = new Set(Object.keys(pre)); return { type: "N", stock: "", vin: "", yr: 2026, mk: "CHEV", mdl: "", trim: "", body: "4D SUV", color: "", intColor: "JET BLACK", miles: 4, msoNo: "", poNo: "", invoiceDate: siToday(), invoiceCost: 0, msrp: 0, asking: 0, description: "", adds: { ...SI_DEFAULT_ADDS }, bank: "GMF", advanced: 0, curtDays: 30, rate: 7.85, keys: 2, fobs: 2, accessories: "Owner manual, Spare key, Floor mats", notes: "", source: "FACTORY", drive: "", engine: "", trans: "", fuel: "", vinOptions: "", ...pre, }; }); const [posted, setPosted] = React.useState(null); const toast = (m) => { setFlash(m); setTimeout(() => setFlash(""), 2800); }; const upd = (k, val) => { touched.current.add(k); setV(p => ({ ...p, [k]: val })); }; // Typing / pasting a VIN fills the still-empty fields from MarketCheck (our server decodes + caches; Undo available). const vinFill = (typeof InvMcUseVinFill === "function") ? InvMcUseVinFill({ vin: v.vin, keys: { ...INV_MC_KEYS_STD, options: "vinOptions" }, read: () => v, write: (p) => setV(prev => ({ ...prev, ...p })), isBlank: (k, raw) => invMcBlankRaw(k, raw) || (!touched.current.has(k) && SI_FILL_DEFAULT[k] !== undefined && String(raw) === String(SI_FILL_DEFAULT[k])), shape: { yr: (n) => n, mk: (t) => t.slice(0, 4), msrp: (n) => n }, }) : null; const updAdd = (k, val) => setV(p => ({ ...p, adds: { ...p.adds, [k]: parseFloat(val) || 0 } })); const totalAdds = Object.values(v.adds).reduce((s, n) => s + (n || 0), 0); const capitalized = siNum(v.invoiceCost) + totalAdds; const retail = siNum(v.asking) || siNum(v.msrp); // retail / asking; falls back to MSRP const spread = retail - capitalized; // Auto-generate stock # when type/yr/mk set React.useEffect(() => { if (!v.stock) { const yy = (v.yr || 2026).toString().slice(-2); const seq = Math.floor(1000 + Math.random() * 8999); upd("stock", `${v.type === "U" ? "U" : "T"}${yy}-${seq}`); } }, [v.type, v.yr]); // Default advanced amount = invoice cost React.useEffect(() => { if (!v.advanced && v.invoiceCost) upd("advanced", siNum(v.invoiceCost)); }, [v.invoiceCost]); // Sync rate/curt when bank changes React.useEffect(() => { const b = SI_BANKS.find(b => b.id === v.bank); if (b) setV(p => ({ ...p, rate: b.rate, curtDays: b.curt })); }, [v.bank]); const validate = () => { if (!v.vin || v.vin.replace(/\*/g, "").length < 11) return "VIN required (17 chars, * for unknowns)."; if (!v.mdl) return "Model is required."; if (!v.color) return "Exterior color required."; if (!siNum(v.invoiceCost)) return v.type === "U" ? "Acquisition cost required (Invoice step)." : "Invoice cost required (Invoice step)."; if (!siNum(v.asking) && !siNum(v.msrp)) return "Enter the retail / asking price (or MSRP) on the Invoice step."; if (v.type === "U" && !(parseInt(String(v.miles).replace(/[^0-9]/g, "")) > 0)) return "Enter the odometer mileage for a used unit."; return null; }; const commit = async () => { // RC33 (mpx): the stock-in is a SERVER command (the unit + its purchase entry in one step) — await the committed answer const err = validate(); if (err) { toast(err); setStep(/cost|retail|MSRP/i.test(err) ? 1 : 0); return; } const newUnit = { stock: v.stock.toUpperCase(), vin: siVinClean(v.vin), yr: parseInt(v.yr) || 2026, mk: (v.mk || "CHEV").toUpperCase().padEnd(4, " ").slice(0, 4), mdl: v.mdl.toUpperCase(), body: v.body.toUpperCase(), color: v.color.toUpperCase(), miles: parseInt(String(v.miles).replace(/[^0-9]/g, "")) || 0, cost: capitalized, list: retail, days: 0, type: v.type, status:"STOCK", }; const bankName = SI_BANKS.find(b => b.id === v.bank)?.name || v.bank; let jeRef = null, jeLines = null; if (window.DMS && window.DMS.stockInVehicle) { // Real posting: adds the unit to DMS inventory + posts the purchase JE. const r = await window.DMS.stockInVehicle({ stock: newUnit.stock, vin: newUnit.vin, yr: newUnit.yr, mk: newUnit.mk.trim(), mdl: newUnit.mdl, body: newUnit.body, color: newUnit.color, miles: newUnit.miles, type: v.type, cost: capitalized, asking: newUnit.list, floorAmt: siNum(v.advanced), floorLender: bankName, recon: v.adds.recon || 0, }); if (!r.ok) { toast(r.msg); return; } jeRef = r.id; jeLines = r.lines; // The rest of the unit schema (not GL-relevant) — recorded on the new unit as received. if (window.DMS.updateUnit) window.DMS.updateUnit(newUnit.stock, { trim: (v.trim || "").toUpperCase(), description: (v.description || "").trim(), msrp: siNum(v.msrp), intColor: (v.intColor || "").toUpperCase(), keyTag: newUnit.stock, options: v.accessories || "", notes: v.notes || "", msoNo: v.msoNo || "", poNo: v.poNo || "", source: v.source || "", invoiceDate: v.invoiceDate || "", invoiceCost: siNum(v.invoiceCost), keys: +v.keys || 0, fobs: +v.fobs || 0, }); // From the VIN decode (all optional): powertrain for the spec sheet, factory options joined with the accessories. const more = {}; ["drive", "engine", "trans", "fuel"].forEach(k => { if ((v[k] || "").trim()) more[k] = v[k].trim(); }); if ((v.vinOptions || "").trim()) more.options = [v.vinOptions.trim(), v.accessories || ""].filter(Boolean).join(" | "); if (window.DMS.updateUnit && Object.keys(more).length) window.DMS.updateUnit(newUnit.stock, more); window.jbInvOpen = newUnit.stock; // "View in INVSTK" opens this unit } else if (typeof INV_STOCK !== "undefined") { // Offline fallback — local list only. INV_STOCK.unshift(newUnit); } setPosted({ stock: newUnit.stock, jeRef: jeRef || "(not posted — ledger offline)", lines: jeLines, capitalized, advanced: parseFloat(v.advanced) || 0, bank: bankName, curtDate: new Date(Date.now() + (parseInt(v.curtDays) || 30) * 86400 * 1000) .toLocaleDateString("en-US", { month: "2-digit", day: "2-digit", year: "2-digit" }), }); setStep(5); toast(`Unit ${newUnit.stock} stocked in.`); }; return (
{}} onMax={() => {}} /> {flash && (
✓ {flash}
)}
{/* Stepper */}
{["1 Vehicle","2 Invoice","3 Dealer Adds","4 Floorplan","5 Keys"].map((label, i) => ( {i < 4 && ›} ))} Capitalized: ${si$(capitalized)}
{/* Step body */}
{step === 0 && } {step === 1 && } {step === 2 && } {step === 3 && } {step === 4 && } {step === 5 && posted && { window.jbInvOpen = null; touched.current = new Set(); setStep(0); setPosted(null); setV(p => ({ ...p, stock: "", vin: "", mdl: "", trim: "", color: "", description: "", notes: "", invoiceCost: 0, msrp: 0, asking: 0, advanced: 0, drive: "", engine: "", trans: "", fuel: "", vinOptions: "", adds: { ...SI_DEFAULT_ADDS } })); }} />}
{/* Sticky deal summary */}
{/* Footer */}
ESC-Close {step > 0 && step < 5 && setStep(s => s - 1)}>‹ Back} {step < 4 && setStep(s => s + 1)}>Next ›} {step === 4 && F10-Post Stock-In} {step === 5 && go && go("inventory")}>View in INVSTK ›}
); }; // ─── Step 1: Vehicle ─────────────────────────────────────────────────────── const StepVehicle = ({ v, upd, fill }) => (
Vehicle Identification
Type........: {["N","U"].map(t => ( ))}
upd("stock", x)} w={140} hi /> upd("source", x)} w={180} options={["FACTORY","AUCTION","TRADE-IN","DEALER TRADE","WHOLESALE"]} /> upd("yr", parseInt(x) || 0)} w={70} field="yr" /> upd("mk", x)} w={80} field="mk" /> upd("mdl", x)} w={220} hi field="mdl" /> upd("trim", x)} w={140} field="trim" /> upd("body", x)} w={120} field="body" />
upd("vin", siVinClean(x))} w={220} hi field="vin" onBlur={fill ? fill.onBlur : undefined} /> {fill && typeof InvMcVinNote === "function" && } upd("color", x)} w={180} /> upd("intColor", x)} w={140} /> upd("miles", x.replace(/[^0-9,]/g, ""))} w={100} hi={v.type === "U"} field="miles" /> upd("drive", x)} w={90} field="drive" /> upd("engine", x)} w={200} field="engine" /> upd("trans", x)} w={170} field="trans" /> upd("fuel", x)} w={110} field="fuel" /> {v.type === "N" && (
Tip: for factory units, miles are typically 4–20 (transport mileage).
)} {v.type === "U" && (
Reminder: request CarFax (F4 in INVSTK) before retail.
)}
Description (shows on the unit, spec sheet and listings)