diff --git a/addons/pos_self_order/__manifest__.py b/addons/pos_self_order/__manifest__.py index 81d33643111..6742fc17657 100644 --- a/addons/pos_self_order/__manifest__.py +++ b/addons/pos_self_order/__manifest__.py @@ -16,6 +16,7 @@ "views/pos_config_view.xml", "views/pos_session_view.xml", "views/custom_link_views.xml", + "views/pos_restaurant_views.xml", "views/product_views.xml", "data/init_access.xml", "data/custom_link_data.xml", diff --git a/addons/pos_self_order/models/pos_restaurant.py b/addons/pos_self_order/models/pos_restaurant.py index 2c1b0bb0126..3fe00a8a820 100644 --- a/addons/pos_self_order/models/pos_restaurant.py +++ b/addons/pos_self_order/models/pos_restaurant.py @@ -14,7 +14,6 @@ class RestaurantTable(models.Model): "Security Token", copy=False, required=True, - readonly=True, default=lambda self: self._get_identifier(), ) diff --git a/addons/pos_self_order/models/res_config_settings.py b/addons/pos_self_order/models/res_config_settings.py index 5ddd93e4713..4bf89082c8c 100644 --- a/addons/pos_self_order/models/res_config_settings.py +++ b/addons/pos_self_order/models/res_config_settings.py @@ -1,4 +1,8 @@ -# -*- coding: utf-8 -*- +# -*- codingimport base64 +import qrcode +import base64 +import zipfile +from io import BytesIO from odoo import models, fields, api, _ from odoo.exceptions import ValidationError @@ -74,6 +78,68 @@ class ResConfigSettings(models.TransientModel): "domain": ['|', ['pos_config_ids', 'in', self.pos_config_id.id], ["pos_config_ids", "=", False]], } + def _generate_single_qr_code(self, url): + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=10, + border=4, + ) + qr.add_data(url) + qr.make(fit=True) + return qr.make_image(fill_color="black", back_color="white") + + def generate_qr_codes_zip(self): + if not self.pos_self_ordering_mode in ['mobile', 'consultation']: + raise ValidationError(_("QR codes can only be generated in mobile or consultation mode.")) + + qr_images = [] + + if self.pos_module_pos_restaurant: + table_ids = self.pos_config_id.floor_ids.table_ids + + if not table_ids: + raise ValidationError(_("In Self-Order mode, you must have at least one table to generate QR codes")) + + for table in table_ids: + qr_images.append({ + 'image': self._generate_single_qr_code(self.pos_config_id._get_self_order_url(table.id)), + 'name': f"{table.floor_id.name} - {table.name}", + }) + else: + qr_images.append({ + 'image': self._generate_single_qr_code(self.pos_config_id._get_self_order_url()), + 'name': "generic", + }) + + # Create a zip with all images in qr_images + zip_buffer = BytesIO() + with zipfile.ZipFile(zip_buffer, "w", 0) as zip_file: + for index, qr_image in enumerate(qr_images): + with zip_file.open(f"{qr_image['name']} ({index + 1}).png", "w") as buf: + qr_image['image'].save(buf, format="PNG") + zip_buffer.seek(0) + + # Delete previous attachments + self.env["ir.attachment"].search([ + ("name", "=", "self_order_qr_code.zip"), + ]).unlink() + + # Create an attachment with the zip + attachment_id = self.env["ir.attachment"].create({ + "name": "self_order_qr_code.zip", + "type": "binary", + "raw": zip_buffer.read(), + "res_model": self._name, + "res_id": self.id, + }) + + return { + "type": "ir.actions.act_url", + "url": f"/web/content/{attachment_id.id}", + "target": "new", + } + def generate_qr_codes_page(self): """ Generate the data needed to print the QR codes page diff --git a/addons/pos_self_order/static/src/app/components/product_card/product_card.js b/addons/pos_self_order/static/src/app/components/product_card/product_card.js index 128fe63317b..eb73bec467f 100644 --- a/addons/pos_self_order/static/src/app/components/product_card/product_card.js +++ b/addons/pos_self_order/static/src/app/components/product_card/product_card.js @@ -33,17 +33,23 @@ export class ProductCard extends Component { return; } - const pic = this.selfRef.el.querySelector(".o_self_order_item_card_image"); + let pic = this.selfRef.el.querySelector(".o_self_order_item_card_image"); if (!pic) { - return; + pic = this.selfRef.el.querySelector(".o_self_order_item_card_no_image"); } const picRect = pic.getBoundingClientRect(); const clonedPic = pic.cloneNode(true); const toOrderRect = toOrder.getBoundingClientRect(); - clonedPic.classList.remove('w-100', 'h-100'); - clonedPic.classList.add('position-fixed', 'border', 'border-white', 'border-4', 'z-index-1'); + clonedPic.classList.remove("w-100", "h-100"); + clonedPic.classList.add( + "position-fixed", + "border", + "border-white", + "border-4", + "z-index-1" + ); clonedPic.style.top = `${picRect.top}px`; clonedPic.style.left = `${picRect.left}px`; clonedPic.style.width = `${picRect.width}px`; @@ -53,9 +59,10 @@ export class ProductCard extends Component { document.body.appendChild(clonedPic); requestAnimationFrame(() => { - let offsetTop = (toOrderRect.top - picRect.top) - picRect.height * 0.5; - let offsetLeft = (toOrderRect.left - picRect.left) - picRect.width * 0.25; - clonedPic.style.transform = 'translateY(' + offsetTop +'px) translateX(' + offsetLeft +'px) scale(0.5)'; + const offsetTop = toOrderRect.top - picRect.top - picRect.height * 0.5; + const offsetLeft = toOrderRect.left - picRect.left - picRect.width * 0.25; + clonedPic.style.transform = + "translateY(" + offsetTop + "px) translateX(" + offsetLeft + "px) scale(0.5)"; clonedPic.style.opacity = "0"; // Fading out the card }); diff --git a/addons/pos_self_order/static/src/app/components/product_card/product_card.scss b/addons/pos_self_order/static/src/app/components/product_card/product_card.scss index f553f5c86cf..225bf33d068 100644 --- a/addons/pos_self_order/static/src/app/components/product_card/product_card.scss +++ b/addons/pos_self_order/static/src/app/components/product_card/product_card.scss @@ -26,3 +26,9 @@ left: 22px; top: 4px; } + +.o_self_order_item_card_no_image { + span { + color: #DFDFDF; + } +} diff --git a/addons/pos_self_order/static/src/app/components/product_card/product_card.xml b/addons/pos_self_order/static/src/app/components/product_card/product_card.xml index 79d104aabfc..11b24e83fbe 100644 --- a/addons/pos_self_order/static/src/app/components/product_card/product_card.xml +++ b/addons/pos_self_order/static/src/app/components/product_card/product_card.xml @@ -12,12 +12,15 @@