forked from alaguraj/odoo-testing-addons
Print QZ receipts as raw ESC POS
This commit is contained in:
parent
66af3e010a
commit
43284d9f1a
@ -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 = `
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
@page { margin: 0; }
|
||||
body {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
width: 300px; /* Adjust based on printer paper width, 80mm = ~300px */
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
.pos-receipt { width: 100%; text-align: center; }
|
||||
.pos-receipt .pos-receipt-logo { max-width: 50%; margin: 0 auto; }
|
||||
.pos-receipt .pos-receipt-contact { text-align: center; font-size: 12px; margin-bottom: 10px; }
|
||||
.pos-receipt .receipt-orderlines { width: 100%; text-align: left; }
|
||||
.pos-receipt .receipt-orderlines td { padding: 2px 0; }
|
||||
.pos-receipt .receipt-total { width: 100%; font-weight: bold; font-size: 16px; margin-top: 10px; text-align: right; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="pos-receipt">
|
||||
${receiptHtml}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
const printData = buildEscPosReceipt(receiptElement);
|
||||
|
||||
await qz.print(config, [
|
||||
{
|
||||
type: 'pixel',
|
||||
format: 'html',
|
||||
flavor: 'plain',
|
||||
data: printData
|
||||
type: "raw",
|
||||
format: "plain",
|
||||
flavor: "plain",
|
||||
data: printData,
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user