pos_closing_receipt/README.md
2026-05-21 20:30:54 +07:00

4.3 KiB

pos_closing_receipt

Odoo 19 custom module — automatically prints a session closing summary via the browser print dialog when a POS session is closed.


Features

  • Intercepts the POS session closing flow.
  • Reads the real session name from the server (the sequence assigned at session opening, e.g. Mie Mapan Barata00001).
  • Collects payment totals per payment method (cash + all non-cash methods).
  • Triggers the browser's native print dialog (window.print()) — no IoT Box or network printer required.
  • Prints cleanly to thermal receipt printers (≤ 80mm paper) via the browser.
  • Fault-tolerant: print failures are caught and logged; they never block the session closing process.

Receipt Layout

     Mie Mapan Barata00001
      SESSION CLOSING SUMMARY
--------------------------------
Cashier         Elisa Ayu
Date/Time       2026-05-21 20:25:00
--------------------------------
Cash                     Rp 0,00
BCA                 Rp 500.000,00
BTN                 Rp 250.000,00
GOPAY               Rp 100.000,00
================================
TOTAL               Rp 850.000,00
--------------------------------
         *** Session Closed ***

Requirements

Dependency Notes
point_of_sale Core Odoo 19 POS module
pos_hr Required for cashier name lookup via pos.getCashier()

Installation

  1. Copy the pos_closing_receipt folder to your customaddons/ directory.
  2. Add the path to addons_path in odoo.conf if not already included.
  3. Restart the Odoo server.
  4. Activate Developer Mode in Odoo settings.
  5. Go to Apps → search for pos_closing_receiptInstall.

Or install via CLI:

python odoo-bin -u pos_closing_receipt --config=odoo.conf -d <your_database> --stop-after-init

How It Works

Sequence Timing

In Odoo, pos.session.name starts as "/" (the default) and gets the real sequence (e.g. Mie Mapan Barata00001) only when the session is opened via set_opening_control(). The frontend JS never receives this updated value, so we perform one server-side read before closing:

const result = await this.pos.data.read("pos.session", [this.pos.session.id], ["name"]);
realSessionName = result[0].name; // → "Mie Mapan Barata00001"

Print Flow

User clicks "Close" in POS closing popup
    │
    ├─ 1. Fetch real session name from server (pos.data.read)
    ├─ 2. Collect payment data from props (default_cash_details, non_cash_payment_methods)
    ├─ 3. Call super.closeSession() — standard Odoo closing
    │
    └─ 4. Session state === "closed"?
           └─ Yes → printer.print(ClosingReceipt, data, { webPrintFallback: true })
                      └─ Browser print dialog opens

Web Print (No IoT Box)

Uses Odoo's built-in printer service with webPrintFallback: true — the same mechanism used by the standard POS order receipt:

  • If an IoT Box printer is configured → sends to the hardware printer.
  • If no printer is configured → falls back to window.print() (browser dialog).

File Structure

pos_closing_receipt/
├── __init__.py
├── __manifest__.py
├── README.md
└── static/
    └── src/
        └── app/
            ├── closing_receipt.xml       # OWL template (receipt layout + inline CSS)
            └── closing_receipt_patch.js  # Patch for ClosePosPopup + ClosingReceipt component

Customization

Change the receipt layout

Edit static/src/app/closing_receipt.xml. The template uses standard HTML table layout with inline CSS for maximum printer compatibility.

Add a company logo or header

Add a <div> above the session name section in the XML template. Use base64-encoded images if needed.

Change paper width

The default max-width is 320px (80mm thermal). For 58mm paper, reduce to 220px:

<div class="pos-receipt" style="... max-width: 220px; ...">

Changelog

v1.0.0

  • Initial release for Odoo 19.
  • Web print via window.print() (no IoT Box required).
  • Reads real session sequence name from server at print time.
  • Fault-tolerant: print errors never block session closing.