From 69e2d08d4e9c5ed352ca90ac93eabb1d2165c487 Mon Sep 17 00:00:00 2001 From: "David Monnom (moda)" Date: Mon, 25 Sep 2023 13:36:41 +0200 Subject: [PATCH] [IMP] point_of_sale: multi-attribute support Prior to this PR, `product_configurator_popup.js` did not support attribute selection of type `multi`. In addition, the `pos_preparation_display` did not display any attributes. Now it's possible to select attributes of type `multi` in the Point of Sale, and the preparation display shows all available attributes. closes odoo/odoo#136441 Taskid: 3497560 Related: odoo/enterprise#47834 Signed-off-by: Adrien Guilliams (adgu) --- .../static/src/app/store/models.js | 3 + .../product_configurator_popup.js | 60 ++++++++++++++----- .../product_configurator_popup.xml | 35 +++++++---- .../src/app/floor_screen/floor_screen.js | 6 +- 4 files changed, 76 insertions(+), 28 deletions(-) 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 67738b09ac8..03bb38e5468 100644 --- a/addons/point_of_sale/static/src/app/store/models.js +++ b/addons/point_of_sale/static/src/app/store/models.js @@ -1712,6 +1712,7 @@ export class Order extends PosModel { this.lastOrderPrepaChange[lineKey]["quantity"] = line.get_quantity(); } else { this.lastOrderPrepaChange[lineKey] = { + attribute_value_ids: line.attribute_value_ids, line_uuid: line.uuid, product_id: line.get_product().id, name: line.get_full_product_name(), @@ -1765,6 +1766,7 @@ export class Order extends PosModel { changes[productKey] = { name: orderline.get_full_product_name(), product_id: product.id, + attribute_value_ids: orderline.attribute_value_ids, quantity: quantityDiff, note: note, }; @@ -1790,6 +1792,7 @@ export class Order extends PosModel { product_id: lineResume["product_id"], name: lineResume["name"], note: lineResume["note"], + attribute_value_ids: lineResume["attribute_value_ids"], quantity: -lineResume["quantity"], }; } else { 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 09a8abb81b6..8dd95338a7c 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 @@ -9,24 +9,32 @@ export class BaseProductAttribute extends Component { this.attribute = this.props.attribute; this.values = this.attribute.values; this.state = useState({ - selected_value: parseFloat(this.values[0].id), + attribute_value_ids: parseFloat(this.values[0].id), custom_value: "", }); } getValue() { - const selected_value = this.values.find( - (val) => val.id === parseFloat(this.state.selected_value) - ); - let value = selected_value.name; - if (selected_value.is_custom && this.state.custom_value) { - value += `: ${this.state.custom_value}`; - } + const attribute_value_ids = + this.attribute.display_type === "multi" + ? this.values.filter((val) => this.state.attribute_value_ids[val.id]) + : [this.values.find((val) => val.id === parseInt(this.state.attribute_value_ids))]; + + const extra = attribute_value_ids.reduce((acc, val) => acc + val.price_extra, 0); + const valueIds = attribute_value_ids.map((val) => val.id); + const value = attribute_value_ids + .map((val) => { + if (val.is_custom && this.state.custom_value) { + return `${val.name}: ${this.state.custom_value}`; + } + return val.name; + }) + .join(", "); return { value, - valueId: selected_value.id, - extra: selected_value.price_extra, + valueIds, + extra, }; } } @@ -56,12 +64,35 @@ export class ColorProductAttribute extends BaseProductAttribute { static template = "point_of_sale.ColorProductAttribute"; } +export class MultiProductAttribute extends BaseProductAttribute { + static template = "point_of_sale.MultiProductAttribute"; + + setup() { + super.setup(); + this.state = useState({ + attribute_value_ids: [], + custom_value: "", + }); + + this.initAttribute(); + } + + initAttribute() { + const attribute = this.props.attribute; + + for (const value of attribute.values) { + this.state.attribute_value_ids[value.id] = false; + } + } +} + export class ProductConfiguratorPopup extends AbstractAwaitablePopup { static template = "point_of_sale.ProductConfiguratorPopup"; static components = { RadioProductAttribute, SelectProductAttribute, ColorProductAttribute, + MultiProductAttribute, }; setup() { @@ -74,18 +105,19 @@ export class ProductConfiguratorPopup extends AbstractAwaitablePopup { } getPayload() { - var selected_attributes = []; - const attribute_value_ids = []; + const selected_attributes = []; + let attribute_value_ids = []; var price_extra = 0.0; const quantity = this.state.quantity; this.env.attribute_components.forEach((attribute_component) => { - const { value, valueId, extra } = attribute_component.getValue(); + const { value, valueIds, extra } = attribute_component.getValue(); selected_attributes.push(value); - attribute_value_ids.push(valueId); + attribute_value_ids.push(valueIds); price_extra += extra; }); + attribute_value_ids = attribute_value_ids.flat(); return { selected_attributes, attribute_value_ids, diff --git a/addons/point_of_sale/static/src/app/store/product_configurator_popup/product_configurator_popup.xml b/addons/point_of_sale/static/src/app/store/product_configurator_popup/product_configurator_popup.xml index c8278bf27f7..885a561ca69 100644 --- a/addons/point_of_sale/static/src/app/store/product_configurator_popup/product_configurator_popup.xml +++ b/addons/point_of_sale/static/src/app/store/product_configurator_popup/product_configurator_popup.xml @@ -6,7 +6,7 @@
-
-
+
@@ -29,9 +29,9 @@
-
+ +
+
+
+
+
+