From 5ca1da8ab33d4dd6a9ed0b6737e5d19f1a3ac9d2 Mon Sep 17 00:00:00 2001 From: "Valentin Vallaeys (vava)" Date: Tue, 5 Sep 2023 10:50:17 +0200 Subject: [PATCH] [ADD] product: add multi-checkbox attribute type for extra options Currently there is no efficient way to suggest extra-options to customers in PoS or eCommerce. Extra options should be easily selected by customers (or PoS waiters) with checkbox. Each checked option would add an extra-price to the product price and appear on tickets, receipts, invoices, kitchen display, ... This commit introduces a new type of attribute: multi-checkbox. This will not create product variants. A default extra-cost is defined at the attribute level, but it can be changed at the product level. The new attribute is available in Sales, not yet in eCommerce nor in PoS (it will be in a future task). task-3256585 closes odoo/odoo#130915 Signed-off-by: Victor Feyens (vfe) --- addons/product/__manifest__.py | 1 + addons/product/models/product_attribute.py | 9 ++++ .../product/models/product_attribute_value.py | 1 + addons/product/models/product_template.py | 4 +- .../models/product_template_attribute_line.py | 3 +- .../views/product_attribute_value_views.xml | 15 +++++++ .../product/views/product_attribute_views.xml | 15 ++++--- addons/sale/models/sale_order_line.py | 13 +++++- .../controllers/main.py | 4 +- .../product_configurator_dialog.js | 29 +++++++++---- .../product_template_attribute_line.js | 17 ++++---- .../product_template_attribute_line.xml | 42 ++++++++++++++++--- .../static/src/js/sale_product_field.js | 4 +- .../views/product_attribute_views.xml | 8 ++-- .../models/website_sale_comparison.py | 10 +++-- .../views/website_sale_comparison_view.xml | 6 +-- 16 files changed, 136 insertions(+), 45 deletions(-) create mode 100644 addons/product/views/product_attribute_value_views.xml diff --git a/addons/product/__manifest__.py b/addons/product/__manifest__.py index 228d69b2b7a..8bb0d8efdc7 100644 --- a/addons/product/__manifest__.py +++ b/addons/product/__manifest__.py @@ -37,6 +37,7 @@ Print product labels with barcode. 'views/res_config_settings_views.xml', 'views/product_attribute_views.xml', + 'views/product_attribute_value_views.xml', 'views/product_category_views.xml', 'views/product_document_views.xml', 'views/product_packaging_views.xml', diff --git a/addons/product/models/product_attribute.py b/addons/product/models/product_attribute.py index c0d32f94469..b3319afa471 100644 --- a/addons/product/models/product_attribute.py +++ b/addons/product/models/product_attribute.py @@ -11,6 +11,14 @@ class ProductAttribute(models.Model): # `_sort_key_attribute_value` in `product.template` _order = 'sequence, id' + _sql_constraints = [ + ( + 'check_multi_checkbox_no_variant', + "CHECK(display_type != 'multi' OR create_variant = 'no_variant')", + "Multi-checkbox display type is not compatible with the creation of variants" + ), + ] + name = fields.Char(string="Attribute", required=True, translate=True) create_variant = fields.Selection( selection=[ @@ -31,6 +39,7 @@ class ProductAttribute(models.Model): ('pills', 'Pills'), ('select', 'Select'), ('color', 'Color'), + ('multi', 'Multi-checkbox (option)'), ], default='radio', required=True, diff --git a/addons/product/models/product_attribute_value.py b/addons/product/models/product_attribute_value.py index 7c4033ea847..b6804793095 100644 --- a/addons/product/models/product_attribute_value.py +++ b/addons/product/models/product_attribute_value.py @@ -34,6 +34,7 @@ class ProductAttributeValue(models.Model): is_used_on_products = fields.Boolean( string="Used on Products", compute='_compute_is_used_on_products') + default_extra_price = fields.Float() is_custom = fields.Boolean( string="Is custom value", help="Allow users to input custom values for this attribute value") diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index 63104d33152..2d6ef6d684e 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -1257,7 +1257,9 @@ class ProductTemplate(models.Model): necessary_values = necessary_values or self.env['product.template.attribute.value'] necessary_attribute_lines = necessary_values.mapped('attribute_line_id') - attribute_lines = self.valid_product_template_attribute_line_ids.filtered(lambda ptal: ptal not in necessary_attribute_lines) + attribute_lines = self.valid_product_template_attribute_line_ids.filtered( + lambda ptal: ptal not in necessary_attribute_lines and ( + ptal.attribute_id.display_type != 'multi')) if not attribute_lines and self._is_combination_possible(necessary_values, parent_combination): yield necessary_values diff --git a/addons/product/models/product_template_attribute_line.py b/addons/product/models/product_template_attribute_line.py index adfc88170ad..9cc23fb1ad1 100644 --- a/addons/product/models/product_template_attribute_line.py +++ b/addons/product/models/product_template_attribute_line.py @@ -235,7 +235,8 @@ class ProductTemplateAttributeLine(models.Model): # create values that didn't exist yet ptav_to_create.append({ 'product_attribute_value_id': pav.id, - 'attribute_line_id': ptal.id + 'attribute_line_id': ptal.id, + 'price_extra': pav.default_extra_price, }) # Handle active at each step in case a following line might want to # re-use a value that was archived at a previous step. diff --git a/addons/product/views/product_attribute_value_views.xml b/addons/product/views/product_attribute_value_views.xml new file mode 100644 index 00000000000..1254bff6fe4 --- /dev/null +++ b/addons/product/views/product_attribute_value_views.xml @@ -0,0 +1,15 @@ + + + + + product.attribute.value.list + product.attribute.value + + + + + + + + + diff --git a/addons/product/views/product_attribute_views.xml b/addons/product/views/product_attribute_views.xml index 6410cde4351..11703518fdf 100644 --- a/addons/product/views/product_attribute_views.xml +++ b/addons/product/views/product_attribute_views.xml @@ -30,11 +30,13 @@ - -