[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) <macr@odoo.com>
This commit is contained in:
Mahdi Cheikh Rouhou (macr)
2023-06-30 00:21:19 +02:00
parent ca64f6f5bb
commit b98425b1d9
6 changed files with 110 additions and 2 deletions
@@ -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;
@@ -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")}));
});
});
},
@@ -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',
@@ -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 (){},
}
]});
@@ -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
@@ -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")