From 0ffd04e7deea9bce8dc5f59e2457737ca7521251 Mon Sep 17 00:00:00 2001 From: vlst Date: Mon, 26 Jun 2023 14:24:02 +0200 Subject: [PATCH] [IMP] point_of_sale,pos_self_order: handling product attributes When selecting an attribute value in POS, what we store is the `description`, which is a string that represents the selected attribute values. Ex: selecting `Size: M` and `Material: Leather` will result in the description: `(L, Leather)`. This choice does not lead to a logical API for dealing with product attibutes. In this pr, we add a new field that stores the selected `ids` of `"product.template.attribute.value"` and remove the `selected_attributes` `Json` field from the `pos_self_order` override of the `pos.order.line` model. The `attributeHelper` function from the `tour_utils.js` file from `pos_self_order` is improved such that it can now handle both checking if a certain attribute is selected and actually selecting an attribute. closes odoo/odoo#126398 Task: 3378533 Related: odoo/upgrade#4992 Signed-off-by: Joseph Caburnay (jcb) --- addons/point_of_sale/models/pos_order.py | 1 + .../static/src/app/store/models.js | 7 +- .../product_configurator_popup.js | 6 +- addons/pos_self_order/__manifest__.py | 1 + addons/pos_self_order/controllers/orders.py | 4 +- addons/pos_self_order/models/pos_order.py | 7 +- .../src/mobile/components/lines/lines.xml | 4 +- .../product_main_view/product_main_view.js | 33 ++++-- .../product_main_view/product_main_view.xml | 19 ++-- .../tours/self_order_after_meal_cart_tour.js | 37 +++--- .../static/tests/tours/tour_utils.js | 107 ++++++++++++------ 11 files changed, 148 insertions(+), 78 deletions(-) diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 04562bc7bac..c9eb9256faf 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -1173,6 +1173,7 @@ class PosOrderLine(models.Model): skip_change = fields.Boolean('Skip line when sending ticket to kitchen printers.') notice = fields.Char(string='Discount Notice') product_id = fields.Many2one('product.product', string='Product', domain=[('sale_ok', '=', True)], required=True, change_default=True) + attribute_value_ids = fields.Many2many('product.template.attribute.value', string="Selected Attributes") price_unit = fields.Float(string='Unit Price', digits=0) qty = fields.Float('Quantity', digits='Product Unit of Measure', default=1) price_subtotal = fields.Float(string='Subtotal w/o Tax', digits=0, diff --git a/addons/point_of_sale/static/src/app/store/models.js b/addons/point_of_sale/static/src/app/store/models.js index 75689edb213..4dfee0499d7 100644 --- a/addons/point_of_sale/static/src/app/store/models.js +++ b/addons/point_of_sale/static/src/app/store/models.js @@ -138,7 +138,7 @@ export class Product extends PosModel { } async getAddProductOptions(code) { let price_extra = 0.0; - let draftPackLotLines, weight, description, packLotLinesToEdit; + let draftPackLotLines, weight, description, packLotLinesToEdit, attribute_value_ids; let quantity = 1; let comboLines = []; @@ -161,6 +161,7 @@ export class Product extends PosModel { if (confirmed) { description = payload.selected_attributes.join(", "); + attribute_value_ids = payload.attribute_value_ids; price_extra += payload.price_extra; quantity = payload.quantity; } else { @@ -262,6 +263,7 @@ export class Product extends PosModel { description, price_extra, comboLines, + attribute_value_ids, }; } isPricelistItemUsable(item, date) { @@ -425,6 +427,7 @@ export class Orderline extends PosModel { this.set_discount(json.discount); this.set_quantity(json.qty, "do not recompute unit price"); this.set_description(json.description); + this.attribute_value_ids = json.attribute_value_ids || []; this.set_price_extra(json.price_extra); this.set_full_product_name(json.full_product_name); this.id = json.server_id || json.id || orderline_id++; @@ -784,6 +787,7 @@ export class Orderline extends PosModel { id: this.id, pack_lot_ids: pack_lot_ids, description: this.description, + attribute_value_ids: this.attribute_value_ids, full_product_name: this.get_full_product_name(), price_extra: this.get_price_extra(), customer_note: this.get_customer_note(), @@ -2155,6 +2159,7 @@ export class Order extends PosModel { if (options.description !== undefined) { orderline.description += options.description; + orderline.attribute_value_ids = options.attribute_value_ids; } if (options.extras !== undefined) { diff --git a/addons/point_of_sale/static/src/app/store/product_configurator_popup/product_configurator_popup.js b/addons/point_of_sale/static/src/app/store/product_configurator_popup/product_configurator_popup.js index 0820e6f4754..09a8abb81b6 100644 --- a/addons/point_of_sale/static/src/app/store/product_configurator_popup/product_configurator_popup.js +++ b/addons/point_of_sale/static/src/app/store/product_configurator_popup/product_configurator_popup.js @@ -25,6 +25,7 @@ export class BaseProductAttribute extends Component { return { value, + valueId: selected_value.id, extra: selected_value.price_extra, }; } @@ -74,17 +75,20 @@ export class ProductConfiguratorPopup extends AbstractAwaitablePopup { getPayload() { var selected_attributes = []; + const attribute_value_ids = []; var price_extra = 0.0; const quantity = this.state.quantity; this.env.attribute_components.forEach((attribute_component) => { - const { value, extra } = attribute_component.getValue(); + const { value, valueId, extra } = attribute_component.getValue(); selected_attributes.push(value); + attribute_value_ids.push(valueId); price_extra += extra; }); return { selected_attributes, + attribute_value_ids, price_extra, quantity, }; diff --git a/addons/pos_self_order/__manifest__.py b/addons/pos_self_order/__manifest__.py index 43684abc1a1..ecb68c5a363 100644 --- a/addons/pos_self_order/__manifest__.py +++ b/addons/pos_self_order/__manifest__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- { "name": "POS Self Order", + 'version': '1.0.1', "summary": """ Addon for the POS App that allows customers to view the menu on their smartphone. """, diff --git a/addons/pos_self_order/controllers/orders.py b/addons/pos_self_order/controllers/orders.py index 383232e8c1f..2f2f1102355 100644 --- a/addons/pos_self_order/controllers/orders.py +++ b/addons/pos_self_order/controllers/orders.py @@ -247,7 +247,7 @@ class PosSelfOrderController(http.Controller): 'product_id': child.get('product_id'), 'qty': child.get('qty'), 'customer_note': child.get('customer_note'), - 'selected_attributes': child.get('selected_attributes'), + 'attribute_value_ids': child.get('selected_attributes') and [int(v) for v in child['selected_attributes'].values()] or [], 'full_product_name': child.get('full_product_name'), 'combo_parent_uuid': child.get('combo_parent_uuid'), 'combo_id': child.get('combo_id'), @@ -273,7 +273,7 @@ class PosSelfOrderController(http.Controller): 'product_id': line.get('product_id'), 'qty': line.get('qty'), 'customer_note': line.get('customer_note'), - 'selected_attributes': line.get('selected_attributes'), + 'attribute_value_ids': line.get('selected_attributes') and [int(v) for v in line['selected_attributes'].values()] or [], 'full_product_name': line.get('full_product_name'), 'combo_parent_uuid': line.get('combo_parent_uuid'), 'combo_id': line.get('combo_id'), diff --git a/addons/pos_self_order/models/pos_order.py b/addons/pos_self_order/models/pos_order.py index 38ae90dae95..5e55f079d38 100644 --- a/addons/pos_self_order/models/pos_order.py +++ b/addons/pos_self_order/models/pos_order.py @@ -9,8 +9,6 @@ from odoo import models, fields, api class PosOrderLine(models.Model): _inherit = "pos.order.line" - # For the moment we need this to keep attributes consistency between the server and client_side. - selected_attributes = fields.Json(string="Selected Attributes") combo_parent_id = fields.Many2one('pos.order.line', string='Combo Parent') combo_line_ids = fields.One2many('pos.order.line', 'combo_parent_id', string='Combo Lines') combo_id = fields.Many2one('pos.combo', string='Combo line reference') @@ -43,6 +41,9 @@ class PosOrderLine(models.Model): **super()._export_for_ui(orderline), } + def _get_selected_attributes(self) -> Dict: + self.ensure_one() + return {value.attribute_line_id.id: value.id for value in self.attribute_value_ids} class PosOrder(models.Model): _inherit = "pos.order" @@ -108,7 +109,7 @@ class PosOrder(models.Model): "price_subtotal": line.price_subtotal, "price_subtotal_incl": line.price_subtotal_incl, "product_id": line.product_id.id, - "selected_attributes": line.selected_attributes, + "selected_attributes": line._get_selected_attributes(), "uuid": line.uuid, "qty": line.qty, "customer_note": line.customer_note, diff --git a/addons/pos_self_order/static/src/mobile/components/lines/lines.xml b/addons/pos_self_order/static/src/mobile/components/lines/lines.xml index d1e1e0892f9..49ef3f297d7 100644 --- a/addons/pos_self_order/static/src/mobile/components/lines/lines.xml +++ b/addons/pos_self_order/static/src/mobile/components/lines/lines.xml @@ -29,10 +29,10 @@