/* © 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. */
/* eslint-disable */
// K2B DMS — check printing on blank security check stock (8.5" × 11").
// stock "top": check on top (3.5"), two stubs below (payee copy + file copy)
// stock "3up": three checks per page (3.5" each) + 0.5" tear strip
// Everything is placed in inches from the page corner with @page margin 0, so
// it lands in the same spot on every printer set to 100% / Actual size.
// MICR line (ANSI X9.100-160 / E-13B positions): characters on an exact 1/8"
// pitch measured from the check's right edge (position 1 starts 5/16" in):
// 1–12 amount (left blank — the bank encodes it) · 14 on-us ⑈ ·
// 15–32 account · 33 ⑆ · 34–42 routing · 43 ⑆ · 45+ aux on-us ⑈check#⑈
// The glyphs need an E-13B MICR font: one installed on the printing PC
// (GnuMICR, "MICR Encoding", "MICR E13B", IDAutomation…) or one uploaded in
// Check Setup. Font character map (the common one): A ⑆ transit, B ⑇ amount,
// C ⑈ on-us, D ⑉ dash.
const CKP_FONT_STACK = `"K2BMICR", "GnuMICR", "MICR Encoding", "MICR E13B", "MICR", "E13B", "IDAutomationMICR", "IDAutomationSMICR", "MICRE13B"`;
const CKP_LOCAL_FONTS = ["GnuMICR", "MICR Encoding", "MICR E13B", "MICR", "E13B", "IDAutomationMICR", "IDAutomationSMICR", "MICRE13B"];
const ckpEsc = (s) => String(s == null ? "" : s).replace(/&/g, "&").replace(//g, ">").replace(/"/g, """);
const ckpMoney = (n) => (Number(n) || 0).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
/* ── amount in words: 1234.56 → "One Thousand Two Hundred Thirty-Four and 56/100" ── */
const CKP_ONES = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"];
const CKP_TENS = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"];
const ckpUnder1000 = (n) => {
const out = [];
if (n >= 100) { out.push(CKP_ONES[Math.floor(n / 100)] + " Hundred"); n %= 100; }
if (n >= 20) { out.push(CKP_TENS[Math.floor(n / 10)] + (n % 10 ? "-" + CKP_ONES[n % 10] : "")); }
else if (n > 0) out.push(CKP_ONES[n]);
return out.join(" ");
};
const ckpWords = (amount) => {
const cents = Math.round((Number(amount) || 0) * 100);
let dollars = Math.floor(cents / 100);
const c = cents % 100;
if (dollars === 0) return `Zero and ${String(c).padStart(2, "0")}/100`;
const parts = [];
[[1e9, "Billion"], [1e6, "Million"], [1e3, "Thousand"], [1, ""]].forEach(([size, name]) => {
if (dollars >= size) { const chunk = Math.floor(dollars / size); dollars %= size; parts.push(ckpUnder1000(chunk) + (name ? " " + name : "")); }
});
return `${parts.join(" ")} and ${String(c).padStart(2, "0")}/100`;
};
/* ── MICR line: [{pos, ch}] for the font (A/B/C/D symbols) ── */
const ckpMicrChars = (bank, num, opts) => {
const routing = String(bank.routing || "").replace(/\D/g, "");
const account = String(bank.account || "").replace(/[^0-9-]/g, "");
const chk = String(num || "").replace(/\D/g, "");
const out = [];
const putRight = (str, endPos) => { const s = String(str); for (let i = 0; i < s.length; i++) out.push({ pos: endPos + (s.length - 1 - i), ch: s[i] }); };
// transit field 33–43
if (routing) putRight("A" + routing + "A", 33);
const acc = account.replace(/-/g, "D");
if ((bank.micrFormat || "business") === "personal") {
// on-us: account ⑈ check# (ending at position 14)
if (acc || chk) putRight(acc + "C" + (chk ? chk.padStart(4, "0") : ""), 14);
} else {
// on-us: account ⑈ at 14; auxiliary on-us ⑈check#⑈ ending at 45
if (acc) putRight(acc + "C", 14);
if (chk) putRight("C" + chk.padStart(opts && opts.auxDigits || 6, "0") + "C", 45);
}
return out;
};
const CKP_SYMBOL_FALLBACK = { A: "⑆", B: "⑇", C: "⑈", D: "⑉" };
/* ── one check face at (x0, y0) inches ── */
const ckpFace = (c, bank, company, x0, y0, opts) => {
const o = opts || {};
const ox = x0 + (+bank.offsetX || 0), oy = y0 + (+bank.offsetY || 0);
const at = (x, y, html, style) => `
${html}
`;
const words = ckpWords(c.amount);
const fill = "*".repeat(Math.max(3, 62 - words.length));
const date = c.date ? new Date(c.date) : new Date();
const dateStr = `${String(date.getMonth() + 1).padStart(2, "0")}/${String(date.getDate()).padStart(2, "0")}/${date.getFullYear()}`;
const top = bank.stock === "3up" ? 0.18 : 0.30; // top-check stock has the "to verify authenticity" bar
const addr = String(c.payeeAddr || "").split(/\r?\n/).map(s => s.trim()).filter(Boolean).slice(0, 3);
let h = "";
h += at(0.40, top, `${ckpEsc(company.name)}
${ckpEsc(company.addr1)}
${ckpEsc(company.addr2)}${company.phone ? "
" + ckpEsc(company.phone) : ""}`, "font-size:8.5pt;line-height:1.25;width:3.3in");
h += at(3.75, top, `${ckpEsc(bank.bankName || "")}${bank.bankLine2 ? "
" + ckpEsc(bank.bankLine2) : ""}${bank.fractional ? "
" + ckpEsc(bank.fractional) : ""}`, "font-size:8pt;line-height:1.25;width:2.4in;text-align:center");
h += at(6.40, top, `${ckpEsc(c.num)}`, "width:1.75in;text-align:right");
h += at(6.00, top + 0.62, `DATE ${dateStr}`, "width:2.15in;text-align:right;font-size:10.5pt");
h += at(0.40, top + 1.00, `PAY ${ckpEsc(words)} ${fill}`, "width:6.6in;white-space:nowrap;overflow:hidden;font-size:10pt");
h += at(7.10, top + 1.00, `DOLLARS`, "width:1.0in;text-align:right");
h += at(0.40, top + 1.38, `TO THE
ORDER OF`, "font-size:7pt;line-height:1.1");
h += at(1.10, top + 1.40, `${ckpEsc(c.payee)}${addr.map(l => "
" + ckpEsc(l)).join("")}`, "width:4.6in;line-height:1.3;font-size:9.5pt");
h += at(6.25, top + 1.32, `$${"*".repeat(Math.max(2, 11 - ckpMoney(c.amount).length))}${ckpMoney(c.amount)}`, "width:1.9in;text-align:right;font-size:12.5pt;border:1px solid #000;padding:3px 6px;box-sizing:border-box");
if (bank.voidAfterDays) h += at(6.25, top + 1.72, `VOID AFTER ${bank.voidAfterDays} DAYS`, "width:1.9in;text-align:right;font-size:6.5pt");
h += at(0.40, top + 2.38, `MEMO ${ckpEsc(c.memo || (c.inv ? "Inv " + c.inv : ""))}`, "width:4.2in;font-size:9pt;white-space:nowrap;overflow:hidden");
if (bank.sigLine && bank.stock !== "3up") {
const lines = bank.sigLines === 2 ? 2 : 1;
for (let i = 0; i < lines; i++) h += at(5.05, top + 2.48 - (lines - 1 - i) * 0.42, `${i === lines - 1 ? "AUTHORIZED SIGNATURE" : (bank.sigOver ? ckpEsc(bank.sigOver) : "AUTHORIZED SIGNATURE")}
`);
}
// MICR — bottom of the characters 0.25" above the check's bottom edge (inside the 5/8" clear band)
const H = 3.5;
const micrTop = oy + H - 0.25 - 0.19 + (+bank.micrOffsetY || 0);
const rightEdge = ox + 8.5;
ckpMicrChars(bank, c.num).forEach(({ pos, ch }) => {
const left = rightEdge - 0.3125 - pos * 0.125;
const glyph = o.fallback ? (CKP_SYMBOL_FALLBACK[ch] || ch) : ch;
h += `${ckpEsc(glyph)}
`;
});
if (o.alignment) {
h += ``;
h += ``;
}
return h;
};
/* ── stub (top-check stock) ── */
const ckpStub = (c, bank, company, y0, label) => {
const at = (x, y, html, style) => `${html}
`;
const D = window.DMS || {};
const name = (a) => (D.acctName ? D.acctName(a) : "") || "";
const d = c.date ? new Date(c.date).toLocaleDateString("en-US") : "";
const rows = (c.lines && c.lines.length ? c.lines : [{ inv: c.inv || "", desc: c.memo || "", amount: c.amount }])
.map(l => `| ${ckpEsc(l.inv || "")} | ${ckpEsc(l.desc || "")} | ${ckpMoney(l.amount)} |
`).join("");
return at(0, 0.30, `| ${ckpEsc(company.name)} | ${ckpEsc(label)} |
| Check # ${ckpEsc(c.num)} | Date ${ckpEsc(d)} | Payee ${ckpEsc(c.payee)} | Amount $${ckpMoney(c.amount)} |
| Invoice | Description | Amount |
${rows}
| GL account | | Debit | Credit |
| ${ckpEsc(c.acct)} | ${ckpEsc(name(c.acct))} | ${ckpMoney(c.amount)} | |
| ${ckpEsc(c.bankAcct || bank.glAcct)} | ${ckpEsc(name(c.bankAcct || bank.glAcct) || bank.label)} | | ${ckpMoney(c.amount)} |
`, "width:7.6in");
};
/* ── whole document ── */
const ckpDoc = (checks, opts) => {
const o = opts || {};
const D = window.DMS || {};
const cfg = D.checkConfig ? D.checkConfig() : { accounts: [] };
// RC35 (brd): Check setup's company lines, else the store's check header, else its print name + address (K2BPrint.checkCompany)
const company = window.K2BPrint ? window.K2BPrint.checkCompany(cfg) : { name: "", addr1: "", addr2: "", phone: "" };
// (ldg) a reprint uses the print data the server stored with the check (what the paper says: company lines, bank name /
// city / fractional, stock and signature settings); the routing / account numbers and the printer offsets stay live settings
const liveBank = (c) => (cfg.accounts || []).find(a => a.id === (c.bankId || o.bankId || cfg.defaultId)) || (cfg.accounts || [])[0] || {};
const bankOf = (c) => (c && c.printData && c.printData.bank) ? { ...liveBank(c), ...c.printData.bank } : liveBank(c);
const companyOf = (c) => (c && c.printData && c.printData.company) ? { ...company, ...c.printData.company } : company;
const stock = o.stock || bankOf(checks[0] || {}).stock || "top";
const pages = [];
if (stock === "3up") {
let pos = Math.min(3, Math.max(1, parseInt(o.startPos, 10) || 1)) - 1;
let page = "";
checks.forEach((c) => { const b = { ...bankOf(c), stock: "3up" }; page += ckpFace(c, b, companyOf(c), 0, pos * 3.5, o); pos++; if (pos === 3) { pages.push(page); page = ""; pos = 0; } });
if (page) pages.push(page);
} else {
checks.forEach((c) => {
const b = { ...bankOf(c), stock: "top" }; const co = companyOf(c);
pages.push(ckpFace(c, b, co, 0, 0, o) + (o.alignment ? "" : ckpStub(c, b, co, 3.5, "PAYEE COPY — DETACH") + ckpStub(c, b, co, 7.25, "FILE COPY")));
});
}
const font = cfg.micrFont ? `@font-face{font-family:"K2BMICR";src:url(${cfg.micrFont});}` : "";
const sid = (window.K2BStore && window.K2BStore.pageId()) || ""; // RC35 (brd): which store printed it
return `${ckpEsc(o.title || "Checks")}
Print at 100% / Actual size, no headers or footers. Load ${stock === "3up" ? "3-per-page" : "check-on-top"} stock face ${o.faceUp === false ? "down" : "as your printer requires"}${o.fallback ? " · No MICR font found — this bank line is for a TEST only, not for real checks." : ""}${o.alignment ? " · ALIGNMENT TEST: print on plain paper, hold it over a blank check against the light." : ""}
${pages.map(p => `${p}
`).join("")}
`;
};
/* ── open the print window (popup, else in-app overlay) ── */
const ckpOpen = (docHtml, title) => {
if (window.K2BPrint && window.K2BPrint._capture(docHtml)) return; // RC35 (brd): the print test reads it (K2BPrint.lastDoc)
let w = null;
try { w = window.open("", "_blank", "width=900,height=1100"); } catch (e) { w = null; }
if (w && w.document) {
w.document.write(docHtml.replace("