From b98425b1d98afd1fa8b292ba7d795a277e5bbc79 Mon Sep 17 00:00:00 2001 From: "Mahdi Cheikh Rouhou (macr)" Date: Wed, 14 Jun 2023 11:33:54 +0000 Subject: [PATCH] [FIX] website_sale_product_configurator : show correct available qty in product page When you add items in the cart it always show the number of available left in stock of the previous state for example : 1- cart is empty it shows 20 items 2- add one into cart - it shows 20 items left in stock (should be 19) 3- add another one into cart - it show 19 items left in stock (should be 18) Steps to reproduce the error : 1 - Go to one of the product and make sure that it has some available quantity 2 - Go to sale configuration on the product and remove "out-of-stock : continue selling" and add show available qty only if below 5000 for example 3 - Go the web page of the product and try to add some items into the cart you will see that the stock message is wrong The origin of the problem is that when we have optional products activated , it will launch a product configurator modal. After posting the update in the database there is no call to the function that updates the stock message. opw-3341377 closes odoo/odoo#126802 X-original-commit: cec84ac8f761b516aef61e2721b7d619834be730 Signed-off-by: Mahdi Cheikh Rouhou (macr) --- .../static/src/js/sale_variant_mixin.js | 3 ++ .../static/src/js/website_sale_options.js | 9 +++- addons/website_sale_stock/__manifest__.py | 1 + ..._message_after_close_configurator_modal.js | 51 +++++++++++++++++++ addons/website_sale_stock/tests/__init__.py | 1 + .../test_website_sale_stock_stock_message.py | 47 +++++++++++++++++ 6 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 addons/website_sale_stock/static/tests/tours/website_sale_stock_message_after_close_configurator_modal.js create mode 100644 addons/website_sale_stock/tests/test_website_sale_stock_stock_message.py diff --git a/addons/website_sale/static/src/js/sale_variant_mixin.js b/addons/website_sale/static/src/js/sale_variant_mixin.js index 67a74ef44fa..c97c552c3d1 100644 --- a/addons/website_sale/static/src/js/sale_variant_mixin.js +++ b/addons/website_sale/static/src/js/sale_variant_mixin.js @@ -57,6 +57,9 @@ var VariantMixin = { } const $parent = $(ev.target).closest('.js_product'); + if(!$parent.length){ + return Promise.resolve(); + } const combination = this.getSelectedVariantValues($parent); let parentCombination; diff --git a/addons/website_sale_product_configurator/static/src/js/website_sale_options.js b/addons/website_sale_product_configurator/static/src/js/website_sale_options.js index 0789dea0e3d..17bd20a212c 100644 --- a/addons/website_sale_product_configurator/static/src/js/website_sale_options.js +++ b/addons/website_sale_product_configurator/static/src/js/website_sale_options.js @@ -43,10 +43,13 @@ publicWidget.registry.WebsiteSale.include({ * @override */ _submitForm() { + var ret = this._super(...arguments); if (this.optionalProductsModal && this.stayOnPageOption) { - this.optionalProductsModal._openedResolver(); + ret.then(()=>{ + this.optionalProductsModal._openedResolver() + }); } - return this._super(...arguments); + return ret; }, /** * Update web shop base form quantity @@ -121,6 +124,8 @@ publicWidget.registry.WebsiteSale.include({ const imgContainerEl = self.$form.closest('div:has(img)'); wsUtils.animateClone($('header .o_wsale_my_cart').first(), imgContainerEl, 25, 40); sessionStorage.setItem('website_sale_cart_quantity', quantity); + }).then(()=>{ + this._getCombinationInfo($.Event('click', {target: $("#add_to_cart")})); }); }); }, diff --git a/addons/website_sale_stock/__manifest__.py b/addons/website_sale_stock/__manifest__.py index d53e009fdc6..8d761a6a048 100644 --- a/addons/website_sale_stock/__manifest__.py +++ b/addons/website_sale_stock/__manifest__.py @@ -37,6 +37,7 @@ Then it can be made specific at the product level. 'web.assets_tests': [ 'website_sale_stock/static/tests/tours/website_sale_stock_multilang.js', 'website_sale_stock/static/tests/tours/website_sale_stock_stock_notification.js', + 'website_sale_stock/static/tests/tours/website_sale_stock_message_after_close_configurator_modal.js' ], }, 'license': 'LGPL-3', diff --git a/addons/website_sale_stock/static/tests/tours/website_sale_stock_message_after_close_configurator_modal.js b/addons/website_sale_stock/static/tests/tours/website_sale_stock_message_after_close_configurator_modal.js new file mode 100644 index 00000000000..8045856ab51 --- /dev/null +++ b/addons/website_sale_stock/static/tests/tours/website_sale_stock_message_after_close_configurator_modal.js @@ -0,0 +1,51 @@ +/** @odoo-module **/ + +import { registry } from "@web/core/registry"; + +registry.category("web_tour.tours").add('website_sale_stock_message_after_close_onfigurator_modal_with_optional_products', { + // This tour relies on a data created from the python test. + test: true, + url: '/shop?search=Product With Optional (TEST)', + steps: [{ + content: "Select Customizable Desk", + trigger: '.oe_product_cart a:contains("Product With Optional (TEST)")', + },{ + content : "Check that the stock quantity is displayed and correct", + trigger : '#threshold_message:contains("30")', + run: function (){}, + },{ + content : "Add to cart", + trigger: '#add_to_cart', + },{ + content: "Continue shoppping", + extra_trigger: '.oe_advanced_configurator_modal', + trigger: 'button span:contains(Continue Shopping)', + run: 'click' + },{ + content : "Check that the stock quantity is displayed and correct after adding to cart", + trigger : '#threshold_message:contains("29")', + run: function (){}, + } +]}); + +registry.category("web_tour.tours").add('website_sale_stock_message_after_close_onfigurator_modal_without_optional_products', { + // This tour relies on a data created from the python test. + test: true, + url: '/shop?search=Product Without Optional (TEST)', + steps: [{ + content: "Select Office Lamp", + trigger: '.oe_product_cart a:contains("Product Without Optional (TEST)")', + },{ + content : "Check that the stock quantity is displayed and correct", + trigger : '#threshold_message:contains("30")', + run: function (){}, + },{ + content : "Add to cart", + trigger: '#add_to_cart', + },{ + content : "Check that the stock quantity is displayed and correct after adding to cart", + trigger : '#threshold_message:contains("29")', + run: function (){}, + } +]}); + diff --git a/addons/website_sale_stock/tests/__init__.py b/addons/website_sale_stock/tests/__init__.py index 967dd33b151..73401d0fc2a 100644 --- a/addons/website_sale_stock/tests/__init__.py +++ b/addons/website_sale_stock/tests/__init__.py @@ -6,3 +6,4 @@ from . import test_website_sale_stock_multilang from . import test_website_sale_stock_product_warehouse from . import test_website_sale_stock_stock_notification from . import test_website_sale_stock_reorder_from_portal +from . import test_website_sale_stock_stock_message diff --git a/addons/website_sale_stock/tests/test_website_sale_stock_stock_message.py b/addons/website_sale_stock/tests/test_website_sale_stock_stock_message.py new file mode 100644 index 00000000000..0bc4beb04c3 --- /dev/null +++ b/addons/website_sale_stock/tests/test_website_sale_stock_stock_message.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.tests import tagged +from odoo.addons.sale_product_configurator.tests.common import TestProductConfiguratorCommon +from odoo.addons.base.tests.common import HttpCaseWithUserPortal + +@tagged('post_install', '-at_install') +class TestWebsiteSaleStockProductConfigurator(TestProductConfiguratorCommon, HttpCaseWithUserPortal): + + def test_01_stock_message_update_after_close_with_optional_products(self): + product_product_with_options = self.env['product.product'].create({ + 'name': 'Product With Optional (TEST)', + 'standard_price': 500.0, + 'list_price': 750.0, + 'optional_product_ids': [(4, self.product_product_conf_chair.id)], + 'website_published': True, + 'show_availability': True, + 'available_threshold': 5000, + 'allow_out_of_stock_order': False, + 'type':'product', + }) + self.product_product_conf_chair.website_published = True + self.env['stock.quant'].create({ + 'product_id': product_product_with_options.id, + 'location_id': self.env.ref('stock.stock_location_stock').id, + 'quantity': 30.0, + }) + self.start_tour("/", 'website_sale_stock_message_after_close_onfigurator_modal_with_optional_products', login="admin") + + def test_02_stock_message_update_after_close_without_optional_products(self): + product_product_without_options = self.env['product.product'].create({ + 'name': 'Product Without Optional (TEST)', + 'standard_price': 500.0, + 'list_price': 750.0, + 'website_published': True, + 'show_availability': True, + 'available_threshold': 5000, + 'allow_out_of_stock_order': False, + 'detailed_type':'product', + }) + self.env['stock.quant'].create({ + 'product_id': product_product_without_options.id, + 'location_id': self.env.ref('stock.stock_location_stock').id, + 'quantity': 30.0, + }) + self.start_tour("/", 'website_sale_stock_message_after_close_onfigurator_modal_without_optional_products', login="admin")