Fix ticket print not opening (variable order) and add error handling
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled

This commit is contained in:
2026-07-18 17:14:13 +00:00
parent ee5075ea2e
commit 667cd3b1eb
2 changed files with 47 additions and 38 deletions

View File

@@ -1660,41 +1660,39 @@ const POS = (() => {
function printTicket() { function printTicket() {
const src = document.getElementById('ticketContent'); const src = document.getElementById('ticketContent');
if (!src) return; if (!src) { console.warn('printTicket: ticketContent not found'); return; }
// Paper width: 58 mm -> 48 mm printable; 80 mm -> 72 mm printable. try {
// Paper width: 58 mm -> 48 mm printable; 80 mm -> 72 mm printable.
const paperWidth = parseInt(rc('paper_width', '80'), 10) || 80;
const is58 = paperWidth === 58;
const printWidth = is58 ? 48 : 72;
const fontSize = is58 ? '12pt' : '14pt';
const smallFont = is58 ? '10pt' : '12pt';
const nameMax = is58 ? '20mm' : '38mm';
let iframe = document.getElementById('ticketPrintFrame');
if (!iframe) {
iframe = document.createElement('iframe');
iframe.id = 'ticketPrintFrame';
iframe.style.position = 'fixed';
iframe.style.left = '-9999px';
iframe.style.top = '0';
iframe.style.width = printWidth + 'mm';
iframe.style.border = '0';
document.body.appendChild(iframe);
}
let iframe = document.getElementById('ticketPrintFrame'); const doc = iframe.contentDocument || iframe.contentWindow.document;
if (!iframe) { doc.open();
iframe = document.createElement('iframe'); doc.write(`<!doctype html>
iframe.id = 'ticketPrintFrame';
iframe.style.position = 'fixed';
iframe.style.left = '-9999px';
iframe.style.top = '0';
iframe.style.width = printWidth + 'mm';
iframe.style.border = '0';
document.body.appendChild(iframe);
}
const paperWidth = parseInt(rc('paper_width', '80'), 10) || 80;
const is58 = paperWidth === 58;
// Render at the real printable width so text is not scaled down by the driver.
const printWidth = is58 ? 48 : 72;
const fontSize = is58 ? '12pt' : '14pt';
const smallFont = is58 ? '10pt' : '12pt';
const nameMax = is58 ? '20mm' : '38mm';
const doc = iframe.contentDocument || iframe.contentWindow.document;
doc.open();
doc.write(`<!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<style> <style>
@page { margin: 0; size: ${printWidth}mm auto; } @page { margin: 0; size: ${printWidth}mm auto; }
* { box-sizing: border-box; } * { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: auto; overflow: visible; background: #fff; color: #000; font-family: 'Courier New', Courier, 'Lucida Console', monospace; font-size: ${fontSize}; line-height: 1.55; -webkit-font-smoothing: none; -moz-osx-font-smoothing: unset; text-rendering: geometricPrecision; image-rendering: pixelated; } html, body { margin: 0; padding: 0; height: auto; overflow: visible; background: #fff; color: #000; font-family: 'Courier New', Courier, 'Lucida Console', monospace; font-size: ${fontSize}; line-height: 1.55; -webkit-font-smoothing: none; -moz-osx-font-smoothing: unset; text-rendering: geometricPrecision; }
body { width: ${printWidth}mm; } body { width: ${printWidth}mm; }
.ticket { width: ${printWidth}mm; padding: 3mm 2.5mm 4mm; border: none !important; box-shadow: none !important; } .ticket { width: ${printWidth}mm; padding: 3mm 2.5mm 4mm; border: none !important; box-shadow: none !important; }
.item-line-wide { display: grid !important; grid-template-columns: ${is58 ? '9mm 1fr auto' : '10mm 1fr auto auto'} !important; gap: 2mm; font-size: ${fontSize}; margin-bottom: 2.5mm; padding-left: 1mm; align-items: start; } .item-line-wide { display: grid !important; grid-template-columns: ${is58 ? '9mm 1fr auto' : '10mm 1fr auto auto'} !important; gap: 2mm; font-size: ${fontSize}; margin-bottom: 2.5mm; padding-left: 1mm; align-items: start; }
@@ -1710,24 +1708,35 @@ const POS = (() => {
.divider-double { border: none; border-top: 2px solid #333; margin: 5px 0; } .divider-double { border: none; border-top: 2px solid #333; margin: 5px 0; }
.footer-section { text-align: center; margin-top: 8px; font-size: ${smallFont}; color: #000; line-height: 1.45; } .footer-section { text-align: center; margin-top: 8px; font-size: ${smallFont}; color: #000; line-height: 1.45; }
.payment-section, .total-section { width: 100%; } .payment-section, .total-section { width: 100%; }
img { max-width: 100%; height: auto; image-rendering: pixelated; } img { max-width: 100%; height: auto; }
</style> </style>
</head> </head>
<body>${src.innerHTML}</body> <body>${src.innerHTML}</body>
</html>`); </html>`);
doc.close(); doc.close();
// Measure real content height and set exact page size (avoids phantom 3276 mm). // Measure real content height and set exact page size (avoids phantom 3276 mm).
const bodyEl = doc.body; const bodyEl = doc.body;
const heightPx = Math.max(bodyEl.scrollHeight, bodyEl.offsetHeight); const heightPx = Math.max(bodyEl.scrollHeight, bodyEl.offsetHeight);
const heightMm = Math.ceil((heightPx * 25.4 / 96) + 5); const heightMm = Math.ceil((heightPx * 25.4 / 96) + 5);
const exactPage = doc.createElement('style'); const exactPage = doc.createElement('style');
exactPage.textContent = `@page { margin: 0; size: ${printWidth}mm ${heightMm}mm; }`; exactPage.textContent = `@page { margin: 0; size: ${printWidth}mm ${heightMm}mm; }`;
doc.head.appendChild(exactPage); doc.head.appendChild(exactPage);
iframe.contentWindow.focus(); iframe.contentWindow.focus();
setTimeout(() => { iframe.contentWindow.print(); }, 150); setTimeout(() => {
try {
iframe.contentWindow.print();
} catch (e) {
console.error('printTicket: iframe.print failed', e);
window.print();
}
}, 200);
} catch (e) {
console.error('printTicket error:', e);
alert('No se pudo preparar la impresion del ticket. Revise la consola.');
}
} }
// ─── Thermal Printing ───────────────── // ─── Thermal Printing ─────────────────

View File

@@ -6,7 +6,7 @@
// The fetch handler normalizes static asset URLs (strips ?v= query strings) // The fetch handler normalizes static asset URLs (strips ?v= query strings)
// so templates can use cache-busting query params freely. // so templates can use cache-busting query params freely.
const VERSION = 50; const VERSION = 51;
const CACHE_NAME = 'nexus-pos-v' + VERSION; const CACHE_NAME = 'nexus-pos-v' + VERSION;
const APP_SHELL = [ const APP_SHELL = [