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 = Form(self.env[backorder_wiz['res_model']].with_context(backorder_wiz['context'])).save() 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) mo_done = backorder.move_lines.move_orig_ids.production_id.filtered(lambda p: p.state == 'done') backorder_mo = backorder.move_lines.move_orig_ids.production_id.filtered(lambda p: p.state != 'done') self.assertTrue(mo_done) self.assertEqual(mo_done.qty_produced, 3) self.assertEqual(mo_done.product_uom_qty, 3) self.assertTrue(backorder_mo) self.assertEqual(backorder_mo.product_uom_qty, 2) self.assertEqual(backorder_mo.qty_produced, 0) backorder.move_lines.quantity_done = 2 backorder._action_done() self.assertTrue(picking_receipt.move_lines.move_orig_ids.production_id.state == 'done')
def test_unbuild_account_01(self): """Test when production location has its valuation accounts. After unbuild, the journal entries are the reversal of the journal entries created when produce the product. """ # set accounts for production location production_location = self.product_A.property_stock_production wip_incoming_account = self.env['account.account'].create({ 'name': 'wip incoming', 'code': '000001', 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, }) wip_outgoing_account = self.env['account.account'].create({ 'name': 'wip outgoing', 'code': '000002', 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, }) production_location.write({ 'valuation_in_account_id': wip_incoming_account.id, 'valuation_out_account_id': wip_outgoing_account.id, }) # build production_form = Form(self.env['mrp.production']) production_form.product_id = self.product_A production_form.bom_id = self.bom production_form.product_qty = 1 production = production_form.save() production.action_confirm() mo_form = Form(production) mo_form.qty_producing = 1 production = mo_form.save() production._post_inventory() production.button_mark_done() # finished product move productA_debit_line = self.env['account.move.line'].search([('ref', 'ilike', 'MO%Product A'), ('credit', '=', 0)]) productA_credit_line = self.env['account.move.line'].search([('ref', 'ilike', 'MO%Product A'), ('debit', '=', 0)]) self.assertEqual(productA_debit_line.account_id, self.stock_valuation_account) self.assertEqual(productA_credit_line.account_id, wip_outgoing_account) # component move productB_debit_line = self.env['account.move.line'].search([('ref', 'ilike', 'MO%Product B'), ('credit', '=', 0)]) productB_credit_line = self.env['account.move.line'].search([('ref', 'ilike', 'MO%Product B'), ('debit', '=', 0)]) self.assertEqual(productB_debit_line.account_id, wip_incoming_account) self.assertEqual(productB_credit_line.account_id, self.stock_valuation_account) # unbuild res_dict = production.button_unbuild() wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() wizard.action_validate() productA_debit_line = self.env['account.move.line'].search([('ref', 'ilike', 'UB%Product A'), ('credit', '=', 0)]) productA_credit_line = self.env['account.move.line'].search([('ref', 'ilike', 'UB%Product A'), ('debit', '=', 0)]) self.assertEqual(productA_debit_line.account_id, wip_outgoing_account) self.assertEqual(productA_credit_line.account_id, self.stock_valuation_account) # component move productB_debit_line = self.env['account.move.line'].search([('ref', 'ilike', 'UB%Product B'), ('credit', '=', 0)]) productB_credit_line = self.env['account.move.line'].search([('ref', 'ilike', 'UB%Product B'), ('debit', '=', 0)]) self.assertEqual(productB_debit_line.account_id, self.stock_valuation_account) self.assertEqual(productB_credit_line.account_id, wip_incoming_account)
def test_picking_state_with_null_qty(self): receipt_form = Form(self.env['stock.picking'].with_context( default_immediate_transfer=False)) picking_type_id = self.warehouse.out_type_id receipt_form.picking_type_id = picking_type_id with receipt_form.move_ids_without_package.new() as move_line: move_line.product_id = self.productA move_line.product_uom_qty = 10 with receipt_form.move_ids_without_package.new() as move_line: move_line.product_id = self.productB move_line.product_uom_qty = 10 receipt = receipt_form.save() receipt.action_confirm() self.assertEqual(receipt.state, 'confirmed') receipt.move_ids_without_package[1].product_uom_qty = 0 self.assertEqual(receipt.state, 'confirmed') receipt_form = Form(self.env['stock.picking'].with_context( default_immediate_transfer=True)) picking_type_id = self.warehouse.out_type_id receipt_form.picking_type_id = picking_type_id with receipt_form.move_ids_without_package.new() as move_line: move_line.product_id = self.productA move_line.quantity_done = 10 with receipt_form.move_ids_without_package.new() as move_line: move_line.product_id = self.productB move_line.quantity_done = 10 receipt = receipt_form.save() receipt.action_confirm() self.assertEqual(receipt.state, 'assigned') receipt.move_ids_without_package[1].product_uom_qty = 0 self.assertEqual(receipt.state, 'assigned')
def test_read_purchase_order(self): """ Check that a purchase user can read all purchase order and 'in' invoices""" purchase_user_2 = self.purchase_user.copy({ 'name': 'Purchase user 2', 'login': '******', 'email': '*****@*****.**', }) purchase_order_form = Form( self.env['purchase.order'].with_user(purchase_user_2)) purchase_order_form.partner_id = self.vendor with purchase_order_form.order_line.new() as line: line.name = self.product.name line.product_id = self.product line.product_qty = 4 line.price_unit = 5 purchase_order_user2 = purchase_order_form.save() purchase_order_user2.button_confirm() purchase_order_user2.order_line.qty_received = 4 purchase_order_user2.action_create_invoice() vendor_bill_user2 = purchase_order_user2.invoice_ids # open purchase_order_user2 and vendor_bill_user2 with `self.purchase_user` purchase_order_user1 = Form( purchase_order_user2.with_user(self.purchase_user)) purchase_order_user1 = purchase_order_user1.save() vendor_bill_user1 = Form( vendor_bill_user2.with_user(self.purchase_user)) vendor_bill_user1 = vendor_bill_user1.save()
def test_manufacturing_3_steps_flexible(self): """ Test MO/picking before manufacturing/picking after manufacturing components and move_orig/move_dest. Ensure that additional moves are put in picking before manufacturing too. """ with Form(self.warehouse) as warehouse: warehouse.manufacture_steps = 'pbm_sam' bom = self.env['mrp.bom'].search([('product_id', '=', self.finished_product.id)]) new_product = self.env['product.product'].create({ 'name': 'New product', 'type': 'product', }) bom.consumption = 'flexible' 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() production_form = Form(production) with production_form.move_raw_ids.new() as move: move.product_id = new_product move.product_uom_qty = 2 production = production_form.save() move_raw_ids = production.move_raw_ids self.assertEqual(len(move_raw_ids), 2) pbm_move = move_raw_ids.move_orig_ids self.assertEqual(len(pbm_move), 2) self.assertTrue(new_product in pbm_move.product_id)
def test_remove_package(self): """ In the overshipping scenario, if I remove the package after adding it, we should not remove the associated stock move. """ self.warehouse.delivery_steps = 'ship_only' package = self.env["stock.quant.package"].create({"name": "Src Pack"}) self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 100, package_id=package) self.warehouse.out_type_id.show_entire_packs = True picking = self.env['stock.picking'].create({ 'location_id': self.stock_location.id, 'location_dest_id': self.customer_location.id, 'picking_type_id': self.warehouse.out_type_id.id, }) with Form(picking) as picking_form: with picking_form.move_ids_without_package.new() as move: move.product_id = self.productA move.product_uom_qty = 75 picking.action_assign() with Form(picking) as picking_form: with picking_form.package_level_ids_details.new() as package_level: package_level.package_id = package with Form(picking) as picking_form: picking_form.package_level_ids.remove(0) self.assertEqual(len(picking.move_lines), 1, 'Should have only 1 stock move')
def test_07_differed_schedule_date(self): warehouse = self.env['stock.warehouse'].search([], limit=1) with Form(warehouse) as w: w.reception_steps = 'three_steps' po_form = Form(self.env['purchase.order']) po_form.partner_id = self.partner_id with po_form.order_line.new() as line: line.product_id = self.product_id_1 line.date_planned = datetime.today() line.product_qty = 1.0 with po_form.order_line.new() as line: line.product_id = self.product_id_1 line.date_planned = datetime.today() + timedelta(days=7) line.product_qty = 1.0 po = po_form.save() po.button_approve() po.picking_ids.move_line_ids.write({'qty_done': 1.0}) po.picking_ids.button_validate() pickings = self.env['stock.picking'].search([('group_id', '=', po.group_id.id)]) for picking in pickings: self.assertEqual(picking.scheduled_date.date(), date.today())
def test_tracking_backorder_immediate_production_serial_1(self): """ Create a MO to build 2 of a SN tracked product. Build both the starting MO and its backorder as immediate productions (i.e. Mark As Done without setting SN/filling any quantities) """ mo, _, p_final, p1, p2 = self.generate_mo(qty_final=2, tracking_final='serial', qty_base_1=2, qty_base_2=2) self.env['stock.quant']._update_available_quantity(p1, self.stock_location_components, 2.0) self.env['stock.quant']._update_available_quantity(p2, self.stock_location_components, 2.0) mo.action_assign() res_dict = mo.button_mark_done() self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') immediate_wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() res_dict = immediate_wizard.process() self.assertEqual(res_dict.get('res_model'), 'mrp.production.backorder') backorder_wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])) # backorder should automatically open action = backorder_wizard.save().action_backorder() self.assertEqual(action.get('res_model'), 'mrp.production') backorder_mo_form = Form(self.env[action['res_model']].with_context(action['context']).browse(action['res_id'])) backorder_mo = backorder_mo_form.save() res_dict = backorder_mo.button_mark_done() self.assertEqual(res_dict.get('res_model'), 'mrp.immediate.production') immediate_wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() immediate_wizard.process() self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 2, "Incorrect number of final product produced.") self.assertEqual(len(self.env['stock.production.lot'].search([('product_id', '=', p_final.id)])), 2, "Serial Numbers were not correctly produced.")
def test_unbuild_decimal_qty(self): """ Use case: - decimal accuracy of Product UoM > decimal accuracy of Units - unbuild a product with a decimal quantity of component """ self.env['decimal.precision'].search([ ('name', '=', 'Product Unit of Measure') ]).digits = 4 self.uom_unit.rounding = 0.001 self.bom_1.product_qty = 3 self.bom_1.bom_line_ids.product_qty = 5 self.env['stock.quant']._update_available_quantity( self.product_2, self.stock_location, 3) mo_form = Form(self.env['mrp.production']) mo_form.product_id = self.bom_1.product_id mo_form.bom_id = self.bom_1 mo = mo_form.save() mo.action_confirm() mo.action_assign() mo_form = Form(mo) mo_form.qty_producing = 3 mo_form.save() mo.button_mark_done() uo_form = Form(self.env['mrp.unbuild']) uo_form.mo_id = mo # Unbuilding one product means a decimal quantity equal to 1 / 3 * 5 for each component uo_form.product_qty = 1 uo = uo_form.save() uo.action_unbuild() self.assertEqual(uo.state, 'done')
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.assertEqual(len(mo_pick1), 1) self.assertEqual(len(mo_pick2), 1) self.assertEqual(mo_pick1.bom_id, self.bom) self.assertEqual(mo_pick2.bom_id, bom2)
def produce_one(mo): mo_form = Form(mo) mo_form.qty_producing = 1 mo = mo_form.save() action = mo.button_mark_done() backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) backorder.save().action_backorder() return mo.procurement_group_id.mrp_production_ids[-1]
def test_stock_valuation_layer_revaluation_fifo(self): self.product1.categ_id.property_cost_method = 'fifo' context = { 'default_product_id': self.product1.id, 'default_company_id': self.env.company.id, 'default_added_value': 0.0 } # Quantity of product1 is zero, raise with self.assertRaises(UserError): Form(self.env['stock.valuation.layer.revaluation'].with_context( context)).save() self._make_in_move(self.product1, 10, unit_cost=2) self._make_in_move(self.product1, 10, unit_cost=4) self.assertEqual(self.product1.standard_price, 2) self.assertEqual(self.product1.quantity_svl, 20) old_layers = self.env['stock.valuation.layer'].search( [('product_id', '=', self.product1.id)], order="create_date desc, id desc") self.assertEqual(len(old_layers), 2) self.assertEqual(old_layers[0].remaining_value, 40) revaluation_wizard = Form( self.env['stock.valuation.layer.revaluation'].with_context( context)) revaluation_wizard.added_value = 20 revaluation_wizard.account_id = self.stock_valuation_account revaluation_wizard.save().action_validate_revaluation() self.assertEqual(self.product1.standard_price, 2) # Check the creation of stock.valuation.layer new_layer = self.env['stock.valuation.layer'].search( [('product_id', '=', self.product1.id)], order="create_date desc, id desc", limit=1) self.assertEqual(new_layer.value, 20) # Check the remaing value of current layers self.assertEqual(old_layers[0].remaining_value, 50) self.assertEqual(sum(slv.remaining_value for slv in old_layers), 80) # Check account move self.assertTrue(bool(new_layer.account_move_id)) self.assertTrue(len(new_layer.account_move_id.line_ids), 2) self.assertEqual( sum(new_layer.account_move_id.line_ids.mapped("debit")), 20) self.assertEqual( sum(new_layer.account_move_id.line_ids.mapped("credit")), 20) credit_lines = [ l for l in new_layer.account_move_id.line_ids if l.credit > 0 ] self.assertEqual(len(credit_lines), 1)
def test_entire_pack_overship(self): """ Test the scenario of overshipping: we send the customer an entire package, even though it might be more than what they initially ordered, and update the quantity on the sales order to reflect what was actually sent. """ self.warehouse.delivery_steps = 'ship_only' package = self.env["stock.quant.package"].create({"name": "Src Pack"}) self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 100, package_id=package) self.warehouse.out_type_id.show_entire_packs = True picking = self.env['stock.picking'].create({ 'location_id': self.stock_location.id, 'location_dest_id': self.customer_location.id, 'picking_type_id': self.warehouse.out_type_id.id, }) with Form(picking) as picking_form: with picking_form.move_ids_without_package.new() as move: move.product_id = self.productA move.product_uom_qty = 75 picking.action_confirm() picking.action_assign() with Form(picking) as picking_form: with picking_form.package_level_ids_details.new() as package_level: package_level.package_id = package self.assertEqual(len(picking.move_lines), 1, 'Should have only 1 stock move') self.assertEqual(len(picking.move_lines), 1, 'Should have only 1 stock move') with Form(picking) as picking_form: with picking_form.package_level_ids_details.edit( 0) as package_level: package_level.is_done = True action = picking.button_validate() self.assertEqual(action, True, 'Should not open wizard') for ml in picking.move_line_ids: self.assertEqual(ml.package_id, package, 'move_line.package') self.assertEqual(ml.result_package_id, package, 'move_line.result_package') self.assertEqual(ml.state, 'done', 'move_line.state') quant = package.quant_ids.filtered( lambda q: q.location_id == self.customer_location) self.assertEqual(len(quant), 1, 'Should have quant at customer location') self.assertEqual(quant.reserved_quantity, 0, 'quant.reserved_quantity should = 0') self.assertEqual(quant.quantity, 100.0, 'quant.quantity should = 100') self.assertEqual(sum(ml.qty_done for ml in picking.move_line_ids), 100.0, 'total move_line.qty_done should = 100') backorders = self.env['stock.picking'].search([('backorder_id', '=', picking.id)]) self.assertEqual(len(backorders), 0, 'Should not create a backorder')
def test_batch_with_immediate_transfer_and_backorder_wizard_with_manual_operations( self): """ Test a simple batch picking with only one quantity fully available. The user set the quantity done only for the partially available picking. The test should run the immediate transfer for the first picking and then the backorder wizard for the second picking. """ self.env['stock.quant']._update_available_quantity( self.productA, self.stock_location, 5.0) self.env['stock.quant']._update_available_quantity( self.productB, self.stock_location, 10.0) # Confirm batch, pickings should not be automatically assigned. self.batch.action_confirm() self.assertEqual(self.picking_client_1.state, 'confirmed', 'Picking 1 should be confirmed') self.assertEqual(self.picking_client_2.state, 'confirmed', 'Picking 2 should be confirmed') # Ask to assign, so pickings should be assigned now. self.batch.action_assign() self.assertEqual(self.picking_client_1.state, 'assigned', 'Picking 1 should be ready') self.assertEqual(self.picking_client_2.state, 'assigned', 'Picking 2 should be ready') self.picking_client_1.move_lines.quantity_done = 5 # There should be a wizard asking to process picking without quantity done immediate_transfer_wizard_dict = self.batch.action_done() self.assertTrue(immediate_transfer_wizard_dict) immediate_transfer_wizard = Form(self.env[( immediate_transfer_wizard_dict.get('res_model'))].with_context( immediate_transfer_wizard_dict['context'])).save() self.assertEqual(len(immediate_transfer_wizard.pick_ids), 1) back_order_wizard_dict = immediate_transfer_wizard.process() self.assertTrue(back_order_wizard_dict) back_order_wizard = Form( self.env[(back_order_wizard_dict.get('res_model'))].with_context( back_order_wizard_dict['context'])).save() self.assertEqual(len(back_order_wizard.pick_ids), 1) back_order_wizard.process() self.assertEqual(self.picking_client_1.state, 'done', 'Picking 1 should be done') self.assertEqual(self.picking_client_1.move_lines.product_uom_qty, 5, 'initial demand should be 5 after picking split') self.assertTrue( self.env['stock.picking'].search([ ('backorder_id', '=', self.picking_client_1.id) ]), 'no back order created') quant_A = self.env['stock.quant']._gather(self.productA, self.stock_location) quant_B = self.env['stock.quant']._gather(self.productB, self.stock_location) # ensure that quantity for picking has been moved self.assertFalse(sum(quant_A.mapped('quantity'))) self.assertFalse(sum(quant_B.mapped('quantity')))
def test_stock_landed_costs_rounding_02(self): """ The landed costs should be correctly computed, even when the decimal accuracy of the deciaml price is increased. """ self.env.ref("product.decimal_price").digits = 4 fifo_pc = self.env['product.category'].create({ 'name': 'Fifo Category', 'parent_id': self.env.ref("product.product_category_all").id, 'property_valuation': 'real_time', 'property_cost_method': 'fifo', }) products = self.Product.create([{ 'name': 'Super Product %s' % price, 'categ_id': fifo_pc.id, 'type': 'product', 'standard_price': price, } for price in [0.91, 0.93, 75.17, 20.54]]) landed_product = self.Product.create({ 'name': 'Landed Costs', 'type': 'service', 'landed_cost_ok': True, 'split_method_landed_cost': 'by_quantity', 'standard_price': 1000.0, }) po = self.env['purchase.order'].create({ 'partner_id': self.partner_a.id, 'order_line': [(0, 0, { 'product_id': product.id, 'product_qty': qty, 'price_unit': product.standard_price, }) for product, qty in zip(products, [6, 6, 3, 6])] }) po.button_confirm() res_dict = po.picking_ids.button_validate() validate_wizard = Form( self.env[(res_dict.get('res_model'))].with_context( res_dict.get('context'))).save() validate_wizard.process() lc_form = Form(self.LandedCost) lc_form.picking_ids.add(po.picking_ids) with lc_form.cost_lines.new() as line: line.product_id = landed_product lc = lc_form.save() lc.compute_landed_cost() self.assertEqual( sum(lc.valuation_adjustment_lines.mapped( 'additional_landed_cost')), 1000.0)
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_tracking_backorder_series_serial_1(self): """ Create a MO of 4 tracked products (serial) with pbm_sam. all component is tracked by serial Produce one by one with one bakorder for each until end. """ nb_product_todo = 4 production, _, p_final, p1, p2 = self.generate_mo(qty_final=nb_product_todo, tracking_final='serial', tracking_base_1='serial', tracking_base_2='serial', qty_base_1=1) serials_final, serials_p1, serials_p2 = [], [], [] for i in range(nb_product_todo): serials_final.append(self.env['stock.production.lot'].create({ 'name': f'lot_final_{i}', 'product_id': p_final.id, 'company_id': self.env.company.id, })) serials_p1.append(self.env['stock.production.lot'].create({ 'name': f'lot_consumed_1_{i}', 'product_id': p1.id, 'company_id': self.env.company.id, })) serials_p2.append(self.env['stock.production.lot'].create({ 'name': f'lot_consumed_2_{i}', 'product_id': p2.id, 'company_id': self.env.company.id, })) self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 1, lot_id=serials_p1[-1]) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 1, lot_id=serials_p2[-1]) production.action_assign() active_production = production for i in range(nb_product_todo): details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p1), view=self.env.ref('stock.view_stock_move_operations')) with details_operation_form.move_line_ids.edit(0) as ml: ml.qty_done = 1 ml.lot_id = serials_p1[i] details_operation_form.save() details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p2), view=self.env.ref('stock.view_stock_move_operations')) with details_operation_form.move_line_ids.edit(0) as ml: ml.qty_done = 1 ml.lot_id = serials_p2[i] details_operation_form.save() production_form = Form(active_production) production_form.qty_producing = 1 production_form.lot_producing_id = serials_final[i] active_production = production_form.save() active_production.button_mark_done() if i + 1 != nb_product_todo: # If last MO, don't make a backorder action = active_production.button_mark_done() backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) backorder.save().action_backorder() active_production = active_production.procurement_group_id.mrp_production_ids[-1] self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), nb_product_todo, f'You should have the {nb_product_todo} final product in stock') self.assertEqual(len(production.procurement_group_id.mrp_production_ids), nb_product_todo)
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 and MO for its components are automatically created. """ # Tick "manufacture" and MTO on self.comp2 mto_route = self.env.ref('stock.route_warehouse0_mto') mto_route.active = True 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 = 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.assertEqual(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.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_message_qty_already_received(self): _product = self.env['product.product'].create({ 'name': 'TempProduct', 'type': 'consu', 'company_id': self.env.user.company_id.id, }) _purchase_order = self.env['purchase.order'].create({ 'company_id': self.env.user.company_id.id, 'partner_id': self.partner_a.id, 'order_line': [(0, 0, { 'name': _product.name, 'product_id': _product.id, 'product_qty': 25.0, 'price_unit': 250.0, })], }) _purchase_order.button_confirm() first_picking = _purchase_order.picking_ids[0] first_picking.move_lines.quantity_done = 5 backorder_wizard_dict = first_picking.button_validate() backorder_wizard = Form( self.env[backorder_wizard_dict['res_model']].with_context( backorder_wizard_dict['context'])).save() backorder_wizard.process() second_picking = _purchase_order.picking_ids[1] second_picking.move_lines.quantity_done = 5 backorder_wizard_dict = second_picking.button_validate() backorder_wizard = Form( self.env[backorder_wizard_dict['res_model']].with_context( backorder_wizard_dict['context'])).save() backorder_wizard.process() third_picking = _purchase_order.picking_ids[2] third_picking.move_lines.quantity_done = 5 backorder_wizard_dict = third_picking.button_validate() backorder_wizard = Form( self.env[backorder_wizard_dict['res_model']].with_context( backorder_wizard_dict['context'])).save() backorder_wizard.process() _message_content = _purchase_order.message_ids.mapped("body")[0] self.assertIsNotNone( re.search(r"Received Quantity: 5.0 -> 10.0", _message_content), "Already received quantity isn't correctly taken into consideration" )
def test_backorder_and_orderpoint(self): """ Same as test_no_tracking_2, except one of components also has an orderpoint (i.e. reordering rule) and not enough components are in stock (i.e. so orderpoint is triggered).""" production, _, product_to_build, product_to_use_1, product_to_use_2 = self.generate_mo(qty_final=4, qty_base_1=1) # Make some stock and reserve for product in production.move_raw_ids.product_id: self.env['stock.quant'].with_context(inventory_mode=True).create({ 'product_id': product.id, 'inventory_quantity': 1, 'location_id': production.location_src_id.id, }) production.action_assign() self.env['stock.warehouse.orderpoint'].create({ 'name': 'product_to_use_1 RR', 'location_id': production.location_src_id.id, 'product_id': product_to_use_1.id, 'product_min_qty': 1, 'product_max_qty': 5, }) self.env['mrp.bom'].create({ 'product_id': product_to_use_1.id, 'product_tmpl_id': product_to_use_1.product_tmpl_id.id, 'product_uom_id': product_to_use_1.uom_id.id, 'product_qty': 1.0, 'type': 'normal', 'consumption': 'flexible', 'bom_line_ids': [ (0, 0, {'product_id': product_to_use_2.id, 'product_qty': 1.0}) ]}) product_to_use_1.write({'route_ids': [(4, self.ref('mrp.route_warehouse0_manufacture'))]}) mo_form = Form(production) mo_form.qty_producing = 1 production = mo_form.save() action = production.button_mark_done() backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) backorder.save().action_backorder() # Two related MO, orig + backorder, in same the procurement group mos = self.env['mrp.production'].search([ ('product_id', '=', product_to_build.id), ]) self.assertEqual(len(mos), 2, "Backorder was not created.") self.assertEqual(len(production.procurement_group_id.mrp_production_ids), 2, "MO backorder not linked to original MO") # Orderpoint MO is NOT part of procurement group mo_orderpoint = self.env['mrp.production'].search([ ('product_id', '=', product_to_use_1.id), ]) self.assertEqual(len(mo_orderpoint.procurement_group_id.mrp_production_ids), 1, "Reordering rule MO incorrectly linked to other MOs")
def setUp(self): super(TestMultistepManufacturing, self).setUp() self.env.ref('stock.route_warehouse0_mto').active = True 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['res.partner'].create( {'name': 'My Test Partner'}) 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 test_vendor_bill_flow_anglo_saxon_2(self): """In anglo saxon accounting, receive 10@10 and invoice with the addition of 1@50 as a landed costs and create a linked landed costs record. """ self.env.company.anglo_saxon_accounting = True # Create an RFQ for self.product1, 10@10 rfq = Form(self.env['purchase.order']) rfq.partner_id = self.vendor1 with rfq.order_line.new() as po_line: po_line.product_id = self.product1 po_line.product_qty = 10 po_line.price_unit = 10 po_line.taxes_id.clear() rfq = rfq.save() rfq.button_confirm() # Process the receipt receipt = rfq.picking_ids wiz = receipt.button_validate() wiz = Form(self.env['stock.immediate.transfer'].with_context(wiz['context'])).save() wiz.process() self.assertEqual(rfq.order_line.qty_received, 10) input_aml = self._get_stock_input_move_lines()[-1] self.assertEqual(input_aml.debit, 0) self.assertEqual(input_aml.credit, 100) valuation_aml = self._get_stock_valuation_move_lines()[-1] self.assertEqual(valuation_aml.debit, 100) self.assertEqual(valuation_aml.credit, 0) # Create a vendor bill for the RFQ and add to it the landed cost vb = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) vb.partner_id = self.vendor1 vb.invoice_date = vb.date with vb.invoice_line_ids.new() as inv_line: inv_line.product_id = self.productlc1 inv_line.price_unit = 50 inv_line.is_landed_costs_line = True vb = vb.save() vb.action_post() action = vb.button_create_landed_costs() lc = Form(self.env[action['res_model']].browse(action['res_id'])) lc.picking_ids.add(receipt) lc = lc.save() lc.button_validate() # Check reconciliation of input aml of lc lc_input_aml = lc.account_move_id.line_ids.filtered(lambda aml: aml.account_id == self.company_data['default_account_stock_in']) self.assertTrue(len(lc_input_aml.full_reconcile_id), 1)
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_screw.standard_price = 0.1 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.mrp_bom_desk.copy() bom.operation_ids = False 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 = 1 production_table = production_table_form.save() production_table.extra_cost = 20 production_table.action_confirm() mo_form = Form(production_table) mo_form.qty_producing = 1 production_table = mo_form.save() 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_edit_warehouse_1(self): wh = Form(self.env['stock.warehouse']) wh.name = "Chicago" wh.code = "chic" warehouse = wh.save() self.assertEqual(warehouse.int_type_id.barcode, 'CHIC-INTERNAL') self.assertEqual(warehouse.int_type_id.sequence_id.prefix, 'chic/INT/') wh = Form(warehouse) wh.code = 'CH' wh.save() self.assertEqual(warehouse.int_type_id.barcode, 'CH-INTERNAL') self.assertEqual(warehouse.int_type_id.sequence_id.prefix, 'CH/INT/')
def test_cancel_multilevel_manufacturing(self): """ Testing for multilevel Manufacturing orders. When user creates multi-level manufacturing orders, and then cancelles child manufacturing order, an activity should be generated on parent MO, to notify user that demands from child MO has been cancelled. """ product_form = Form(self.env['product.product']) product_form.name = 'Screw' self.product_screw = product_form.save() # Add routes for manufacturing and make to order to the raw material product with Form(self.product_raw) as p1: p1.route_ids.clear() p1.route_ids.add(self.warehouse_1.manufacture_pull_id.route_id) p1.route_ids.add(self.warehouse_1.mto_pull_id.route_id) # New BoM for raw material product, it will generate another Production order i.e. child Production order bom_product_form = Form(self.env['mrp.bom']) bom_product_form.product_id = self.product_raw bom_product_form.product_tmpl_id = self.product_raw.product_tmpl_id bom_product_form.product_qty = 1.0 with bom_product_form.bom_line_ids.new() as bom_line: bom_line.product_id = self.product_screw bom_line.product_qty = 5.0 self.bom_prod_manu = bom_product_form.save() # create MO from sale order. self.sale_order.action_confirm() # Find child MO. child_manufaturing = self.env['mrp.production'].search([ ('product_id', '=', self.product_raw.id) ]) self.assertTrue( (len(child_manufaturing.ids) == 1), 'Manufacturing order of raw material must be generated.') # Cancel child MO. child_manufaturing.action_cancel() manufaturing_from_so = self.env['mrp.production'].search([ ('product_id', '=', self.product_manu.id) ]) # Check if activity is generated or not on parent MO. exception = self.env['mail.activity'].search([ ('res_model', '=', 'mrp.production'), ('res_id', '=', manufaturing_from_so.id) ]) self.assertEqual( len(exception.ids), 1, 'When user cancelled child manufacturing, exception must be generated on parent manufacturing.' )
def test_change_product(self): """ Create a production order for a specific product with a BoM. Then change the BoM and the finished product for other ones and check the finished product of the first mo did not became a byproduct of the second one.""" # Create BOM for product A with product B as component 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_b.id, 'product_uom_id': self.uom_unit_id, 'product_qty': 2 })], }) bom_product_a_2 = 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 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 = 1.0 mnf_product_a = mnf_product_a_form.save() mnf_product_a_form = Form(mnf_product_a) mnf_product_a_form.bom_id = bom_product_a_2 mnf_product_a = mnf_product_a_form.save() self.assertEqual(mnf_product_a.move_raw_ids.product_id.id, self.product_c_id) self.assertFalse(mnf_product_a.move_byproduct_ids)
def test_00_procurement_exception(self): res_partner_2 = self.env['res.partner'].create({'name': 'My Test Partner'}) res_partner_address = self.env['res.partner'].create({ 'name': 'My Test Partner Address', 'parent_id': res_partner_2.id, }) # I create a product with no supplier define for it. product_form = Form(self.env['product.product']) product_form.name = 'product with no seller' product_form.lst_price = 20.00 product_form.categ_id = self.env.ref('product.product_category_1') product_with_no_seller = product_form.save() product_with_no_seller.standard_price = 70.0 # I create a sales order with this product with route dropship. so_form = Form(self.env['sale.order']) so_form.partner_id = res_partner_2 so_form.partner_invoice_id = res_partner_address so_form.partner_shipping_id = res_partner_address so_form.payment_term_id = self.env.ref('account.account_payment_term_end_following_month') with so_form.order_line.new() as line: line.product_id = product_with_no_seller line.product_uom_qty = 3 line.route_id = self.env.ref('stock_dropshipping.route_drop_shipping') sale_order_route_dropship01 = so_form.save() # I confirm the sales order, but it will raise an error with self.assertRaises(Exception): sale_order_route_dropship01.action_confirm() # I set the at least one supplier on the product. with Form(product_with_no_seller) as f: with f.seller_ids.new() as seller: seller.delay = 1 seller.name = res_partner_2 seller.min_qty = 2.0 # I confirm the sales order, no error this time sale_order_route_dropship01.action_confirm() # I check a purchase quotation was created. purchase = self.env['purchase.order.line'].search([ ('sale_line_id', '=', sale_order_route_dropship01.order_line.ids[0])]).order_id self.assertTrue(purchase, 'No Purchase Quotation is created')
def test_bom_report_dozens(self): """ Simulate a drawer bom with dozens as bom units """ uom_dozen = self.env.ref('uom.product_uom_dozen') uom_unit = self.env.ref('uom.product_uom_unit') drawer = self.env['product.product'].create({ 'name': 'drawer', 'type': 'product', 'uom_id': uom_unit.id, 'uom_po_id': uom_unit.id, }) screw = self.env['product.product'].create({ 'name': 'screw', 'type': 'product', 'uom_id': uom_unit.id, 'uom_po_id': uom_unit.id, 'standard_price': 7.01 }) bom_form_drawer = Form(self.env['mrp.bom']) bom_form_drawer.product_tmpl_id = drawer.product_tmpl_id bom_form_drawer.product_qty = 11 bom_form_drawer.product_uom_id = uom_dozen bom_drawer = bom_form_drawer.save() workcenter = self.env['mrp.workcenter'].create({ 'costs_hour': 10, 'name': 'Deserts Table' }) with Form(bom_drawer) as bom: with bom.bom_line_ids.new() as line: line.product_id = screw line.product_uom_id = uom_unit line.product_qty = 5 with bom.operation_ids.new() as operation: operation.workcenter_id = workcenter operation.name = 'Screw drawer' operation.time_cycle_manual = 5 # TEST BOM STRUCTURE VALUE WITH BOM QUANTITY report_values = self.env[ 'report.mrp.report_bom_structure']._get_report_data( bom_id=bom_drawer.id, searchQty=11, searchVariant=False) # 5 min 'Prepare biscuits' + 3 min 'Prepare butter' + 5 min 'Mix manually' = 13 minutes self.assertEqual( report_values['lines']['operations_time'], 660.0, 'Operation time should be the same for 1 unit or for the batch')
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_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.assertEqual(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.active = True 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()