From 83def413b8c132d8981114684ec93f2cd1f8b643 Mon Sep 17 00:00:00 2001 From: Adrien Widart Date: Wed, 8 Sep 2021 10:24:40 +0000 Subject: [PATCH] [FIX] purchase_stock: include qty in lead days computation The combination of a RR and a supplier that has a minimum quantity and a lead time leads to incorrect results To reproduce the issue: 1. Create a product P: - Type: Storable 2. Add a reordering rule for P (min: 10, max: 50) 3. Add a vendor to P - Quantity: 1 - Price: 1 - Delivery Lead Time: 7 4. Run the scheduler 5. Open the generated PO Error: The order deadline is instead of today. The receipt date is today instead of When computing the quantity to order, the method needs the value of `qty_forecast` (L254 in [1]) The computation of `qty_forecast` leads to the computation of `lead_days_date`. To do so, it gets the lead days of the associated stock rule `_get_lead_days`. In this method, a seller is selected: [2] However, none of the parameter is defined: [3] In the above case, the seller has a minimum quantity of 1. Therefore, since this information is not given in [2], the vendor is not selected and his lead time is therefore not taken into account. So, `lead_days_date` will be equal to 0 and won't be recomputed. As a result, the planned delivery date is today. Then, the quantity to order is computed (L260 in [1]), so later, the module is able to select the correct seller. However, this one has a lead time of 7 days -> the generated PO will have the planned date to today and the order deadline to Once an orderpoint has its quantity to order defined, its lead time should be recomputed because it may be different depending to the selected seller (and thus we should take this quantity into account when searching for a seller) [1] https://github.com/odoo/odoo/blob/59ac8d891de6e20604494d6cfc6fc357a88d226c/addons/stock/models/stock_orderpoint.py#L254-L260 [2] https://github.com/odoo/odoo/blob/1b03087524080f1a9751b1561cd8891466e72367/addons/purchase_stock/models/stock_rule.py#L153 [3] https://github.com/odoo/odoo/blob/045c6ad3353bb0849d3f93d3488d8dcd8b8975b0/addons/product/models/product.py#L602 OPW-2614798 closes odoo/odoo#77110 X-original-commit: f2eb1dca99d16d70613c2f724d4b73f273a49ae7 Signed-off-by: Arnold Moyaux Signed-off-by: Adrien Widart --- addons/product/models/product.py | 2 +- addons/purchase_stock/models/stock_rule.py | 2 +- .../tests/test_purchase_lead_time.py | 25 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/addons/product/models/product.py b/addons/product/models/product.py index 9cbca007a4b..d3680c4f1e5 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -659,7 +659,7 @@ class ProductProduct(models.Model): continue if partner_id and seller.name not in [partner_id, partner_id.parent_id]: continue - if float_compare(quantity_uom_seller, seller.min_qty, precision_digits=precision) == -1: + if quantity is not None and float_compare(quantity_uom_seller, seller.min_qty, precision_digits=precision) == -1: continue if seller.product_id and seller.product_id != self: continue diff --git a/addons/purchase_stock/models/stock_rule.py b/addons/purchase_stock/models/stock_rule.py index b9c5fbd7cdf..6cf956b8fb5 100644 --- a/addons/purchase_stock/models/stock_rule.py +++ b/addons/purchase_stock/models/stock_rule.py @@ -150,7 +150,7 @@ class StockRule(models.Model): delay, delay_description = super()._get_lead_days(product, **values) bypass_delay_description = self.env.context.get('bypass_delay_description') buy_rule = self.filtered(lambda r: r.action == 'buy') - seller = 'supplierinfo' in values and values['supplierinfo'] or product.with_company(buy_rule.company_id)._select_seller() + seller = 'supplierinfo' in values and values['supplierinfo'] or product.with_company(buy_rule.company_id)._select_seller(quantity=None) if not buy_rule or not seller: return delay, delay_description buy_rule.ensure_one() diff --git a/addons/purchase_stock/tests/test_purchase_lead_time.py b/addons/purchase_stock/tests/test_purchase_lead_time.py index 486dbefe270..886b519ee39 100644 --- a/addons/purchase_stock/tests/test_purchase_lead_time.py +++ b/addons/purchase_stock/tests/test_purchase_lead_time.py @@ -339,3 +339,28 @@ class TestPurchaseLeadTime(PurchaseTestCommon): self.assertEqual(fields.Date.to_date(new_order.date_order), fields.Date.today() + timedelta(days=2)) self.assertEqual(new_order.order_line.product_uom_qty, 5.0) self.patcher.stop() + + def test_supplier_lead_time(self): + """ Basic stock configuration and a supplier with a minimum qty and a lead time """ + self.env['stock.warehouse.orderpoint'].search([]).unlink() + orderpoint_form = Form(self.env['stock.warehouse.orderpoint']) + orderpoint_form.product_id = self.product_1 + orderpoint_form.product_min_qty = 10 + orderpoint_form.product_max_qty = 50 + orderpoint_form.save() + + self.env['product.supplierinfo'].search([('product_tmpl_id', '=', self.product_1.product_tmpl_id.id)]).unlink() + self.env['product.supplierinfo'].create({ + 'name': self.partner_1.id, + 'min_qty': 1, + 'price': 1, + 'delay': 7, + 'product_tmpl_id': self.product_1.product_tmpl_id.id, + }) + + self.env['procurement.group'].run_scheduler() + purchase_order = self.env['purchase.order'].search([('partner_id', '=', self.partner_1.id)]) + + today = fields.Datetime.start_of(fields.Datetime.now(), 'day') + self.assertEqual(purchase_order.date_order, today) + self.assertEqual(fields.Datetime.start_of(purchase_order.date_planned, 'day'), today + timedelta(days=7))