/* 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. */ // JBREW DMS — Lease calculation engine (pure functions, no React, no JSX). // // Standard closed-end lease math, the way the captive lenders compute it: // Money factor MF = APR / 2400 (0.00125 MF = 3.00% APR) // Residual value = residual % × MSRP (rounded to cents) // Gross cap cost = selling price + capitalized fees + add-ons // + NEGATIVE trade equity rolled in // Cap cost reduction = cash + rebates + POSITIVE trade equity // Adjusted cap cost = gross cap − total cap reduction // Depreciation / mo = (adjusted cap − residual) / term // Rent charge / mo = (adjusted cap + residual) × effective MF // Base payment = depreciation + rent charge // Tax = per taxMethod: "monthly" (on the payment, MO style) · // "upfront_on_payment_stream" · "upfront_on_capred" // MO/GMF monthly-receipts practice: cap-cost reduction is // ALSO taxed at signing (taxCapRedAtSigning — defaults // true when taxMethod === "monthly"; overridable). // Effective MF = base MF + tier MF add + dealer participation markup; // single-pay leases subtract the GMF band reduction // (24-27 / 36-48 mo) with an absolute floor (minMf) and // are priced at A+/A1 (tier add NOT applied — GMF rule). // // Residual mileage adjustments (GMF / RouteOne behavior): // · Extra mileage purchased up front → residual − miles × rate ($0.20/mi) // · Inception (odometer) miles → residual − miles × rate ($0.20/mi) // auto-applies in the 1,250–7,500 mi retro-adjustment window // residualValue = round(msrp × residual%) − residualAdjustments. // The MONTHLY use tax is computed on the base payment at the UNADJUSTED // residual — the mileage-adjustment portion of the payment is not taxed // (validated to the cent against a live RouteOne/GMF worksheet: // base 774.36 + tax 60.41 = 834.77 where 60.41 = 9.537% × 633.43, the // unadjusted base). // Payment counts: first payment is paid AT INCEPTION → remaining payments // = term − 1 (single-pay: 1 at inception, 0 remaining) for the RouteOne // "N Payment(s) of $X" display. // // Rounding: every money figure is rounded to cents at each display step. // Guard rail: if adjusted cap < residual we FLAG upsideDown:true and still // compute (depreciation goes negative — never silently clamped). // // Loaded BEFORE DeskingTool (see index.html); everything hangs on window.* // and also exports CommonJS-style for the Node unit-test harness. const jbLeaseAprToMf = (apr) => { const n = +apr; return isFinite(n) ? n / 2400 : 0; }; const jbLeaseMfToApr = (mf) => { const n = +mf; return isFinite(n) ? n * 2400 : 0; }; const jbLeaseRound2 = (n) => { const v = +n; return isFinite(v) ? Math.round((v + (v >= 0 ? 1 : -1) * 1e-9) * 100) / 100 : 0; }; // Default GMF single-pay MF reductions (overridable per call / per program). const JB_SP_DEFAULT = { "24-27": 0.00042, "36-48": 0.00073, minMf: 0.00001 }; /* Single-pay MF reduction for a term, per the GMF band table. */ function jbGmfSinglePayReduction(term, cfg) { const c = cfg || JB_SP_DEFAULT; const t = +term || 0; if (t >= 36 && c["36-48"] != null) return +c["36-48"] || 0; if (t >= 24 && t <= 27 && c["24-27"] != null) return +c["24-27"] || 0; // terms 28-35 with only the two published bands: use the 24-27 band if (t >= 24 && t < 36) return +(c["24-27"] != null ? c["24-27"] : 0) || 0; return 0; } /* Tier MF add from the program table ("A+/A1" → 0 … "B3" → 0.00313). */ function jbGmfTierAdd(tier, program) { const adds = (program && program.tierMfAdds) || {}; const v = adds[tier]; return v == null ? 0 : +v || 0; } /* Mileage residual ADD (percentage points) by annual mileage + term band. GMF publishes 7500/10000/12000/15000 with bands 24-35 / 36-47 / 48. */ function jbGmfMileageAdd(term, milesPerYr, program) { const table = (program && program.mileageResidualAdds) || {}; const row = table[String(milesPerYr)] || table[+milesPerYr]; if (!row) return 0; const t = +term || 0; let key; if (t >= 48) key = "48"; else if (t >= 36) key = "36-47"; else key = "24-35"; const v = row[key]; return v == null ? 0 : +v || 0; } /* MF + residual straight off a rate-sheet row for a published term. */ function jbGmfRateFor(row, term) { if (!row) return null; const cell = row["t" + (+term || 0)]; if (!cell) return null; return { mf: +cell.mf || 0, rv: +cell.rv || 0, apr: +cell.apr || 0 }; } /* B2/B3 auto security deposit — the payment rounded UP to the next $25. */ function jbGmfSecurityDeposit(payment) { const p = +payment || 0; if (p <= 0) return 0; return Math.ceil((p - 1e-9) / 25) * 25; } /* Full closed-end lease breakdown for ONE lease option. All money outputs rounded to cents. Inputs (all optional except the core): msrp, sellingPrice, term, milesPerYr, residualPct (of MSRP), moneyFactor (or apr — APR = MF × 2400), acqFee + acqFeeCapitalized, capReductionCash, rebates, tradeAllowance, tradePayoff (neg equity → capitalized; pos → cap red), docFee + docFeeCapitalized, titleLicenseFee + titleLicenseCapitalized, addOns (capitalized products), taxMethod + taxRate, securityDeposit, dispositionFee, excessMileageRate, purchaseOptionFee, singlePay (bool), tierMfAdd, dealerMarkupMf, singlePayMfReduction ({ "24-27", "36-48", minMf } — GMF defaults), extraMilesPurchased (mi) + extraMileageRate ($/mi, default 0.20), inceptionMiles (odometer at signing) + inceptionMileageRate (default 0.20), inceptionMileageAdjust (bool; default AUTO — true when 1250 ≤ inceptionMiles ≤ 7500, the GMF retro-adjustment window). */ function jbLeaseCalc(inp) { const i = inp || {}; const R = jbLeaseRound2; const msrp = +i.msrp || 0; const sellingPrice = +i.sellingPrice || 0; const term = Math.max(1, Math.round(+i.term || 36)); const residualPct = +i.residualPct || 0; const singlePay = !!i.singlePay; const spCfg = i.singlePayMfReduction || JB_SP_DEFAULT; // ── money factor stack ── const baseMf = i.moneyFactor != null && i.moneyFactor !== "" ? (+i.moneyFactor || 0) : jbLeaseAprToMf(i.apr); // GMF: single-pay is priced at A+/A1 — the tier add is NOT applied. const tierMfAdd = singlePay ? 0 : (+i.tierMfAdd || 0); const dealerMarkupMf = +i.dealerMarkupMf || 0; let effectiveMf = baseMf + tierMfAdd + dealerMarkupMf; let spReduction = 0; if (singlePay) { spReduction = jbGmfSinglePayReduction(term, spCfg); const floor = spCfg.minMf != null ? +spCfg.minMf : JB_SP_DEFAULT.minMf; effectiveMf = Math.max(floor, effectiveMf - spReduction); } // ── trade equity split ── const tradeAllowance = +i.tradeAllowance || 0; const tradePayoff = +i.tradePayoff || 0; const equity = tradeAllowance - tradePayoff; const negativeEquity = R(Math.max(0, -equity)); const positiveEquity = R(Math.max(0, equity)); // ── fees, capitalized vs upfront ── const acqFee = +i.acqFee || 0; const acqCapped = !!i.acqFeeCapitalized; const docFee = +i.docFee || 0; const docCapped = !!i.docFeeCapitalized; const titleLicenseFee = +i.titleLicenseFee || 0; const titleCapped = !!i.titleLicenseCapitalized; const addOns = +i.addOns || 0; // ── cap cost build-up ── const grossCapCost = R(sellingPrice + addOns + negativeEquity + (acqCapped ? acqFee : 0) + (docCapped ? docFee : 0) + (titleCapped ? titleLicenseFee : 0)); const capReductionCash = +i.capReductionCash || 0; const rebates = +i.rebates || 0; const totalCapReduction = R(capReductionCash + rebates + positiveEquity); const adjustedCapCost = R(grossCapCost - totalCapReduction); // ── residual mileage adjustments (GMF/RouteOne) ── // Extra mileage purchased up front and inception (odometer) miles both // reduce the residual dollar-for-mile at their respective rates. The // inception adjustment auto-applies inside the GMF retro window // (1,250–7,500 mi) unless explicitly overridden. const extraMilesPurchased = Math.max(0, +i.extraMilesPurchased || 0); const extraMileageRate = i.extraMileageRate != null && i.extraMileageRate !== "" ? (+i.extraMileageRate || 0) : 0.20; const inceptionMiles = Math.max(0, +i.inceptionMiles || 0); const inceptionMileageRate = i.inceptionMileageRate != null && i.inceptionMileageRate !== "" ? (+i.inceptionMileageRate || 0) : 0.20; const inceptionMileageAdjust = i.inceptionMileageAdjust != null ? !!i.inceptionMileageAdjust : (inceptionMiles >= 1250 && inceptionMiles <= 7500); const extraMileageCost = R(extraMilesPurchased * extraMileageRate); const inceptionMileageAdjustment = inceptionMileageAdjust ? R(inceptionMiles * inceptionMileageRate) : 0; const residualAdjustments = R(extraMileageCost + inceptionMileageAdjustment); // ── residual / depreciation / rent ── const residualValueUnadjusted = R(msrp * residualPct / 100); const residualValue = R(residualValueUnadjusted - residualAdjustments); const upsideDown = adjustedCapCost < residualValue; const baseDepreciation = R((adjustedCapCost - residualValue) / term); const rentCharge = R((adjustedCapCost + residualValue) * effectiveMf); const baseMonthly = R(baseDepreciation + rentCharge); // Taxable base payment — RouteOne/GMF worksheet behavior: the monthly use // tax is figured on the payment at the UNADJUSTED residual; the mileage- // adjustment portion of the payment is not taxed. With no adjustments this // is identical to baseMonthly (all pre-existing deals unchanged). const taxableBaseMonthly = residualAdjustments ? R(R((adjustedCapCost - residualValueUnadjusted) / term) + R((adjustedCapCost + residualValueUnadjusted) * effectiveMf)) : baseMonthly; // ── tax per method ── const taxMethod = i.taxMethod || "none"; const taxRate = +i.taxRate || 0; let monthlyTax = 0, upfrontTax = 0; if (taxRate > 0) { if (taxMethod === "monthly") monthlyTax = R(taxableBaseMonthly * taxRate / 100); else if (taxMethod === "upfront_on_payment_stream") upfrontTax = R(taxableBaseMonthly * term * taxRate / 100); else if (taxMethod === "upfront_on_capred") upfrontTax = R(totalCapReduction * taxRate / 100); } // MO/GMF monthly-receipts practice: the cap-cost reduction (cash + rebates // applied as CCR + positive trade equity) is ALSO taxed at signing. Separate // flag so it can be switched off; defaults ON for the monthly method only. const taxCapRedAtSigning = i.taxCapRedAtSigning != null ? !!i.taxCapRedAtSigning : taxMethod === "monthly"; const capReductionTax = (taxRate > 0 && taxCapRedAtSigning && taxMethod !== "upfront_on_capred") ? R(totalCapReduction * taxRate / 100) : 0; // RouteOne "Tax on Upfront Fees" — sales tax on the NON-capitalized fees // collected at signing (acq/doc/title-license), monthly method only. const taxOnUpfrontFees = (taxRate > 0 && taxMethod === "monthly") ? R(((acqCapped ? 0 : acqFee) + (docCapped ? 0 : docFee) + (titleCapped ? 0 : titleLicenseFee)) * taxRate / 100) : 0; const totalMonthly = R(baseMonthly + monthlyTax); // ── single-pay amount: term × base monthly at the reduced MF, plus tax ── const totalTax = R(monthlyTax * term + upfrontTax); const singlePayAmount = singlePay ? R(baseMonthly * term + totalTax) : 0; // ── due at signing itemization ── const securityDeposit = R(+i.securityDeposit || 0); const due = { firstPayment: singlePay ? 0 : totalMonthly, singlePayAmount: singlePay ? singlePayAmount : 0, capReductionCash: R(capReductionCash), acqFee: acqCapped ? 0 : R(acqFee), docFee: docCapped ? 0 : R(docFee), titleLicense: titleCapped ? 0 : R(titleLicenseFee), securityDeposit: securityDeposit, upfrontTax: upfrontTax, capReductionTax: capReductionTax, taxOnUpfrontFees: taxOnUpfrontFees, total: 0, }; due.total = R(due.firstPayment + due.singlePayAmount + due.capReductionCash + due.acqFee + due.docFee + due.titleLicense + due.securityDeposit + due.upfrontTax + due.capReductionTax + due.taxOnUpfrontFees); // ── totals ── const totalOfPayments = singlePay ? singlePayAmount : R(totalMonthly * term); const dispositionFee = R(+i.dispositionFee || 0); // Total lease cost = everything the lessee pays out over the life of the // lease (payments + cap reduction cash + rebate value applied + non-capped // fees + upfront tax + disposition at turn-in). Security deposit excluded — // it is refundable. const totalLeaseCost = R(totalOfPayments + capReductionCash + rebates + positiveEquity + due.acqFee + due.docFee + due.titleLicense + upfrontTax + capReductionTax + taxOnUpfrontFees + dispositionFee); // ── payment counts (RouteOne display: first payment paid AT INCEPTION) ── const paymentsAtInception = 1; const remainingPayments = singlePay ? 0 : Math.max(0, term - 1); // ── mileage summary ── const totalAllowedLeaseEndMileage = Math.round( inceptionMiles + (term / 12) * (+i.milesPerYr || 0) + extraMilesPurchased); // ── RouteOne-style tax panel itemization ── const taxItemization = { capReductionTax, taxOnUpfrontFees, monthlyPaymentTax: monthlyTax, estimatedUpfrontTotal: R(capReductionTax + taxOnUpfrontFees + upfrontTax), }; return { // inputs echoed / derived term, msrp: R(msrp), sellingPrice: R(sellingPrice), milesPerYr: +i.milesPerYr || 0, moneyFactor: baseMf, tierMfAdd, dealerMarkupMf, singlePay, singlePayMfReduction: spReduction, effectiveMoneyFactor: effectiveMf, apr: jbLeaseRound2(jbLeaseMfToApr(effectiveMf)), aprEquivalent: jbLeaseRound2(jbLeaseMfToApr(effectiveMf)), residualPct, // cap cost negativeEquity, positiveEquity, grossCapCost, capReductionCash: R(capReductionCash), rebates: R(rebates), totalCapReduction, adjustedCapCost, // residual mileage adjustments (unadjusted + itemized + adjusted) residualValueUnadjusted, residualAdjustments, extraMilesPurchased, extraMileageRate, extraMileageCost, inceptionMiles, inceptionMileageRate, inceptionMileageAdjust, inceptionMileageAdjustment, totalAllowedLeaseEndMileage, // the ladder residualValue, baseDepreciation, rentCharge, baseMonthly, taxableBaseMonthly, monthlyTax, upfrontTax, capReductionTax, taxOnUpfrontFees, taxCapRedAtSigning, totalMonthly, taxItemization, paymentsAtInception, remainingPayments, singlePayAmount, // due at signing + totals dueAtSigningItems: due, totalOfPayments, totalLeaseCost, // other charges carried for disclosure prints securityDeposit, dispositionFee, excessMileageRate: +i.excessMileageRate || 0, purchaseOptionFee: R(+i.purchaseOptionFee || 0), upsideDown, }; } const JB_LEASE_API = { jbLeaseCalc, jbLeaseAprToMf, jbLeaseMfToApr, jbLeaseRound2, jbGmfSinglePayReduction, jbGmfTierAdd, jbGmfMileageAdd, jbGmfRateFor, jbGmfSecurityDeposit, }; if (typeof window !== "undefined") { Object.assign(window, JB_LEASE_API); window.LeaseCalc = JB_LEASE_API; } if (typeof module !== "undefined" && module.exports) module.exports = JB_LEASE_API;