From 672c853ab7d77ac1cebd2f4d16bd98fc454b2d55 Mon Sep 17 00:00:00 2001 From: rhe-odoo Date: Mon, 29 Jan 2024 10:15:39 +0100 Subject: [PATCH] [FIX] point_of_sale: display attributes In the current system, the order widget experienced undesired updates to all order lines when a new product with the same attribute was added. Our recent changes address this issue, ensuring that existing attribute values remain unaffected by the addition of new ones. Moreover, we've refined the display of attribute information. If an attribute is designated as "never," it will now be incorporated into the order line note. Conversely, attributes with different settings will continue to be displayed in their usual format. closes odoo/odoo#152213 Signed-off-by: Vlad Stroia (vlst) --- .../orderline/orderline.xml | 4 +-- .../static/src/app/store/models.js | 25 +++++++++++-------- addons/point_of_sale/static/src/utils.js | 2 -- .../tests/tours/ProductConfigurator.tour.js | 22 ++++++++++------ .../generic_components/OrderWidgetMethods.js | 4 +++ addons/point_of_sale/tests/test_frontend.py | 1 - 6 files changed, 36 insertions(+), 22 deletions(-) diff --git a/addons/point_of_sale/static/src/app/generic_components/orderline/orderline.xml b/addons/point_of_sale/static/src/app/generic_components/orderline/orderline.xml index 0c34a98d75a..06498e94a67 100644 --- a/addons/point_of_sale/static/src/app/generic_components/orderline/orderline.xml +++ b/addons/point_of_sale/static/src/app/generic_components/orderline/orderline.xml @@ -36,7 +36,7 @@
  • - +
    : @@ -46,7 +46,7 @@
    -
    +
  • 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 4da50821fcf..b9993c52532 100644 --- a/addons/point_of_sale/static/src/app/store/models.js +++ b/addons/point_of_sale/static/src/app/store/models.js @@ -1,6 +1,6 @@ /** @odoo-module */ -import { random5Chars, uuidv4, qrCodeSrc, constructFullProductName } from "@point_of_sale/utils"; +import { random5Chars, uuidv4, qrCodeSrc } from "@point_of_sale/utils"; // FIXME POSREF - unify use of native parseFloat and web's parseFloat. We probably don't need the native version. import { parseFloat as oParseFloat } from "@web/views/fields/parsers"; import { @@ -574,11 +574,7 @@ export class Orderline extends PosModel { this.price_extra = parseFloat(price_extra) || 0.0; } set_full_product_name() { - this.full_product_name = constructFullProductName( - this, - this.pos.db.attribute_value_by_id, - this.product.display_name - ); + this.full_product_name = this.product.display_name; } get_price_extra() { return this.price_extra; @@ -738,7 +734,10 @@ export class Orderline extends PosModel { orderline.compute_fixed_price(order_line_price), this.pos.currency.decimal_places ); - // only orderlines of the same product can be merged + let hasSameAttributes = Object.keys(Object(orderline.attribute_value_ids)).length === Object.keys(Object(this.attribute_value_ids)).length; + if(hasSameAttributes && Object(orderline.attribute_value_ids)?.length && Object(this.attribute_value_ids)?.length) { + hasSameAttributes = orderline.attribute_value_ids.every((value, index) => value === this.attribute_value_ids[index]); + } return ( !this.skipChange && orderline.getNote() === this.getNote() && @@ -759,7 +758,8 @@ export class Orderline extends PosModel { orderline.get_customer_note() === this.get_customer_note() && !this.refunded_orderline_id && !this.isPartOfCombo() && - !orderline.isPartOfCombo() + !orderline.isPartOfCombo() && + hasSameAttributes ); } is_pos_groupable() { @@ -1077,13 +1077,18 @@ export class Orderline extends PosModel { return Boolean(this.comboParent || this.comboLines?.length); } findAttribute(values) { - const listOfAttributes = Object.values(this.pos.attributes_by_ptal_id).filter( + const listOfAttributes = []; + Object.values(this.pos.attributes_by_ptal_id).filter( (attribute) => { const attFound = attribute.values.filter((target) => { return Object.values(values).includes(target.id); }); if (attFound.length > 0) { - attribute.valuesForOrderLine = attFound; + const modifiedAttribute = { + ...attribute, + valuesForOrderLine: attFound, + }; + listOfAttributes.push(modifiedAttribute); return true; } return false; diff --git a/addons/point_of_sale/static/src/utils.js b/addons/point_of_sale/static/src/utils.js index d00254c19c3..1bad27f7ef0 100644 --- a/addons/point_of_sale/static/src/utils.js +++ b/addons/point_of_sale/static/src/utils.js @@ -29,10 +29,8 @@ export function deduceUrl(url) { } return url; } - export function constructFullProductName(line, attribute_value_by_id, display_name) { let attributeString = ""; - if (line.attribute_value_ids && line.attribute_value_ids.length > 0) { for (const valId of line.attribute_value_ids) { const value = attribute_value_by_id[valId]; diff --git a/addons/point_of_sale/static/tests/tours/ProductConfigurator.tour.js b/addons/point_of_sale/static/tests/tours/ProductConfigurator.tour.js index e7fbee1ca0b..ae872b8502d 100644 --- a/addons/point_of_sale/static/tests/tours/ProductConfigurator.tour.js +++ b/addons/point_of_sale/static/tests/tours/ProductConfigurator.tour.js @@ -4,6 +4,8 @@ import * as ProductScreen from "@point_of_sale/../tests/tours/helpers/ProductScr import * as Chrome from "@point_of_sale/../tests/tours/helpers/ChromeTourMethods"; import * as ProductConfigurator from "@point_of_sale/../tests/tours/helpers/ProductConfiguratorTourMethods"; import { registry } from "@web/core/registry"; +import * as Order from "@point_of_sale/../tests/tours/helpers/generic_components/OrderWidgetMethods"; +import { inLeftSide } from "@point_of_sale/../tests/tours/helpers/utils"; registry.category("web_tour.tours").add("ProductConfiguratorTour", { test: true, @@ -43,7 +45,7 @@ registry.category("web_tour.tours").add("ProductConfiguratorTour", { // Check that the product has been added to the order with correct attributes and price ProductScreen.selectedOrderlineHas( - "Configurable Chair (Red, Metal, Other: Custom Fabric)", + "Configurable Chair", "1.0", "11.0" ), @@ -56,12 +58,18 @@ registry.category("web_tour.tours").add("ProductConfiguratorTour", { ProductConfigurator.pickRadio("Other"), ProductConfigurator.fillCustomAttribute("Custom Fabric"), ProductConfigurator.confirmAttributes(), - ProductScreen.selectedOrderlineHas( - "Configurable Chair (Red, Metal, Other: Custom Fabric)", - "2.0", - "22.0" + inLeftSide(Order.hasLine({ + withClass: ".selected", + productName: "Configurable Chair", + quantity: "2", + price: "22.0", + atts: { + "Color": "Red ($ 1.00)", + "Chair Legs": "Metal", + "Fabrics": "Other" + } + }) ), - // Orderlines with different attributes shouldn't be merged ProductScreen.clickHomeCategory(), ProductScreen.clickDisplayedProduct("Configurable Chair"), @@ -70,7 +78,7 @@ registry.category("web_tour.tours").add("ProductConfiguratorTour", { ProductConfigurator.pickRadio("Leather"), ProductConfigurator.confirmAttributes(), ProductScreen.selectedOrderlineHas( - "Configurable Chair (Blue, Metal, Leather)", + "Configurable Chair", "1.0", "10.0" ), diff --git a/addons/point_of_sale/static/tests/tours/helpers/generic_components/OrderWidgetMethods.js b/addons/point_of_sale/static/tests/tours/helpers/generic_components/OrderWidgetMethods.js index c84bacc1906..2c18fb904f9 100644 --- a/addons/point_of_sale/static/tests/tours/helpers/generic_components/OrderWidgetMethods.js +++ b/addons/point_of_sale/static/tests/tours/helpers/generic_components/OrderWidgetMethods.js @@ -31,6 +31,7 @@ export function hasLine({ comboParent, discount, oldPrice, + atts } = {}) { let trigger = `.order-container .orderline${withClass}`; if (withoutClass) { @@ -60,6 +61,9 @@ export function hasLine({ if (oldPrice) { trigger += `:has(.info-list .price-per-unit s:contains("${oldPrice}"))`; } + if(atts) { + trigger += Object.entries(atts).map(([key, value]) => `:has(.info-list div:contains("${key}: ${value}"))`).join(); + } const args = JSON.stringify(arguments[0]); return [ { diff --git a/addons/point_of_sale/tests/test_frontend.py b/addons/point_of_sale/tests/test_frontend.py index c54ee11ce05..d1afed74432 100644 --- a/addons/point_of_sale/tests/test_frontend.py +++ b/addons/point_of_sale/tests/test_frontend.py @@ -570,7 +570,6 @@ class TestUi(TestPointOfSaleHttpCommon): self.assertEqual(n_paid, 2, 'There should be 2 paid order.') def test_04_product_configurator(self): - self.main_pos_config.with_user(self.pos_user).open_ui() self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config, 'ProductConfiguratorTour', login="pos_user")