diff --git a/addons/purchase_stock/models/stock_rule.py b/addons/purchase_stock/models/stock_rule.py index 499d0a3bc75..475de4e5e4c 100644 --- a/addons/purchase_stock/models/stock_rule.py +++ b/addons/purchase_stock/models/stock_rule.py @@ -305,9 +305,10 @@ class StockRule(models.Model): ('company_id', '=', company_id.id), ('user_id', '=', False), ) - if values.get('orderpoint_id'): + delta_days = self.env['ir.config_parameter'].sudo().get_param('purchase_stock.delta_days_merge') + if values.get('orderpoint_id') and delta_days is not False: procurement_date = fields.Date.to_date(values['date_planned']) - relativedelta(days=int(values['supplier'].delay)) - delta_days = int(self.env['ir.config_parameter'].sudo().get_param('purchase_stock.delta_days_merge') or 0) + delta_days = int(delta_days) domain += ( ('date_order', '<=', datetime.combine(procurement_date + relativedelta(days=delta_days), datetime.max.time())), ('date_order', '>=', datetime.combine(procurement_date - relativedelta(days=delta_days), datetime.min.time())) diff --git a/addons/purchase_stock/tests/test_purchase_lead_time.py b/addons/purchase_stock/tests/test_purchase_lead_time.py index 852b5501b3f..f15827f2b45 100644 --- a/addons/purchase_stock/tests/test_purchase_lead_time.py +++ b/addons/purchase_stock/tests/test_purchase_lead_time.py @@ -344,7 +344,8 @@ class TestPurchaseLeadTime(PurchaseTestCommon): delivery_moves._action_confirm() self.env['procurement.group'].run_scheduler() po_line = self.env['purchase.order.line'].search([('product_id', '=', product.id)]) - self.assertEqual(fields.Date.to_date(po_line.order_id.date_order), fields.Date.today() + timedelta(days=2)) + expected_date_order = fields.Date.today() + timedelta(days=2) + self.assertEqual(fields.Date.to_date(po_line.order_id.date_order), expected_date_order) self.assertEqual(len(po_line), 1) self.assertEqual(po_line.product_uom_qty, 25.0) self.assertEqual(len(po_line.order_id), 1) @@ -354,12 +355,10 @@ class TestPurchaseLeadTime(PurchaseTestCommon): self.mock_date.today.return_value = fields.Date.today() + timedelta(days=2) orderpoint._compute_qty() self.env['procurement.group'].run_scheduler() - po_line = self.env['purchase.order.line'].search([('product_id', '=', product.id)]) - self.assertEqual(len(po_line), 2) - self.assertEqual(len(po_line.order_id), 2) - new_order = po_line.order_id.sorted('date_order')[-1] - 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) + po_line02 = self.env['purchase.order.line'].search([('product_id', '=', product.id)]) + self.assertEqual(po_line02, po_line, 'The orderpoint execution should not create a new POL') + self.assertEqual(fields.Date.to_date(po_line.order_id.date_order), expected_date_order, 'The Order Deadline should not change') + self.assertEqual(po_line.product_uom_qty, 30.0, 'The existing POL should be updated with the quantity of the last execution') def test_supplier_lead_time(self): """ Basic stock configuration and a supplier with a minimum qty and a lead time """ diff --git a/addons/purchase_stock/tests/test_reordering_rule.py b/addons/purchase_stock/tests/test_reordering_rule.py index 028a0ca1fec..0471ea81a77 100644 --- a/addons/purchase_stock/tests/test_reordering_rule.py +++ b/addons/purchase_stock/tests/test_reordering_rule.py @@ -824,3 +824,89 @@ class TestReorderingRule(TransactionCase): {'location_id': supplier_location_id, 'location_dest_id': input_location_id, 'product_qty': 1}, {'location_id': input_location_id, 'location_dest_id': stock_location_id, 'product_qty': 1}, ]) + + def test_add_line_to_existing_draft_po(self): + """ + Days to purchase = 10 + Two products P1, P2 from the same supplier + Several use cases, each time we run the RR one by one. Then, according + to the dates and the configuration, it should use the existing PO or not + """ + warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1) + + self.env.company.days_to_purchase = 10 + expected_order_date = dt.combine(dt.today() + td(days=10), dt.min.time()) + expected_delivery_date = expected_order_date + td(days=1.0) + # expected_delivery_date = expected_delivery_date.replace(hour=12, minute=0, second=0) + + product_02 = self.env['product.product'].create({ + 'name': 'Super Product', + 'type': 'product', + 'seller_ids': [(0, 0, {'partner_id': self.partner.id})], + }) + + op_01, op_02 = self.env['stock.warehouse.orderpoint'].create([{ + 'warehouse_id': warehouse.id, + 'location_id': warehouse.lot_stock_id.id, + 'product_id': p.id, + 'product_min_qty': 1, + 'product_max_qty': 0, + } for p in [self.product_01, product_02]]) + + op_01.action_replenish() + po01 = self.env['purchase.order'].search([], order='id desc', limit=1) + self.assertEqual(po01.date_order, expected_order_date) + + op_02.action_replenish() + self.assertEqual(po01.date_order, expected_order_date) + self.assertRecordValues(po01.order_line, [ + {'product_id': self.product_01.id, 'date_planned': expected_delivery_date}, + {'product_id': product_02.id, 'date_planned': expected_delivery_date}, + ]) + + # Reset and try another flow + po01.button_cancel() + op_01.action_replenish() + po02 = self.env['purchase.order'].search([], order='id desc', limit=1) + self.assertNotEqual(po02, po01) + + with freeze_time(dt.today() + td(days=1)): + op_02.invalidate_recordset(fnames=['lead_days_date']) + op_02.action_replenish() + self.assertEqual(po02.date_order, expected_order_date) + self.assertRecordValues(po02.order_line, [ + {'product_id': self.product_01.id, 'date_planned': expected_delivery_date}, + {'product_id': product_02.id, 'date_planned': expected_delivery_date + td(days=1)}, + ]) + + # Restrict the merge with POs that have their order deadline in [today - 2 days, today + 2 days] + self.env['ir.config_parameter'].set_param('purchase_stock.delta_days_merge', '2') + + # Reset and try with a second RR executed in the dates range (-> should still use the existing PO) + po02.button_cancel() + op_01.action_replenish() + po03 = self.env['purchase.order'].search([], order='id desc', limit=1) + self.assertNotEqual(po03, po02) + + with freeze_time(dt.today() + td(days=2)): + op_02.invalidate_recordset(fnames=['lead_days_date']) + op_02.action_replenish() + self.assertEqual(po03.date_order, expected_order_date) + self.assertRecordValues(po03.order_line, [ + {'product_id': self.product_01.id, 'date_planned': expected_delivery_date}, + {'product_id': product_02.id, 'date_planned': expected_delivery_date + td(days=2)}, + ]) + + # Reset and try with a second RR executed after the dates range (-> should not use the existing PO) + po03.button_cancel() + op_01.action_replenish() + po04 = self.env['purchase.order'].search([], order='id desc', limit=1) + self.assertNotEqual(po04, po03) + + with freeze_time(dt.today() + td(days=3)): + op_02.invalidate_recordset(fnames=['lead_days_date']) + op_02.action_replenish() + self.assertEqual(po04.order_line.product_id, self.product_01, 'There should be only a line for product 01') + po05 = self.env['purchase.order'].search([], order='id desc', limit=1) + self.assertNotEqual(po05, po04, 'A new PO should be generated') + self.assertEqual(po05.order_line.product_id, product_02)