From ce1fef9113f4ab0e52061fb73261ae8ca5b71976 Mon Sep 17 00:00:00 2001 From: "Pedram (pebr)" Date: Mon, 26 Feb 2024 10:39:12 +0100 Subject: [PATCH] [FIX] point_of_sale: ensure QR code loads in auto-printed receipts Prior to this commit, enabling auto receipt printing resulted in the QR code not being printed on the receipt. This was due to the QR image being fetched post printing. This commit addresses the issue by first loading the QR code image, then sending it to the printer, ensuring its presence on the printed receipt. opw-3763169 closes odoo/odoo#155354 Signed-off-by: Joseph Caburnay (jcb) --- .../static/src/app/printer/printer_service.js | 3 ++ .../partner_editor/partner_editor.js | 32 ++++++------------- addons/point_of_sale/static/src/utils.js | 30 +++++++++++++++++ 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/addons/point_of_sale/static/src/app/printer/printer_service.js b/addons/point_of_sale/static/src/app/printer/printer_service.js index 79f93d3c9ed..ad07e55730c 100644 --- a/addons/point_of_sale/static/src/app/printer/printer_service.js +++ b/addons/point_of_sale/static/src/app/printer/printer_service.js @@ -1,4 +1,5 @@ /** @odoo-module **/ +import { loadAllImages } from "@point_of_sale/utils"; export const printerService = { dependencies: ["renderer"], @@ -36,6 +37,8 @@ export class PrinterService { } async print(component, props, options) { const el = await this.renderer.toHtml(component, props); + // Load all images before printing + await loadAllImages(el); return await this.printHtml(el, options); } is = () => Boolean(this.device?.printReceipt); diff --git a/addons/point_of_sale/static/src/app/screens/partner_list/partner_editor/partner_editor.js b/addons/point_of_sale/static/src/app/screens/partner_list/partner_editor/partner_editor.js index 70d17a9685b..daed0d02cfe 100644 --- a/addons/point_of_sale/static/src/app/screens/partner_list/partner_editor/partner_editor.js +++ b/addons/point_of_sale/static/src/app/screens/partner_list/partner_editor/partner_editor.js @@ -6,6 +6,7 @@ import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup"; import { useService } from "@web/core/utils/hooks"; import { Component, useState } from "@odoo/owl"; import { usePos } from "@point_of_sale/app/store/pos_hook"; +import { loadImage } from "@point_of_sale/utils"; export class PartnerDetailsEdit extends Component { static template = "point_of_sale.PartnerDetailsEdit"; @@ -92,7 +93,14 @@ export class PartnerDetailsEdit extends Component { }); } else { const imageUrl = await getDataURLFromFile(file); - const loadedImage = await this._loadImage(imageUrl); + const loadedImage = await loadImage(imageUrl, { + onError: () => { + this.popup.add(ErrorPopup, { + title: _t("Loading Image Error"), + body: _t("Encountered error when loading image. Please try again."), + }); + } + }); if (loadedImage) { const resizedImage = await this._resizeImage(loadedImage, 800, 600); this.changes.image_1920 = resizedImage.toDataURL(); @@ -118,28 +126,6 @@ export class PartnerDetailsEdit extends Component { ctx.drawImage(img, 0, 0, width, height); return canvas; } - /** - * Loading image is converted to a Promise to allow await when - * loading an image. It resolves to the loaded image if successful, - * else, resolves to false. - * - * [Source](https://stackoverflow.com/questions/45788934/how-to-turn-this-callback-into-a-promise-using-async-await) - */ - _loadImage(url) { - return new Promise((resolve) => { - const img = new Image(); - img.addEventListener("load", () => resolve(img)); - img.addEventListener("error", () => { - this.popup.add(ErrorPopup, { - title: _t("Loading Image Error"), - body: _t("Encountered error when loading image. Please try again."), - }); - resolve(false); - }); - img.src = url; - }); - } - isFieldCommercialAndPartnerIsChild(field) { return ( this.pos.isChildPartner(this.props.partner) && diff --git a/addons/point_of_sale/static/src/utils.js b/addons/point_of_sale/static/src/utils.js index 1bad27f7ef0..780a29c0d81 100644 --- a/addons/point_of_sale/static/src/utils.js +++ b/addons/point_of_sale/static/src/utils.js @@ -66,3 +66,33 @@ export function random5Chars() { export function qrCodeSrc(url, { size = 200 } = {}) { return `/report/barcode/QR/${encodeURIComponent(url)}?width=${size}&height=${size}`; } + +/** + * Loading image is converted to a Promise to allow await when + * loading an image. It resolves to the loaded image if successful, + * else, resolves to false. + * + * [Source](https://stackoverflow.com/questions/45788934/how-to-turn-this-callback-into-a-promise-using-async-await) + */ +export function loadImage(url, options = {}) { + return new Promise((resolve, reject) => { + const img = new Image(); + img.addEventListener("load", () => resolve(img)); + img.addEventListener("error", () => { + if (options.onError) { + options.onError(); + } + reject(new Error(`Failed to load image at ${url}`)); + }); + img.src = url; + }); +} + +/** + * Load all images in the given element. + * @param {HTMLElement} el + */ +export function loadAllImages(el) { + const images = el.querySelectorAll("img"); + return Promise.all(Array.from(images).map(img => loadImage(img.src))); +}