def test_production_2(self): """Check that confirming a production in company b with user_a will create stock moves on company b. """ product_a = self.env['product.product'].create({ 'name': 'p1', 'company_id': self.company_a.id, }) component_a = self.env['product.product'].create({ 'name': 'p2', 'company_id': self.company_a.id, }) self.env['mrp.bom'].create({ 'product_id': product_a.id, 'product_tmpl_id': product_a.product_tmpl_id.id, 'company_id': self.company_a.id, 'bom_line_ids': [(0, 0, { 'product_id': component_a.id })] }) mo_form = Form(self.env['mrp.production'].with_user(self.user_a)) mo_form.product_id = product_a mo = mo_form.save() mo.with_user(self.user_b).action_confirm() self.assertEqual(mo.move_raw_ids.company_id, self.company_a) self.assertEqual(mo.move_finished_ids.company_id, self.company_a)
def test_procurement_2(self): """Check that a manufacturing order create the right procurements when the route are set on a parent category of a product""" # find a child category id all_categ_id = self.env['product.category'].search( [('parent_id', '=', None)], limit=1) child_categ_id = self.env['product.category'].search( [('parent_id', '=', all_categ_id.id)], limit=1) # set the product of `self.bom_1` to this child category for bom_line_id in self.bom_1.bom_line_ids: # check that no routes are defined on the product self.assertEquals(len(bom_line_id.product_id.route_ids), 0) # set the category of the product to a child category bom_line_id.product_id.categ_id = child_categ_id # set the MTO route to the parent category (all) self.warehouse = self.env.ref('stock.warehouse0') mto_route = self.warehouse.mto_pull_id.route_id mto_route.product_categ_selectable = True all_categ_id.write({'route_ids': [(6, 0, [mto_route.id])]}) # create MO, but check it raises error as components are in make to order and not everyone has with self.assertRaises(UserError): production_form = Form(self.env['mrp.production']) production_form.product_id = self.product_4 production_form.product_uom_id = self.product_4.uom_id production_form.product_qty = 1 production_product_4 = production_form.save() production_product_4.action_confirm()
def _make_mo(self, bom, quantity=1): mo_form = Form(self.env['mrp.production']) mo_form.product_id = bom.product_id mo_form.bom_id = bom mo_form.product_qty = quantity mo = mo_form.save() mo.action_confirm() return mo
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_reordering_rule(self): """ - Receive products in 2 steps - The product has a reordering rule - On the po generated, the source document should be the name of the reordering rule """ warehouse_1 = self.env['stock.warehouse'].search( [('company_id', '=', self.env.user.id)], limit=1) warehouse_1.write({'reception_steps': 'two_steps'}) # Create a supplier partner = self.env['res.partner'].create({'name': 'Smith'}) # create product and set the vendor product_form = Form(self.env['product.product']) product_form.name = 'Product A' product_form.type = 'product' with product_form.seller_ids.new() as seller: seller.name = partner product_form.route_ids.add( self.env.ref('purchase_stock.route_warehouse0_buy')) product_01 = product_form.save() # create reordering rule orderpoint_form = Form(self.env['stock.warehouse.orderpoint']) orderpoint_form.warehouse_id = warehouse_1 orderpoint_form.location_id = warehouse_1.lot_stock_id orderpoint_form.product_id = product_01 orderpoint_form.product_min_qty = 0.000 orderpoint_form.product_max_qty = 0.000 order_point = orderpoint_form.save() # Create Delivery Order of 10 product picking_form = Form(self.env['stock.picking']) picking_form.partner_id = partner picking_form.picking_type_id = self.env.ref('stock.picking_type_out') with picking_form.move_ids_without_package.new() as move: move.product_id = product_01 move.product_uom_qty = 10.0 customer_picking = picking_form.save() # picking confirm customer_picking.action_confirm() # Run scheduler self.env['procurement.group'].run_scheduler() # Check purchase order created or not purchase_order = self.env['purchase.order'].search([('partner_id', '=', partner.id)]) self.assertTrue(purchase_order, 'No purchase order created.') # On the po generated, the source document should be the name of the reordering rule self.assertEqual( order_point.name, purchase_order.origin, 'Source document on purchase order should be the name of the reordering rule.' )
def setUp(self): super(TestMultistepManufacturing, self).setUp() self.MrpProduction = self.env['mrp.production'] # Create warehouse warehouse_form = Form(self.env['stock.warehouse']) warehouse_form.name = 'Test' warehouse_form.code = 'Test' self.warehouse = warehouse_form.save() self.uom_unit = self.env.ref('uom.product_uom_unit') # Create manufactured product product_form = Form(self.env['product.product']) product_form.name = 'Stick' product_form.uom_id = self.uom_unit product_form.uom_po_id = self.uom_unit product_form.route_ids.clear() product_form.route_ids.add(self.warehouse.manufacture_pull_id.route_id) product_form.route_ids.add(self.warehouse.mto_pull_id.route_id) self.product_manu = product_form.save() # Create raw product for manufactured product product_form = Form(self.env['product.product']) product_form.name = 'Raw Stick' product_form.uom_id = self.uom_unit product_form.uom_po_id = self.uom_unit self.product_raw = product_form.save() # Create bom for manufactured product bom_product_form = Form(self.env['mrp.bom']) bom_product_form.product_id = self.product_manu bom_product_form.product_tmpl_id = self.product_manu.product_tmpl_id bom_product_form.product_qty = 1.0 bom_product_form.type = 'normal' with bom_product_form.bom_line_ids.new() as bom_line: bom_line.product_id = self.product_raw bom_line.product_qty = 2.0 self.bom_prod_manu = bom_product_form.save() # Create sale order sale_form = Form(self.env['sale.order']) sale_form.partner_id = self.env.ref('base.res_partner_1') sale_form.picking_policy = 'direct' sale_form.warehouse_id = self.warehouse with sale_form.order_line.new() as line: line.name = self.product_manu.name line.product_id = self.product_manu line.product_uom_qty = 1.0 line.product_uom = self.uom_unit line.price_unit = 10.0 self.sale_order = sale_form.save()
def setUp(self): super(TestMultistepManufacturingWarehouse, self).setUp() # Create warehouse self.customer_location = self.env['ir.model.data'].xmlid_to_res_id( 'stock.stock_location_customers') warehouse_form = Form(self.env['stock.warehouse']) warehouse_form.name = 'Test Warehouse' warehouse_form.code = 'TWH' self.warehouse = warehouse_form.save() self.uom_unit = self.env.ref('uom.product_uom_unit') # Create manufactured product product_form = Form(self.env['product.product']) product_form.name = 'Stick' product_form.uom_id = self.uom_unit product_form.uom_po_id = self.uom_unit product_form.type = 'product' product_form.route_ids.clear() product_form.route_ids.add(self.warehouse.manufacture_pull_id.route_id) product_form.route_ids.add(self.warehouse.mto_pull_id.route_id) self.finished_product = product_form.save() # Create raw product for manufactured product product_form = Form(self.env['product.product']) product_form.name = 'Raw Stick' product_form.type = 'product' product_form.uom_id = self.uom_unit product_form.uom_po_id = self.uom_unit self.raw_product = product_form.save() # Create bom for manufactured product bom_product_form = Form(self.env['mrp.bom']) bom_product_form.product_id = self.finished_product bom_product_form.product_tmpl_id = self.finished_product.product_tmpl_id bom_product_form.product_qty = 1.0 bom_product_form.type = 'normal' with bom_product_form.bom_line_ids.new() as bom_line: bom_line.product_id = self.raw_product bom_line.product_qty = 2.0 self.bom = bom_product_form.save()
def test_product_produce_2(self): """Check that using a component lot of company b in the produce wizard of a production of company a is not allowed """ product = self.env['product.product'].create({ 'name': 'p1', }) component = self.env['product.product'].create({ 'name': 'p2', 'tracking': 'lot', }) lot_b = self.env['stock.production.lot'].create({ 'product_id': component.id, 'company_id': self.company_b.id, }) self.env['mrp.bom'].create({ 'product_id': product.id, 'product_tmpl_id': product.product_tmpl_id.id, 'company_id': self.company_a.id, 'bom_line_ids': [(0, 0, { 'product_id': component.id })] }) mo_form = Form(self.env['mrp.production'].with_user(self.user_a)) mo_form.product_id = product mo = mo_form.save() mo.with_user(self.user_b).action_confirm() produce_form = Form(self.env['mrp.product.produce'].with_user( self.user_b).with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) with produce_form.raw_workorder_line_ids.edit(0) as line: line.lot_id = lot_b with self.assertRaises(UserError): produce_form.save()
def test_manufacturing_3_steps(self): """ Test MO/picking before manufacturing/picking after manufacturing components and move_orig/move_dest. Ensure that everything is created correctly. """ with Form(self.warehouse) as warehouse: warehouse.manufacture_steps = 'pbm_sam' production_form = Form(self.env['mrp.production']) production_form.product_id = self.finished_product production_form.picking_type_id = self.warehouse.manu_type_id production = production_form.save() production.action_confirm() move_raw_ids = production.move_raw_ids self.assertEqual(len(move_raw_ids), 1) self.assertEqual(move_raw_ids.product_id, self.raw_product) self.assertEqual(move_raw_ids.picking_type_id, self.warehouse.manu_type_id) pbm_move = move_raw_ids.move_orig_ids self.assertEqual(len(pbm_move), 1) self.assertEqual(pbm_move.location_id, self.warehouse.lot_stock_id) self.assertEqual(pbm_move.location_dest_id, self.warehouse.pbm_loc_id) self.assertEqual(pbm_move.picking_type_id, self.warehouse.pbm_type_id) self.assertFalse(pbm_move.move_orig_ids) move_finished_ids = production.move_finished_ids self.assertEqual(len(move_finished_ids), 1) self.assertEqual(move_finished_ids.product_id, self.finished_product) self.assertEqual(move_finished_ids.picking_type_id, self.warehouse.manu_type_id) sam_move = move_finished_ids.move_dest_ids self.assertEqual(len(sam_move), 1) self.assertEqual(sam_move.location_id, self.warehouse.sam_loc_id) self.assertEqual(sam_move.location_dest_id, self.warehouse.lot_stock_id) self.assertEqual(sam_move.picking_type_id, self.warehouse.sam_type_id) self.assertFalse(sam_move.move_dest_ids)
def test_unbuild_standart(self): """ This test creates a MO and then creates 3 unbuild orders for the final product. None of the products for this test are tracked. It checks the stock state after each order and ensure it is correct. """ mo, bom, p_final, p1, p2 = self.generate_mo() self.assertEqual(len(mo), 1, 'MO should have been created') self.env['stock.quant']._update_available_quantity( p1, self.stock_location, 100) self.env['stock.quant']._update_available_quantity( p2, self.stock_location, 5) mo.action_assign() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.qty_producing = 5.0 produce_wizard = produce_form.save() produce_wizard.do_produce() mo.button_mark_done() self.assertEqual(mo.state, 'done', "Production order should be in done state.") # Check quantity in stock before unbuild. self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location), 5, 'You should have the 5 final product in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location), 80, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location), 0, 'You should have consumed all the 5 product in stock') # --------------------------------------------------- # unbuild # --------------------------------------------------- x = Form(self.env['mrp.unbuild']) x.product_id = p_final x.bom_id = bom x.product_qty = 3 x.product_uom_id = self.uom_unit x.save().action_unbuild() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location), 2, 'You should have consumed 3 final product in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location), 92, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location), 3, 'You should have consumed all the 5 product in stock') x = Form(self.env['mrp.unbuild']) x.product_id = p_final x.bom_id = bom x.product_qty = 2 x.product_uom_id = self.uom_unit x.save().action_unbuild() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location), 0, 'You should have 0 finalproduct in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location), 100, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location), 5, 'You should have consumed all the 5 product in stock') x = Form(self.env['mrp.unbuild']) x.product_id = p_final x.bom_id = bom x.product_qty = 5 x.product_uom_id = self.uom_unit x.save().action_unbuild() # Check quantity in stock after last unbuild. self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location, allow_negative=True), -5, 'You should have negative quantity for final product in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location), 120, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location), 10, 'You should have consumed all the 5 product in stock')
def test_00_mrp_byproduct(self): """ Test by product with production order.""" # Create BOM for product B # ------------------------ bom_product_b = self.MrpBom.create({ 'product_tmpl_id': self.product_b.product_tmpl_id.id, 'product_qty': 1.0, 'type': 'normal', 'product_uom_id': self.uom_unit_id, 'bom_line_ids': [(0, 0, { 'product_id': self.product_c_id, 'product_uom_id': self.uom_unit_id, 'product_qty': 2 })] }) # Create BOM for product A and set byproduct product B bom_product_a = self.MrpBom.create({ 'product_tmpl_id': self.product_a.product_tmpl_id.id, 'product_qty': 1.0, 'type': 'normal', 'product_uom_id': self.uom_unit_id, 'bom_line_ids': [(0, 0, { 'product_id': self.product_c_id, 'product_uom_id': self.uom_unit_id, 'product_qty': 2 })], 'byproduct_ids': [(0, 0, { 'product_id': self.product_b.id, 'product_uom_id': self.uom_unit_id, 'product_qty': 1 })] }) # Create production order for product A # ------------------------------------- mnf_product_a_form = Form(self.env['mrp.production']) mnf_product_a_form.product_id = self.product_a mnf_product_a_form.bom_id = bom_product_a mnf_product_a_form.product_qty = 2.0 mnf_product_a = mnf_product_a_form.save() mnf_product_a.action_confirm() # I compute the data of production order context = { "active_model": "mrp.production", "active_ids": [mnf_product_a.id], "active_id": mnf_product_a.id } # I confirm the production order. self.assertEqual(mnf_product_a.state, 'confirmed', 'Production order should be in state confirmed') # Now I check the stock moves for the byproduct I created in the bill of material. # This move is created automatically when I confirmed the production order. moves = mnf_product_a.move_raw_ids | mnf_product_a.move_finished_ids self.assertTrue(moves, 'No moves are created !') # I consume and produce the production of products. # I create record for selecting mode and quantity of products to produce. produce_form = Form( self.env['mrp.product.produce'].with_context(context)) produce_form.qty_producing = 2.00 product_consume = produce_form.save() # I finish the production order. self.assertEqual(len(mnf_product_a.move_raw_ids), 1, "Wrong consume move on production order.") product_consume.do_produce() consume_move_c = mnf_product_a.move_raw_ids by_product_move = mnf_product_a.move_finished_ids.filtered( lambda x: x.product_id.id == self.product_b.id) # Check sub production produced quantity... self.assertEqual(consume_move_c.product_uom_qty, 4, "Wrong consumed quantity of product c.") self.assertEqual(by_product_move.product_uom_qty, 2, "Wrong produced quantity of sub product.") mnf_product_a.post_inventory() # I see that stock moves of External Hard Disk including Headset USB are done now. self.assertFalse(any(move.state != 'done' for move in moves), 'Moves are not done!')
def test_unbuild_with_duplicate_move(self): """ This test creates a MO from 3 different lot on a consumed product (p2). The unbuild order should revert the correct quantity for each specific lot. """ mo, bom, p_final, p1, p2 = self.generate_mo(tracking_final='none', tracking_base_2='lot', tracking_base_1='none') self.assertEqual(len(mo), 1, 'MO should have been created') lot_1 = self.env['stock.production.lot'].create({ 'name': 'lot_1', 'product_id': p2.id, 'company_id': self.env.company.id, }) lot_2 = self.env['stock.production.lot'].create({ 'name': 'lot_2', 'product_id': p2.id, 'company_id': self.env.company.id, }) lot_3 = self.env['stock.production.lot'].create({ 'name': 'lot_3', 'product_id': p2.id, 'company_id': self.env.company.id, }) self.env['stock.quant']._update_available_quantity( p1, self.stock_location, 100) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 1, lot_id=lot_1) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 3, lot_id=lot_2) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 2, lot_id=lot_3) mo.action_assign() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.qty_producing = 5.0 produce_wizard = produce_form.save() produce_wizard.do_produce() mo.button_mark_done() self.assertEqual(mo.state, 'done', "Production order should be in done state.") # Check quantity in stock before unbuild. self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location), 5, 'You should have the 5 final product in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location), 80, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location, lot_id=lot_1), 0, 'You should have consumed all the 1 product for lot 1 in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location, lot_id=lot_2), 0, 'You should have consumed all the 3 product for lot 2 in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location, lot_id=lot_3), 1, 'You should have consumed only 1 product for lot3 in stock') x = Form(self.env['mrp.unbuild']) x.product_id = p_final x.bom_id = bom x.product_uom_id = self.uom_unit x.mo_id = mo x.product_qty = 5 x.save().action_unbuild() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location), 0, 'You should have no more final product in stock after unbuild') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location), 100, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location, lot_id=lot_1), 1, 'You should have get your product with lot 1 in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location, lot_id=lot_2), 3, 'You should have the 3 basic product for lot 2 in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location, lot_id=lot_3), 2, 'You should have get one product back for lot 3')
def test_00_production_order_with_accounting(self): self.product_table_sheet.standard_price = 20.0 self.product_table_leg.standard_price = 15.0 self.product_bolt.standard_price = 10.0 self.product_table_leg.tracking = 'none' self.product_table_sheet.tracking = 'none' inventory = self.env['stock.inventory'].create({ 'name': 'Inventory Product Table', 'line_ids': [ ( 0, 0, { 'product_id': self.product_table_sheet.id, # tracking serial 'product_uom_id': self.product_table_sheet.uom_id.id, 'product_qty': 20, 'location_id': self.source_location_id }), ( 0, 0, { 'product_id': self.product_table_leg.id, # tracking lot 'product_uom_id': self.product_table_leg.uom_id.id, 'product_qty': 20, 'location_id': self.source_location_id }), (0, 0, { 'product_id': self.product_bolt.id, 'product_uom_id': self.product_bolt.uom_id.id, 'product_qty': 20, 'location_id': self.source_location_id }), (0, 0, { 'product_id': self.product_screw.id, 'product_uom_id': self.product_screw.uom_id.id, 'product_qty': 200000, 'location_id': self.source_location_id }), ] }) inventory.action_validate bom = self.env.ref('mrp.mrp_bom_desk').copy() bom.routing_id = False # TODO: extend the test later with the necessary operations production_table_form = Form(self.env['mrp.production']) production_table_form.product_id = self.dining_table production_table_form.bom_id = bom production_table_form.product_qty = 5.0 production_table = production_table_form.save() production_table.extra_cost = 20 production_table.action_confirm() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': production_table.id, 'active_ids': [production_table.id], })) produce_form.qty_producing = 1.0 produce_wizard = produce_form.save() produce_wizard.do_produce() production_table.post_inventory() move_value = production_table.move_finished_ids.filtered( lambda x: x.state == "done").stock_valuation_layer_ids.value # 1 table head at 20 + 4 table leg at 15 + 4 bolt at 10 + 10 screw at 10 + 1*20 (extra cost) self.assertEqual(move_value, 141, 'Thing should have the correct price')
def test_tracking_on_byproducts(self): product_final = self.env['product.product'].create({ 'name': 'Finished Product', 'type': 'product', 'tracking': 'serial', }) product_1 = self.env['product.product'].create({ 'name': 'Raw 1', 'type': 'product', 'tracking': 'serial', }) product_2 = self.env['product.product'].create({ 'name': 'Raw 2', 'type': 'product', 'tracking': 'serial', }) byproduct_1 = self.env['product.product'].create({ 'name': 'Byproduct 1', 'type': 'product', 'tracking': 'serial', }) byproduct_2 = self.env['product.product'].create({ 'name': 'Byproduct 2', 'type': 'product', 'tracking': 'serial', }) bom_1 = self.env['mrp.bom'].create({ 'product_id': product_final.id, 'product_tmpl_id': product_final.product_tmpl_id.id, 'product_uom_id': self.uom_unit.id, 'product_qty': 1.0, 'type': 'normal', 'bom_line_ids': [(0, 0, { 'product_id': product_1.id, 'product_qty': 1 }), (0, 0, { 'product_id': product_2.id, 'product_qty': 1 })], 'byproduct_ids': [(0, 0, { 'product_id': byproduct_1.id, 'product_qty': 1, 'product_uom_id': byproduct_1.uom_id.id }), (0, 0, { 'product_id': byproduct_2.id, 'product_qty': 1, 'product_uom_id': byproduct_2.uom_id.id })] }) mo_form = Form(self.env['mrp.production']) mo_form.product_id = product_final mo_form.bom_id = bom_1 mo_form.product_qty = 2 mo = mo_form.save() mo.action_confirm() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.finished_lot_id = self.env['stock.production.lot'].create( { 'product_id': product_final.id, 'name': 'Final_lot_1', 'company_id': self.env.company.id, }) with produce_form.raw_workorder_line_ids.edit(0) as line: line.lot_id = self.env['stock.production.lot'].create({ 'product_id': product_1.id, 'name': 'Raw_1_lot_1', 'company_id': self.env.company.id, }) with produce_form.raw_workorder_line_ids.edit(1) as line: line.lot_id = self.env['stock.production.lot'].create({ 'product_id': product_2.id, 'name': 'Raw_2_lot_1', 'company_id': self.env.company.id, }) with produce_form.finished_workorder_line_ids.edit(0) as line: line.lot_id = self.env['stock.production.lot'].create({ 'product_id': byproduct_1.id, 'name': 'Byproduct_1_lot_1', 'company_id': self.env.company.id, }) with produce_form.finished_workorder_line_ids.edit(1) as line: line.lot_id = self.env['stock.production.lot'].create({ 'product_id': byproduct_2.id, 'name': 'Byproduct_2_lot_1', 'company_id': self.env.company.id, }) produce_wizard = produce_form.save() produce_wizard.continue_production() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.finished_lot_id = self.env['stock.production.lot'].create( { 'product_id': product_final.id, 'name': 'Final_lot_2', 'company_id': self.env.company.id, }) with produce_form.raw_workorder_line_ids.edit(0) as line: line.lot_id = self.env['stock.production.lot'].create({ 'product_id': product_1.id, 'name': 'Raw_1_lot_2', 'company_id': self.env.company.id, }) with produce_form.raw_workorder_line_ids.edit(1) as line: line.lot_id = self.env['stock.production.lot'].create({ 'product_id': product_2.id, 'name': 'Raw_2_lot_2', 'company_id': self.env.company.id, }) with produce_form.finished_workorder_line_ids.edit(0) as line: line.lot_id = self.env['stock.production.lot'].create({ 'product_id': byproduct_1.id, 'name': 'Byproduct_1_lot_2', 'company_id': self.env.company.id, }) with produce_form.finished_workorder_line_ids.edit(1) as line: line.lot_id = self.env['stock.production.lot'].create({ 'product_id': byproduct_2.id, 'name': 'Byproduct_2_lot_2', 'company_id': self.env.company.id, }) produce_wizard = produce_form.save() produce_wizard.do_produce() mo.button_mark_done() self.assertEqual(len(mo.move_raw_ids.mapped('move_line_ids')), 4) self.assertEqual(len(mo.move_finished_ids.mapped('move_line_ids')), 6) raw_move_lines = mo.move_raw_ids.mapped('move_line_ids') raw_line_raw_1_lot_1 = raw_move_lines.filtered( lambda ml: ml.lot_id.name == 'Raw_1_lot_1') self.assertEqual( set(raw_line_raw_1_lot_1.lot_produced_ids.mapped('name')), set(['Final_lot_1', 'Byproduct_1_lot_1', 'Byproduct_2_lot_1'])) raw_line_raw_1_lot_2 = raw_move_lines.filtered( lambda ml: ml.lot_id.name == 'Raw_1_lot_2') self.assertEqual( set(raw_line_raw_1_lot_2.lot_produced_ids.mapped('name')), set(['Final_lot_2', 'Byproduct_1_lot_2', 'Byproduct_2_lot_2'])) raw_line_raw_2_lot_1 = raw_move_lines.filtered( lambda ml: ml.lot_id.name == 'Raw_2_lot_1') self.assertEqual( set(raw_line_raw_2_lot_1.lot_produced_ids.mapped('name')), set(['Final_lot_1', 'Byproduct_1_lot_1', 'Byproduct_2_lot_1'])) raw_line_raw_2_lot_2 = raw_move_lines.filtered( lambda ml: ml.lot_id.name == 'Raw_2_lot_2') self.assertEqual( set(raw_line_raw_2_lot_2.lot_produced_ids.mapped('name')), set(['Final_lot_2', 'Byproduct_1_lot_2', 'Byproduct_2_lot_2'])) finished_move_lines = mo.move_finished_ids.mapped('move_line_ids') finished_move_line_lot_1 = finished_move_lines.filtered( lambda ml: ml.lot_id.name == 'Final_lot_1') self.assertEqual(finished_move_line_lot_1.consume_line_ids, raw_line_raw_1_lot_1 | raw_line_raw_2_lot_1) finished_move_line_lot_2 = finished_move_lines.filtered( lambda ml: ml.lot_id.name == 'Final_lot_2') self.assertEqual(finished_move_line_lot_2.consume_line_ids, raw_line_raw_1_lot_2 | raw_line_raw_2_lot_2) byproduct_move_line_1_lot_1 = finished_move_lines.filtered( lambda ml: ml.lot_id.name == 'Byproduct_1_lot_1') self.assertEqual(byproduct_move_line_1_lot_1.consume_line_ids, raw_line_raw_1_lot_1 | raw_line_raw_2_lot_1) byproduct_move_line_1_lot_2 = finished_move_lines.filtered( lambda ml: ml.lot_id.name == 'Byproduct_1_lot_2') self.assertEqual(byproduct_move_line_1_lot_2.consume_line_ids, raw_line_raw_1_lot_2 | raw_line_raw_2_lot_2) byproduct_move_line_2_lot_1 = finished_move_lines.filtered( lambda ml: ml.lot_id.name == 'Byproduct_2_lot_1') self.assertEqual(byproduct_move_line_2_lot_1.consume_line_ids, raw_line_raw_1_lot_1 | raw_line_raw_2_lot_1) byproduct_move_line_2_lot_2 = finished_move_lines.filtered( lambda ml: ml.lot_id.name == 'Byproduct_2_lot_2') self.assertEqual(byproduct_move_line_2_lot_2.consume_line_ids, raw_line_raw_1_lot_2 | raw_line_raw_2_lot_2)
def test_unbuild_with_comnsumed_lot(self): """ This test creates a MO and then creates 3 unbuild orders for the final product. Only once of the two consumed product is tracked by lot. It checks the stock state after each order and ensure it is correct. """ mo, bom, p_final, p1, p2 = self.generate_mo(tracking_base_1='lot') self.assertEqual(len(mo), 1, 'MO should have been created') lot = self.env['stock.production.lot'].create({ 'name': 'lot1', 'product_id': p1.id, 'company_id': self.env.company.id, }) self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 100, lot_id=lot) self.env['stock.quant']._update_available_quantity( p2, self.stock_location, 5) mo.action_assign() for ml in mo.move_raw_ids.mapped('move_line_ids'): if ml.product_id.tracking != 'none': self.assertEqual(ml.lot_id, lot, 'Wrong reserved lot.') produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.qty_producing = 5.0 produce_wizard = produce_form.save() produce_wizard.do_produce() mo.button_mark_done() self.assertEqual(mo.state, 'done', "Production order should be in done state.") # Check quantity in stock before unbuild. self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location), 5, 'You should have the 5 final product in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location, lot_id=lot), 80, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location), 0, 'You should have consumed all the 5 product in stock') # --------------------------------------------------- # unbuild # --------------------------------------------------- x = Form(self.env['mrp.unbuild']) x.product_id = p_final x.bom_id = bom x.product_qty = 3 x.product_uom_id = self.uom_unit unbuild_order = x.save() # This should fail since we do not provide the MO that we wanted to unbuild. (without MO we do not know which consumed lot we have to restore) with self.assertRaises(UserError): unbuild_order.action_unbuild() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location), 5, 'You should have consumed 3 final product in stock') unbuild_order.mo_id = mo.id unbuild_order.action_unbuild() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location), 2, 'You should have consumed 3 final product in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location, lot_id=lot), 92, 'You should have 92 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location), 3, 'You should have consumed all the 5 product in stock') x = Form(self.env['mrp.unbuild']) x.product_id = p_final x.bom_id = bom x.product_uom_id = self.uom_unit x.mo_id = mo x.product_qty = 2 x.save().action_unbuild() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location), 0, 'You should have 0 finalproduct in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location, lot_id=lot), 100, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location), 5, 'You should have consumed all the 5 product in stock') x = Form(self.env['mrp.unbuild']) x.product_id = p_final x.bom_id = bom x.product_uom_id = self.uom_unit x.mo_id = mo x.product_qty = 5 x.save().action_unbuild() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location, allow_negative=True), -5, 'You should have negative quantity for final product in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location, lot_id=lot), 120, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location), 10, 'You should have consumed all the 5 product in stock')
def generate_mo(self, tracking_final='none', tracking_base_1='none', tracking_base_2='none', qty_final=5, qty_base_1=4, qty_base_2=1): """ This function generate a manufacturing order with one final product and two consumed product. Arguments allows to choose the tracking/qty for each different products. It returns the MO, used bom and the tree products. """ product_to_build = self.env['product.product'].create({ 'name': 'Young Tom', 'type': 'product', 'tracking': tracking_final, }) product_to_use_1 = self.env['product.product'].create({ 'name': 'Botox', 'type': 'product', 'tracking': tracking_base_1, }) product_to_use_2 = self.env['product.product'].create({ 'name': 'Old Tom', 'type': 'product', 'tracking': tracking_base_2, }) bom_1 = self.env['mrp.bom'].create({ 'product_id': product_to_build.id, 'product_tmpl_id': product_to_build.product_tmpl_id.id, 'product_uom_id': self.uom_unit.id, 'product_qty': 1.0, 'type': 'normal', 'bom_line_ids': [(0, 0, { 'product_id': product_to_use_2.id, 'product_qty': qty_base_2 }), (0, 0, { 'product_id': product_to_use_1.id, 'product_qty': qty_base_1 })] }) mo_form = Form(self.env['mrp.production']) mo_form.product_id = product_to_build mo_form.bom_id = bom_1 mo_form.product_qty = qty_final mo = mo_form.save() mo.action_confirm() return mo, bom_1, product_to_build, product_to_use_1, product_to_use_2
def setUp(self): super(TestBom, self).setUp() self.Product = self.env['product.product'] self.Bom = self.env['mrp.bom'] self.Routing = self.env['mrp.routing'] self.operation = self.env['mrp.routing.workcenter'] # Products. self.dining_table = self._create_product('Dining Table', 1000) self.table_head = self._create_product('Table Head', 300) self.screw = self._create_product('Screw', 10) self.leg = self._create_product('Leg', 25) self.glass = self._create_product('Glass', 100) # Unit of Measure. self.unit = self.env.ref("uom.product_uom_unit") self.dozen = self.env.ref("uom.product_uom_dozen") # Bills Of Materials. # ------------------------------------------------------------------------------- # Cost of BoM (Dining Table 1 Unit) # Component Cost = Table Head 1 Unit * 300 = 300 (468.75 from it's components) # Screw 5 Unit * 10 = 50 # Leg 4 Unit * 25 = 100 # Glass 1 Unit * 100 = 100 # Total = 550 [718.75 if components of Table Head considered] (for 1 Unit) # ------------------------------------------------------------------------------- bom_form = Form(self.Bom) bom_form.product_id = self.dining_table bom_form.product_tmpl_id = self.dining_table.product_tmpl_id bom_form.product_qty = 1.0 bom_form.product_uom_id = self.unit bom_form.type = 'normal' with bom_form.bom_line_ids.new() as line: line.product_id = self.table_head line.product_qty = 1 with bom_form.bom_line_ids.new() as line: line.product_id = self.screw line.product_qty = 5 with bom_form.bom_line_ids.new() as line: line.product_id = self.leg line.product_qty = 4 with bom_form.bom_line_ids.new() as line: line.product_id = self.glass line.product_qty = 1 self.bom_1 = bom_form.save() # Table Head's components. self.plywood_sheet = self._create_product('Plywood Sheet', 200) self.bolt = self._create_product('Bolt', 10) self.colour = self._create_product('Colour', 100) self.corner_slide = self._create_product('Corner Slide', 25) # ----------------------------------------------------------------- # Cost of BoM (Table Head 1 Dozen) # Component Cost = Plywood Sheet 12 Unit * 200 = 2400 # Bolt 60 Unit * 10 = 600 # Colour 12 Unit * 100 = 1200 # Corner Slide 57 Unit * 25 = 1425 # Total = 5625 # 1 Unit price (5625/12) = 468.75 # ----------------------------------------------------------------- bom_form2 = Form(self.Bom) bom_form2.product_id = self.table_head bom_form2.product_tmpl_id = self.table_head.product_tmpl_id bom_form2.product_qty = 1.0 bom_form2.product_uom_id = self.dozen bom_form2.type = 'phantom' with bom_form2.bom_line_ids.new() as line: line.product_id = self.plywood_sheet line.product_qty = 12 with bom_form2.bom_line_ids.new() as line: line.product_id = self.bolt line.product_qty = 60 with bom_form2.bom_line_ids.new() as line: line.product_id = self.colour line.product_qty = 12 with bom_form2.bom_line_ids.new() as line: line.product_id = self.corner_slide line.product_qty = 57 self.bom_2 = bom_form2.save()
def test_unbuild_with_routes(self): """ This test creates a MO of a stockable product (Table). A new route for rule QC/Unbuild -> Stock is created with Warehouse -> True. The unbuild order should revert the consumed components into QC/Unbuild location for quality check and then a picking should be generated for transferring components from QC/Unbuild location to stock. """ StockQuant = self.env['stock.quant'] ProductObj = self.env['product.product'] # Create new QC/Unbuild location warehouse = self.env.ref('stock.warehouse0') unbuild_location = self.env['stock.location'].create({ 'name': 'QC/Unbuild', 'usage': 'internal', 'location_id': warehouse.view_location_id.id }) # Create a product route containing a stock rule that will move product from QC/Unbuild location to stock product_route = self.env['stock.location.route'].create({ 'name': 'QC/Unbuild -> Stock', 'warehouse_selectable': True, 'warehouse_ids': [(4, warehouse.id)], 'rule_ids': [(0, 0, { 'name': 'Send Matrial QC/Unbuild -> Stock', 'action': 'push', 'picking_type_id': self.ref('stock.picking_type_internal'), 'location_src_id': unbuild_location.id, 'location_id': self.stock_location.id, })], }) # Create a stockable product and its components finshed_product = ProductObj.create({ 'name': 'Table', 'type': 'product', }) component1 = ProductObj.create({ 'name': 'Table head', 'type': 'product', }) component2 = ProductObj.create({ 'name': 'Table stand', 'type': 'product', }) # Create bom and add components bom = self.env['mrp.bom'].create({ 'product_id': finshed_product.id, 'product_tmpl_id': finshed_product.product_tmpl_id.id, 'product_uom_id': self.uom_unit.id, 'product_qty': 1.0, 'type': 'normal', 'bom_line_ids': [(0, 0, { 'product_id': component1.id, 'product_qty': 1 }), (0, 0, { 'product_id': component2.id, 'product_qty': 1 })] }) # Set on hand quantity StockQuant._update_available_quantity(component1, self.stock_location, 1) StockQuant._update_available_quantity(component2, self.stock_location, 1) # Create mo mo_form = Form(self.env['mrp.production']) mo_form.product_id = finshed_product mo_form.bom_id = bom mo_form.product_uom_id = finshed_product.uom_id mo_form.product_qty = 1.0 mo = mo_form.save() self.assertEqual(len(mo), 1, 'MO should have been created') mo.action_confirm() mo.action_assign() # Produce the final product produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.qty_producing = 1.0 produce_wizard = produce_form.save() produce_wizard.do_produce() mo.button_mark_done() self.assertEqual(mo.state, 'done', "Production order should be in done state.") # Check quantity in stock before unbuild self.assertEqual( StockQuant._get_available_quantity(finshed_product, self.stock_location), 1, 'Table should be available in stock') self.assertEqual( StockQuant._get_available_quantity(component1, self.stock_location), 0, 'Table head should not be available in stock') self.assertEqual( StockQuant._get_available_quantity(component2, self.stock_location), 0, 'Table stand should not be available in stock') # --------------------------------------------------- # Unbuild # --------------------------------------------------- # Create an unbuild order of the finished product and set the destination loacation = QC/Unbuild x = Form(self.env['mrp.unbuild']) x.product_id = finshed_product x.bom_id = bom x.product_uom_id = self.uom_unit x.mo_id = mo x.product_qty = 1 x.location_id = self.stock_location x.location_dest_id = unbuild_location x.save().action_unbuild() # Check the available quantity of components and final product in stock self.assertEqual( StockQuant._get_available_quantity(finshed_product, self.stock_location), 0, 'Table should not be available in stock as it is unbuild') self.assertEqual( StockQuant._get_available_quantity(component1, self.stock_location), 0, 'Table head should not be available in stock as it is in QC/Unbuild location' ) self.assertEqual( StockQuant._get_available_quantity(component2, self.stock_location), 0, 'Table stand should not be available in stock as it is in QC/Unbuild location' ) # Find new generated picking picking = self.env['stock.picking'].search([ ('product_id', 'in', [component1.id, component2.id]) ]) self.assertEqual(picking.location_id.id, unbuild_location.id, 'Wrong source location in picking') self.assertEqual(picking.location_dest_id.id, self.stock_location.id, 'Wrong destination location in picking') # Transfer it for ml in picking.move_ids_without_package: ml.quantity_done = 1 picking.action_done() # Check the available quantity of components and final product in stock self.assertEqual( StockQuant._get_available_quantity(finshed_product, self.stock_location), 0, 'Table should not be available in stock') self.assertEqual( StockQuant._get_available_quantity(component1, self.stock_location), 1, 'Table head should be available in stock as the picking is transferred' ) self.assertEqual( StockQuant._get_available_quantity(component2, self.stock_location), 1, 'Table stand should be available in stock as the picking is transferred' )
def test_procurement(self): """This test case when create production order check procurement is create""" # Update BOM self.bom_3.bom_line_ids.filtered( lambda x: x.product_id == self.product_5).unlink() self.bom_1.bom_line_ids.filtered( lambda x: x.product_id == self.product_1).unlink() # Update route self.warehouse = self.env.ref('stock.warehouse0') route_manufacture = self.warehouse.manufacture_pull_id.route_id.id route_mto = self.warehouse.mto_pull_id.route_id.id self.product_4.write( {'route_ids': [(6, 0, [route_manufacture, route_mto])]}) # Create production order # ------------------------- # Product6 Unit 24 # Product4 8 Dozen # Product2 12 Unit # ----------------------- 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 = 24 production_form.product_uom_id = self.product_6.uom_id production_product_6 = production_form.save() production_product_6.action_confirm() production_product_6.action_assign() # check production state is Confirmed self.assertEqual(production_product_6.state, 'confirmed', 'Production order should be for Confirmed state') # Check procurement for product 4 created or not. # Check it created a purchase order move_raw_product4 = production_product_6.move_raw_ids.filtered( lambda x: x.product_id == self.product_4) produce_product_4 = self.env['mrp.production'].search([ ('product_id', '=', self.product_4.id), ('move_dest_ids', '=', move_raw_product4[0].id) ]) # produce product self.assertEqual(produce_product_4.reservation_state, 'confirmed', "Consume material not available") # Create production order # ------------------------- # Product 4 96 Unit # Product2 48 Unit # --------------------- # Update Inventory self.env['stock.quant'].with_context(inventory_mode=True).create({ 'product_id': self.product_2.id, 'inventory_quantity': 48, 'location_id': self.warehouse.lot_stock_id.id, }) produce_product_4.action_assign() self.assertEqual(produce_product_4.product_qty, 8, "Wrong quantity of finish product.") self.assertEqual(produce_product_4.product_uom_id, self.uom_dozen, "Wrong quantity of finish product.") self.assertEqual(produce_product_4.reservation_state, 'assigned', "Consume material not available") # produce product4 # --------------- produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': produce_product_4.id, 'active_ids': [produce_product_4.id], })) produce_form.qty_producing = produce_product_4.product_qty product_produce = produce_form.save() product_produce.do_produce() produce_product_4.post_inventory() # Check procurement and Production state for product 4. produce_product_4.button_mark_done() self.assertEqual(produce_product_4.state, 'done', 'Production order should be in state done') # Produce product 6 # ------------------ # Update Inventory self.env['stock.quant'].with_context(inventory_mode=True).create({ 'product_id': self.product_2.id, 'inventory_quantity': 12, 'location_id': self.warehouse.lot_stock_id.id, }) production_product_6.action_assign() # ------------------------------------ self.assertEqual(production_product_6.reservation_state, 'assigned', "Consume material not available") produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': production_product_6.id, 'active_ids': [production_product_6.id], })) produce_form.qty_producing = production_product_6.product_qty product_produce = produce_form.save() product_produce.do_produce() production_product_6.post_inventory() # Check procurement and Production state for product 6. production_product_6.button_mark_done() self.assertEqual(production_product_6.state, 'done', 'Production order should be in state done') self.assertEqual(self.product_6.qty_available, 24, 'Wrong quantity available of finished product.')
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.ref('stock.stock_location_14')}), ]}) 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.ref('stock.stock_location_14')}) ]}) (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(except_orm): 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})
def test_flow_4(self): """ Tick "Manufacture" and "MTO" on the components and trigger the creation of the subcontracting manufacturing order through a receipt picking. Checks that the delivery to the subcontractor is not created at the receipt creation. Then run the scheduler and check that the delivery and MO exist. """ # Tick "manufacture" and MTO on self.comp2 mto_route = self.env['stock.location.route'].search([ ('name', '=', 'Replenish on Order (MTO)') ]) manufacture_route = self.env['stock.location.route'].search([ ('name', '=', 'Manufacture') ]) self.comp2.write({'route_ids': [(4, manufacture_route.id, None)]}) self.comp2.write({'route_ids': [(4, mto_route.id, None)]}) orderpoint_form = Form(self.env['stock.warehouse.orderpoint']) orderpoint_form.product_id = self.comp2 orderpoint_form.product_min_qty = 0.0 orderpoint_form.product_max_qty = 10.0 orderpoint_form.location_id = self.env.company.subcontracting_location_id orderpoint_form.save() # Create a receipt picking from the subcontractor picking_form = Form(self.env['stock.picking']) picking_form.picking_type_id = self.env.ref('stock.picking_type_in') picking_form.partner_id = self.subcontractor_partner1 with picking_form.move_ids_without_package.new() as move: move.product_id = self.finished move.product_uom_qty = 1 picking_receipt = picking_form.save() picking_receipt.action_confirm() warehouse = picking_receipt.picking_type_id.warehouse_id # Pickings should directly be created mo = self.env['mrp.production'].search([('bom_id', '=', self.bom.id)]) self.assertEquals(mo.state, 'confirmed') picking_delivery = mo.picking_ids self.assertFalse(picking_delivery) picking_delivery = self.env['stock.picking'].search([ ('origin', 'ilike', '%' + picking_receipt.name + '%') ]) self.assertFalse(picking_delivery) move = self.env['stock.move'].search([ ('product_id', '=', self.comp2.id), ('location_id', '=', warehouse.lot_stock_id.id), ('location_dest_id', '=', self.env.company.subcontracting_location_id.id) ]) self.assertFalse(move) self.env['procurement.group'].run_scheduler( company_id=self.env.company.id) move = self.env['stock.move'].search([ ('product_id', '=', self.comp2.id), ('location_id', '=', warehouse.lot_stock_id.id), ('location_dest_id', '=', self.env.company.subcontracting_location_id.id) ]) self.assertTrue(move) picking_delivery = move.picking_id self.assertTrue(picking_delivery) self.assertEqual(move.product_uom_qty, 11.0) # As well as a manufacturing order for `self.comp2` comp2mo = self.env['mrp.production'].search([('bom_id', '=', self.comp2_bom.id)]) self.assertEqual(len(comp2mo), 1)
def test_unbuild_with_everything_tracked(self): """ This test creates a MO and then creates 3 unbuild orders for the final product. All the products for this test are tracked. It checks the stock state after each order and ensure it is correct. """ mo, bom, p_final, p1, p2 = self.generate_mo(tracking_final='lot', tracking_base_2='lot', tracking_base_1='lot') self.assertEqual(len(mo), 1, 'MO should have been created') lot_final = self.env['stock.production.lot'].create({ 'name': 'lot_final', 'product_id': p_final.id, 'company_id': self.env.company.id, }) lot_1 = self.env['stock.production.lot'].create({ 'name': 'lot_consumed_1', 'product_id': p1.id, 'company_id': self.env.company.id, }) lot_2 = self.env['stock.production.lot'].create({ 'name': 'lot_consumed_2', 'product_id': p2.id, 'company_id': self.env.company.id, }) self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 100, lot_id=lot_1) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 5, lot_id=lot_2) mo.action_assign() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.qty_producing = 5.0 produce_form.finished_lot_id = lot_final produce_wizard = produce_form.save() produce_wizard.do_produce() mo.button_mark_done() self.assertEqual(mo.state, 'done', "Production order should be in done state.") # Check quantity in stock before unbuild. self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location, lot_id=lot_final), 5, 'You should have the 5 final product in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location, lot_id=lot_1), 80, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location, lot_id=lot_2), 0, 'You should have consumed all the 5 product in stock') # --------------------------------------------------- # unbuild # --------------------------------------------------- x = Form(self.env['mrp.unbuild']) with self.assertRaises(AssertionError): x.product_id = p_final x.bom_id = bom x.product_uom_id = self.uom_unit x.product_qty = 3 x.save() with self.assertRaises(AssertionError): x.product_id = p_final x.bom_id = bom x.product_uom_id = self.uom_unit x.product_qty = 3 x.save() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location, lot_id=lot_final), 5, 'You should have consumed 3 final product in stock') with self.assertRaises(AssertionError): x.product_id = p_final x.bom_id = bom x.product_uom_id = self.uom_unit x.mo_id = mo x.product_qty = 3 x.save() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location, lot_id=lot_final), 5, 'You should have consumed 3 final product in stock') x = Form(self.env['mrp.unbuild']) x.product_id = p_final x.bom_id = bom x.product_uom_id = self.uom_unit x.mo_id = mo x.product_qty = 3 x.lot_id = lot_final x.save().action_unbuild() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location, lot_id=lot_final), 2, 'You should have consumed 3 final product in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location, lot_id=lot_1), 92, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location, lot_id=lot_2), 3, 'You should have consumed all the 5 product in stock') x = Form(self.env['mrp.unbuild']) x.product_id = p_final x.bom_id = bom x.product_uom_id = self.uom_unit x.mo_id = mo x.product_qty = 2 x.lot_id = lot_final x.save().action_unbuild() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location, lot_id=lot_final), 0, 'You should have 0 finalproduct in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location, lot_id=lot_1), 100, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location, lot_id=lot_2), 5, 'You should have consumed all the 5 product in stock') x = Form(self.env['mrp.unbuild']) x.product_id = p_final x.bom_id = bom x.product_uom_id = self.uom_unit x.mo_id = mo x.product_qty = 5 x.lot_id = lot_final x.save().action_unbuild() self.assertEqual( self.env['stock.quant']._get_available_quantity( p_final, self.stock_location, lot_id=lot_final, allow_negative=True), -5, 'You should have negative quantity for final product in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p1, self.stock_location, lot_id=lot_1), 120, 'You should have 80 products in stock') self.assertEqual( self.env['stock.quant']._get_available_quantity( p2, self.stock_location, lot_id=lot_2), 10, 'You should have consumed all the 5 product in stock')
def test_tracking_types_on_mo(self): finished_no_track = self._create_product('none') finished_lot = self._create_product('lot') finished_serial = self._create_product('serial') consumed_no_track = self._create_product('none') consumed_lot = self._create_product('lot') consumed_serial = self._create_product('serial') stock_id = self.env.ref('stock.stock_location_stock').id inventory_adjustment = self.env['stock.inventory'].create({ 'name': 'Initial Inventory', 'location_ids': [(4, stock_id)], }) inventory_adjustment.action_start() inventory_adjustment.write({ 'line_ids': [ (0, 0, { 'product_id': consumed_no_track.id, 'product_qty': 3, 'location_id': stock_id }), (0, 0, { 'product_id': consumed_lot.id, 'product_qty': 3, 'prod_lot_id': self.env['stock.production.lot'].create({ 'name': 'L1', 'product_id': consumed_lot.id, 'company_id': self.env.company.id }).id, 'location_id': stock_id }), (0, 0, { 'product_id': consumed_serial.id, 'product_qty': 1, 'prod_lot_id': self.env['stock.production.lot'].create({ 'name': 'S1', 'product_id': consumed_serial.id, 'company_id': self.env.company.id }).id, 'location_id': stock_id }), (0, 0, { 'product_id': consumed_serial.id, 'product_qty': 1, 'prod_lot_id': self.env['stock.production.lot'].create({ 'name': 'S2', 'product_id': consumed_serial.id, 'company_id': self.env.company.id }).id, 'location_id': stock_id }), (0, 0, { 'product_id': consumed_serial.id, 'product_qty': 1, 'prod_lot_id': self.env['stock.production.lot'].create({ 'name': 'S3', 'product_id': consumed_serial.id, 'company_id': self.env.company.id }).id, 'location_id': stock_id }), ] }) inventory_adjustment.action_validate() for finished_product in [ finished_no_track, finished_lot, finished_serial ]: bom = self.env['mrp.bom'].create({ 'product_id': finished_product.id, 'product_tmpl_id': finished_product.product_tmpl_id.id, 'product_uom_id': self.env.ref('uom.product_uom_unit').id, 'product_qty': 1.0, 'type': 'normal', 'bom_line_ids': [ (0, 0, { 'product_id': consumed_no_track.id, 'product_qty': 1 }), (0, 0, { 'product_id': consumed_lot.id, 'product_qty': 1 }), (0, 0, { 'product_id': consumed_serial.id, 'product_qty': 1 }), ], }) mo_form = Form(self.env['mrp.production']) mo_form.product_id = finished_product mo_form.bom_id = bom mo_form.product_uom_id = self.env.ref('uom.product_uom_unit') mo_form.product_qty = 1 mo = mo_form.save() mo.action_confirm() mo.action_assign() # Start MO production produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) if finished_product.tracking != 'serial': produce_form.qty_producing = 1 if finished_product.tracking != 'none': produce_form.finished_lot_id = self.env[ 'stock.production.lot'].create({ 'name': 'Serial or Lot finished', 'product_id': finished_product.id, 'company_id': self.env.company.id }) produce_wizard = produce_form.save() produce_wizard.do_produce() mo.button_mark_done() self.assertEqual(mo.state, 'done', "Production order should be in done state.") # Check results of traceability context = ({ 'active_id': mo.id, 'model': 'mrp.production', }) lines = self.env['stock.traceability.report'].with_context( context).get_lines() self.assertEqual( len(lines), 1, "Should always return 1 line : the final product") final_product = lines[0] self.assertEqual(final_product['unfoldable'], True, "Final product should always be unfoldable") # Find parts of the final products lines = self.env['stock.traceability.report'].get_lines( final_product['id'], **{ 'level': final_product['level'], 'model_id': final_product['model_id'], 'model_name': final_product['model'], }) self.assertEqual( len(lines), 3, "There should be 3 lines. 1 for untracked, 1 for lot, and 1 for serial" ) for line in lines: tracking = line['columns'][1].split(' ')[1] self.assertEqual( line['columns'][-1], "1.000 Units", 'Part with tracking type "%s", should have quantity = 1' % (tracking)) unfoldable = False if tracking == 'none' else True self.assertEqual( line['unfoldable'], unfoldable, 'Parts with tracking type "%s", should have be unfoldable : %s' % (tracking, unfoldable))
def test_12_multi_level_variants2(self): """Test skip bom line with same attribute values in bom lines.""" Product = self.env['product.product'] ProductAttribute = self.env['product.attribute'] ProductAttributeValue = self.env['product.attribute.value'] # Product Attribute att_color = ProductAttribute.create({'name': 'Color', 'sequence': 1}) att_size = ProductAttribute.create({'name': 'size', 'sequence': 2}) # Product Attribute color Value att_color_red = ProductAttributeValue.create({ 'name': 'red', 'attribute_id': att_color.id, 'sequence': 1 }) att_color_blue = ProductAttributeValue.create({ 'name': 'blue', 'attribute_id': att_color.id, 'sequence': 2 }) # Product Attribute size Value att_size_big = ProductAttributeValue.create({ 'name': 'big', 'attribute_id': att_size.id, 'sequence': 1 }) att_size_medium = ProductAttributeValue.create({ 'name': 'medium', 'attribute_id': att_size.id, 'sequence': 2 }) # Create Template Product product_template = self.env['product.template'].create({ 'name': 'Sofa', 'attribute_line_ids': [(0, 0, { 'attribute_id': att_color.id, 'value_ids': [(6, 0, [att_color_red.id, att_color_blue.id])] }), (0, 0, { 'attribute_id': att_size.id, 'value_ids': [(6, 0, [att_size_big.id, att_size_medium.id])] })] }) sofa_red = product_template.attribute_line_ids[ 0].product_template_value_ids[0] sofa_blue = product_template.attribute_line_ids[ 0].product_template_value_ids[1] sofa_big = product_template.attribute_line_ids[ 1].product_template_value_ids[0] sofa_medium = product_template.attribute_line_ids[ 1].product_template_value_ids[1] # Create components Of BOM product_A = Product.create({'name': 'Wood'}) product_B = Product.create({'name': 'Clothes'}) # Create BOM self.env['mrp.bom'].create({ 'product_tmpl_id': product_template.id, 'product_qty': 1.0, 'type': 'normal', 'bom_line_ids': [(0, 0, { 'product_id': product_A.id, 'product_qty': 1, 'bom_product_template_attribute_value_ids': [(4, sofa_red.id), (4, sofa_blue.id), (4, sofa_big.id)], }), (0, 0, { 'product_id': product_B.id, 'product_qty': 1, 'bom_product_template_attribute_value_ids': [(4, sofa_red.id), (4, sofa_blue.id)] })] }) dict_consumed_products = { sofa_red + sofa_big: product_A + product_B, sofa_red + sofa_medium: product_B, sofa_blue + sofa_big: product_A + product_B, sofa_blue + sofa_medium: product_B, } # Create production order for all variants. for combination, consumed_products in dict_consumed_products.items(): product = product_template.product_variant_ids.filtered( lambda p: p.product_template_attribute_value_ids == combination ) mrp_order_form = Form(self.env['mrp.production']) mrp_order_form.product_id = product mrp_order = mrp_order_form.save() # Check consumed materials in production order. self.assertEqual(mrp_order.move_raw_ids.product_id, consumed_products)