summaryrefslogtreecommitdiff
path: root/addons/mrp/tests/test_stock.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/mrp/tests/test_stock.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/mrp/tests/test_stock.py')
-rw-r--r--addons/mrp/tests/test_stock.py350
1 files changed, 350 insertions, 0 deletions
diff --git a/addons/mrp/tests/test_stock.py b/addons/mrp/tests/test_stock.py
new file mode 100644
index 00000000..64587e1c
--- /dev/null
+++ b/addons/mrp/tests/test_stock.py
@@ -0,0 +1,350 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import common
+from odoo.exceptions import UserError
+from odoo.tests import Form
+
+
+class TestWarehouse(common.TestMrpCommon):
+ def setUp(self):
+ super(TestWarehouse, self).setUp()
+
+ unit = self.env.ref("uom.product_uom_unit")
+ self.stock_location = self.env.ref('stock.stock_location_stock')
+ self.depot_location = self.env['stock.location'].create({
+ 'name': 'Depot',
+ 'usage': 'internal',
+ 'location_id': self.stock_location.id,
+ })
+ self.env["stock.putaway.rule"].create({
+ "location_in_id": self.stock_location.id,
+ "location_out_id": self.depot_location.id,
+ 'category_id': self.env.ref('product.product_category_all').id,
+ })
+ mrp_workcenter = self.env['mrp.workcenter'].create({
+ 'name': 'Assembly Line 1',
+ 'resource_calendar_id': self.env.ref('resource.resource_calendar_std').id,
+ })
+ inventory = self.env['stock.inventory'].create({
+ 'name': 'Initial inventory',
+ 'line_ids': [(0, 0, {
+ 'product_id': self.graphics_card.id,
+ 'product_uom_id': self.graphics_card.uom_id.id,
+ 'product_qty': 16.0,
+ 'location_id': self.stock_location_14.id,
+ })]
+ })
+ inventory.action_start()
+ inventory.action_validate()
+
+ self.bom_laptop = self.env['mrp.bom'].create({
+ 'product_tmpl_id': self.laptop.product_tmpl_id.id,
+ 'product_qty': 1,
+ 'product_uom_id': unit.id,
+ 'consumption': 'flexible',
+ 'bom_line_ids': [(0, 0, {
+ 'product_id': self.graphics_card.id,
+ 'product_qty': 1,
+ 'product_uom_id': unit.id
+ })],
+ 'operation_ids': [
+ (0, 0, {'name': 'Cutting Machine', 'workcenter_id': self.workcenter_1.id, 'time_cycle': 12, 'sequence': 1}),
+ ],
+ })
+
+ def new_mo_laptop(self):
+ form = Form(self.env['mrp.production'])
+ form.product_id = self.laptop
+ form.product_qty = 1
+ form.bom_id = self.bom_laptop
+ p = form.save()
+ p.action_confirm()
+ p.action_assign()
+ return p
+
+ def test_manufacturing_route(self):
+ warehouse_1_stock_manager = self.warehouse_1.with_user(self.user_stock_manager)
+ manu_rule = self.env['stock.rule'].search([
+ ('action', '=', 'manufacture'),
+ ('warehouse_id', '=', self.warehouse_1.id)])
+ self.assertEqual(self.warehouse_1.manufacture_pull_id, manu_rule)
+ manu_route = manu_rule.route_id
+ self.assertIn(manu_route, warehouse_1_stock_manager._get_all_routes())
+ warehouse_1_stock_manager.write({
+ 'manufacture_to_resupply': False
+ })
+ self.assertFalse(self.warehouse_1.manufacture_pull_id.active)
+ self.assertFalse(self.warehouse_1.manu_type_id.active)
+ self.assertNotIn(manu_route, warehouse_1_stock_manager._get_all_routes())
+ warehouse_1_stock_manager.write({
+ 'manufacture_to_resupply': True
+ })
+ manu_rule = self.env['stock.rule'].search([
+ ('action', '=', 'manufacture'),
+ ('warehouse_id', '=', self.warehouse_1.id)])
+ self.assertEqual(self.warehouse_1.manufacture_pull_id, manu_rule)
+ self.assertTrue(self.warehouse_1.manu_type_id.active)
+ self.assertIn(manu_route, warehouse_1_stock_manager._get_all_routes())
+
+ def test_manufacturing_scrap(self):
+ """
+ Testing to do a scrap of consumed material.
+ """
+
+ # Update demo products
+ (self.product_4 | self.product_2).write({
+ 'tracking': 'lot',
+ })
+
+ # Update Bill Of Material to remove product with phantom bom.
+ self.bom_3.bom_line_ids.filtered(lambda x: x.product_id == self.product_5).unlink()
+
+ # Create Inventory Adjustment For Stick and Stone Tools with lot.
+ lot_product_4 = self.env['stock.production.lot'].create({
+ 'name': '0000000000001',
+ 'product_id': self.product_4.id,
+ 'company_id': self.env.company.id,
+ })
+ lot_product_2 = self.env['stock.production.lot'].create({
+ 'name': '0000000000002',
+ 'product_id': self.product_2.id,
+ 'company_id': self.env.company.id,
+ })
+
+ stock_inv_product_4 = self.env['stock.inventory'].create({
+ 'name': 'Stock Inventory for Stick',
+ 'product_ids': [(4, self.product_4.id)],
+ 'line_ids': [
+ (0, 0, {'product_id': self.product_4.id, 'product_uom_id': self.product_4.uom_id.id, 'product_qty': 8, 'prod_lot_id': lot_product_4.id, 'location_id': self.stock_location_14.id}),
+ ]})
+
+ stock_inv_product_2 = self.env['stock.inventory'].create({
+ 'name': 'Stock Inventory for Stone Tools',
+ 'product_ids': [(4, self.product_2.id)],
+ 'line_ids': [
+ (0, 0, {'product_id': self.product_2.id, 'product_uom_id': self.product_2.uom_id.id, 'product_qty': 12, 'prod_lot_id': lot_product_2.id, 'location_id': self.stock_location_14.id})
+ ]})
+ (stock_inv_product_4 | stock_inv_product_2)._action_start()
+ stock_inv_product_2.action_validate()
+ stock_inv_product_4.action_validate()
+
+ #Create Manufacturing order.
+ production_form = Form(self.env['mrp.production'])
+ production_form.product_id = self.product_6
+ production_form.bom_id = self.bom_3
+ production_form.product_qty = 12
+ production_form.product_uom_id = self.product_6.uom_id
+ production_3 = production_form.save()
+ production_3.action_confirm()
+ production_3.action_assign()
+
+ # Check Manufacturing order's availability.
+ self.assertEqual(production_3.reservation_state, 'assigned', "Production order's availability should be Available.")
+
+ location_id = production_3.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel')) and production_3.location_src_id.id or production_3.location_dest_id.id,
+
+ # Scrap Product Wood without lot to check assert raise ?.
+ scrap_id = self.env['stock.scrap'].with_context(active_model='mrp.production', active_id=production_3.id).create({'product_id': self.product_2.id, 'scrap_qty': 1.0, 'product_uom_id': self.product_2.uom_id.id, 'location_id': location_id, 'production_id': production_3.id})
+ with self.assertRaises(UserError):
+ scrap_id.do_scrap()
+
+ # Scrap Product Wood with lot.
+ self.env['stock.scrap'].with_context(active_model='mrp.production', active_id=production_3.id).create({'product_id': self.product_2.id, 'scrap_qty': 1.0, 'product_uom_id': self.product_2.uom_id.id, 'location_id': location_id, 'lot_id': lot_product_2.id, 'production_id': production_3.id})
+
+ #Check scrap move is created for this production order.
+ #TODO: should check with scrap objects link in between
+
+# scrap_move = production_3.move_raw_ids.filtered(lambda x: x.product_id == self.product_2 and x.scrapped)
+# self.assertTrue(scrap_move, "There are no any scrap move created for production order.")
+
+ def test_putaway_after_manufacturing_3(self):
+ """ This test checks a tracked manufactured product will go to location
+ defined in putaway strategy when the production is recorded with
+ product.produce wizard.
+ """
+ self.laptop.tracking = 'serial'
+ mo_laptop = self.new_mo_laptop()
+ serial = self.env['stock.production.lot'].create({'product_id': self.laptop.id, 'company_id': self.env.company.id})
+
+ mo_form = Form(mo_laptop)
+ mo_form.qty_producing = 1
+ mo_form.lot_producing_id = serial
+ mo_laptop = mo_form.save()
+ mo_laptop.button_mark_done()
+
+ # We check if the laptop go in the depot and not in the stock
+ move = mo_laptop.move_finished_ids
+ location_dest = move.move_line_ids.location_dest_id
+ self.assertEqual(location_dest.id, self.depot_location.id)
+ self.assertNotEqual(location_dest.id, self.stock_location.id)
+
+class TestKitPicking(common.TestMrpCommon):
+ def setUp(self):
+ super(TestKitPicking, self).setUp()
+
+ def create_product(name):
+ p = Form(self.env['product.product'])
+ p.name = name
+ p.type = 'product'
+ return p.save()
+
+ # Create a kit 'kit_parent' :
+ # ---------------------------
+ #
+ # kit_parent --|- kit_2 x2 --|- component_d x1
+ # | |- kit_1 x2 -------|- component_a x2
+ # | |- component_b x1
+ # | |- component_c x3
+ # |
+ # |- kit_3 x1 --|- component_f x1
+ # | |- component_g x2
+ # |
+ # |- component_e x1
+ # Creating all components
+ component_a = create_product('Comp A')
+ component_b = create_product('Comp B')
+ component_c = create_product('Comp C')
+ component_d = create_product('Comp D')
+ component_e = create_product('Comp E')
+ component_f = create_product('Comp F')
+ component_g = create_product('Comp G')
+ # Creating all kits
+ kit_1 = create_product('Kit 1')
+ kit_2 = create_product('Kit 2')
+ kit_3 = create_product('kit 3')
+ self.kit_parent = create_product('Kit Parent')
+ # Linking the kits and the components via some 'phantom' BoMs
+ bom_kit_1 = self.env['mrp.bom'].create({
+ 'product_tmpl_id': kit_1.product_tmpl_id.id,
+ 'product_qty': 1.0,
+ 'type': 'phantom'})
+ BomLine = self.env['mrp.bom.line']
+ BomLine.create({
+ 'product_id': component_a.id,
+ 'product_qty': 2.0,
+ 'bom_id': bom_kit_1.id})
+ BomLine.create({
+ 'product_id': component_b.id,
+ 'product_qty': 1.0,
+ 'bom_id': bom_kit_1.id})
+ BomLine.create({
+ 'product_id': component_c.id,
+ 'product_qty': 3.0,
+ 'bom_id': bom_kit_1.id})
+ bom_kit_2 = self.env['mrp.bom'].create({
+ 'product_tmpl_id': kit_2.product_tmpl_id.id,
+ 'product_qty': 1.0,
+ 'type': 'phantom'})
+ BomLine.create({
+ 'product_id': component_d.id,
+ 'product_qty': 1.0,
+ 'bom_id': bom_kit_2.id})
+ BomLine.create({
+ 'product_id': kit_1.id,
+ 'product_qty': 2.0,
+ 'bom_id': bom_kit_2.id})
+ bom_kit_parent = self.env['mrp.bom'].create({
+ 'product_tmpl_id': self.kit_parent.product_tmpl_id.id,
+ 'product_qty': 1.0,
+ 'type': 'phantom'})
+ BomLine.create({
+ 'product_id': component_e.id,
+ 'product_qty': 1.0,
+ 'bom_id': bom_kit_parent.id})
+ BomLine.create({
+ 'product_id': kit_2.id,
+ 'product_qty': 2.0,
+ 'bom_id': bom_kit_parent.id})
+ bom_kit_3 = self.env['mrp.bom'].create({
+ 'product_tmpl_id': kit_3.product_tmpl_id.id,
+ 'product_qty': 1.0,
+ 'type': 'phantom'})
+ BomLine.create({
+ 'product_id': component_f.id,
+ 'product_qty': 1.0,
+ 'bom_id': bom_kit_3.id})
+ BomLine.create({
+ 'product_id': component_g.id,
+ 'product_qty': 2.0,
+ 'bom_id': bom_kit_3.id})
+ BomLine.create({
+ 'product_id': kit_3.id,
+ 'product_qty': 1.0,
+ 'bom_id': bom_kit_parent.id})
+
+ # We create an 'immediate transfer' receipt for x3 kit_parent
+ self.test_partner = self.env['res.partner'].create({
+ 'name': 'Notthat Guyagain',
+ })
+ self.test_supplier = self.env['stock.location'].create({
+ 'name': 'supplier',
+ 'usage': 'supplier',
+ 'location_id': self.env.ref('stock.stock_location_stock').id,
+ })
+
+ self.expected_quantities = {
+ component_a: 24,
+ component_b: 12,
+ component_c: 36,
+ component_d: 6,
+ component_e: 3,
+ component_f: 3,
+ component_g: 6
+ }
+
+ def test_kit_immediate_transfer(self):
+ """ Make sure a kit is split in the corrects quantity_done by components in case of an
+ immediate transfer.
+ """
+ picking = self.env['stock.picking'].create({
+ 'location_id': self.test_supplier.id,
+ 'location_dest_id': self.warehouse_1.wh_input_stock_loc_id.id,
+ 'partner_id': self.test_partner.id,
+ 'picking_type_id': self.env.ref('stock.picking_type_in').id,
+ 'immediate_transfer': True
+ })
+ move_receipt_1 = self.env['stock.move'].create({
+ 'name': self.kit_parent.name,
+ 'product_id': self.kit_parent.id,
+ 'quantity_done': 3,
+ 'product_uom': self.kit_parent.uom_id.id,
+ 'picking_id': picking.id,
+ 'picking_type_id': self.env.ref('stock.picking_type_in').id,
+ 'location_id': self.test_supplier.id,
+ 'location_dest_id': self.warehouse_1.wh_input_stock_loc_id.id,
+ })
+ picking.button_validate()
+
+ # We check that the picking has the correct quantities after its move were splitted.
+ self.assertEqual(len(picking.move_lines), 7)
+ for move_line in picking.move_lines:
+ self.assertEqual(move_line.quantity_done, self.expected_quantities[move_line.product_id])
+
+ def test_kit_planned_transfer(self):
+ """ Make sure a kit is split in the corrects product_qty by components in case of a
+ planned transfer.
+ """
+ picking = self.env['stock.picking'].create({
+ 'location_id': self.test_supplier.id,
+ 'location_dest_id': self.warehouse_1.wh_input_stock_loc_id.id,
+ 'partner_id': self.test_partner.id,
+ 'picking_type_id': self.env.ref('stock.picking_type_in').id,
+ 'immediate_transfer': False,
+ })
+ move_receipt_1 = self.env['stock.move'].create({
+ 'name': self.kit_parent.name,
+ 'product_id': self.kit_parent.id,
+ 'product_uom_qty': 3,
+ 'product_uom': self.kit_parent.uom_id.id,
+ 'picking_id': picking.id,
+ 'picking_type_id': self.env.ref('stock.picking_type_in').id,
+ 'location_id': self.test_supplier.id,
+ 'location_dest_id': self.warehouse_1.wh_input_stock_loc_id.id,
+ })
+ picking.action_confirm()
+
+ # We check that the picking has the correct quantities after its move were splitted.
+ self.assertEqual(len(picking.move_lines), 7)
+ for move_line in picking.move_lines:
+ self.assertEqual(move_line.product_qty, self.expected_quantities[move_line.product_id])