From 6be9785544a19b38fa64182b24c8405d02abcbca Mon Sep 17 00:00:00 2001 From: MerlinGuillaume Date: Thu, 14 Jul 2022 15:26:40 +0000 Subject: [PATCH] [FIX] sale_product_configurator: use float quantities in configurator The product configurator doesn't allow you to use non-integer quantities Steps to reproduce: 1. Install Sales 2. Go to Settings > Sales > Product Catalog and enable Product Configurator 3. Create a Quotation and add product 'Conference Chair (CONFIG)' 4. In the product configurator, specify 3.5 as quantity and click on 'ADD' 5. The total price is wrong 6. Add the optional product 'Chair floor protection' and confirm 7. The quantity of 'Chair floor protection' rounds to 3 Solution: Parse the quantity as a float instead of an integer (and replace potential commas to dots in case of different decimal separator), get the quantity from default_quantity for the rpc call (as it was converted to an integer because of its type) and convert the quantity to float in the controllers Problem: parseInt was used to retrieve the quantity and the controllers converted the quantity to an integer. The field quantity of the SaleProductConfigurator is of type Integer, which rounded the quantity when opening the configurator. opw-2896367 closes odoo/odoo#96275 X-original-commit: 884a99357c1c44b2201e7116d7f6189626695f92 Signed-off-by: Victor Feyens (vfe) Signed-off-by: Guillaume Merlin (megu) --- addons/sale_product_configurator/controllers/main.py | 6 +++--- .../static/src/js/product_configurator_controller.js | 3 ++- .../static/src/js/product_configurator_modal.js | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/addons/sale_product_configurator/controllers/main.py b/addons/sale_product_configurator/controllers/main.py index 541246ba703..edb0c2be7f5 100644 --- a/addons/sale_product_configurator/controllers/main.py +++ b/addons/sale_product_configurator/controllers/main.py @@ -8,7 +8,7 @@ from odoo.http import request class ProductConfiguratorController(http.Controller): @http.route(['/sale_product_configurator/configure'], type='json', auth="user", methods=['POST']) def configure(self, product_template_id, pricelist_id, **kw): - add_qty = int(kw.get('add_qty', 1)) + add_qty = float(kw.get('add_qty', 1)) product_template = request.env['product.template'].browse(int(product_template_id)) pricelist = self._get_pricelist(pricelist_id) @@ -39,7 +39,7 @@ class ProductConfiguratorController(http.Controller): return self._optional_product_items(product_id, pricelist, **kw) def _optional_product_items(self, product_id, pricelist, **kw): - add_qty = int(kw.get('add_qty', 1)) + add_qty = float(kw.get('add_qty', 1)) product = request.env['product.product'].browse(int(product_id)) parent_combination = product.product_template_attribute_value_ids @@ -59,7 +59,7 @@ class ProductConfiguratorController(http.Controller): def _show_advanced_configurator(self, product_id, variant_values, pricelist, handle_stock, **kw): product = request.env['product.product'].browse(int(product_id)) combination = request.env['product.template.attribute.value'].browse(variant_values) - add_qty = int(kw.get('add_qty', 1)) + add_qty = float(kw.get('add_qty', 1)) no_variant_attribute_values = combination.filtered( lambda product_template_attribute_value: product_template_attribute_value.attribute_id.create_variant == 'no_variant' diff --git a/addons/sale_product_configurator/static/src/js/product_configurator_controller.js b/addons/sale_product_configurator/static/src/js/product_configurator_controller.js index 825aebc630f..6d7448f0e6b 100644 --- a/addons/sale_product_configurator/static/src/js/product_configurator_controller.js +++ b/addons/sale_product_configurator/static/src/js/product_configurator_controller.js @@ -118,12 +118,13 @@ var ProductConfiguratorFormController = FormController.extend({ var initialProduct = this.initialState.data.product_template_id; var changed = initialProduct && initialProduct.data.id !== productTemplateId; var data = this.renderer.state.data; + var quantity = initialProduct.context && initialProduct.context.default_quantity ? initialProduct.context.default_quantity : data.quantity; return this._rpc({ route: '/sale_product_configurator/configure', params: { product_template_id: productTemplateId, pricelist_id: this.renderer.pricelistId, - add_qty: data.quantity, + add_qty: quantity, product_template_attribute_value_ids: changed ? [] : this._getAttributeValueIds( data.product_template_attribute_value_ids ), diff --git a/addons/sale_product_configurator/static/src/js/product_configurator_modal.js b/addons/sale_product_configurator/static/src/js/product_configurator_modal.js index f9bdb5e7e0c..b6dbb6037be 100644 --- a/addons/sale_product_configurator/static/src/js/product_configurator_modal.js +++ b/addons/sale_product_configurator/static/src/js/product_configurator_modal.js @@ -185,7 +185,7 @@ var OptionalProductsModal = Dialog.extend(ServicesMixin, VariantMixin, { let noVariantAttributeValues; for (const product of self.$modal.find('.js_product.in_cart')) { var $item = $(product); - var quantity = parseInt($item.find('input[name="add_qty"]').val(), 10); + var quantity = parseFloat($item.find('input[name="add_qty"]').val().replace(',', '.') || 1); var parentUniqueId = product.dataset.parentUniqueId; var uniqueId = product.dataset.uniqueId; productCustomVariantValues = self.getCustomVariantValues($item); @@ -488,7 +488,7 @@ var OptionalProductsModal = Dialog.extend(ServicesMixin, VariantMixin, { if (this.$modal.find('.js_price_total').length) { var price = 0; this.$modal.find('.js_product.in_cart').each(function () { - var quantity = parseInt($(this).find('input[name="add_qty"]').first().val(), 10); + var quantity = parseFloat($(this).find('input[name="add_qty"]').first().val().replace(',', '.') || 1); price += parseFloat($(this).find('.js_raw_price').html()) * quantity; });