refactor: replace Odoo printer service with direct window-based HTML rendering for closing receipts

This commit is contained in:
Suherdy Yacob 2026-06-05 09:28:38 +07:00
parent 9710d798b4
commit 527b0f63bf
2 changed files with 128 additions and 22 deletions

View File

@ -21,23 +21,11 @@
border: 0 !important; border: 0 !important;
} }
.pos-closing-receipt-print {
width: 100% !important;
}
.pos-closing-receipt-print .pos-receipt { .pos-closing-receipt-print .pos-receipt {
padding-left: 20px !important; padding-left: 20px !important;
padding-right: 20px !important; padding-right: 20px !important;
box-sizing: border-box !important; box-sizing: border-box !important;
} }
.render-container .pos-closing-receipt-print .pos-receipt {
font-size: 28px !important;
width: 320px !important;
max-width: 320px !important;
padding: 12px !important;
margin: 0 auto !important;
}
} }

View File

@ -165,16 +165,134 @@ patch(ClosePosPopup.prototype, {
this.pos.env.services.ui.block(); this.pos.env.services.ui.block();
} }
try { try {
const printResult = await this.printer.print(ClosingReceipt, receiptData, { let cashRow = "";
webPrintFallback: true, if (receiptData.cashPayment) {
}); cashRow = `
console.log("[pos_closing_receipt] Print operation resolved with result:", printResult); <tr>
<td style="padding:3px 0;">${receiptData.cashPayment.name}</td>
// Explicit safety delay to let printer buffers flush (especially for Bluetooth/JSPM) <td style="text-align:right;padding:3px 0;">${receiptData.cashPayment.formattedAmount}</td>
const delayMs = 1500; </tr>`;
console.log(`[pos_closing_receipt] Applying safety buffer delay of ${delayMs}ms...`); }
await new Promise((resolve) => setTimeout(resolve, delayMs));
console.log("[pos_closing_receipt] Safety buffer complete."); const nonCashRows = (receiptData.nonCashPayments || []).map(
(pm) => `
<tr>
<td style="padding:3px 0;">${pm.name}</td>
<td style="text-align:right;padding:3px 0;">${pm.formattedAmount}</td>
</tr>`
);
const html = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Closing Summary</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Courier New', Courier, monospace;
font-size: 28px;
background: #fff;
color: #000;
}
.receipt {
width: 100%;
max-width: 320px;
margin: 0 auto;
padding: 12px;
}
.center { text-align: center; }
.header-title {
font-size: 36px;
font-weight: bold;
letter-spacing: 1px;
text-transform: uppercase;
}
.header-sub {
margin-top: 4px;
font-size: 24px;
letter-spacing: 2px;
}
.dashed { border-top: 1px dashed #000; margin: 8px 0; }
.solid { border-top: 1px solid #000; margin: 8px 0; }
table { width: 100%; border-collapse: collapse; margin-bottom: 8px; }
td { padding: 5px 0; }
.right { text-align: right; }
.bold { font-weight: bold; }
.total-row td { font-weight: bold; font-size: 32px; padding: 6px 0; }
.footer {
text-align: center;
margin-top: 12px;
font-size: 24px;
letter-spacing: 1px;
}
.feed { margin-top: 28px; }
@media print {
@page { size: 80mm auto; margin: 3mm; }
}
</style>
</head>
<body>
<div class="receipt">
<div class="center" style="margin-bottom:10px;">
<div class="header-title">${receiptData.sessionName}</div>
<div class="header-sub">SESSION CLOSING SUMMARY</div>
</div>
<div class="dashed"></div>
<table>
<tr>
<td class="bold">Cashier</td>
<td class="right">${receiptData.cashierName}</td>
</tr>
<tr>
<td class="bold">Date/Time</td>
<td class="right" style="font-size:24px;">${receiptData.closingTime}</td>
</tr>
</table>
<div class="dashed"></div>
<table>
${cashRow}
${nonCashRows.join("")}
</table>
<div class="solid"></div>
<table>
<tr class="total-row">
<td>TOTAL</td>
<td class="right">${receiptData.grandTotal}</td>
</tr>
</table>
<div class="dashed"></div>
<div class="footer">*** Session Closed ***</div>
<div class="feed">&nbsp;</div>
</div>
<script>
window.onload = function() {
window.print();
setTimeout(function() { window.close(); }, 1000);
};
</script>
</body>
</html>`;
const printWindow = window.open("", "_blank", "width=400,height=600");
if (!printWindow) {
const notification = this.pos?.env?.services?.notification;
if (notification) {
notification.add(
_t("Pop-up blocked. Please allow pop-ups for this site and try again to print closing receipt."),
{ type: "warning" }
);
} else {
alert("Pop-up blocked. Please allow pop-ups for this site and try again to print closing receipt.");
}
return;
}
printWindow.document.open();
printWindow.document.write(html);
printWindow.document.close();
// Safety delay to allow window to open and print dialog to spawn before proceeding
await new Promise((resolve) => setTimeout(resolve, 1500));
} catch (err) { } catch (err) {
console.error("[pos_closing_receipt] CRITICAL: Failed to print closing receipt:", err); console.error("[pos_closing_receipt] CRITICAL: Failed to print closing receipt:", err);
} finally { } finally {