[FIX] website_sale_stock: use correct qty to show warning/error

Without this commit, if you had:
- 3 Qty for product P in WH1
- 10 Qty for product P in WH2
- no warehouse set on website
- set show stock and prevent sales if not enough stock enabled

And then:
- Add 3 P in your cart
- In cart, add more P, it would let you do it, while it shouldn't

You would then be stuck on payment step as it would tell you only 3 are
available.

This commit improves 6b05fb2b21a3 by ensuring the warehouse_id used is the
correct one (the one that will be used on the SO (required field)).
That commit was fixing a case that was not supposed to happen[1], it is that
case that should have been fixed (which is fixed by previous commit of this PR)

[1]: it would fix the 'issue' when you add a product which has no stock
     available for the warehouse that will be used when creating the SO, by
     letting you through the warning, but you would then be stuck on the
     payment step as the qty check would be correctly done.
     The fix should have been to display the correct qty and prevent the add to
     cart in that case.

closes odoo/odoo#78045

X-original-commit: 5f74b84f67222147b2eb7caadb2d831a059aae4e
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
Signed-off-by: Adrien Widart <adwid@users.noreply.github.com>
Co-authored-by: Romain Derie <rde@odoo.com>
Co-authored-by: Adrien Widart <awt@odoo.com>
This commit is contained in:
Romain Derie
2021-10-11 09:02:32 +00:00
committed by Adrien Widart
co-authored by Adrien Widart
parent 4680f66586
commit e5a77f2cc1
2 changed files with 39 additions and 21 deletions
@@ -17,12 +17,8 @@ class SaleOrder(models.Model):
for line in self.order_line:
if line.product_id.type == 'product' and not line.product_id.allow_out_of_stock_order:
cart_qty = sum(self.order_line.filtered(lambda p: p.product_id.id == line.product_id.id).mapped('product_uom_qty'))
# The quantity should be computed based on the warehouse of the website, not the
# warehouse of the SO.
website = self.env['website'].get_current_website()
avl_qty = line.product_id.with_context(warehouse=website.warehouse_id.id).free_qty
if cart_qty > avl_qty and (line_id == line.id):
qty = avl_qty - cart_qty
if cart_qty > line.product_id.with_context(warehouse=self.warehouse_id.id).free_qty and (line_id == line.id):
qty = line.product_id.with_context(warehouse=self.warehouse_id.id).free_qty - cart_qty
new_val = super(SaleOrder, self)._cart_update(line.product_id.id, line.id, qty, 0, **kwargs)
values.update(new_val)
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.website.tools import MockRequest
from odoo.addons.sale.tests.test_sale_product_attribute_value_config import TestSaleProductAttributeValueCommon
from odoo.tests import tagged
@@ -9,31 +10,31 @@ from odoo.tests import tagged
class TestWebsiteSaleStockProductWarehouse(TestSaleProductAttributeValueCommon):
@classmethod
def setUpClass(self):
def setUpClass(cls):
super().setUpClass()
# Run the tests in another company, so the tests do not rely on the
# database state (eg the default company's warehouse)
self.company = self.env['res.company'].create({'name': 'Company C'})
self.env.user.company_id = self.company
self.website = self.env['website'].create({'name': 'Website Company C'})
self.website.company_id = self.company
cls.company = cls.env['res.company'].create({'name': 'Company C'})
cls.env.user.company_id = cls.company
cls.website = cls.env['website'].create({'name': 'Website Company C'})
cls.website.company_id = cls.company
# Set two warehouses (one was created on company creation)
self.warehouse_1 = self.env['stock.warehouse'].search([('company_id', '=', self.company.id)])
self.warehouse_2 = self.env['stock.warehouse'].create({
cls.warehouse_1 = cls.env['stock.warehouse'].search([('company_id', '=', cls.company.id)])
cls.warehouse_2 = cls.env['stock.warehouse'].create({
'name': 'Warehouse 2',
'code': 'WH2'
})
# Create two stockable products
self.product_A = self.env['product.product'].create({
cls.product_A = cls.env['product.product'].create({
'name': 'Product A',
'allow_out_of_stock_order': False,
'type': 'product',
'default_code': 'E-COM1',
})
self.product_B = self.env['product.product'].create({
cls.product_B = cls.env['product.product'].create({
'name': 'Product B',
'allow_out_of_stock_order': False,
'type': 'product',
@@ -41,17 +42,17 @@ class TestWebsiteSaleStockProductWarehouse(TestSaleProductAttributeValueCommon):
})
# Add 10 Product A in WH1 and 15 Product 1 in WH2
quants = self.env['stock.quant'].with_context(inventory_mode=True).create([{
'product_id': self.product_A.id,
quants = cls.env['stock.quant'].with_context(inventory_mode=True).create([{
'product_id': cls.product_A.id,
'inventory_quantity': qty,
'location_id': wh.lot_stock_id.id,
} for wh, qty in [(self.warehouse_1, 10.0), (self.warehouse_2, 15.0)]])
} for wh, qty in [(cls.warehouse_1, 10.0), (cls.warehouse_2, 15.0)]])
# Add 10 Product 2 in WH2
quants |= self.env['stock.quant'].with_context(inventory_mode=True).create({
'product_id': self.product_B.id,
quants |= cls.env['stock.quant'].with_context(inventory_mode=True).create({
'product_id': cls.product_B.id,
'inventory_quantity': 10.0,
'location_id': self.warehouse_2.lot_stock_id.id,
'location_id': cls.warehouse_2.lot_stock_id.id,
})
quants.action_apply_inventory()
@@ -79,3 +80,24 @@ class TestWebsiteSaleStockProductWarehouse(TestSaleProductAttributeValueCommon):
# Check available quantity of product is according to warehouse
self.assertEqual(combination_info['free_qty'], qty_b, "%s units of Product B should be available in warehouse %s" % (qty_b, wh))
def test_02_update_cart_with_multi_warehouses(self):
""" When the user updates his cart and increases a product quantity, if
this quantity is not available in the SO's warehouse, a warning should
be returned and the quantity updated to its maximum. """
so = self.env['sale.order'].create({
'partner_id': self.env.user.partner_id.id,
'order_line': [(0, 0, {
'name': self.product_A.name,
'product_id': self.product_A.id,
'product_uom_qty': 5,
'product_uom': self.product_A.uom_id.id,
'price_unit': self.product_A.list_price,
})]
})
with MockRequest(self.env, website=self.website, sale_order_id=so.id):
values = so._cart_update(product_id=self.product_A.id, line_id=so.order_line.id, set_qty=20)
self.assertTrue(values.get('warning', False))
self.assertEqual(values.get('quantity'), 10)