From eda65ef3b73a6418599f5ba95d6a0c15302719bc Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Thu, 4 Jun 2026 08:25:22 +0700 Subject: [PATCH] fix: improve print type detection logic and cash drawer triggering for Bluetooth thermal printers --- static/src/js/pos_receipt_printer.js | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/static/src/js/pos_receipt_printer.js b/static/src/js/pos_receipt_printer.js index 1ed3912..30fcde3 100755 --- a/static/src/js/pos_receipt_printer.js +++ b/static/src/js/pos_receipt_printer.js @@ -77,7 +77,7 @@ patch(PosPrinterService.prototype, { * This gives us access to real model data regardless of basic_receipt mode. */ async print(component, props, options) { - // Capture the order object from props before rendering to HTML + // Capture the order object and print type flags from props before rendering to HTML if (props && props.order) { this._currentPrintOrder = props.order; this._currentPrintBasic = !!props.basic_receipt; @@ -108,18 +108,38 @@ patch(PosPrinterService.prototype, { console.log('[BluetoothPrint] Element classes:', el?.className); // Determine print context + // Priority: hardware proxy context (set by pos_cash_drawer_cash_only) > local flags > HTML heuristics const pos = this.env?.services?.pos; const currentPrintContext = pos?.hardwareProxy?.currentPrintContext; const order = this._currentPrintOrder || currentPrintContext?.order || pos?.getOrder(); let printType = currentPrintContext?.printType; if (!printType) { + // Fallback heuristics when hardware proxy context is not yet set + // (can happen if bluetooth module loads before cash_drawer module, or context race) if (this._currentPrintBasic) { + // basic_receipt flag set in print() props → table checker printType = 'CHECKER'; } else if (el && el.querySelector && el.querySelector('.new-changes, .preset-name, .o-employee-name, .order-ref-prefix')) { + // HTML contains table-checker specific elements printType = 'CHECKER'; + } else if (el && el.querySelector && el.querySelector('.proforma-invoice, .bill-receipt, .pre-payment')) { + // HTML contains proforma/bill specific elements + printType = 'BILL'; } else { - printType = 'PAYMENT'; + // Cannot determine from HTML — check order state. + // An order with state 'open' (not yet paid) printed is a BILL/proforma. + // An order with state 'paid' is a PAYMENT receipt. + const orderState = order?.state; + if (orderState && orderState !== 'paid' && orderState !== 'invoiced') { + // Order not yet paid — this must be a bill/proforma print + printType = 'BILL'; + } else if (orderState === 'paid' || orderState === 'invoiced') { + printType = 'PAYMENT'; + } else { + // Unknown state — fail safe: treat as BILL (no drawer) + printType = 'BILL'; + } } } @@ -130,8 +150,9 @@ patch(PosPrinterService.prototype, { this._currentPrintBasic = true; } + // Cash drawer should only open for actual cash payment receipts this._isCashPayment = printType === 'PAYMENT' && order && (typeof order.isPaidWithCash === 'function' ? order.isPaidWithCash() : false); - console.log(`[BluetoothPrint] printHtml context check - printType: ${printType}, order: ${order?.pos_reference}, resolved isCashPayment: ${this._isCashPayment}`); + console.log(`[BluetoothPrint] printHtml context - printType: ${printType}, orderState: ${order?.state}, isCashPayment: ${this._isCashPayment}`); // Check if a Bluetooth printer is configured (from localStorage) const storage = new BluetoothPrinterStorage();