[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 <today minus 7 days> instead of today. The
receipt date is today instead of <today plus 7 days>

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 <today minus 7 days>

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 <amoyaux@users.noreply.github.com>
Signed-off-by: Adrien Widart <adwid@users.noreply.github.com>
This commit is contained in:
Adrien Widart
2021-09-24 11:09:00 +00:00
parent 20d6c0c7e2
commit 83def413b8
3 changed files with 27 additions and 2 deletions
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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()
@@ -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))