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 6e4f0f2..a823a6d 100644 --- a/addons/dine360_qz_printer/static/src/js/qz_wrapper.js +++ b/addons/dine360_qz_printer/static/src/js/qz_wrapper.js @@ -4,6 +4,7 @@ import { patch } from "@web/core/utils/patch"; import { ReceiptScreen } from "@point_of_sale/app/screens/receipt_screen/receipt_screen"; const RECEIPT_COLUMNS = 42; +const NEWLINE = "\r\n"; function normalizeReceiptText(text) { return (text || "") @@ -34,20 +35,87 @@ function wrapLine(line, width = RECEIPT_COLUMNS) { return wrapped; } -function buildEscPosReceipt(receiptElement) { +function money(value, currency) { + const amount = Number(value || 0).toFixed(2); + return currency?.symbol ? `${currency.symbol}${amount}` : amount; +} + +function leftRight(left, right, width = RECEIPT_COLUMNS) { + const cleanLeft = String(left || ""); + const cleanRight = String(right || ""); + const space = Math.max(1, width - cleanLeft.length - cleanRight.length); + return `${cleanLeft}${" ".repeat(space)}${cleanRight}`; +} + +function buildReceiptLinesFromOrder(order) { + const currency = order?.pos?.currency; + const lines = []; + const company = order?.pos?.company; + const client = order?.get_partner?.(); + + if (company?.name) { + lines.push(company.name); + } + if (company?.phone) { + lines.push(company.phone); + } + lines.push("-".repeat(RECEIPT_COLUMNS)); + + const receiptNumber = order?.name || order?.uid || ""; + if (receiptNumber) { + lines.push(`Receipt: ${receiptNumber}`); + } + lines.push(new Date().toLocaleString()); + if (client?.name) { + lines.push(`Customer: ${client.name}`); + } + lines.push("-".repeat(RECEIPT_COLUMNS)); + + for (const orderline of order?.get_orderlines?.() || []) { + const product = orderline.get_product?.(); + const name = product?.display_name || product?.name || ""; + const qty = orderline.get_quantity?.() || 0; + const total = orderline.get_price_with_tax?.() ?? orderline.get_display_price?.() ?? 0; + for (const wrapped of wrapLine(name, RECEIPT_COLUMNS)) { + lines.push(wrapped); + } + lines.push(leftRight(` ${qty} x`, money(total, currency))); + } + + lines.push("-".repeat(RECEIPT_COLUMNS)); + lines.push(leftRight("TOTAL", money(order?.get_total_with_tax?.(), currency))); + const tax = order?.get_total_tax?.(); + if (tax) { + lines.push(leftRight("Tax", money(tax, currency))); + } + const change = order?.get_change?.(); + if (change) { + lines.push(leftRight("Change", money(change, currency))); + } + lines.push("-".repeat(RECEIPT_COLUMNS)); + lines.push("Thank you"); + return lines; +} + +function buildReceiptLines(receiptElement, order) { + const domLines = normalizeReceiptText(receiptElement?.innerText || ""); + if (domLines.length > 1) { + return domLines; + } + return buildReceiptLinesFromOrder(order); +} + +function buildEscPosReceipt(receiptElement, order) { const ESC = "\x1B"; const GS = "\x1D"; - const lines = normalizeReceiptText(receiptElement.innerText); - const body = lines.flatMap((line) => wrapLine(line)).join("\n"); + const lines = buildReceiptLines(receiptElement, order); + const body = lines.flatMap((line) => wrapLine(line)).join(NEWLINE); 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", + body, + NEWLINE + NEWLINE + NEWLINE, GS + "V" + "\x00", // Full cut on Epson-compatible printers ].join(""); } @@ -76,16 +144,9 @@ patch(ReceiptScreen.prototype, { return false; } - const printData = buildEscPosReceipt(receiptElement); + const printData = buildEscPosReceipt(receiptElement, this.currentOrder); - await qz.print(config, [ - { - type: "raw", - format: "command", - flavor: "plain", - data: printData, - } - ]); + await qz.print(config, [printData]); if (this.currentOrder) { this.currentOrder._printed = true;