From 775a7ec52cece79a531606bebc5636b99c2c6cff Mon Sep 17 00:00:00 2001 From: Martin Maes Date: Tue, 7 Nov 2023 10:43:25 +0100 Subject: [PATCH] [IMP] mrp,stock,purchase_stock: add test for replenishment wizard This commit adds tests for the computation of the date of the replenishment wizard. Taken into account for the date computation: - vendor lead time - days to purchase - security days for purchase - security days for mrp - rule lead time task-3527727 Part-of: odoo/odoo#145384 --- addons/mrp/tests/__init__.py | 1 + addons/mrp/tests/test_replenish.py | 57 +++++++++ .../tests/test_replenish_wizard.py | 121 +++++++++++++++++- .../tests/test_stockvaluation.py | 2 +- addons/stock/tests/__init__.py | 1 + addons/stock/tests/test_move2.py | 2 +- addons/stock/tests/test_replenish.py | 68 ++++++++++ addons/stock/tests/test_stock_flow.py | 2 +- 8 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 addons/mrp/tests/test_replenish.py create mode 100644 addons/stock/tests/test_replenish.py diff --git a/addons/mrp/tests/__init__.py b/addons/mrp/tests/__init__.py index 6467e3450df..f52a3d6e529 100644 --- a/addons/mrp/tests/__init__.py +++ b/addons/mrp/tests/__init__.py @@ -8,6 +8,7 @@ from . import test_stock from . import test_stock_report from . import test_warehouse_multistep_manufacturing from . import test_procurement +from . import test_replenish from . import test_unbuild from . import test_oee from . import test_traceability diff --git a/addons/mrp/tests/test_replenish.py b/addons/mrp/tests/test_replenish.py new file mode 100644 index 00000000000..63002c62465 --- /dev/null +++ b/addons/mrp/tests/test_replenish.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from freezegun import freeze_time + +from odoo.addons.mrp.tests.common import TestMrpCommon +from odoo import fields + + + +class TestMrpReplenish(TestMrpCommon): + + def _create_wizard(self, product, wh): + return self.env['product.replenish'].with_context(default_product_tmpl_id=product.product_tmpl_id.id).create({ + 'product_id': product.id, + 'product_uom_id': self.uom_unit.id, + 'quantity': 1, + 'warehouse_id': wh.id, + }) + + def test_mrp_delay(self): + """Open the replenish view and check if delay is taken into account + in the base date computation + """ + route = self.env.ref('mrp.route_warehouse0_manufacture') + product = self.product_4 + product.route_ids = route + wh = self.env['stock.warehouse'].search([('company_id', '=', self.env.user.id)], limit=1) + self.env.company.manufacturing_lead = 0 + self.env['ir.config_parameter'].sudo().set_param('mrp.use_manufacturing_lead', True) + + with freeze_time("2023-01-01"): + wizard = self._create_wizard(product, wh) + self.assertEqual(fields.Datetime.from_string('2023-01-01 00:00:00'), wizard.date_planned) + self.env.company.manufacturing_lead = 3 + wizard2 = self._create_wizard(product, wh) + self.assertEqual(fields.Datetime.from_string('2023-01-04 00:00:00'), wizard2.date_planned) + route.rule_ids[0].delay = 2 + wizard3 = self._create_wizard(product, wh) + self.assertEqual(fields.Datetime.from_string('2023-01-06 00:00:00'), wizard3.date_planned) + + def test_mrp_delay_bom(self): + route = self.env.ref('mrp.route_warehouse0_manufacture') + product = self.product_4 + bom = product.bom_ids + product.route_ids = route + wh = self.env['stock.warehouse'].search([('company_id', '=', self.env.user.id)], limit=1) + self.env.company.manufacturing_lead = 0 + with freeze_time("2023-01-01"): + wizard = self._create_wizard(product, wh) + self.assertEqual(fields.Datetime.from_string('2023-01-01 00:00:00'), wizard.date_planned) + bom.produce_delay = 2 + wizard2 = self._create_wizard(product, wh) + self.assertEqual(fields.Datetime.from_string('2023-01-03 00:00:00'), wizard2.date_planned) + bom.days_to_prepare_mo = 4 + wizard3 = self._create_wizard(product, wh) + self.assertEqual(fields.Datetime.from_string('2023-01-07 00:00:00'), wizard3.date_planned) diff --git a/addons/purchase_stock/tests/test_replenish_wizard.py b/addons/purchase_stock/tests/test_replenish_wizard.py index a60624905cd..47491652a68 100644 --- a/addons/purchase_stock/tests/test_replenish_wizard.py +++ b/addons/purchase_stock/tests/test_replenish_wizard.py @@ -1,7 +1,11 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from freezegun import freeze_time + from odoo.addons.stock.tests.common import TestStockCommon +from odoo import fields + class TestReplenishWizard(TestStockCommon): @classmethod @@ -36,7 +40,7 @@ class TestReplenishWizard(TestStockCommon): """ self.product_uom_qty = 42 - replenish_wizard = self.env['product.replenish'].create({ + replenish_wizard = self.env['product.replenish'].with_context(default_product_tmpl_id=self.product1.product_tmpl_id.id).create({ 'product_id': self.product1.id, 'product_tmpl_id': self.product1.product_tmpl_id.id, 'product_uom_id': self.uom_unit.id, @@ -89,7 +93,7 @@ class TestReplenishWizard(TestStockCommon): 'sequence': 2, }) - replenish_wizard = self.env['product.replenish'].create({ + replenish_wizard = self.env['product.replenish'].with_context(default_product_tmpl_id=product_to_buy.product_tmpl_id.id).create({ 'product_id': product_to_buy.id, 'product_tmpl_id': product_to_buy.product_tmpl_id.id, 'product_uom_id': self.uom_unit.id, @@ -148,7 +152,7 @@ class TestReplenishWizard(TestStockCommon): 'sequence': 3, }) - replenish_wizard = self.env['product.replenish'].create({ + replenish_wizard = self.env['product.replenish'].with_context(default_product_tmpl_id=product_to_buy.product_tmpl_id.id).create({ 'product_id': product_to_buy.id, 'product_tmpl_id': product_to_buy.product_tmpl_id.id, 'product_uom_id': self.uom_unit.id, @@ -197,7 +201,7 @@ class TestReplenishWizard(TestStockCommon): 'sequence': 1, }) - replenish_wizard = self.env['product.replenish'].create({ + replenish_wizard = self.env['product.replenish'].with_context(default_product_tmpl_id=product_to_buy.product_tmpl_id.id).create({ 'product_id': product_to_buy.id, 'product_tmpl_id': product_to_buy.product_tmpl_id.id, 'product_uom_id': self.uom_unit.id, @@ -250,7 +254,7 @@ class TestReplenishWizard(TestStockCommon): 'product_tmpl_id': product_to_buy.product_tmpl_id.id, 'min_qty': 5 }) - replenish_wizard = self.env['product.replenish'].create({ + replenish_wizard = self.env['product.replenish'].with_context(default_product_tmpl_id=product_to_buy.product_tmpl_id.id).create({ 'product_id': product_to_buy.id, 'product_tmpl_id': product_to_buy.product_tmpl_id.id, 'product_uom_id': self.uom_unit.id, @@ -268,3 +272,110 @@ class TestReplenishWizard(TestStockCommon): self.assertEqual(last_po_id.partner_id, vendor1) self.assertEqual(last_po_id.order_line.price_unit, 60) + + def test_supplier_delay(self): + product_to_buy = self.env['product.product'].create({ + 'name': "Furniture Service", + 'type': 'product', + 'categ_id': self.env.ref('product.product_category_all').id, + 'route_ids': [(4, self.env.ref('purchase_stock.route_warehouse0_buy').id, 0)], + }) + vendor1 = self.env['res.partner'].create({'name': 'vendor1', 'email': 'from.test@example.com'}) + supplier_delay = self.env['product.supplierinfo'].create({ + 'partner_id': vendor1.id, + 'price': 100, + 'product_tmpl_id': product_to_buy.product_tmpl_id.id, + 'min_qty': 2, + 'delay': 3 + }) + supplier_no_delay = self.env['product.supplierinfo'].create({ + 'partner_id': vendor1.id, + 'price': 100, + 'product_tmpl_id': product_to_buy.product_tmpl_id.id, + 'min_qty': 2, + 'delay' : 0 + }) + with freeze_time("2023-01-01"): + wizard = self.env['product.replenish'].create({ + 'product_id': product_to_buy.id, + 'product_tmpl_id': product_to_buy.product_tmpl_id.id, + 'product_uom_id': self.uom_unit.id, + 'quantity': 1, + 'warehouse_id': self.wh.id, + 'route_id': self.env.ref('purchase_stock.route_warehouse0_buy').id + }) + wizard.supplier_id = supplier_no_delay + self.assertEqual(fields.Datetime.from_string('2023-01-01 00:00:00'), wizard.date_planned) + wizard.supplier_id = supplier_delay + self.assertEqual(fields.Datetime.from_string('2023-01-04 00:00:00'), wizard.date_planned) + + def test_purchase_delay(self): + product_to_buy = self.env['product.product'].create({ + 'name': "Furniture Service", + 'type': 'product', + 'categ_id': self.env.ref('product.product_category_all').id, + 'route_ids': [(4, self.env.ref('purchase_stock.route_warehouse0_buy').id, 0)], + }) + vendor = self.env['res.partner'].create({'name': 'vendor1', 'email': 'from.test@example.com'}) + supplier1 = self.env['product.supplierinfo'].create({ + 'partner_id': vendor.id, + 'price': 100, + 'product_tmpl_id': product_to_buy.product_tmpl_id.id, + 'min_qty': 2, + 'delay': 0 + }) + supplier2 = self.env['product.supplierinfo'].create({ + 'partner_id': vendor.id, + 'price': 100, + 'product_tmpl_id': product_to_buy.product_tmpl_id.id, + 'min_qty': 2, + 'delay' : 0 + }) + self.env['ir.config_parameter'].sudo().set_param('purchase.use_po_lead', True) + self.env.company.days_to_purchase = 0 + + with freeze_time("2023-01-01"): + wizard = self.env['product.replenish'].create({ + 'product_id': product_to_buy.id, + 'product_tmpl_id': product_to_buy.product_tmpl_id.id, + 'product_uom_id': self.uom_unit.id, + 'quantity': 1, + 'warehouse_id': self.wh.id, + 'route_id': self.env.ref('purchase_stock.route_warehouse0_buy').id + }) + wizard.supplier_id = supplier1 + self.assertEqual(fields.Datetime.from_string('2023-01-01 00:00:00'), wizard.date_planned) + self.env.company.days_to_purchase = 5 + # change the supplier to trigger the date computation + wizard.supplier_id = supplier2 + self.assertEqual(fields.Datetime.from_string('2023-01-06 00:00:00'), wizard.date_planned) + + def test_purchase_supplier_route_delay(self): + product_to_buy = self.env['product.product'].create({ + 'name': "Furniture Service", + 'type': 'product', + 'categ_id': self.env.ref('product.product_category_all').id, + 'route_ids': [(4, self.env.ref('purchase_stock.route_warehouse0_buy').id, 0)], + }) + vendor = self.env['res.partner'].create({'name': 'vendor1', 'email': 'from.test@example.com'}) + supplier = self.env['product.supplierinfo'].create({ + 'partner_id': vendor.id, + 'price': 100, + 'product_tmpl_id': product_to_buy.product_tmpl_id.id, + 'min_qty': 2, + 'delay': 2 + }) + self.env['ir.config_parameter'].sudo().set_param('purchase.use_po_lead', True) + self.env.company.days_to_purchase = 5 + + with freeze_time("2023-01-01"): + wizard = self.env['product.replenish'].create({ + 'product_id': product_to_buy.id, + 'product_tmpl_id': product_to_buy.product_tmpl_id.id, + 'product_uom_id': self.uom_unit.id, + 'quantity': 1, + 'warehouse_id': self.wh.id, + 'route_id': self.env.ref('purchase_stock.route_warehouse0_buy').id + }) + wizard.supplier_id = supplier + self.assertEqual(fields.Datetime.from_string('2023-01-08 00:00:00'), wizard.date_planned) diff --git a/addons/purchase_stock/tests/test_stockvaluation.py b/addons/purchase_stock/tests/test_stockvaluation.py index 8f9862a8e18..6b06be75df3 100644 --- a/addons/purchase_stock/tests/test_stockvaluation.py +++ b/addons/purchase_stock/tests/test_stockvaluation.py @@ -103,7 +103,7 @@ class TestStockValuation(TransactionCase): # Create a manual replenishment replenishment_uom_qty = 200 - replenish_wizard = self.env['product.replenish'].create({ + replenish_wizard = self.env['product.replenish'].with_context(default_product_tmpl_id=self.product1.product_tmpl_id.id).create({ 'product_id': self.product1.id, 'product_tmpl_id': self.product1.product_tmpl_id.id, 'product_uom_id': ap.id, diff --git a/addons/stock/tests/__init__.py b/addons/stock/tests/__init__.py index 74613df028f..9cfe78269f6 100644 --- a/addons/stock/tests/__init__.py +++ b/addons/stock/tests/__init__.py @@ -24,3 +24,4 @@ from . import test_stock_return_picking from . import test_stock_lot from . import test_picking from . import test_picking_tours +from . import test_replenish diff --git a/addons/stock/tests/test_move2.py b/addons/stock/tests/test_move2.py index 5097c63c95b..cc757e8d25f 100644 --- a/addons/stock/tests/test_move2.py +++ b/addons/stock/tests/test_move2.py @@ -2742,7 +2742,7 @@ class TestRoutes(TestStockCommon): self.product1.write({'route_ids': [(4, resupply_route.id), (4, self.env.ref('stock.route_warehouse0_mto').id)]}) self.wh = warehouse_1 - replenish_wizard = self.env['product.replenish'].create({ + replenish_wizard = self.env['product.replenish'].with_context(default_product_tmpl_id=self.product1.product_tmpl_id.id).create({ 'product_id': self.product1.id, 'product_tmpl_id': self.product1.product_tmpl_id.id, 'product_uom_id': self.uom_unit.id, diff --git a/addons/stock/tests/test_replenish.py b/addons/stock/tests/test_replenish.py new file mode 100644 index 00000000000..b66a5009b8f --- /dev/null +++ b/addons/stock/tests/test_replenish.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from freezegun import freeze_time + +from odoo.addons.stock.tests.common import TestStockCommon +from odoo.tests import Form +from odoo import fields + + + +class TestStockReplenish(TestStockCommon): + + def test_base_delay(self): + """Open the replenish view and check if delay is taken into account + in the base date computation + """ + stock_location = self.env.ref('stock.stock_location_stock') + + push_location = self.env['stock.location'].create({ + 'location_id': stock_location.location_id.id, + 'name': 'push location', + }) + + route_no_delay = self.env['stock.route'].create({ + 'name': 'new route', + 'rule_ids': [(0, False, { + 'name': 'create a move to push location', + 'location_src_id': stock_location.id, + 'location_dest_id': push_location.id, + 'company_id': self.env.company.id, + 'action': 'push', + 'auto': 'manual', + 'picking_type_id': self.env.ref('stock.picking_type_in').id, + 'delay': 0, + })], + }) + + route_delay = self.env['stock.route'].create({ + 'name': 'new route', + 'rule_ids': [(0, False, { + 'name': 'create a move to push location', + 'location_src_id': stock_location.id, + 'location_dest_id': push_location.id, + 'company_id': self.env.company.id, + 'action': 'push', + 'auto': 'manual', + 'picking_type_id': self.env.ref('stock.picking_type_in').id, + 'delay': 2, + }), + (0, False, { + 'name': 'create a move to push location', + 'location_src_id': push_location.id, + 'location_dest_id': stock_location.id, + 'company_id': self.env.company.id, + 'action': 'push', + 'auto': 'manual', + 'picking_type_id': self.env.ref('stock.picking_type_in').id, + 'delay': 4, + })], + }) + + with freeze_time("2023-01-01"): + wizard = Form(self.env['product.replenish']) + wizard.route_id = route_no_delay + self.assertEqual(fields.Datetime.from_string('2023-01-01 00:00:00'), wizard._values['date_planned']) + wizard.route_id = route_delay + self.assertEqual(fields.Datetime.from_string('2023-01-07 00:00:00'), wizard._values['date_planned']) diff --git a/addons/stock/tests/test_stock_flow.py b/addons/stock/tests/test_stock_flow.py index 53c9379724d..a6eaff54b2e 100644 --- a/addons/stock/tests/test_stock_flow.py +++ b/addons/stock/tests/test_stock_flow.py @@ -1801,7 +1801,7 @@ class TestStockFlow(TestStockCommon): 'route_ids': [(4, route_a.id), (4, route_b.id)] }) - replenish_wizard = self.env['product.replenish'].create({ + replenish_wizard = self.env['product.replenish'].with_context(default_product_tmpl_id=product.product_tmpl_id.id).create({ 'product_id': product.id, 'product_tmpl_id': product.product_tmpl_id.id, 'product_uom_id': self.uom_unit.id,