refactor: rename receipt print fields and implement multi-copy printing via a single print dialog

This commit is contained in:
Suherdy Yacob 2026-05-13 15:13:26 +07:00
parent f111296ecc
commit 71fc1ea0d2
4 changed files with 64 additions and 18 deletions

View File

@ -3,14 +3,13 @@ from odoo import fields, models, api
class PosConfig(models.Model): class PosConfig(models.Model):
_inherit = 'pos.config' _inherit = 'pos.config'
receipt_print_copies = fields.Integer(string='Default Number of Copies', default=1, help="Default number of copies to print for receipts.") imin_print_copies = fields.Integer(string='Default Print Copies', default=1, help="Default number of copies to print.")
receipt_paper_size = fields.Selection([ imin_paper_size = fields.Selection([
('57mm', '57mm (ISO 57)'), ('57mm', '57mm (ISO 57)'),
('58mm', '58mm'), ('58mm', '58mm'),
('80mm', '80mm'), ('80mm', '80mm'),
('80x210mm', '80 x 210 mm'), ('80x210mm', '80x210mm'),
('80x297mm', '80 x 297 mm'), ('80x297mm', '80x297mm'),
('112mm', '112mm'), ('112mm', '112mm'),
('A4', 'A4'), ('A4', 'A4'),
], string='Default Paper Size', default='57mm', help="Default paper size for browser print dialog.") ], string='Default Paper Size', default='57mm', help="Default paper size for browser print dialog.")

View File

@ -3,5 +3,5 @@ from odoo import fields, models
class ResConfigSettings(models.TransientModel): class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings' _inherit = 'res.config.settings'
pos_receipt_print_copies = fields.Integer(related='pos_config_id.receipt_print_copies', readonly=False) pos_imin_print_copies = fields.Integer(related='pos_config_id.imin_print_copies', readonly=False)
pos_receipt_paper_size = fields.Selection(related='pos_config_id.receipt_paper_size', readonly=False) pos_imin_paper_size = fields.Selection(related='pos_config_id.imin_paper_size', readonly=False)

View File

@ -2,20 +2,67 @@
import { PosStore } from "@point_of_sale/app/services/pos_store"; import { PosStore } from "@point_of_sale/app/services/pos_store";
import { patch } from "@web/core/utils/patch"; import { patch } from "@web/core/utils/patch";
import { OrderReceipt } from "@point_of_sale/app/screens/receipt_screen/receipt/order_receipt";
import { waitImages } from "@point_of_sale/utils";
patch(PosStore.prototype, { patch(PosStore.prototype, {
async printReceipt(params = {}) { async printReceipt(params = {}) {
const copies = this.config.receipt_print_copies || 1; const config = this.config;
const paperSize = this.config.receipt_paper_size || '57mm'; const copies = config.imin_print_copies || 1;
const paperSize = config.imin_paper_size || '57mm';
// Inject CSS for paper size to guide browser print dialog // Inject CSS for paper size to guide browser print dialog
this._injectReceiptPaperSizeCSS(paperSize); this._injectReceiptPaperSizeCSS(paperSize);
let result; if (copies <= 1) {
// Print multiple copies return super.printReceipt(params);
for (let i = 0; i < copies; i++) {
result = await super.printReceipt(params);
} }
const { basic = false, order = this.getOrder(), printBillActionTriggered = false } = params;
// Manually render the receipt element
const el = await this.printer.renderer.toHtml(OrderReceipt, {
order,
basic_receipt: basic,
});
await waitImages(el);
// Duplicate the receipt content in a container
const container = document.createElement('div');
container.classList.add('pos-multi-receipt-container');
for (let i = 0; i < copies; i++) {
const clone = el.cloneNode(true);
if (i < copies - 1) {
// Add a page break between receipts
clone.style.breakAfter = "page";
// Add a small margin for thermal printers that don't support hard breaks
clone.style.marginBottom = "20px";
}
container.appendChild(clone);
}
// Print the combined container (only one print dialog will show)
const result = await this.printer.printHtml(container, this.printOptions);
// Update print count logic (matching Odoo core)
if (!printBillActionTriggered && result) {
const count = order.nb_print ? order.nb_print + 1 : 1;
if (order.isSynced) {
const wasDirty = order.isDirty();
await this.data.write("pos.order", [order.id], { nb_print: count });
if (!wasDirty) {
order._dirty = false;
}
} else {
order.nb_print = count;
}
}
if (result?.warningCode) {
this.displayPrinterWarning(result, "Receipt Printer");
}
return result; return result;
}, },

View File

@ -9,12 +9,12 @@
<setting string="Receipt Print Defaults" help="Set default printing behavior for receipts."> <setting string="Receipt Print Defaults" help="Set default printing behavior for receipts.">
<div class="content-group"> <div class="content-group">
<div class="row"> <div class="row">
<label for="pos_receipt_print_copies" class="col-lg-4 o_light_label" string="Number of Copies"/> <label for="pos_imin_print_copies" class="col-lg-4 o_light_label" string="Number of Copies"/>
<field name="pos_receipt_print_copies" class="col-lg-2"/> <field name="pos_imin_print_copies" class="col-lg-2"/>
</div> </div>
<div class="row mt-2"> <div class="row mt-2">
<label for="pos_receipt_paper_size" class="col-lg-4 o_light_label" string="Paper Size"/> <label for="pos_imin_paper_size" class="col-lg-4 o_light_label" string="Paper Size"/>
<field name="pos_receipt_paper_size" class="col-lg-4"/> <field name="pos_imin_paper_size" class="col-lg-4"/>
</div> </div>
</div> </div>
</setting> </setting>