diff --git a/addons/dine360_qz_printer/static/src/js/qz_wrapper.js b/addons/dine360_qz_printer/static/src/js/qz_wrapper.js index 34c2dcb..8391feb 100644 --- a/addons/dine360_qz_printer/static/src/js/qz_wrapper.js +++ b/addons/dine360_qz_printer/static/src/js/qz_wrapper.js @@ -3,6 +3,55 @@ import { patch } from "@web/core/utils/patch"; import { ReceiptScreen } from "@point_of_sale/app/screens/receipt_screen/receipt_screen"; +const RECEIPT_COLUMNS = 42; + +function normalizeReceiptText(text) { + return (text || "") + .replace(/\u00a0/g, " ") + .replace(/[ \t]+/g, " ") + .split("\n") + .map((line) => line.trim()) + .filter(Boolean); +} + +function wrapLine(line, width = RECEIPT_COLUMNS) { + if (line.length <= width) { + return [line]; + } + const wrapped = []; + let remaining = line; + while (remaining.length > width) { + let breakpoint = remaining.lastIndexOf(" ", width); + if (breakpoint <= 0) { + breakpoint = width; + } + wrapped.push(remaining.slice(0, breakpoint).trimEnd()); + remaining = remaining.slice(breakpoint).trimStart(); + } + if (remaining) { + wrapped.push(remaining); + } + return wrapped; +} + +function buildEscPosReceipt(receiptElement) { + const ESC = "\x1B"; + const GS = "\x1D"; + const lines = normalizeReceiptText(receiptElement.innerText); + const body = lines.flatMap((line) => wrapLine(line)).join("\n"); + + return [ + ESC + "@", // Initialize printer + ESC + "a" + "\x01", // Center + ESC + "E" + "\x01", // Bold on + body, + ESC + "E" + "\x00", // Bold off + ESC + "a" + "\x00", // Left align + "\n\n\n", + GS + "V" + "\x00", // Full cut on Epson-compatible printers + ].join(""); +} + patch(ReceiptScreen.prototype, { async printReceipt() { if (this.pos.config.use_qz_printer && this.pos.config.qz_printer_name) { @@ -17,52 +66,24 @@ patch(ReceiptScreen.prototype, { } const printerName = this.pos.config.qz_printer_name; - const config = qz.configs.create(printerName); + const config = qz.configs.create(printerName, { + encoding: "CP437", + spool: { end: "\n" }, + }); - // Get inner HTML of receipt - const receiptElement = document.querySelector('.pos-receipt-container'); + const receiptElement = document.querySelector(".pos-receipt") || document.querySelector(".pos-receipt-container"); if (!receiptElement) { return false; } - const receiptHtml = receiptElement.innerHTML; - - // Odoo receipt styling is necessary for QZ pixel print - const printData = ` - - - - - -
- ${receiptHtml} -
- - - `; + const printData = buildEscPosReceipt(receiptElement); await qz.print(config, [ { - type: 'pixel', - format: 'html', - flavor: 'plain', - data: printData + type: "raw", + format: "plain", + flavor: "plain", + data: printData, } ]);