def test_flow_5(self): """ Check that the correct BoM is chosen accordingly to the partner """ # We create a second partner of type subcontractor main_partner_2 = self.env['res.partner'].create({'name': 'main_partner'}) subcontractor_partner2 = self.env['res.partner'].create({ 'name': 'subcontractor_partner', 'parent_id': main_partner_2.id, 'company_id': self.env.ref('base.main_company').id }) # We create a different BoM for the same product comp3 = self.env['product.product'].create({ 'name': 'Component1', 'type': 'product', 'categ_id': self.env.ref('product.product_category_all').id, }) bom_form = Form(self.env['mrp.bom']) bom_form.type = 'subcontract' bom_form.product_tmpl_id = self.finished.product_tmpl_id with bom_form.bom_line_ids.new() as bom_line: bom_line.product_id = self.comp1 bom_line.product_qty = 1 with bom_form.bom_line_ids.new() as bom_line: bom_line.product_id = comp3 bom_line.product_qty = 1 bom2 = bom_form.save() # We assign the second BoM to the new partner self.bom.write({'subcontractor_ids': [(4, self.subcontractor_partner1.id, None)]}) bom2.write({'subcontractor_ids': [(4, subcontractor_partner2.id, None)]}) # Create a receipt picking from the subcontractor1 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_receipt1 = picking_form.save() picking_receipt1.action_confirm() # Create a receipt picking from the subcontractor2 picking_form = Form(self.env['stock.picking']) picking_form.picking_type_id = self.env.ref('stock.picking_type_in') picking_form.partner_id = subcontractor_partner2 with picking_form.move_ids_without_package.new() as move: move.product_id = self.finished move.product_uom_qty = 1 picking_receipt2 = picking_form.save() picking_receipt2.action_confirm() mo_pick1 = picking_receipt1.move_lines.mapped('move_orig_ids.production_id') mo_pick2 = picking_receipt2.move_lines.mapped('move_orig_ids.production_id') self.assertEquals(len(mo_pick1), 1) self.assertEquals(len(mo_pick2), 1) self.assertEquals(mo_pick1.bom_id, self.bom) self.assertEquals(mo_pick2.bom_id, bom2)
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_flow_9(self): """Ensure that cancel the subcontract moves will also delete the components need for the subcontractor. """ resupply_sub_on_order_route = self.env['stock.location.route'].search([ ('name', '=', 'Resupply Subcontractor on Order') ]) (self.comp1 + self.comp2).write({ 'route_ids': [(4, resupply_sub_on_order_route.id)] }) 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 = 5 picking_receipt = picking_form.save() picking_receipt.action_confirm() picking_delivery = self.env['stock.move'].search([ ('product_id', 'in', (self.comp1 | self.comp2).ids) ]).picking_id self.assertTrue(picking_delivery) self.assertEqual(picking_delivery.state, 'confirmed') self.assertEqual(self.comp1.virtual_available, -5) self.assertEqual(self.comp2.virtual_available, -5) # action_cancel is not call on the picking in order # to test behavior from other source than picking (e.g. puchase). picking_receipt.move_lines._action_cancel() self.assertEqual(picking_delivery.state, 'cancel') self.assertEqual(self.comp1.virtual_available, 0.0) self.assertEqual(self.comp1.virtual_available, 0.0)
def test_flow_8(self): resupply_sub_on_order_route = self.env['stock.location.route'].search([('name', '=', 'Resupply Subcontractor on Order')]) (self.comp1 + self.comp2).write({'route_ids': [(4, resupply_sub_on_order_route.id, None)]}) # 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 = 5 picking_receipt = picking_form.save() picking_receipt.action_confirm() picking_receipt.move_lines.quantity_done = 3 backorder_wiz = picking_receipt.button_validate() backorder_wiz = self.env['stock.backorder.confirmation'].browse(backorder_wiz['res_id']) backorder_wiz.process() backorder = self.env['stock.picking'].search([('backorder_id', '=', picking_receipt.id)]) self.assertTrue(backorder) self.assertEqual(backorder.move_lines.product_uom_qty, 2) subcontract_order = backorder.move_lines.move_orig_ids.production_id.filtered(lambda p: p.state != 'done') self.assertTrue(subcontract_order) self.assertEqual(subcontract_order.product_uom_qty, 5) self.assertEqual(subcontract_order.qty_produced, 3) backorder.move_lines.quantity_done = 2 backorder.action_done() self.assertTrue(picking_receipt.move_lines.move_orig_ids.production_id.state == 'done')
def test_flow_3(self): """ Tick "Resupply Subcontractor on Order" and "MTO" on the components and trigger the creation of the subcontracting manufacturing order through a receipt picking. Checks if the resupplying actually works. One of the component has also "manufacture" set and a BOM linked. Checks that an MO is created for this one. """ # Tick "resupply subconractor on order" resupply_sub_on_order_route = self.env['stock.location.route'].search([('name', '=', 'Resupply Subcontractor on Order')]) (self.comp1 + self.comp2).write({'route_ids': [(4, resupply_sub_on_order_route.id, None)]}) # 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)]}) # 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() # Nothing should be tracked self.assertFalse(picking_receipt.display_action_record_components) # 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.assertEqual(len(picking_delivery), 1) self.assertEqual(len(picking_delivery.move_lines), 2) self.assertEquals(picking_delivery.origin, picking_receipt.name) self.assertEquals(picking_delivery.partner_id, picking_receipt.partner_id) # The picking should be a delivery order wh = picking_receipt.picking_type_id.warehouse_id self.assertEquals(mo.picking_ids.picking_type_id, wh.out_type_id) self.assertEquals(mo.picking_type_id, wh.subcontracting_type_id) self.assertFalse(mo.picking_type_id.active) # 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) picking_receipt.move_lines.quantity_done = 1 picking_receipt.button_validate() self.assertEquals(mo.state, 'done') # Available quantities should be negative at the subcontracting location for each components avail_qty_comp1 = self.env['stock.quant']._get_available_quantity(self.comp1, self.subcontractor_partner1.property_stock_subcontractor, allow_negative=True) avail_qty_comp2 = self.env['stock.quant']._get_available_quantity(self.comp2, self.subcontractor_partner1.property_stock_subcontractor, allow_negative=True) avail_qty_finished = self.env['stock.quant']._get_available_quantity(self.finished, wh.lot_stock_id) self.assertEquals(avail_qty_comp1, -1) self.assertEquals(avail_qty_comp2, -1) self.assertEquals(avail_qty_finished, 1)
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 test_flow_6(self): """ Extra quantity on the move. """ # We create a second partner of type subcontractor main_partner_2 = self.env['res.partner'].create({'name': 'main_partner'}) subcontractor_partner2 = self.env['res.partner'].create({ 'name': 'subcontractor_partner', 'parent_id': main_partner_2.id, 'company_id': self.env.ref('base.main_company').id, }) self.env.cache.invalidate() # We create a different BoM for the same product comp3 = self.env['product.product'].create({ 'name': 'Component3', 'type': 'product', 'categ_id': self.env.ref('product.product_category_all').id, }) bom_form = Form(self.env['mrp.bom']) bom_form.type = 'subcontract' bom_form.product_tmpl_id = self.finished.product_tmpl_id with bom_form.bom_line_ids.new() as bom_line: bom_line.product_id = self.comp1 bom_line.product_qty = 1 with bom_form.bom_line_ids.new() as bom_line: bom_line.product_id = comp3 bom_line.product_qty = 2 bom2 = bom_form.save() # We assign the second BoM to the new partner self.bom.write({'subcontractor_ids': [(4, self.subcontractor_partner1.id, None)]}) bom2.write({'subcontractor_ids': [(4, subcontractor_partner2.id, None)]}) # Create a receipt picking from the subcontractor1 picking_form = Form(self.env['stock.picking']) picking_form.picking_type_id = self.env.ref('stock.picking_type_in') picking_form.partner_id = subcontractor_partner2 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() picking_receipt.move_lines.quantity_done = 3.0 picking_receipt.action_done() mo = picking_receipt._get_subcontracted_productions() move_comp1 = mo.move_raw_ids.filtered(lambda m: m.product_id == self.comp1) move_comp3 = mo.move_raw_ids.filtered(lambda m: m.product_id == comp3) self.assertEqual(sum(move_comp1.mapped('product_uom_qty')), 3.0) self.assertEqual(sum(move_comp3.mapped('product_uom_qty')), 6.0) self.assertEqual(sum(move_comp1.mapped('quantity_done')), 3.0) self.assertEqual(sum(move_comp3.mapped('quantity_done')), 6.0) move_finished = mo.move_finished_ids self.assertEqual(sum(move_finished.mapped('product_uom_qty')), 3.0) self.assertEqual(sum(move_finished.mapped('quantity_done')), 3.0)
def test_no_initial_demand(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.move_raw_ids.product_uom_qty = 0 production.action_confirm() production.action_assign() self.assertFalse(production.move_raw_ids.move_orig_ids) self.assertEqual(production.state, 'confirmed') self.assertEqual(production.reservation_state, 'assigned')
def test_flow_10(self): """Receipts from a children contact of a subcontractor are properly handled. """ # Create a children contact subcontractor_contact = self.env['res.partner'].create({ 'name': 'Test children subcontractor contact', 'parent_id': self.subcontractor_partner1.id, }) # 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 = subcontractor_contact 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() # Check that a manufacturing order is created mo = self.env['mrp.production'].search([('bom_id', '=', self.bom.id)]) self.assertEqual(len(mo), 1)
def test_lifoprice(self): self._load('account', 'test', 'account_minimal_test.xml') self._load('stock_account', 'test', 'stock_valuation_account.xml') # Set product category removal strategy as LIFO product_category_001 = self.env['product.category'].create({ 'name': 'Lifo Category', 'removal_strategy_id': self.env.ref('stock.removal_lifo').id, 'property_valuation': 'real_time', 'property_cost_method': 'fifo', }) # Set a product as using lifo price product_form = Form(self.env['product.product']) product_form.default_code = 'LIFO' product_form.name = 'LIFO Ice Cream' product_form.type = 'product' product_form.categ_id = product_category_001 product_form.lst_price = 100.0 product_form.uom_id = self.env.ref('uom.product_uom_kgm') product_form.uom_po_id = self.env.ref('uom.product_uom_kgm') # these are not available (visible) in either product or variant # for views, apparently from the UI you can only set the product # category (or hand-assign the property_* version which seems...) # product_form.categ_id.valuation = 'real_time' # product_form.categ_id.property_cost_method = 'fifo' product_form.categ_id.property_stock_account_input_categ_id = self.env.ref( 'stock_dropshipping.o_expense') product_form.categ_id.property_stock_account_output_categ_id = self.env.ref( 'stock_dropshipping.o_income') product_lifo_icecream = product_form.save() std_price_wiz = Form( self.env['stock.change.standard.price'].with_context( active_id=product_lifo_icecream.id, active_model='product.product')) std_price_wiz.new_price = 70.0 std_price_wiz.save() # I create a draft Purchase Order for first in move for 10 pieces at 60 euro order_form = Form(self.env['purchase.order']) order_form.partner_id = self.env.ref('base.res_partner_3') with order_form.order_line.new() as line: line.product_id = product_lifo_icecream line.product_qty = 10.0 line.price_unit = 60.0 purchase_order_lifo1 = order_form.save() # I create a draft Purchase Order for second shipment for 30 pieces at 80 euro order2_form = Form(self.env['purchase.order']) order2_form.partner_id = self.env.ref('base.res_partner_3') with order2_form.order_line.new() as line: line.product_id = product_lifo_icecream line.product_qty = 30.0 line.price_unit = 80.0 purchase_order_lifo2 = order2_form.save() # I confirm the first purchase order purchase_order_lifo1.button_confirm() # I check the "Approved" status of purchase order 1 self.assertEqual(purchase_order_lifo1.state, 'purchase') # Process the receipt of purchase order 1 purchase_order_lifo1.picking_ids[ 0].move_lines.quantity_done = purchase_order_lifo1.picking_ids[ 0].move_lines.product_qty purchase_order_lifo1.picking_ids[0].button_validate() # I confirm the second purchase order purchase_order_lifo2.button_confirm() # Process the receipt of purchase order 2 purchase_order_lifo2.picking_ids[ 0].move_lines.quantity_done = purchase_order_lifo2.picking_ids[ 0].move_lines.product_qty purchase_order_lifo2.picking_ids[0].button_validate() # Let us send some goods out_form = Form(self.env['stock.picking']) out_form.picking_type_id = self.env.ref('stock.picking_type_out') out_form.immediate_transfer = True with out_form.move_ids_without_package.new() as move: move.product_id = product_lifo_icecream move.quantity_done = 20.0 move.date_expected = fields.Datetime.now() outgoing_lifo_shipment = out_form.save() # I assign this outgoing shipment outgoing_lifo_shipment.action_assign() # Process the delivery of the outgoing shipment outgoing_lifo_shipment.button_validate() # Check if the move value correctly reflects the fifo costing method self.assertEqual( outgoing_lifo_shipment.move_lines.stock_valuation_layer_ids.value, -1400.0, 'Stock move value should have been 1400 euro')
def test_pack_in_receipt_two_step_multi_putaway(self): """ Checks all works right in the following specific corner case: * For a two-step receipt, receives two products using two putaways targeting different locations. * Puts these products in a package then valid the receipt. * Cancels the automatically generated internal transfer then create a new one. * In this internal transfer, adds the package then valid it. """ grp_multi_loc = self.env.ref('stock.group_stock_multi_locations') grp_multi_step_rule = self.env.ref('stock.group_adv_location') grp_pack = self.env.ref('stock.group_tracking_lot') self.env.user.write({'groups_id': [(3, grp_multi_loc.id)]}) self.env.user.write({'groups_id': [(3, grp_multi_step_rule.id)]}) self.env.user.write({'groups_id': [(3, grp_pack.id)]}) self.warehouse.reception_steps = 'two_steps' # Settings of receipt. self.warehouse.in_type_id.show_operations = True self.warehouse.in_type_id.show_entire_packs = True self.warehouse.in_type_id.show_reserved = True # Settings of internal transfer. self.warehouse.int_type_id.show_operations = True self.warehouse.int_type_id.show_entire_packs = True self.warehouse.int_type_id.show_reserved = True # Creates two new locations for putaway. location_form = Form(self.env['stock.location']) location_form.name = 'Shelf A' location_form.location_id = self.stock_location loc_shelf_A = location_form.save() location_form = Form(self.env['stock.location']) location_form.name = 'Shelf B' location_form.location_id = self.stock_location loc_shelf_B = location_form.save() # Creates a new putaway rule for productA and productB. putaway_A = self.env['stock.putaway.rule'].create({ 'product_id': self.productA.id, 'location_in_id': self.stock_location.id, 'location_out_id': loc_shelf_A.id, }) putaway_B = self.env['stock.putaway.rule'].create({ 'product_id': self.productB.id, 'location_in_id': self.stock_location.id, 'location_out_id': loc_shelf_B.id, }) self.stock_location.putaway_rule_ids = [(4, putaway_A.id, 0), (4, putaway_B.id, 0)] # location_form = Form(self.stock_location) # location_form.putaway_rule_ids = [(4, putaway_A.id, 0), (4, putaway_B.id, 0), ], # self.stock_location = location_form.save() # Create a new receipt with the two products. receipt_form = Form(self.env['stock.picking']) receipt_form.picking_type_id = self.warehouse.in_type_id # Add 2 lines with receipt_form.move_ids_without_package.new() as move_line: move_line.product_id = self.productA move_line.product_uom_qty = 1 with receipt_form.move_ids_without_package.new() as move_line: move_line.product_id = self.productB move_line.product_uom_qty = 1 receipt = receipt_form.save() receipt.action_confirm() # Adds quantities then packs them and valids the receipt. receipt_form = Form(receipt) with receipt_form.move_line_ids_without_package.edit(0) as move_line: move_line.qty_done = 1 with receipt_form.move_line_ids_without_package.edit(1) as move_line: move_line.qty_done = 1 receipt = receipt_form.save() receipt.put_in_pack() receipt.button_validate() receipt_package = receipt.package_level_ids_details[0] self.assertEqual(receipt_package.location_dest_id.id, receipt.location_dest_id.id) self.assertEqual( receipt_package.move_line_ids[0].location_dest_id.id, receipt.location_dest_id.id) self.assertEqual( receipt_package.move_line_ids[1].location_dest_id.id, receipt.location_dest_id.id) # Checks an internal transfer was created following the validation of the receipt. internal_transfer = self.env['stock.picking'].search([ ('picking_type_id', '=', self.warehouse.int_type_id.id) ], order='id desc', limit=1) self.assertEqual(internal_transfer.origin, receipt.name) self.assertEqual( len(internal_transfer.package_level_ids_details), 1) internal_package = internal_transfer.package_level_ids_details[0] self.assertEqual( internal_package.location_dest_id.id, internal_transfer.location_dest_id.id) self.assertNotEqual( internal_package.location_dest_id.id, putaway_A.location_out_id.id, "The package destination location must be the one from the picking.") self.assertNotEqual( internal_package.move_line_ids[0].location_dest_id.id, putaway_A.location_out_id.id, "The move line destination location must be the one from the picking.") self.assertNotEqual( internal_package.move_line_ids[1].location_dest_id.id, putaway_A.location_out_id.id, "The move line destination location must be the one from the picking.") # Cancels the internal transfer and creates a new one. internal_transfer.action_cancel() internal_form = Form(self.env['stock.picking']) internal_form.picking_type_id = self.warehouse.int_type_id internal_form.location_id = self.warehouse.wh_input_stock_loc_id with internal_form.package_level_ids_details.new() as pack_line: pack_line.package_id = receipt_package.package_id internal_transfer = internal_form.save() # Checks the package fields have been correctly set. internal_package = internal_transfer.package_level_ids_details[0] self.assertEqual( internal_package.location_dest_id.id, internal_transfer.location_dest_id.id) internal_transfer.action_assign() self.assertEqual( internal_package.location_dest_id.id, internal_transfer.location_dest_id.id) self.assertNotEqual( internal_package.location_dest_id.id, putaway_A.location_out_id.id, "The package destination location must be the one from the picking.") self.assertNotEqual( internal_package.move_line_ids[0].location_dest_id.id, putaway_A.location_out_id.id, "The move line destination location must be the one from the picking.") self.assertNotEqual( internal_package.move_line_ids[1].location_dest_id.id, putaway_A.location_out_id.id, "The move line destination location must be the one from the picking.") internal_transfer.button_validate()
def test_flow_2(self): """ Tick "Resupply Subcontractor on Order" on the components and trigger the creation of the subcontracting manufacturing order through a receipt picking. Checks if the resupplying actually works. Also set a different subcontracting location on the partner. """ # Tick "resupply subconractor on order" resupply_sub_on_order_route = self.env['stock.location.route'].search([('name', '=', 'Resupply Subcontractor on Order')]) (self.comp1 + self.comp2).write({'route_ids': [(4, resupply_sub_on_order_route.id, None)]}) # Create a different subcontract location partner_subcontract_location = self.env['stock.location'].create({ 'name': 'Specific partner location', 'location_id': self.env.ref('stock.stock_location_locations_partner').id, 'usage': 'internal', 'company_id': self.env.company.id, }) self.subcontractor_partner1.property_stock_subcontractor = partner_subcontract_location.id resupply_rule = resupply_sub_on_order_route.rule_ids.filtered(lambda l: l.location_id == self.comp1.property_stock_production and l.location_src_id == self.env.company.subcontracting_location_id) resupply_rule.copy({'location_src_id': partner_subcontract_location.id}) resupply_warehouse_rule = self.warehouse.route_ids.rule_ids.filtered(lambda l: l.location_id == self.env.company.subcontracting_location_id and l.location_src_id == self.warehouse.lot_stock_id) resupply_warehouse_rule.copy({'location_id': partner_subcontract_location.id}) # 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() # Nothing should be tracked self.assertFalse(picking_receipt.display_action_record_components) # Pickings should directly be created mo = self.env['mrp.production'].search([('bom_id', '=', self.bom.id)]) self.assertEqual(len(mo.picking_ids), 1) self.assertEquals(mo.state, 'confirmed') self.assertEqual(len(mo.picking_ids.move_lines), 2) picking = mo.picking_ids wh = picking.picking_type_id.warehouse_id # The picking should be a delivery order self.assertEquals(picking.picking_type_id, wh.out_type_id) self.assertEquals(mo.picking_type_id, wh.subcontracting_type_id) self.assertFalse(mo.picking_type_id.active) # No manufacturing order for `self.comp2` comp2mo = self.env['mrp.production'].search([('bom_id', '=', self.comp2_bom.id)]) self.assertEqual(len(comp2mo), 0) picking_receipt.move_lines.quantity_done = 1 picking_receipt.button_validate() self.assertEquals(mo.state, 'done') # Available quantities should be negative at the subcontracting location for each components avail_qty_comp1 = self.env['stock.quant']._get_available_quantity(self.comp1, self.subcontractor_partner1.property_stock_subcontractor, allow_negative=True) avail_qty_comp2 = self.env['stock.quant']._get_available_quantity(self.comp2, self.subcontractor_partner1.property_stock_subcontractor, allow_negative=True) avail_qty_finished = self.env['stock.quant']._get_available_quantity(self.finished, wh.lot_stock_id) self.assertEquals(avail_qty_comp1, -1) self.assertEquals(avail_qty_comp2, -1) self.assertEquals(avail_qty_finished, 1) avail_qty_comp1_in_global_location = self.env['stock.quant']._get_available_quantity(self.comp1, self.env.company.subcontracting_location_id, allow_negative=True) avail_qty_comp2_in_global_location = self.env['stock.quant']._get_available_quantity(self.comp2, self.env.company.subcontracting_location_id, allow_negative=True) self.assertEqual(avail_qty_comp1_in_global_location, 0.0) self.assertEqual(avail_qty_comp2_in_global_location, 0.0)
def test_flow_tracked_1(self): """ This test mimics test_flow_1 but with a BoM that has tracking included in it. """ # 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_lot move.product_uom_qty = 1 picking_receipt = picking_form.save() picking_receipt.action_confirm() # We should be able to call the 'record_components' button self.assertTrue(picking_receipt.display_action_record_components) # Check the created manufacturing order mo = self.env['mrp.production'].search([('bom_id', '=', self.bom_tracked.id)]) self.assertEqual(len(mo), 1) self.assertEquals(mo.state, 'confirmed') self.assertEqual(len(mo.picking_ids), 0) wh = picking_receipt.picking_type_id.warehouse_id self.assertEquals(mo.picking_type_id, wh.subcontracting_type_id) self.assertFalse(mo.picking_type_id.active) # Create a RR pg1 = self.env['procurement.group'].create({}) self.env['stock.warehouse.orderpoint'].create({ 'name': 'xxx', 'product_id': self.comp1_sn.id, 'product_min_qty': 0, 'product_max_qty': 0, 'location_id': self.env.user.company_id.subcontracting_location_id.id, 'group_id': pg1.id, }) # Run the scheduler and check the created picking self.env['procurement.group'].run_scheduler() picking = self.env['stock.picking'].search([('group_id', '=', pg1.id)]) self.assertEqual(len(picking), 1) self.assertEquals(picking.picking_type_id, wh.out_type_id) lot_id = self.env['stock.production.lot'].create({ 'name': 'lot1', 'product_id': self.finished_lot.id, 'company_id': self.env.company.id, }) serial_id = self.env['stock.production.lot'].create({ 'name': 'lot1', 'product_id': self.comp1_sn.id, 'company_id': self.env.company.id, }) produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.finished_lot_id = lot_id produce_form.raw_workorder_line_ids._records[0]['lot_id'] = serial_id.id wiz_produce = produce_form.save() wiz_produce.do_produce() # We should not be able to call the 'record_components' button self.assertFalse(picking_receipt.display_action_record_components) picking_receipt.move_lines.quantity_done = 1 picking_receipt.move_lines.move_line_ids.lot_id = lot_id.id picking_receipt.button_validate() self.assertEquals(mo.state, 'done') # Available quantities should be negative at the subcontracting location for each components avail_qty_comp1 = self.env['stock.quant']._get_available_quantity(self.comp1_sn, self.subcontractor_partner1.property_stock_subcontractor, allow_negative=True) avail_qty_comp2 = self.env['stock.quant']._get_available_quantity(self.comp2, self.subcontractor_partner1.property_stock_subcontractor, allow_negative=True) avail_qty_finished = self.env['stock.quant']._get_available_quantity(self.finished_lot, wh.lot_stock_id) self.assertEquals(avail_qty_comp1, -1) self.assertEquals(avail_qty_comp2, -1) self.assertEquals(avail_qty_finished, 1)
def test_flow_7(self): """ Process a subcontracting receipt with tracked component and finished product. Simulate the regiter components button. Once the components are registered, try to do a correction on exisiting move lines and check that the subcontracting document is updated. """ # Create a receipt picking from the subcontractor (self.comp1 | self.comp2 | self.finished).write({'tracking': 'lot'}) 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 = 5 picking_receipt = picking_form.save() picking_receipt.action_confirm() mo = picking_receipt.move_lines.move_orig_ids.production_id move_comp1 = mo.move_raw_ids.filtered(lambda m: m.product_id == self.comp1) move_comp2 = mo.move_raw_ids.filtered(lambda m: m.product_id == self.comp2) # move_finished is linked to receipt and not MO finished move. move_finished = picking_receipt.move_lines self.assertEqual(move_comp1.quantity_done, 0) self.assertEqual(move_comp2.quantity_done, 0) lot_c1 = self.env['stock.production.lot'].create({ 'name': 'LOT C1', 'product_id': self.comp1.id, 'company_id': self.env.company.id, }) lot_c2 = self.env['stock.production.lot'].create({ 'name': 'LOT C2', 'product_id': self.comp2.id, 'company_id': self.env.company.id, }) lot_f1 = self.env['stock.production.lot'].create({ 'name': 'LOT F1', 'product_id': self.finished.id, 'company_id': self.env.company.id, }) register_form = Form(self.env['mrp.product.produce'].with_context( active_id=picking_receipt._get_subcontracted_productions().id, default_subcontract_move_id=picking_receipt.move_lines.id )) register_form.qty_producing = 3.0 self.assertEqual(len(register_form._values['raw_workorder_line_ids']), 2, 'Register Components Form should contains one line per component.') self.assertTrue(all(p[2]['product_id'] in (self.comp1 | self.comp2).ids for p in register_form._values['raw_workorder_line_ids']), 'Register Components Form should contains component.') with register_form.raw_workorder_line_ids.edit(0) as pl: pl.lot_id = lot_c1 with register_form.raw_workorder_line_ids.edit(1) as pl: pl.lot_id = lot_c2 register_form.finished_lot_id = lot_f1 register_wizard = register_form.save() action = register_wizard.continue_production() register_form = Form(self.env['mrp.product.produce'].with_context( **action['context'] )) with register_form.raw_workorder_line_ids.edit(0) as pl: pl.lot_id = lot_c1 with register_form.raw_workorder_line_ids.edit(1) as pl: pl.lot_id = lot_c2 register_form.finished_lot_id = lot_f1 register_wizard = register_form.save() register_wizard.do_produce() self.assertEqual(move_comp1.quantity_done, 5.0) self.assertEqual(move_comp1.move_line_ids.filtered(lambda ml: not ml.product_uom_qty).lot_id.name, 'LOT C1') self.assertEqual(move_comp2.quantity_done, 5.0) self.assertEqual(move_comp2.move_line_ids.filtered(lambda ml: not ml.product_uom_qty).lot_id.name, 'LOT C2') self.assertEqual(move_finished.quantity_done, 5.0) self.assertEqual(move_finished.move_line_ids.filtered(lambda ml: ml.product_uom_qty).lot_id.name, 'LOT F1') corrected_final_lot = self.env['stock.production.lot'].create({ 'name': 'LOT F2', 'product_id': self.finished.id, 'company_id': self.env.company.id, }) details_operation_form = Form(picking_receipt.move_lines, view=self.env.ref('stock.view_stock_move_operations')) for i in range(len(details_operation_form._values['move_line_ids'])): with details_operation_form.move_line_ids.edit(i) as ml: if ml._values['qty_done']: ml.lot_id = corrected_final_lot details_operation_form.save() move_raw_comp_1 = picking_receipt.move_lines.move_orig_ids.production_id.move_raw_ids.filtered(lambda m: m.product_id == self.comp1) move_raw_comp_2 = picking_receipt.move_lines.move_orig_ids.production_id.move_raw_ids.filtered(lambda m: m.product_id == self.comp2) details_subcontract_moves_form = Form(move_raw_comp_1, view=self.env.ref('mrp_subcontracting.mrp_subcontracting_move_form_view')) for i in range(len(details_subcontract_moves_form._values['move_line_ids'])): with details_subcontract_moves_form.move_line_ids.edit(i) as sc: if sc._values['qty_done']: sc.lot_produced_ids.remove(index=0) sc.lot_produced_ids.add(corrected_final_lot) details_subcontract_moves_form.save() details_subcontract_moves_form = Form(move_raw_comp_2, view=self.env.ref('mrp_subcontracting.mrp_subcontracting_move_form_view')) for i in range(len(details_subcontract_moves_form._values['move_line_ids'])): with details_subcontract_moves_form.move_line_ids.edit(i) as sc: if sc._values['qty_done']: sc.lot_produced_ids.remove(index=0) sc.lot_produced_ids.add(corrected_final_lot) details_subcontract_moves_form.save() self.assertEqual(move_comp1.move_line_ids.filtered(lambda ml: not ml.product_uom_qty).lot_produced_ids.name, 'LOT F2') self.assertEqual(move_comp2.move_line_ids.filtered(lambda ml: not ml.product_uom_qty).lot_produced_ids.name, 'LOT F2')
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_flow_1(self): """ Don't tick any route on the components and trigger the creation of the subcontracting manufacturing order through a receipt picking. Create a reordering rule in the subcontracting locations for a component and run the scheduler to resupply. Checks if the resupplying actually works """ # Check subcontracting picking Type self.assertTrue(all(self.env['stock.warehouse'].search([]).with_context(active_test=False).mapped('subcontracting_type_id.use_create_components_lots'))) # 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() # Nothing should be tracked self.assertTrue(all(m.product_uom_qty == m.reserved_availability for m in picking_receipt.move_lines)) self.assertEqual(picking_receipt.state, 'assigned') self.assertFalse(picking_receipt.display_action_record_components) # Check the created manufacturing order mo = self.env['mrp.production'].search([('bom_id', '=', self.bom.id)]) self.assertEqual(len(mo), 1) self.assertEqual(len(mo.picking_ids), 0) wh = picking_receipt.picking_type_id.warehouse_id self.assertEquals(mo.picking_type_id, wh.subcontracting_type_id) self.assertFalse(mo.picking_type_id.active) # Create a RR pg1 = self.env['procurement.group'].create({}) self.env['stock.warehouse.orderpoint'].create({ 'name': 'xxx', 'product_id': self.comp1.id, 'product_min_qty': 0, 'product_max_qty': 0, 'location_id': self.env.user.company_id.subcontracting_location_id.id, 'group_id': pg1.id, }) # Run the scheduler and check the created picking self.env['procurement.group'].run_scheduler() picking = self.env['stock.picking'].search([('group_id', '=', pg1.id)]) self.assertEqual(len(picking), 1) self.assertEquals(picking.picking_type_id, wh.out_type_id) picking_receipt.move_lines.quantity_done = 1 picking_receipt.button_validate() self.assertEquals(mo.state, 'done') # Available quantities should be negative at the subcontracting location for each components avail_qty_comp1 = self.env['stock.quant']._get_available_quantity(self.comp1, self.subcontractor_partner1.property_stock_subcontractor, allow_negative=True) avail_qty_comp2 = self.env['stock.quant']._get_available_quantity(self.comp2, self.subcontractor_partner1.property_stock_subcontractor, allow_negative=True) avail_qty_finished = self.env['stock.quant']._get_available_quantity(self.finished, wh.lot_stock_id) self.assertEquals(avail_qty_comp1, -1) self.assertEquals(avail_qty_comp2, -1) self.assertEquals(avail_qty_finished, 1) # Ensure returns to subcontractor location return_form = Form(self.env['stock.return.picking'].with_context(active_id=picking_receipt.id, active_model='stock.picking')) return_wizard = return_form.save() return_picking_id, pick_type_id = return_wizard._create_returns() return_picking = self.env['stock.picking'].browse(return_picking_id) self.assertEqual(len(return_picking), 1) self.assertEqual(return_picking.move_lines.location_dest_id, self.subcontractor_partner1.property_stock_subcontractor)