def test_survey_invite(self): Answer = self.env['survey.user_input'] deadline = fields.Datetime.now() + relativedelta(months=1) self.survey.write({'access_mode': 'public'}) action = self.survey.action_send_survey() invite_form = Form(self.env[action['res_model']].with_context(action['context'])) # some lowlevel checks that action is correctly configured self.assertEqual(Answer.search([('survey_id', '=', self.survey.id)]), self.env['survey.user_input']) self.assertEqual(invite_form.survey_id, self.survey) invite_form.partner_ids.add(self.customer) invite_form.deadline = fields.Datetime.to_string(deadline) invite = invite_form.save() invite.action_invite() answers = Answer.search([('survey_id', '=', self.survey.id)]) self.assertEqual(len(answers), 1) self.assertEqual( set(answers.mapped('email')), set([self.customer.email])) self.assertEqual(answers.mapped('partner_id'), self.customer) self.assertEqual(set(answers.mapped('deadline')), set([deadline]))
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) self.assertFalse(picking_receipt.display_view_subcontracted_move_lines) # 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, 'to_close') self.assertEqual(len(mo.picking_ids.move_lines), 2) # 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') # Now that the picking is done, the details stat button should be visible self.assertTrue(picking_receipt.display_view_subcontracted_move_lines) # 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_supplier, allow_negative=True) avail_qty_comp2 = self.env['stock.quant']._get_available_quantity(self.comp2, self.subcontractor_partner1.property_stock_supplier, 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_rounding(self): """ In previous versions we had rounding and efficiency fields. We check if we can still do the same, but with only the rounding on the UoM""" self.product_6.uom_id.rounding = 1.0 bom_eff = self.env['mrp.bom'].create({'product_id': self.product_6.id, 'product_tmpl_id': self.product_6.product_tmpl_id.id, 'product_qty': 1, 'product_uom_id': self.product_6.uom_id.id, 'type': 'normal', 'bom_line_ids': [ (0, 0, {'product_id': self.product_2.id, 'product_qty': 2.03}), (0, 0, {'product_id': self.product_8.id, 'product_qty': 4.16}) ]}) production = self.env['mrp.production'].create({'name': 'MO efficiency test', 'product_id': self.product_6.id, 'product_qty': 20, 'bom_id': bom_eff.id, 'product_uom_id': self.product_6.uom_id.id,}) #Check the production order has the right quantities self.assertEqual(production.move_raw_ids[0].product_qty, 41, 'The quantity should be rounded up') self.assertEqual(production.move_raw_ids[1].product_qty, 84, 'The quantity should be rounded up') # produce product produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': production.id, 'active_ids': [production.id], })) produce_form.product_qty = 8 produce_wizard = produce_form.save() produce_wizard.do_produce() self.assertEqual(production.move_raw_ids[0].quantity_done, 16, 'Should use half-up rounding when producing') self.assertEqual(production.move_raw_ids[1].quantity_done, 34, 'Should use half-up rounding when producing')
def test_dropship_standard_perpetual_anglosaxon_ordered_return(self): self.env.user.company_id.anglo_saxon_accounting = True self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard' self.product1.product_tmpl_id.standard_price = 10 self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time' self.product1.product_tmpl_id.invoice_policy = 'order' all_amls = self._dropship_product1() # return what we've done stock_return_picking_form = Form(self.env['stock.return.picking'] .with_context(active_ids=self.sale_order1.picking_ids.ids, active_id=self.sale_order1.picking_ids.ids[0], active_model='stock.picking')) stock_return_picking = stock_return_picking_form.save() stock_return_picking_action = stock_return_picking.create_returns() return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id']) return_pick.move_lines[0].move_line_ids[0].qty_done = 1.0 return_pick.action_done() self.assertEqual(return_pick.move_lines._is_dropshipped_returned(), True) all_amls_return = self.vendor_bill1.move_id.line_ids + self.customer_invoice1.move_id.line_ids if self.sale_order1.picking_ids.mapped('move_lines.account_move_ids'): all_amls_return |= self.sale_order1.picking_ids.mapped('move_lines.account_move_ids.line_ids') # Two extra AML should have been created for the return expected_aml = { self.acc_stock_in: (10.0, 0.0), self.acc_stock_out: (0.0, 10.0), } self._check_results(expected_aml, 2, all_amls_return - all_amls)
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() 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_survey_invite_authentication_nosignup(self): Answer = self.env['survey.user_input'] self.survey.write({'access_mode': 'authentication'}) action = self.survey.action_send_survey() invite_form = Form(self.env[action['res_model']].with_context(action['context'])) with self.assertRaises(UserError): # do not allow to add customer (partner without user) invite_form.partner_ids.add(self.customer) invite_form.partner_ids.clear() invite_form.partner_ids.add(self.user_portal.partner_id) invite_form.partner_ids.add(self.user_emp.partner_id) with self.assertRaises(UserError): invite_form.emails = '[email protected], Raoulette Vignolette <*****@*****.**>' invite_form.emails = False invite = invite_form.save() invite.action_invite() answers = Answer.search([('survey_id', '=', self.survey.id)]) self.assertEqual(len(answers), 2) self.assertEqual( set(answers.mapped('email')), set([self.user_emp.email, self.user_portal.email])) self.assertEqual(answers.mapped('partner_id'), self.user_emp.partner_id | self.user_portal.partner_id)
def test_procurement_2(self): """Check that a manufacturing order create the right procurements when the route are set on a parent category of a product""" # find a child category id all_categ_id = self.env['product.category'].search([('parent_id', '=', None)], limit=1) child_categ_id = self.env['product.category'].search([('parent_id', '=', all_categ_id.id)], limit=1) # set the product of `self.bom_1` to this child category for bom_line_id in self.bom_1.bom_line_ids: # check that no routes are defined on the product self.assertEquals(len(bom_line_id.product_id.route_ids), 0) # set the category of the product to a child category bom_line_id.product_id.categ_id = child_categ_id # set the MTO route to the parent category (all) self.warehouse = self.env.ref('stock.warehouse0') mto_route = self.warehouse.mto_pull_id.route_id mto_route.product_categ_selectable = True all_categ_id.write({'route_ids': [(6, 0, [mto_route.id])]}) # create MO, but check it raises error as components are in make to order and not everyone has with self.assertRaises(UserError): production_form = Form(self.env['mrp.production']) production_form.product_id = self.product_4 production_form.product_uom_id = self.product_4.uom_id production_form.product_qty = 1 production_product_4 = production_form.save() production_product_4.action_confirm()
def test_product_produce_6(self): """ Build some final products and change the quantity to produce directly in the wizard. The component line should be updated . """ self.stock_location = self.env.ref('stock.stock_location_stock') mo, bom, p_final, p1, p2 = self.generate_mo(qty_final=1) self.assertEqual(len(mo), 1, 'MO should have been created') mo.action_assign() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.qty_producing = 3 self.assertEqual(len(produce_form.workorder_line_ids._records), 4, 'Update the produce quantity should change the components quantity.') self.assertEqual(sum([x['qty_done'] for x in produce_form.workorder_line_ids._records]), 15, 'Update the produce quantity should change the components quantity.') produce_form.qty_producing = 4 self.assertEqual(len(produce_form.workorder_line_ids._records), 6, 'Update the produce quantity should change the components quantity.') self.assertEqual(sum([x['qty_done'] for x in produce_form.workorder_line_ids._records]), 20, 'Update the produce quantity should change the components quantity.') produce_form.qty_producing = 1 self.assertEqual(len(produce_form.workorder_line_ids._records), 2, 'Update the produce quantity should change the components quantity.') self.assertEqual(sum([x['qty_done'] for x in produce_form.workorder_line_ids._records]), 5, 'Update the produce quantity should change the components quantity.') produce_wizard = produce_form.save() produce_wizard.do_produce()
def test_product_produce_1(self): """ Checks the production wizard contains lines even for untracked products. """ self.stock_location = self.env.ref('stock.stock_location_stock') mo, bom, p_final, p1, p2 = self.generate_mo() self.assertEqual(len(mo), 1, 'MO should have been created') self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 100) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 5) mo.action_assign() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) # change the quantity done in one line produce_form.workorder_line_ids._records[0]['qty_done'] = 1 # change the quantity producing produce_form.qty_producing = 3 # check than all quantities are update correctly line1 = produce_form.workorder_line_ids._records[0] line2 = produce_form.workorder_line_ids._records[1] self.assertEqual(line1['qty_to_consume'], 3, "Wrong quantity to consume") self.assertEqual(line1['qty_done'], 3, "Wrong quantity done") self.assertEqual(line2['qty_to_consume'], 12, "Wrong quantity to consume") self.assertEqual(line2['qty_done'], 12, "Wrong quantity done") product_produce = produce_form.save() self.assertEqual(len(product_produce.workorder_line_ids), 2, 'You should have produce lines even the consumed products are not tracked.') product_produce.do_produce()
def test_product_produce_9(self): """ Checks the constraints of a strict BOM without tracking when playing around in the produce wizard. """ self.stock_location = self.env.ref('stock.stock_location_stock') mo, bom, p_final, p1, p2 = self.generate_mo() self.assertEqual(len(mo), 1, 'MO should have been created') self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 100) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 5) mo.action_assign() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) with self.assertRaises(UserError): # try adding another line for a bom product to increase the quantity produce_form.qty_producing = 1 with produce_form.raw_workorder_line_ids.new() as line: line.product_id = p1 line.qty_done = 1 product_produce = produce_form.save() product_produce.do_produce() with self.assertRaises(UserError): # Try updating qty_done product_produce = produce_form.save() product_produce.raw_workorder_line_ids[0].qty_done += 1 product_produce.do_produce() with self.assertRaises(UserError): # try adding another product produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.qty_producing = 1 with produce_form.raw_workorder_line_ids.new() as line: line.product_id = self.product_4 line.qty_done = 1 product_produce = produce_form.save() product_produce.do_produce() # try adding another line for a bom product but the total quantity is good produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.qty_producing = 1 with produce_form.raw_workorder_line_ids.new() as line: line.product_id = p1 line.qty_done = 1 product_produce = produce_form.save() product_produce.raw_workorder_line_ids[1].qty_done -= 1 product_produce.do_produce()
def test_empty_routing(self): """ Check what happens when you work with an empty routing""" routing = self.env['mrp.routing'].create({'name': 'Routing without operations'}) self.bom_3.routing_id = routing.id production_form = Form(self.env['mrp.production']) production_form.product_id = self.product_6 production = production_form.save() self.assertEqual(production.routing_id.id, False, 'The routing field should be empty on the mo')
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 """ # 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) self.assertFalse(picking_receipt.display_view_subcontracted_move_lines) # 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') # Now that the picking is done, the details stat button should be visible self.assertTrue(picking_receipt.display_view_subcontracted_move_lines) # 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_supplier, allow_negative=True) avail_qty_comp2 = self.env['stock.quant']._get_available_quantity(self.comp2, self.subcontractor_partner1.property_stock_supplier, 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_00_dropship(self): # Create a vendor supplier_dropship = self.env['res.partner'].create({'name': 'Vendor of Dropshipping test'}) # Create new product without any routes drop_shop_product = self.env['product.product'].create({ 'name': "Pen drive", 'type': "product", 'categ_id': self.env.ref('product.product_category_1').id, 'lst_price': 100.0, 'standard_price': 0.0, 'uom_id': self.env.ref('uom.product_uom_unit').id, 'uom_po_id': self.env.ref('uom.product_uom_unit').id, 'seller_ids': [(0, 0, { 'delay': 1, 'name': supplier_dropship.id, 'min_qty': 2.0 })] }) # Create a sales order with a line of 200 PCE incoming shipment, with route_id drop shipping so_form = Form(self.env['sale.order']) so_form.partner_id = self.env.ref('base.res_partner_2') so_form.payment_term_id = self.env.ref('account.account_payment_term') with mute_logger('odoo.tests.common.onchange'): # otherwise complains that there's not enough inventory and # apparently that's normal according to @jco and @sle with so_form.order_line.new() as line: line.product_id = drop_shop_product line.product_uom_qty = 200 line.price_unit = 1.00 line.route_id = self.env.ref('stock_dropshipping.route_drop_shipping') sale_order_drp_shpng = so_form.save() # Confirm sales order sale_order_drp_shpng.action_confirm() # Check the sales order created a procurement group which has a procurement of 200 pieces self.assertTrue(sale_order_drp_shpng.procurement_group_id, 'SO should have procurement group') # Check a quotation was created to a certain vendor and confirm so it becomes a confirmed purchase order purchase = self.env['purchase.order'].search([('partner_id', '=', supplier_dropship.id)]) self.assertTrue(purchase, "an RFQ should have been created by the scheduler") purchase.button_confirm() self.assertEquals(purchase.state, 'purchase', 'Purchase order should be in the approved state') self.assertEquals(len(purchase.ids), 1, 'There should be one picking') # Send the 200 pieces purchase.picking_ids.move_lines.quantity_done = purchase.picking_ids.move_lines.product_qty purchase.picking_ids.button_validate() # Check one move line was created in Customers location with 200 pieces move_line = self.env['stock.move.line'].search([ ('location_dest_id', '=', self.env.ref('stock.stock_location_customers').id), ('product_id', '=', drop_shop_product.id)]) self.assertEquals(len(move_line.ids), 1, 'There should be exactly one move line')
def new_mo_laptop(self): form = Form(self.env['mrp.production']) form.product_id = self.laptop form.product_qty = 1 form.bom_id = self.bom_laptop p = form.save() p.action_confirm() p.action_assign() return p
def test_03b_test_serial_number_defaults(self): """ Check the constraint on the workorder final_lot. The first workorder produces 2/2 units without serial number (serial is only required when you register a component) then the second workorder try to register a serial number. It should be allowed since the first workorder did not specify a seiral number. """ bom = self.env.ref('mrp.mrp_bom_laptop_cust_rout') product = bom.product_tmpl_id.product_variant_id product.tracking = 'serial' lot_1 = self.env['stock.production.lot'].create({ 'product_id': product.id, 'name': 'LOT000001' }) lot_2 = self.env['stock.production.lot'].create({ 'product_id': product.id, 'name': 'LOT000002' }) self.env['stock.production.lot'].create({ 'product_id': product.id, 'name': 'LOT000003' }) mo_form = Form(self.env['mrp.production']) mo_form.product_id = product mo_form.bom_id = bom mo_form.product_qty = 2.0 mo = mo_form.save() mo.action_confirm() mo.button_plan() workorder_0 = mo.workorder_ids[0] workorder_0.record_production() workorder_0.record_production() with self.assertRaises(UserError): workorder_0.record_production() workorder_1 = mo.workorder_ids[1] with Form(workorder_1) as wo: wo.finished_lot_id = lot_1 workorder_1.record_production() self.assertTrue(len(workorder_1.allowed_lots_domain) > 1) with Form(workorder_1) as wo: wo.finished_lot_id = lot_2 workorder_1.record_production() workorder_2 = mo.workorder_ids[2] self.assertEqual(workorder_2.allowed_lots_domain, lot_1 | lot_2) self.assertEqual(workorder_0.finished_workorder_line_ids.qty_done, 2) self.assertFalse(workorder_0.finished_workorder_line_ids.lot_id) self.assertEqual(sum(workorder_1.finished_workorder_line_ids.mapped('qty_done')), 2) self.assertEqual(workorder_1.finished_workorder_line_ids.mapped('lot_id'), lot_1 | lot_2)
def test_00_purchase_order_report(self): uom_dozen = self.env.ref('uom.product_uom_dozen') eur_currency = self.env.ref('base.EUR') self.company_id.currency_id = self.env.ref('base.USD').id self.env['res.currency.rate'].search([]).unlink() self.env['res.currency.rate'].create({ 'name': datetime.today(), 'rate': 2.0, 'currency_id': eur_currency.id, }) po = self.env['purchase.order'].create({ 'partner_id': self.partner_id.id, 'currency_id': eur_currency.id, 'order_line': [ (0, 0, { 'name': self.product1.name, 'product_id': self.product1.id, 'product_qty': 1.0, 'product_uom': uom_dozen.id, 'price_unit': 100.0, 'date_planned': datetime.today(), }), (0, 0, { 'name': self.product2.name, 'product_id': self.product2.id, 'product_qty': 1.0, 'product_uom': uom_dozen.id, 'price_unit': 200.0, 'date_planned': datetime.today(), }), ], }) po.button_confirm() f = Form(self.env['account.invoice']) f.partner_id = po.partner_id f.purchase_id = po invoice = f.save() invoice.action_invoice_open() res_product1 = self.PurchaseReport.search([ ('order_id', '=', po.id), ('product_id', '=', self.product1.id)]) # check that report will convert dozen to unit or not self.assertEquals(res_product1.qty_ordered, 12.0, 'UoM conversion is not working') # report should show in company currency (amount/rate) = (100/2) self.assertEquals(res_product1.price_total, 50.0, 'Currency conversion is not working') res_product2 = self.PurchaseReport.search([ ('order_id', '=', po.id), ('product_id', '=', self.product2.id)]) # Check that repost should show 6 unit of product self.assertEquals(res_product2.qty_ordered, 12.0, 'UoM conversion is not working') # report should show in company currency (amount/rate) = (200/2) self.assertEquals(res_product2.price_total, 100.0, 'Currency conversion is not working')
def test_employee_resource(self): _tz = 'Pacific/Apia' self.res_users_hr_officer.company_id.resource_calendar_id.tz = _tz Employee = self.env['hr.employee'].sudo(self.res_users_hr_officer) employee_form = Form(Employee) employee_form.name = 'Raoul Grosbedon' employee_form.work_email = '*****@*****.**' employee = employee_form.save() self.assertEqual(employee.tz, _tz)
def test_invoice_shipment(self): """ Tests the case into which we make the invoice first, and then send the goods to our customer. """ test_product = self.test_product_delivery #since the invoice come first, the COGS will use the standard price on product self.test_product_delivery.standard_price = 13 self._set_initial_stock_for_product(test_product) sale_order = self._create_sale(test_product, '2018-01-01') invoice = self._create_invoice_for_so(sale_order, test_product, '2018-02-03') self.env['res.currency.rate'].create({ 'currency_id': self.currency_one.id, 'company_id': self.company.id, 'rate': 0.974784, 'name': '2018-02-01', }) invoice.action_invoice_open() self._process_pickings(sale_order.picking_ids) picking = self.env['stock.picking'].search([('sale_id', '=', sale_order.id)]) self.check_reconciliation(invoice, picking, operation='sale') #return the goods and refund the invoice self.env['res.currency.rate'].create({ 'currency_id': self.currency_one.id, 'company_id': self.company.id, 'rate': 10.54739702, 'name': '2018-03-01', }) stock_return_picking_form = Form(self.env['stock.return.picking'] .with_context(active_ids=picking.ids, active_id=picking.ids[0], active_model='stock.picking')) stock_return_picking = stock_return_picking_form.save() stock_return_picking.product_return_moves.quantity = 1.0 stock_return_picking_action = stock_return_picking.create_returns() return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id']) return_pick.action_assign() return_pick.move_lines.quantity_done = 1 return_pick.action_done() self.env['res.currency.rate'].create({ 'currency_id': self.currency_one.id, 'company_id': self.company.id, 'rate': 9.56564564, 'name': '2018-04-01', }) refund_invoice_wiz = self.env['account.invoice.refund'].with_context(active_ids=[invoice.id]).create({ 'description': 'test_invoice_shipment_refund', 'filter_refund': 'cancel', }) refund_invoice_wiz.invoice_refund() refund_invoice = self.env['account.invoice'].search([('name', '=', 'test_invoice_shipment_refund')])[0] self.assertTrue(invoice.state == refund_invoice.state == 'paid'), "Invoice and refund should both be in 'Paid' state" self.check_reconciliation(refund_invoice, return_pick, operation='sale')
def test_unbuild_with_duplicate_move(self): """ This test creates a MO from 3 different lot on a consumed product (p2). The unbuild order should revert the correct quantity for each specific lot. """ mo, bom, p_final, p1, p2 = self.generate_mo(tracking_final='none', tracking_base_2='lot', tracking_base_1='none') self.assertEqual(len(mo), 1, 'MO should have been created') lot_1 = self.env['stock.production.lot'].create({ 'name': 'lot_1', 'product_id': p2.id, }) lot_2 = self.env['stock.production.lot'].create({ 'name': 'lot_2', 'product_id': p2.id, }) lot_3 = self.env['stock.production.lot'].create({ 'name': 'lot_3', 'product_id': p2.id, }) self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 100) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 1, lot_id=lot_1) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 3, lot_id=lot_2) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 2, lot_id=lot_3) mo.action_assign() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.qty_producing = 5.0 produce_wizard = produce_form.save() produce_wizard.do_produce() mo.button_mark_done() self.assertEqual(mo.state, 'done', "Production order should be in done state.") # Check quantity in stock before unbuild. self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 5, 'You should have the 5 final product in stock') self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location), 80, 'You should have 80 products in stock') self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location, lot_id=lot_1), 0, 'You should have consumed all the 1 product for lot 1 in stock') self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location, lot_id=lot_2), 0, 'You should have consumed all the 3 product for lot 2 in stock') self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location, lot_id=lot_3), 1, 'You should have consumed only 1 product for lot3 in stock') self.env['mrp.unbuild'].create({ 'product_id': p_final.id, 'bom_id': bom.id, 'product_qty': 5.0, 'mo_id': mo.id, 'product_uom_id': self.uom_unit.id, }).action_unbuild() self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 0, 'You should have no more final product in stock after unbuild') self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location), 100, 'You should have 80 products in stock') self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location, lot_id=lot_1), 1, 'You should have get your product with lot 1 in stock') self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location, lot_id=lot_2), 3, 'You should have the 3 basic product for lot 2 in stock') self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location, lot_id=lot_3), 2, 'You should have get one product back for lot 3')
def test_01_sale_mrp_delivery_kit(self): """ Test delivered quantity on SO based on delivered quantity in pickings.""" # intial so product = self.env.ref('mrp.product_product_table_kit') product.type = 'consu' product.invoice_policy = 'delivery' # Remove the MTO route as purchase is not installed and since the procurement removal the exception is directly raised product.write({'route_ids': [(6, 0, [self.warehouse.manufacture_pull_id.route_id.id])]}) partner = self.env.ref('base.res_partner_1') # if `delivery` module is installed, a default property is set for the carrier to use # However this will lead to an extra line on the SO (the delivery line), which will force # the SO to have a different flow (and `invoice_state` value) partner.property_delivery_carrier_id = False f = Form(self.env['sale.order']) f.partner_id = partner with f.order_line.new() as line: line.product_id = product line.product_uom_qty = 5 so = f.save() # confirm our standard so, check the picking so.action_confirm() self.assertTrue(so.picking_ids, 'Sale MRP: no picking created for "invoice on delivery" storable products') # invoice in on delivery, nothing should be invoiced with self.assertRaises(UserError): so.action_invoice_create() self.assertEqual(so.invoice_status, 'no', 'Sale MRP: so invoice_status should be "nothing to invoice" after invoicing') # deliver partially (1 of each instead of 5), check the so's invoice_status and delivered quantities pick = so.picking_ids pick.move_lines.write({'quantity_done': 1}) wiz_act = pick.button_validate() wiz = self.env[wiz_act['res_model']].browse(wiz_act['res_id']) wiz.process() self.assertEqual(so.invoice_status, 'no', 'Sale MRP: so invoice_status should be "no" after partial delivery of a kit') del_qty = sum(sol.qty_delivered for sol in so.order_line) self.assertEqual(del_qty, 0.0, 'Sale MRP: delivered quantity should be zero after partial delivery of a kit') # deliver remaining products, check the so's invoice_status and delivered quantities self.assertEqual(len(so.picking_ids), 2, 'Sale MRP: number of pickings should be 2') pick_2 = so.picking_ids[0] for move in pick_2.move_lines: if move.product_id.id == self.env.ref('mrp.product_product_computer_desk_bolt').id: move.write({'quantity_done': 19}) else: move.write({'quantity_done': 4}) pick_2.button_validate() del_qty = sum(sol.qty_delivered for sol in so.order_line) self.assertEqual(del_qty, 5.0, 'Sale MRP: delivered quantity should be 5.0 after complete delivery of a kit') self.assertEqual(so.invoice_status, 'to invoice', 'Sale MRP: so invoice_status should be "to invoice" after complete delivery of a kit')
def test_empty_routing(self): """ Check what happens when you work with an empty routing""" routing = self.env['mrp.routing'].create({'name': 'Routing without operations', 'location_id': self.warehouse_1.wh_input_stock_loc_id.id,}) self.bom_3.routing_id = routing.id production_form = Form(self.env['mrp.production']) production_form.product_id = self.product_6 production_form.product_qty = 3 production_form.product_uom_id = self.product_6.uom_id production = production_form.save() self.assertEqual(production.routing_id.id, False, 'The routing field should be empty on the mo') self.assertEqual(production.move_raw_ids[0].location_id.id, self.warehouse_1.wh_input_stock_loc_id.id, 'Raw moves start location should have altered.')
def test_03_test_serial_number_defaults(self): """ Test that the correct serial number is suggested on consecutive work orders. """ laptop = self.env.ref("product.product_product_25") graphics_card = self.env.ref("product.product_product_24") unit = self.env.ref("uom.product_uom_unit") three_step_routing = self.env.ref("mrp.mrp_routing_1") laptop.tracking = 'serial' bom_laptop = self.env['mrp.bom'].create({ 'product_tmpl_id': laptop.product_tmpl_id.id, 'product_qty': 1, 'product_uom_id': unit.id, 'bom_line_ids': [(0, 0, { 'product_id': graphics_card.id, 'product_qty': 1, 'product_uom_id': unit.id })], 'routing_id': three_step_routing.id }) mo_laptop_form = Form(self.env['mrp.production']) mo_laptop_form.product_id = laptop mo_laptop_form.bom_id = bom_laptop mo_laptop_form.product_qty = 3 mo_laptop = mo_laptop_form.save() mo_laptop.action_confirm() mo_laptop.button_plan() workorders = mo_laptop.workorder_ids self.assertEqual(len(workorders), 3) workorders[0].button_start() serial_a = self.env['stock.production.lot'].create({'product_id': laptop.id}) workorders[0].final_lot_id = serial_a workorders[0].record_production() serial_b = self.env['stock.production.lot'].create({'product_id': laptop.id}) workorders[0].final_lot_id = serial_b workorders[0].record_production() serial_c = self.env['stock.production.lot'].create({'product_id': laptop.id}) workorders[0].final_lot_id = serial_c workorders[0].record_production() self.assertEqual(workorders[0].state, 'done') for workorder in workorders - workorders[0]: self.assertEqual(workorder.final_lot_id, serial_a) workorder.record_production() self.assertEqual(workorder.final_lot_id, serial_b) workorder.record_production() self.assertEqual(workorder.final_lot_id, serial_c) workorder.record_production() self.assertEqual(workorder.state, 'done')
def test_shipping_cost(self): # Free delivery should not be taken into account when checking for minimum required threshold p_minimum_threshold_free_delivery = self.env['sale.coupon.program'].create({ 'name': 'free shipping if > 872 tax exl', 'promo_code_usage': 'no_code_needed', 'reward_type': 'free_shipping', 'program_type': 'promotion_program', 'rule_minimum_amount': 872, }) p_minimum_threshold_discount = self.env['sale.coupon.program'].create({ 'name': '10% reduction if > 872 tax exl', 'promo_code_usage': 'no_code_needed', 'reward_type': 'discount', 'program_type': 'promotion_program', 'discount_type': 'percentage', 'discount_percentage': 10.0, 'rule_minimum_amount': 872, }) order = self.empty_order self.iPadMini.taxes_id = self.tax_10pc_incl sol1 = self.env['sale.order.line'].create({ 'product_id': self.iPadMini.id, 'name': 'Large Cabinet', 'product_uom_qty': 3.0, 'order_id': order.id, }) order.recompute_coupon_lines() self.assertEqual(len(order.order_line.ids), 2, "We should get the 10% discount line since we bought 872.73$") order.carrier_id = self.env['delivery.carrier'].search([])[1] # I add delivery cost in Sales order delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({ 'default_order_id': order.id, 'default_carrier_id': self.env['delivery.carrier'].search([])[1] })) choose_delivery_carrier = delivery_wizard.save() choose_delivery_carrier.button_confirm() order.recompute_coupon_lines() self.assertEqual(len(order.order_line.ids), 3, "We should get the delivery line but not the free delivery since we are below 872.73$ with the 10% discount") p_minimum_threshold_free_delivery.sequence = 10 (order.order_line - sol1).unlink() # I add delivery cost in Sales order delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({ 'default_order_id': order.id, 'default_carrier_id': self.env['delivery.carrier'].search([])[1] })) choose_delivery_carrier = delivery_wizard.save() choose_delivery_carrier.button_confirm() order.recompute_coupon_lines() self.assertEqual(len(order.order_line.ids), 4, "We should get both promotion line since the free delivery will be applied first and won't change the SO total")
def create_account_invoice(self, invoice_type, partner, product, quantity=0.0, price_unit=0.0): """ Create an invoice as in a view by triggering its onchange methods""" invoice_form = Form(self.env['account.invoice'].with_context(type=invoice_type)) invoice_form.partner_id = partner with invoice_form.invoice_line_ids.new() as line: line.product_id = product line.quantity = quantity line.price_unit = price_unit invoice = invoice_form.save() invoice.action_invoice_open() return invoice
def test_product_produce_2(self): """ Checks that, for a BOM where one of the components is tracked by serial number and the other is not tracked, when creating a manufacturing order for two finished products and reserving, the produce wizards proposes the corrects lines when producing one at a time. """ self.stock_location = self.env.ref('stock.stock_location_stock') mo, bom, p_final, p1, p2 = self.generate_mo(tracking_base_1='serial', qty_base_1=1, qty_final=2) self.assertEqual(len(mo), 1, 'MO should have been created') lot_p1_1 = self.env['stock.production.lot'].create({ 'name': 'lot1', 'product_id': p1.id, }) lot_p1_2 = self.env['stock.production.lot'].create({ 'name': 'lot2', 'product_id': p1.id, }) self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 1, lot_id=lot_p1_1) self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 1, lot_id=lot_p1_2) self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 5) mo.action_assign() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) self.assertEqual(len(produce_form.workorder_line_ids), 3, 'You should have 3 produce lines. One for each serial to consume and for the untracked product.') produce_form.qty_producing = 1 # get the proposed lot consumed_lots = self.env['stock.production.lot'] for workorder_line in produce_form.workorder_line_ids._records: if workorder_line['product_id'] == p1.id: consumed_lots |= self.env['stock.production.lot'].browse(workorder_line['lot_id']) consumed_lots.ensure_one() product_produce = produce_form.save() product_produce.do_produce() remaining_lot = (lot_p1_1 | lot_p1_2) - consumed_lots remaining_lot.ensure_one() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) product_produce = produce_form.save() self.assertEqual(len(product_produce.workorder_line_ids), 2, 'You should have 2 produce lines left.') for line in product_produce.workorder_line_ids.filtered(lambda x: x.lot_id): self.assertEqual(line.lot_id, remaining_lot, 'Wrong lot proposed.')
def test_employee_from_user(self): _tz = 'Pacific/Apia' _tz2 = 'America/Tijuana' self.res_users_hr_officer.company_id.resource_calendar_id.tz = _tz self.res_users_hr_officer.tz = _tz2 Employee = self.env['hr.employee'].sudo(self.res_users_hr_officer) employee_form = Form(Employee) employee_form.name = 'Raoul Grosbedon' employee_form.work_email = '*****@*****.**' employee_form.user_id = self.res_users_hr_officer employee = employee_form.save() self.assertEqual(employee.name, 'Raoul Grosbedon') self.assertEqual(employee.work_email, self.res_users_hr_officer.email) self.assertEqual(employee.tz, self.res_users_hr_officer.tz)
def test_product_produce_uom_2(self): """ Create a bom with a serial tracked component and a pair UoM (2 x unit). The produce wizard should create 2 line with quantity = 1 and UoM = unit for this component. """ unit = self.env.ref("uom.product_uom_unit") categ_unit_id = self.env.ref('uom.product_uom_categ_unit') paire = self.env['uom.uom'].create({ 'name': 'Paire', 'factor_inv': 2, 'uom_type': 'bigger', 'rounding': 0.001, 'category_id': categ_unit_id.id }) binocular = self.env['product.product'].create({ 'name': 'Binocular', 'type': 'product', 'uom_id': unit.id, 'uom_po_id': unit.id }) nocular = self.env['product.product'].create({ 'name': 'Nocular', 'type': 'product', 'tracking': 'serial', 'uom_id': unit.id, 'uom_po_id': unit.id }) bom_binocular = self.env['mrp.bom'].create({ 'product_tmpl_id': binocular.product_tmpl_id.id, 'product_qty': 1, 'product_uom_id': unit.id, 'bom_line_ids': [(0, 0, { 'product_id': nocular.id, 'product_qty': 1, 'product_uom_id': paire.id })] }) mo_form = Form(self.env['mrp.production']) mo_form.product_id = binocular mo_form.bom_id = bom_binocular mo_form.product_uom_id = unit mo_form.product_qty = 1 mo = mo_form.save() mo.action_confirm() self.assertEqual(mo.move_raw_ids.product_uom_qty, 1, 'Quantity should be 1.') self.assertEqual(mo.move_raw_ids.product_uom, paire, 'Move UoM should be "Paire".') # produce product produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) product_produce = produce_form.save() self.assertEqual(product_produce.qty_producing, 1) self.assertEqual(len(product_produce.workorder_line_ids), 2, 'Should be 2 lines since the component tracking is serial and quantity 2.') self.assertEqual(product_produce.workorder_line_ids[0].qty_to_consume, 1, 'Should be 1 unit since the tracking is serial and quantity 2.') self.assertEqual(product_produce.workorder_line_ids[0].product_uom_id, unit, 'Should be the product uom so "unit"') self.assertEqual(product_produce.workorder_line_ids[1].qty_to_consume, 1, 'Should be 1 unit since the tracking is serial and quantity 2.') self.assertEqual(product_produce.workorder_line_ids[1].product_uom_id, unit, 'should be the product uom so "unit"')
def test_anglosaxon_valuation(self): self.env.user.company_id.anglo_saxon_accounting = True self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo' self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time' self.product1.product_tmpl_id.invoice_policy = 'delivery' price_diff_account = self.env['account.account'].create({ 'name': 'price diff account', 'code': 'price diff account', 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, }) self.product1.property_account_creditor_price_difference = price_diff_account # Create PO po_form = Form(self.env['purchase.order']) po_form.partner_id = self.partner_id with po_form.order_line.new() as po_line: po_line.product_id = self.product1 po_line.product_qty = 1 po_line.price_unit = 10.0 order = po_form.save() order.button_confirm() # Receive the goods receipt = order.picking_ids[0] receipt.move_lines.quantity_done = 1 receipt.button_validate() # Create an invoice with a different price invoice = self.env['account.invoice'].create({ 'partner_id': order.partner_id.id, 'purchase_id': order.id, 'account_id': order.partner_id.property_account_payable_id.id, 'type': 'in_invoice', }) invoice.purchase_order_change() invoice.invoice_line_ids[0].price_unit = 15.0 invoice.action_invoice_open() # Check what was posted in the price difference account price_diff_aml = self.env['account.move.line'].search([('account_id','=',price_diff_account.id)]) self.assertEquals(len(price_diff_aml), 1, "Only one line should have been generated in the price difference account.") self.assertAlmostEquals(price_diff_aml.debit, 5, "Price difference should be equal to 5 (15-10)") # Check what was posted in stock input account input_aml = self.env['account.move.line'].search([('account_id','=',self.stock_input_account.id)]) self.assertEquals(len(input_aml), 2, "Only two lines should have been generated in stock input account: one when receiving the product, one when making the invoice.") self.assertAlmostEquals(sum(input_aml.mapped('debit')), 10, "Total debit value on stock input account should be equal to the original PO price of the product.") self.assertAlmostEquals(sum(input_aml.mapped('credit')), 10, "Total credit value on stock input account should be equal to the original PO price of the product.")
def test_partner_4(self): """ Create a new partner, select a parent company, and choose type subcontractor (debug not active). Checks the customer and supplier locations are set to the subcontracting one onces saved. """ that_company = self.env['res.partner'].create({ 'is_company': True, 'name': "That Company", }) partner_form = Form(self.env['res.partner']) partner_form.name = 'That Guy' partner_form.parent_id = that_company partner_form.type = 'subcontractor' subcontractor = partner_form.save() self.assertEquals(subcontractor.property_stock_supplier, self.env.user.company_id.subcontracting_location_id) self.assertEquals(subcontractor.property_stock_customer, self.env.user.company_id.subcontracting_location_id)
def test_planning_4(self): """ Plan a manufacturing orders with 1 workorder on 1 workcenter the workcenter calendar is empty. which means the workcenter is never available. Planning a workorder on it should raise an error""" self.workcenter_1.alternative_workcenter_ids = self.wc_alt_1 | self.wc_alt_2 self.env['resource.calendar'].search([]).write({'attendance_ids': [(5, False, False)]}) mo_form = Form(self.env['mrp.production']) mo_form.product_id = self.product_4 mo_form.bom_id = self.planning_bom mo_form.product_qty = 1 mo = mo_form.save() mo.action_confirm() with self.assertRaises(UserError): mo.button_plan()
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_03_po_return_and_modify(self): """Change the picking code of the delivery to internal. Make a PO for 10 units, go to the picking and return 5, edit the PO line to 15 units. The purpose of the test is to check the consistencies across the received quantities and the procurement quantities. """ # Change the code of the picking type delivery self.env['stock.picking.type'].search([('code', '=', 'outgoing') ]).write({'code': 'internal'}) # Sell and deliver 10 units item1 = self.product_id_1 uom_unit = self.env.ref('uom.product_uom_unit') po1 = self.env['purchase.order'].create({ 'partner_id': self.partner_a.id, 'order_line': [ (0, 0, { 'name': item1.name, 'product_id': item1.id, 'product_qty': 10, 'product_uom': uom_unit.id, 'price_unit': 123.0, 'date_planned': datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT), }), ], }) po1.button_confirm() picking = po1.picking_ids wiz_act = picking.button_validate() wiz = Form(self.env[wiz_act['res_model']].with_context( wiz_act['context'])).save() wiz.process() # Return 5 units stock_return_picking_form = Form( self.env['stock.return.picking'].with_context( active_ids=picking.ids, active_id=picking.ids[0], active_model='stock.picking')) return_wiz = stock_return_picking_form.save() for return_move in return_wiz.product_return_moves: return_move.write({'quantity': 5, 'to_refund': True}) res = return_wiz.create_returns() return_pick = self.env['stock.picking'].browse(res['res_id']) wiz_act = return_pick.button_validate() wiz = Form(self.env[wiz_act['res_model']].with_context( wiz_act['context'])).save() wiz.process() self.assertEqual(po1.order_line.qty_received, 5) # Deliver 15 instead of 10. po1.write( {'order_line': [ (1, po1.order_line[0].id, { 'product_qty': 15 }), ]}) # A new move of 10 unit (15 - 5 units) self.assertEqual(po1.order_line.qty_received, 5) self.assertEqual(po1.picking_ids[-1].move_lines.product_qty, 10)
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_manufacturing_complex_product_3_steps(self): """ Test MO/picking after manufacturing a complex product which uses manufactured components. Ensure that everything is created and picked correctly. """ # Create manifactured product which uses another manifactured product_form = Form(self.env['product.product']) product_form.name = 'Arrow' product_form.type = 'product' product_form.route_ids.clear() product_form.route_ids.add(self.warehouse.manufacture_pull_id.route_id) product_form.route_ids.add(self.warehouse.mto_pull_id.route_id) self.complex_product = product_form.save() ## Create raw product for manufactured product product_form = Form(self.env['product.product']) product_form.name = 'Raw Iron' product_form.type = 'product' product_form.uom_id = self.uom_unit product_form.uom_po_id = self.uom_unit self.raw_product_2 = product_form.save() ## Create bom for manufactured product bom_product_form = Form(self.env['mrp.bom']) bom_product_form.product_id = self.complex_product bom_product_form.product_tmpl_id = self.complex_product.product_tmpl_id with bom_product_form.bom_line_ids.new() as line: line.product_id = self.finished_product line.product_qty = 1.0 with bom_product_form.bom_line_ids.new() as line: line.product_id = self.raw_product_2 line.product_qty = 1.0 self.complex_bom = bom_product_form.save() with Form(self.warehouse) as warehouse: warehouse.manufacture_steps = 'pbm_sam' production_form = Form(self.env['mrp.production']) production_form.product_id = self.complex_product production_form.picking_type_id = self.warehouse.manu_type_id production = production_form.save() move_raw_ids = production.move_raw_ids self.assertEqual(len(move_raw_ids), 2) sfp_move_raw_id, raw_move_raw_id = move_raw_ids self.assertEqual(sfp_move_raw_id.product_id, self.finished_product) self.assertEqual(raw_move_raw_id.product_id, self.raw_product_2) for move_raw_id in move_raw_ids: self.assertEqual(move_raw_id.picking_type_id, self.warehouse.manu_type_id) pbm_move = move_raw_id.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) move_finished_ids = production.move_finished_ids self.assertEqual(len(move_finished_ids), 1) self.assertEqual(move_finished_ids.product_id, self.complex_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) pickings = production.picking_ids.sorted('id', reverse=True) self.assertEqual(len(pickings), 3) # Picking: SFP PostProcessing -> Stock ## Stick from Subprocess picking = pickings[1] self.assertEqual(len(picking.move_lines), 1) picking.product_id = self.finished_product # Picking: PC Stock -> Preprocessing ## Stick ## Raw Iron picking = pickings[0] self.assertEqual(len(picking.move_lines), 2) picking.move_lines[0].product_id = self.finished_product picking.move_lines[1].product_id = self.raw_product_2 # Picking: SFP PostProcessing -> Stock ## Arrow from this process picking = pickings[2] self.assertEqual(len(picking.move_lines), 1) picking.product_id = self.complex_product
def test_sale(self): so = Form(self.env["sale.order"]) so.partner_id = self.partner_a with so.order_line.new() as so_line: so_line.product_id = self.product_a so_line.product_uom_qty = 100 with so.order_line.new() as so_line: so_line.product_id = self.product_b so_line.product_uom_qty = 10 self.so = so.save() self.so.action_confirm() wizard = Form(self.env["sale.advance.payment.inv"].with_context(active_ids=self.so.ids)) wizard.advance_payment_method = "percentage" wizard.amount = "50" wizard = wizard.save() wizard.create_invoices()
def setUp(self): super(TestMultistepManufacturingWarehouse, self).setUp() # Create warehouse self.customer_location = self.env['ir.model.data'].xmlid_to_res_id( 'stock.stock_location_customers') warehouse_form = Form(self.env['stock.warehouse']) warehouse_form.name = 'Test Warehouse' warehouse_form.code = 'TWH' self.warehouse = warehouse_form.save() self.uom_unit = self.env.ref('uom.product_uom_unit') # Create manufactured product product_form = Form(self.env['product.product']) product_form.name = 'Stick' product_form.uom_id = self.uom_unit product_form.uom_po_id = self.uom_unit product_form.type = 'product' product_form.route_ids.clear() product_form.route_ids.add(self.warehouse.manufacture_pull_id.route_id) product_form.route_ids.add(self.warehouse.mto_pull_id.route_id) self.finished_product = product_form.save() # Create raw product for manufactured product product_form = Form(self.env['product.product']) product_form.name = 'Raw Stick' product_form.type = 'product' product_form.uom_id = self.uom_unit product_form.uom_po_id = self.uom_unit self.raw_product = product_form.save() # Create bom for manufactured product bom_product_form = Form(self.env['mrp.bom']) bom_product_form.product_id = self.finished_product bom_product_form.product_tmpl_id = self.finished_product.product_tmpl_id bom_product_form.product_qty = 1.0 bom_product_form.type = 'normal' with bom_product_form.bom_line_ids.new() as bom_line: bom_line.product_id = self.raw_product bom_line.product_qty = 2.0 self.bom = bom_product_form.save()
def test_manufacturing_flow(self): """ Simulate a pick pack ship delivery combined with a picking before manufacturing and store after manufacturing. Also ensure that the MO and the moves to stock are created with the generic pull rules. In order to trigger the rule we create a picking to the customer with the 'make to order' procure method """ with Form(self.warehouse) as warehouse: warehouse.manufacture_steps = 'pbm_sam' warehouse.delivery_steps = 'pick_pack_ship' self.warehouse.flush() self.env['stock.quant']._update_available_quantity( self.raw_product, self.warehouse.lot_stock_id, 4.0) picking_customer = self.env['stock.picking'].create({ 'location_id': self.warehouse.wh_output_stock_loc_id.id, 'location_dest_id': self.customer_location, 'partner_id': self.env['ir.model.data'].xmlid_to_res_id('base.res_partner_4'), 'picking_type_id': self.warehouse.out_type_id.id, }) self.env['stock.move'].create({ 'name': self.finished_product.name, 'product_id': self.finished_product.id, 'product_uom_qty': 2, 'product_uom': self.uom_unit.id, 'picking_id': picking_customer.id, 'location_id': self.warehouse.wh_output_stock_loc_id.id, 'location_dest_id': self.customer_location, 'procure_method': 'make_to_order', 'state': 'draft', }) picking_customer.action_confirm() production_order = self.env['mrp.production'].search([ ('product_id', '=', self.finished_product.id) ]) self.assertTrue(production_order) picking_stock_preprod = self.env['stock.move'].search([ ('product_id', '=', self.raw_product.id), ('location_id', '=', self.warehouse.lot_stock_id.id), ('location_dest_id', '=', self.warehouse.pbm_loc_id.id), ('picking_type_id', '=', self.warehouse.pbm_type_id.id) ]).picking_id picking_stock_postprod = self.env['stock.move'].search([ ('product_id', '=', self.finished_product.id), ('location_id', '=', self.warehouse.sam_loc_id.id), ('location_dest_id', '=', self.warehouse.lot_stock_id.id), ('picking_type_id', '=', self.warehouse.sam_type_id.id) ]).picking_id self.assertTrue(picking_stock_preprod) self.assertTrue(picking_stock_postprod) self.assertEqual(picking_stock_preprod.state, 'confirmed') self.assertEqual(picking_stock_postprod.state, 'waiting') picking_stock_preprod.action_assign() picking_stock_preprod.move_line_ids.qty_done = 4 picking_stock_preprod._action_done() self.assertFalse( sum(self.env['stock.quant']._gather( self.raw_product, self.warehouse.lot_stock_id).mapped('quantity'))) self.assertTrue(self.env['stock.quant']._gather( self.raw_product, self.warehouse.pbm_loc_id)) production_order.action_assign() self.assertEqual(production_order.reservation_state, 'assigned') self.assertEqual(picking_stock_postprod.state, 'waiting') produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': production_order.id, 'active_ids': [production_order.id], })) produce_form.qty_producing = production_order.product_qty product_produce = produce_form.save() product_produce.do_produce() production_order.button_mark_done() self.assertFalse( sum(self.env['stock.quant']._gather( self.raw_product, self.warehouse.pbm_loc_id).mapped('quantity'))) self.assertEqual(picking_stock_postprod.state, 'assigned') picking_stock_pick = self.env['stock.move'].search([ ('product_id', '=', self.finished_product.id), ('location_id', '=', self.warehouse.lot_stock_id.id), ('location_dest_id', '=', self.warehouse.wh_pack_stock_loc_id.id), ('picking_type_id', '=', self.warehouse.pick_type_id.id) ]).picking_id self.assertEqual( picking_stock_pick.move_lines.move_orig_ids.picking_id, picking_stock_postprod)
def test_product_produce_uom_2(self): unit = self.env.ref("uom.product_uom_unit") categ_unit_id = self.env.ref('uom.product_uom_categ_unit') paire = self.env['uom.uom'].create({ 'name': 'Paire', 'factor_inv': 2, 'uom_type': 'bigger', 'rounding': 0.001, 'category_id': categ_unit_id.id }) binocular = self.env['product.product'].create({ 'name': 'Binocular', 'type': 'product', 'uom_id': unit.id, 'uom_po_id': unit.id }) nocular = self.env['product.product'].create({ 'name': 'Nocular', 'type': 'product', 'tracking': 'serial', 'uom_id': unit.id, 'uom_po_id': unit.id }) bom_binocular = self.env['mrp.bom'].create({ 'product_tmpl_id': binocular.product_tmpl_id.id, 'product_qty': 1, 'product_uom_id': unit.id, 'bom_line_ids': [(0, 0, { 'product_id': nocular.id, 'product_qty': 1, 'product_uom_id': paire.id })] }) mo_form = Form(self.env['mrp.production']) mo_form.product_id = binocular mo_form.bom_id = bom_binocular mo_form.product_uom_id = unit mo_form.product_qty = 1 mo = mo_form.save() mo.action_confirm() self.assertEqual(mo.move_raw_ids.product_uom_qty, 1, 'Quantity should be 1.') self.assertEqual(mo.move_raw_ids.product_uom, paire, 'Move UoM should be "Paire".') # produce product produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) product_produce = produce_form.save() self.assertEqual(product_produce.qty_producing, 1) self.assertEqual( len(product_produce.workorder_line_ids), 2, 'Should be 2 lines since the component tracking is serial and quantity 2.' ) self.assertEqual( product_produce.workorder_line_ids[0].qty_to_consume, 1, 'Should be 1 unit since the tracking is serial and quantity 2.') self.assertEqual(product_produce.workorder_line_ids[0].product_uom_id, unit, 'Should be the product uom so "unit"') self.assertEqual( product_produce.workorder_line_ids[1].qty_to_consume, 1, 'Should be 1 unit since the tracking is serial and quantity 2.') self.assertEqual(product_produce.workorder_line_ids[1].product_uom_id, unit, 'should be the product uom so "unit"')
def test_product_produce_uom(self): plastic_laminate = self.env.ref('mrp.product_product_plastic_laminate') bom = self.env.ref('mrp.mrp_bom_plastic_laminate') dozen = self.env.ref('uom.product_uom_dozen') unit = self.env.ref('uom.product_uom_unit') plastic_laminate.tracking = 'serial' mo_form = Form(self.env['mrp.production']) mo_form.product_id = plastic_laminate mo_form.bom_id = bom mo_form.product_uom_id = dozen mo_form.product_qty = 1 mo = mo_form.save() final_product_lot = self.env['stock.production.lot'].create({ 'name': 'lot1', 'product_id': plastic_laminate.id, }) mo.action_confirm() mo.action_assign() self.assertEqual(mo.move_raw_ids.product_qty, 12, '12 units should be reserved.') # produce product produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.final_lot_id = final_product_lot product_produce = produce_form.save() self.assertEqual(product_produce.qty_producing, 1) self.assertEqual(product_produce.product_uom_id, unit, 'Should be 1 unit since the tracking is serial.') product_produce.final_lot_id = final_product_lot.id product_produce.do_produce() move_line_raw = mo.move_raw_ids.mapped('move_line_ids').filtered( lambda m: m.qty_done) self.assertEqual(move_line_raw.qty_done, 1) self.assertEqual(move_line_raw.product_uom_id, unit, 'Should be 1 unit since the tracking is serial.') move_line_finished = mo.move_finished_ids.mapped( 'move_line_ids').filtered(lambda m: m.qty_done) self.assertEqual(move_line_finished.qty_done, 1) self.assertEqual(move_line_finished.product_uom_id, unit, 'Should be 1 unit since the tracking is serial.')
def test_explode_from_order(self): # # bom3 produces 2 Dozen of Doors (p6), aka 24 # To produce 24 Units of Doors (p6) # - 2 Units of Tools (p5) -> need 4 # - 8 Dozen of Sticks (p4) -> need 16 # - 12 Units of Wood (p2) -> need 24 # bom2 produces 1 Unit of Sticks (p4) # To produce 1 Unit of Sticks (p4) # - 2 Dozen of Sticks (p4) -> need 8 # - 3 Dozen of Stones (p3) -> need 12 # Update capacity, start time, stop time, and time efficiency. # ------------------------------------------------------------ self.workcenter_1.write({ 'capacity': 1, 'time_start': 0, 'time_stop': 0, 'time_efficiency': 100 }) # Set manual time cycle 20 and 10. # -------------------------------- self.operation_1.write({'time_cycle_manual': 20}) (self.operation_2 | self.operation_3).write({'time_cycle_manual': 10}) man_order_form = Form(self.env['mrp.production']) man_order_form.product_id = self.product_6 man_order_form.bom_id = self.bom_3 man_order_form.product_qty = 48 man_order_form.product_uom_id = self.product_6.uom_id man_order = man_order_form.save() # reset quantities self.product_1.type = "product" self.env['stock.change.product.qty'].create({ 'product_id': self.product_1.id, 'new_quantity': 0.0, 'location_id': self.warehouse_1.lot_stock_id.id, }).change_product_qty() (self.product_2 | self.product_4).write({ 'tracking': 'none', }) # assign consume material man_order.action_confirm() man_order.action_assign() self.assertEqual(man_order.reservation_state, 'confirmed', "Production order should be in waiting state.") # check consume materials of manufacturing order self.assertEqual(len(man_order.move_raw_ids), 4, "Consume material lines are not generated proper.") product_2_consume_moves = man_order.move_raw_ids.filtered( lambda x: x.product_id == self.product_2) product_3_consume_moves = man_order.move_raw_ids.filtered( lambda x: x.product_id == self.product_3) product_4_consume_moves = man_order.move_raw_ids.filtered( lambda x: x.product_id == self.product_4) product_5_consume_moves = man_order.move_raw_ids.filtered( lambda x: x.product_id == self.product_5) consume_qty_2 = product_2_consume_moves.product_uom_qty self.assertEqual( consume_qty_2, 24.0, "Consume material quantity of Wood should be 24 instead of %s" % str(consume_qty_2)) consume_qty_3 = product_3_consume_moves.product_uom_qty self.assertEqual( consume_qty_3, 12.0, "Consume material quantity of Stone should be 12 instead of %s" % str(consume_qty_3)) self.assertEqual(len(product_4_consume_moves), 2, "Consume move are not generated proper.") for consume_moves in product_4_consume_moves: consume_qty_4 = consume_moves.product_uom_qty self.assertIn( consume_qty_4, [8.0, 16.0], "Consume material quantity of Stick should be 8 or 16 instead of %s" % str(consume_qty_4)) self.assertFalse(product_5_consume_moves, "Move should not create for phantom bom") # create required lots lot_product_2 = self.env['stock.production.lot'].create( {'product_id': self.product_2.id}) lot_product_4 = self.env['stock.production.lot'].create( {'product_id': self.product_4.id}) # refuel stock inventory = self.env['stock.inventory'].create({ 'name': 'Inventory For Product C', 'filter': 'partial', 'line_ids': [(0, 0, { 'product_id': self.product_2.id, 'product_uom_id': self.product_2.uom_id.id, 'product_qty': 30, 'prod_lot_id': lot_product_2.id, 'location_id': self.ref('stock.stock_location_14') }), (0, 0, { 'product_id': self.product_3.id, 'product_uom_id': self.product_3.uom_id.id, 'product_qty': 60, 'location_id': self.ref('stock.stock_location_14') }), (0, 0, { 'product_id': self.product_4.id, 'product_uom_id': self.product_4.uom_id.id, 'product_qty': 60, 'prod_lot_id': lot_product_4.id, 'location_id': self.ref('stock.stock_location_14') })] }) inventory.action_start() inventory.action_validate() # re-assign consume material man_order.action_assign() # Check production order status after assign. self.assertEqual(man_order.reservation_state, 'assigned', "Production order should be in assigned state.") # Plan production order. man_order.button_plan() # check workorders # - main bom: Door: 2 operations # operation 1: Cutting # operation 2: Welding, waiting for the previous one # - kit bom: Stone Tool: 1 operation # operation 1: Gift Wrapping workorders = man_order.workorder_ids kit_wo = man_order.workorder_ids.filtered( lambda wo: wo.operation_id == self.operation_1) door_wo_1 = man_order.workorder_ids.filtered( lambda wo: wo.operation_id == self.operation_2) door_wo_2 = man_order.workorder_ids.filtered( lambda wo: wo.operation_id == self.operation_3) for workorder in workorders: self.assertEqual(workorder.workcenter_id, self.workcenter_1, "Workcenter does not match.") self.assertEqual(kit_wo.state, 'ready', "Workorder should be in ready state.") self.assertEqual(door_wo_1.state, 'ready', "Workorder should be in ready state.") self.assertEqual(door_wo_2.state, 'pending', "Workorder should be in pending state.") self.assertEqual( kit_wo.duration_expected, 80, "Workorder duration should be 80 instead of %s." % str(kit_wo.duration_expected)) self.assertEqual( door_wo_1.duration_expected, 20, "Workorder duration should be 20 instead of %s." % str(door_wo_1.duration_expected)) self.assertEqual( door_wo_2.duration_expected, 20, "Workorder duration should be 20 instead of %s." % str(door_wo_2.duration_expected)) # subbom: kit for stone tools kit_wo.button_start() finished_lot = self.env['stock.production.lot'].create( {'product_id': man_order.product_id.id}) kit_wo.write({'final_lot_id': finished_lot.id, 'qty_producing': 48}) kit_wo.record_production() self.assertEqual(kit_wo.state, 'done', "Workorder should be in done state.") # first operation of main bom finished_lot = self.env['stock.production.lot'].create( {'product_id': man_order.product_id.id}) door_wo_1.write({'final_lot_id': finished_lot.id, 'qty_producing': 48}) door_wo_1.record_production() self.assertEqual(door_wo_1.state, 'done', "Workorder should be in done state.") # second operation of main bom self.assertEqual(door_wo_2.state, 'ready', "Workorder should be in ready state.") door_wo_2.record_production() self.assertEqual(door_wo_2.state, 'done', "Workorder should be in done state.")
def test_rounding(self): """ In previous versions we had rounding and efficiency fields. We check if we can still do the same, but with only the rounding on the UoM""" self.product_6.uom_id.rounding = 1.0 bom_eff = self.env['mrp.bom'].create({ 'product_id': self.product_6.id, 'product_tmpl_id': self.product_6.product_tmpl_id.id, 'product_qty': 1, 'product_uom_id': self.product_6.uom_id.id, 'type': 'normal', 'bom_line_ids': [(0, 0, { 'product_id': self.product_2.id, 'product_qty': 2.03 }), (0, 0, { 'product_id': self.product_8.id, 'product_qty': 4.16 })] }) production_form = Form(self.env['mrp.production']) production_form.product_id = self.product_6 production_form.bom_id = bom_eff production_form.product_qty = 20 production_form.product_uom_id = self.product_6.uom_id production = production_form.save() production.action_confirm() #Check the production order has the right quantities self.assertEqual(production.move_raw_ids[0].product_qty, 41, 'The quantity should be rounded up') self.assertEqual(production.move_raw_ids[1].product_qty, 84, 'The quantity should be rounded up') # produce product produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': production.id, 'active_ids': [production.id], })) produce_form.qty_producing = 8 produce_wizard = produce_form.save() produce_wizard.do_produce() self.assertEqual(production.move_raw_ids[0].quantity_done, 16, 'Should use half-up rounding when producing') self.assertEqual(production.move_raw_ids[1].quantity_done, 34, 'Should use half-up rounding when producing')
def test_no_tracking_pbm_sam_1(self): """Create a MO for 4 product. Produce 1. The backorder button should appear and hitting mark as done should open the backorder wizard. In the backorder wizard, choose to do the backorder. A new MO for 3 self.untracked_bom should be created. The sequence of the first MO should be MO/001-01, the sequence of the second MO should be MO/001-02. Check that all MO are reachable through the procurement group. """ with Form(self.warehouse) as warehouse: warehouse.manufacture_steps = 'pbm_sam' production, _, product_to_build, product_to_use_1, product_to_use_2 = self.generate_mo( qty_base_1=4, qty_final=4, picking_type_id=self.warehouse.manu_type_id) move_raw_ids = production.move_raw_ids self.assertEqual(len(move_raw_ids), 2) self.assertEqual(set(move_raw_ids.mapped("product_id")), {product_to_use_1, product_to_use_2}) pbm_move = move_raw_ids.move_orig_ids self.assertEqual(len(pbm_move), 2) self.assertEqual(set(pbm_move.mapped("product_id")), {product_to_use_1, product_to_use_2}) self.assertFalse(pbm_move.move_orig_ids) self.assertEqual( sum( pbm_move.filtered(lambda m: m.product_id.id == product_to_use_1 .id).mapped("product_qty")), 16) self.assertEqual( sum( pbm_move.filtered(lambda m: m.product_id.id == product_to_use_2 .id).mapped("product_qty")), 4) sam_move = production.move_finished_ids.move_dest_ids self.assertEqual(len(sam_move), 1) self.assertEqual(sam_move.product_id.id, product_to_build.id) self.assertEqual(sum(sam_move.mapped("product_qty")), 4) 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() mo_backorder = production.procurement_group_id.mrp_production_ids[-1] self.assertEqual(mo_backorder.delivery_count, 2) pbm_move |= mo_backorder.move_raw_ids.move_orig_ids self.assertEqual( sum( pbm_move.filtered(lambda m: m.product_id.id == product_to_use_1 .id).mapped("product_qty")), 16) self.assertEqual( sum( pbm_move.filtered(lambda m: m.product_id.id == product_to_use_2 .id).mapped("product_qty")), 4) sam_move |= mo_backorder.move_finished_ids.move_orig_ids self.assertEqual(sum(sam_move.mapped("product_qty")), 4)
def test_multiple_post_inventory(self): """ Check the consumed quants of the produced quants when intermediate calls to `post_inventory` during a MO.""" # create a bom for `custom_laptop` with components that aren't tracked unit = self.ref("uom.product_uom_unit") custom_laptop = self.env.ref("product.product_product_27") custom_laptop.tracking = 'none' product_charger = self.env['product.product'].create({ 'name': 'Charger', 'type': 'product', 'uom_id': unit, 'uom_po_id': unit }) product_keybord = self.env['product.product'].create({ 'name': 'Usb Keybord', 'type': 'product', 'uom_id': unit, 'uom_po_id': unit }) bom_custom_laptop = self.env['mrp.bom'].create({ 'product_tmpl_id': custom_laptop.product_tmpl_id.id, 'product_qty': 1, 'product_uom_id': unit, 'bom_line_ids': [(0, 0, { 'product_id': product_charger.id, 'product_qty': 1, 'product_uom_id': unit }), (0, 0, { 'product_id': product_keybord.id, 'product_qty': 1, 'product_uom_id': unit })] }) # put the needed products in stock source_location_id = self.ref('stock.stock_location_14') inventory = self.env['stock.inventory'].create({ 'name': 'Inventory Product Table', 'filter': 'partial', 'line_ids': [(0, 0, { 'product_id': product_charger.id, 'product_uom_id': product_charger.uom_id.id, 'product_qty': 2, 'location_id': source_location_id }), (0, 0, { 'product_id': product_keybord.id, 'product_uom_id': product_keybord.uom_id.id, 'product_qty': 2, 'location_id': source_location_id })] }) inventory.action_validate() # create a mo for this bom mo_custom_laptop_form = Form(self.env['mrp.production']) mo_custom_laptop_form.product_id = custom_laptop mo_custom_laptop_form.product_qty = 2 mo_custom_laptop = mo_custom_laptop_form.save() mo_custom_laptop.action_confirm() mo_custom_laptop.action_assign() self.assertEqual(mo_custom_laptop.reservation_state, 'assigned') # produce one item, call `post_inventory` context = { "active_ids": [mo_custom_laptop.id], "active_id": mo_custom_laptop.id } produce_form = Form( self.env['mrp.product.produce'].with_context(context)) produce_form.qty_producing = 1.00 custom_laptop_produce = produce_form.save() custom_laptop_produce.do_produce() mo_custom_laptop.post_inventory() # check the consumed quants of the produced quant first_move = mo_custom_laptop.move_finished_ids.filtered( lambda mo: mo.state == 'done') second_move = mo_custom_laptop.move_finished_ids.filtered( lambda mo: mo.state == 'confirmed') # produce the second item, call `post_inventory` context = { "active_ids": [mo_custom_laptop.id], "active_id": mo_custom_laptop.id } produce_form = Form( self.env['mrp.product.produce'].with_context(context)) produce_form.qty_producing = 1.00 custom_laptop_produce = produce_form.save() custom_laptop_produce.do_produce() mo_custom_laptop.post_inventory()
def test_reminder_1(self): """Set to send reminder today, check if a reminder can be send to the partner. """ po = Form(self.env['purchase.order']) po.partner_id = self.partner_a with po.order_line.new() as po_line: po_line.product_id = self.product_a po_line.product_qty = 1 po_line.price_unit = 100 with po.order_line.new() as po_line: po_line.product_id = self.product_b po_line.product_qty = 10 po_line.price_unit = 200 # set to send reminder today po.date_planned = fields.Datetime.now() + timedelta(days=1) po.receipt_reminder_email = True po.reminder_date_before_receipt = 1 po = po.save() po.button_confirm() # check vendor is a message recipient self.assertTrue(po.partner_id in po.message_partner_ids) old_messages = po.message_ids po._send_reminder_mail() messages_send = po.message_ids - old_messages # check reminder send self.assertTrue(messages_send) self.assertTrue(po.partner_id in messages_send.mapped('partner_ids')) # check confirm button po.confirm_reminder_mail() self.assertTrue(po.mail_reminder_confirmed)
def test_flow_tracked_backorder(self): """ This test uses tracked (serial and lot) component and tracked (serial) finished product """ todo_nb = 4 self.comp2.tracking = 'lot' self.finished_product.tracking = 'serial' # 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_product move.product_uom_qty = todo_nb 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.assertEqual(len(mo.picking_ids), 0) wh = picking_receipt.picking_type_id.warehouse_id self.assertEqual(mo.picking_type_id, wh.subcontracting_type_id) self.assertFalse(mo.picking_type_id.active) lot_comp2 = self.env['stock.production.lot'].create({ 'name': 'lot_comp2', 'product_id': self.comp2.id, 'company_id': self.env.company.id, }) serials_finished = [] serials_comp1 = [] for i in range(todo_nb): serials_finished.append(self.env['stock.production.lot'].create({ 'name': 'serial_fin_%s' % i, 'product_id': self.finished_product.id, 'company_id': self.env.company.id, })) serials_comp1.append(self.env['stock.production.lot'].create({ 'name': 'serials_comp1_%s' % i, 'product_id': self.comp1_sn.id, 'company_id': self.env.company.id, })) for i in range(todo_nb): action = picking_receipt.action_record_components() mo = self.env['mrp.production'].browse(action['res_id']) mo_form = Form(mo.with_context(**action['context']), view=action['view_id']) mo_form.lot_producing_id = serials_finished[i] with mo_form.move_line_raw_ids.edit(0) as ml: self.assertEqual(ml.product_id, self.comp1_sn) ml.lot_id = serials_comp1[i] with mo_form.move_line_raw_ids.edit(1) as ml: self.assertEqual(ml.product_id, self.comp2) ml.lot_id = lot_comp2 mo = mo_form.save() mo.subcontracting_record_component() # We should not be able to call the 'record_components' button self.assertFalse(picking_receipt.display_action_record_components) picking_receipt.button_validate() self.assertEqual(mo.state, 'done') self.assertEqual( mo.procurement_group_id.mrp_production_ids.mapped("state"), ['done'] * todo_nb) self.assertEqual(len(mo.procurement_group_id.mrp_production_ids), todo_nb) self.assertEqual( mo.procurement_group_id.mrp_production_ids.mapped("qty_produced"), [1] * todo_nb) # 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_product, wh.lot_stock_id) self.assertEqual(avail_qty_comp1, -todo_nb) self.assertEqual(avail_qty_comp2, -todo_nb) self.assertEqual(avail_qty_finished, todo_nb)
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_product 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.assertEqual(len(mo.picking_ids), 0) wh = picking_receipt.picking_type_id.warehouse_id self.assertEqual(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.assertEqual(picking.picking_type_id, wh.out_type_id) lot_id = self.env['stock.production.lot'].create({ 'name': 'lot1', 'product_id': self.finished_product.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, }) action = picking_receipt.action_record_components() mo = self.env['mrp.production'].browse(action['res_id']) mo_form = Form(mo.with_context(**action['context']), view=action['view_id']) mo_form.qty_producing = 1 mo_form.lot_producing_id = lot_id with mo_form.move_line_raw_ids.edit(0) as ml: ml.lot_id = serial_id mo = mo_form.save() mo.subcontracting_record_component() # We should not be able to call the 'record_components' button self.assertFalse(picking_receipt.display_action_record_components) picking_receipt.button_validate() self.assertEqual(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_product, wh.lot_stock_id) self.assertEqual(avail_qty_comp1, -1) self.assertEqual(avail_qty_comp2, -1) self.assertEqual(avail_qty_finished, 1)
def _dropship_product1(self): # enable the dropship and MTO route on the product dropshipping_route = self.env.ref( 'stock_dropshipping.route_drop_shipping') mto_route = self.env.ref('stock.route_warehouse0_mto') self.product1.write( {'route_ids': [(6, 0, [dropshipping_route.id, mto_route.id])]}) # add a vendor vendor1 = self.env['res.partner'].create({'name': 'vendor1'}) seller1 = self.env['product.supplierinfo'].create({ 'name': vendor1.id, 'price': 8, }) self.product1.write({'seller_ids': [(6, 0, [seller1.id])]}) # sell one unit of this product customer1 = self.env['res.partner'].create({'name': 'customer1'}) self.sale_order1 = self.env['sale.order'].create({ 'partner_id': customer1.id, 'partner_invoice_id': customer1.id, 'partner_shipping_id': customer1.id, 'order_line': [(0, 0, { 'name': self.product1.name, 'product_id': self.product1.id, 'product_uom_qty': 1, 'product_uom': self.product1.uom_id.id, 'price_unit': 12, })], 'pricelist_id': self.env.ref('product.list0').id, 'picking_policy': 'direct', }) self.sale_order1.action_confirm() # confirm the purchase order self.purchase_order1 = self.env['purchase.order'].search([ ('group_id', '=', self.sale_order1.procurement_group_id.id) ]) self.purchase_order1.button_confirm() # validate the dropshipping picking self.assertEqual(len(self.sale_order1.picking_ids), 1) #self.assertEqual(self.sale_order1.picking_ids.move_lines._is_dropshipped(), True) wizard = self.sale_order1.picking_ids.button_validate() immediate_transfer = self.env[wizard['res_model']].browse( wizard['res_id']).with_context(wizard['context']) immediate_transfer.process() self.assertEqual(self.sale_order1.picking_ids.state, 'done') # create the vendor bill move_form = Form( self.env['account.move'].with_context(default_type='in_invoice')) move_form.partner_id = vendor1 move_form.purchase_id = self.purchase_order1 self.vendor_bill1 = move_form.save() self.vendor_bill1.post() # create the customer invoice self.customer_invoice1 = self.sale_order1._create_invoices() self.customer_invoice1.post() all_amls = self.vendor_bill1.line_ids + self.customer_invoice1.line_ids if self.sale_order1.picking_ids.move_lines.account_move_ids: all_amls |= self.sale_order1.picking_ids.move_lines.account_move_ids.line_ids return all_amls
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_01_product_route_level_delays(self): """ In order to check schedule dates, set product's Manufacturing Lead Time and Customer Lead Time and also set warehouse route's delay.""" # Update warehouse_1 with Outgoing Shippings pick + pack + ship self.warehouse_1.write({'delivery_steps': 'pick_pack_ship'}) # Set delay on pull rule for pull_rule in self.warehouse_1.delivery_route_id.rule_ids: pull_rule.write({'delay': 2}) # Create sale order of product_1 order_form = Form(self.env['sale.order']) order_form.partner_id = self.partner_1 order_form.warehouse_id = self.warehouse_1 with order_form.order_line.new() as line: line.product_id = self.product_1 line.product_uom_qty = 6 order = order_form.save() # Confirm sale order order.action_confirm() # Run scheduler self.env['procurement.group'].run_scheduler() # Check manufacturing order created or not manufacturing_order = self.env['mrp.production'].search([ ('product_id', '=', self.product_1.id) ]) self.assertTrue(manufacturing_order, 'Manufacturing order should be created.') # Check the picking crated or not self.assertTrue(order.picking_ids, "Pickings should be created.") # Check schedule date of ship type picking out = order.picking_ids.filtered( lambda r: r.picking_type_id == self.warehouse_1.out_type_id) out_min_date = fields.Datetime.from_string(out.scheduled_date) out_date = fields.Datetime.from_string(order.date_order) + timedelta( days=self.product_1.sale_delay) - timedelta( days=out.move_lines[0].rule_id.delay) self.assertAlmostEqual( out_min_date, out_date, delta=timedelta(seconds=1), msg= 'Schedule date of ship type picking should be equal to: order date + Customer Lead Time - pull rule delay.' ) # Check schedule date of pack type picking pack = order.picking_ids.filtered( lambda r: r.picking_type_id == self.warehouse_1.pack_type_id) pack_min_date = fields.Datetime.from_string(pack.scheduled_date) pack_date = out_date - timedelta(days=pack.move_lines[0].rule_id.delay) self.assertAlmostEqual( pack_min_date, pack_date, delta=timedelta(seconds=1), msg= 'Schedule date of pack type picking should be equal to: Schedule date of ship type picking - pull rule delay.' ) # Check schedule date of pick type picking pick = order.picking_ids.filtered( lambda r: r.picking_type_id == self.warehouse_1.pick_type_id) pick_min_date = fields.Datetime.from_string(pick.scheduled_date) self.assertAlmostEqual( pick_min_date, pack_date, delta=timedelta(seconds=1), msg= 'Schedule date of pick type picking should be equal to: Schedule date of pack type picking.' ) # Check schedule date of manufacturing order mo_date = pack_date - timedelta(days=self.product_1.produce_delay) date_planned_start = fields.Datetime.from_string( manufacturing_order.date_planned_start) self.assertAlmostEqual( date_planned_start, mo_date, delta=timedelta(seconds=1), msg= "Schedule date of manufacturing order should be equal to: Schedule date of pack type picking - product's Manufacturing Lead Time." )
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 test_00_purchase_order_flow(self): # Ensure product_id_2 doesn't have res_partner_1 as supplier if self.partner_a in self.product_id_2.seller_ids.mapped('name'): id_to_remove = self.product_id_2.seller_ids.filtered( lambda r: r.name == self.partner_a ).ids[0] if self.product_id_2.seller_ids.filtered( lambda r: r.name == self.partner_a) else False if id_to_remove: self.product_id_2.write({ 'seller_ids': [(2, id_to_remove, False)], }) self.assertFalse( self.product_id_2.seller_ids.filtered( lambda r: r.name == self.partner_a), 'Purchase: the partner should not be in the list of the product suppliers' ) self.po = self.env['purchase.order'].create(self.po_vals) self.assertTrue(self.po, 'Purchase: no purchase order created') self.assertEqual( self.po.invoice_status, 'no', 'Purchase: PO invoice_status should be "Not purchased"') self.assertEqual(self.po.order_line.mapped('qty_received'), [0.0, 0.0], 'Purchase: no product should be received"') self.assertEqual(self.po.order_line.mapped('qty_invoiced'), [0.0, 0.0], 'Purchase: no product should be invoiced"') self.po.button_confirm() self.assertEqual(self.po.state, 'purchase', 'Purchase: PO state should be "Purchase"') self.assertEqual( self.po.invoice_status, 'to invoice', 'Purchase: PO invoice_status should be "Waiting Invoices"') self.assertTrue( self.product_id_2.seller_ids.filtered( lambda r: r.name == self.partner_a), 'Purchase: the partner should be in the list of the product suppliers' ) seller = self.product_id_2._select_seller( partner_id=self.partner_a, quantity=2.0, date=self.po.date_planned, uom_id=self.product_id_2.uom_po_id) price_unit = seller.price if seller else 0.0 if price_unit and seller and self.po.currency_id and seller.currency_id != self.po.currency_id: price_unit = seller.currency_id._convert(price_unit, self.po.currency_id, self.po.company_id, self.po.date_order) self.assertEqual( price_unit, 250.0, 'Purchase: the price of the product for the supplier should be 250.0.' ) self.assertEqual(self.po.picking_count, 1, 'Purchase: one picking should be created"') self.picking = self.po.picking_ids[0] self.picking.move_line_ids.write({'qty_done': 5.0}) self.picking.button_validate() self.assertEqual(self.po.order_line.mapped('qty_received'), [5.0, 5.0], 'Purchase: all products should be received"') move_form = Form(self.env['account.move'].with_context( default_move_type='in_invoice')) move_form.partner_id = self.partner_a move_form.purchase_id = self.po self.invoice = move_form.save() self.assertEqual(self.po.order_line.mapped('qty_invoiced'), [5.0, 5.0], 'Purchase: all products should be invoiced"')
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_02_po_return(self): """ Test a PO with a product on Incoming shipment. Validate the PO, then do a return of the picking with Refund. """ # Draft purchase order created self.po = self.env['purchase.order'].create(self.po_vals) self.assertTrue(self.po, 'Purchase: no purchase order created') self.assertEqual(self.po.order_line.mapped('qty_received'), [0.0, 0.0], 'Purchase: no product should be received"') self.assertEqual(self.po.order_line.mapped('qty_invoiced'), [0.0, 0.0], 'Purchase: no product should be invoiced"') self.po.button_confirm() self.assertEqual(self.po.state, 'purchase', 'Purchase: PO state should be "Purchase"') self.assertEqual( self.po.invoice_status, 'to invoice', 'Purchase: PO invoice_status should be "Waiting Invoices"') # Confirm the purchase order self.po.button_confirm() self.assertEqual(self.po.state, 'purchase', 'Purchase: PO state should be "Purchase') self.assertEqual(self.po.picking_count, 1, 'Purchase: one picking should be created"') self.picking = self.po.picking_ids[0] self.picking.move_line_ids.write({'qty_done': 5.0}) self.picking.button_validate() self.assertEqual(self.po.order_line.mapped('qty_received'), [5.0, 5.0], 'Purchase: all products should be received"') #After Receiving all products create vendor bill. move_form = Form(self.env['account.move'].with_context( default_move_type='in_invoice')) move_form.partner_id = self.partner_a move_form.purchase_id = self.po self.invoice = move_form.save() self.invoice.action_post() self.assertEqual(self.po.order_line.mapped('qty_invoiced'), [5.0, 5.0], 'Purchase: all products should be invoiced"') # Check quantity received received_qty = sum(pol.qty_received for pol in self.po.order_line) self.assertEqual( received_qty, 10.0, 'Purchase: Received quantity should be 10.0 instead of %s after validating incoming shipment' % received_qty) # Create return picking pick = self.po.picking_ids stock_return_picking_form = Form( self.env['stock.return.picking'].with_context( active_ids=pick.ids, active_id=pick.ids[0], active_model='stock.picking')) return_wiz = stock_return_picking_form.save() return_wiz.product_return_moves.write({ 'quantity': 2.0, 'to_refund': True }) # Return only 2 res = return_wiz.create_returns() return_pick = self.env['stock.picking'].browse(res['res_id']) # Validate picking return_pick.move_line_ids.write({'qty_done': 2}) return_pick.button_validate() # Check Received quantity self.assertEqual( self.po.order_line[0].qty_received, 3.0, 'Purchase: delivered quantity should be 3.0 instead of "%s" after picking return' % self.po.order_line[0].qty_received) #Create vendor bill for refund qty move_form = Form(self.env['account.move'].with_context( default_move_type='in_refund')) move_form.partner_id = self.partner_a move_form.purchase_id = self.po self.invoice = move_form.save() move_form = Form(self.invoice) with move_form.invoice_line_ids.edit(0) as line_form: line_form.quantity = 2.0 with move_form.invoice_line_ids.edit(1) as line_form: line_form.quantity = 2.0 self.invoice = move_form.save() self.invoice.action_post() self.assertEqual(self.po.order_line.mapped('qty_invoiced'), [3.0, 3.0], 'Purchase: Billed quantity should be 3.0')
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.assertEqual(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.assertEqual(picking.picking_type_id, wh.out_type_id) picking_receipt.move_lines.quantity_done = 1 picking_receipt.button_validate() self.assertEqual(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.assertEqual(avail_qty_comp1, -1) self.assertEqual(avail_qty_comp2, -1) self.assertEqual(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)
def test_invoice_after_lc(self): self.env.company.anglo_saxon_accounting = True self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo' self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time' self.price_diff_account = self.env['account.account'].create({ 'name': 'price diff account', 'code': 'price diff account', 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, }) self.product1.property_account_creditor_price_difference = self.price_diff_account # Create PO po_form = Form(self.env['purchase.order']) po_form.partner_id = self.env['res.partner'].create({'name': 'vendor'}) with po_form.order_line.new() as po_line: po_line.product_id = self.product1 po_line.product_qty = 1 po_line.price_unit = 455.0 order = po_form.save() order.button_confirm() # Receive the goods receipt = order.picking_ids[0] receipt.move_lines.quantity_done = 1 receipt.button_validate() # Check SVL and AML svl = self.env['stock.valuation.layer'].search([ ('stock_move_id', '=', receipt.move_lines.id) ]) self.assertAlmostEqual(svl.value, 455) aml = self.env['account.move.line'].search([ ('account_id', '=', self.company_data['default_account_stock_valuation'].id) ]) self.assertAlmostEqual(aml.debit, 455) # Create and validate LC lc = self.env['stock.landed.cost'].create( dict( picking_ids=[(6, 0, [receipt.id])], account_journal_id=self.stock_journal.id, cost_lines=[ (0, 0, { 'name': 'equal split', 'split_method': 'equal', 'price_unit': 99, 'product_id': self.productlc1.id, }), ], )) lc.compute_landed_cost() lc.button_validate() # Check LC, SVL and AML self.assertAlmostEqual(lc.valuation_adjustment_lines.final_cost, 554) svl = self.env['stock.valuation.layer'].search( [('stock_move_id', '=', receipt.move_lines.id)], order='id desc', limit=1) self.assertAlmostEqual(svl.value, 99) aml = self.env['account.move.line'].search( [('account_id', '=', self.company_data['default_account_stock_valuation'].id)], order='id desc', limit=1) self.assertAlmostEqual(aml.debit, 99) # Create an invoice with the same price move_form = Form(self.env['account.move'].with_context( default_move_type='in_invoice')) move_form.partner_id = order.partner_id move_form.purchase_id = order move = move_form.save() move.action_post() # Check nothing was posted in the price difference account price_diff_aml = self.env['account.move.line'].search([ ('account_id', '=', self.price_diff_account.id), ('move_id', '=', move.id) ]) self.assertEqual( len(price_diff_aml), 0, "No line should have been generated in the price difference account." )
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.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)]}) # 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(mo.state, 'confirmed') picking_delivery = mo.picking_ids self.assertEqual(len(picking_delivery), 1) self.assertEqual(len(picking_delivery.move_lines), 2) self.assertEqual(picking_delivery.origin, picking_receipt.name) self.assertEqual(picking_delivery.partner_id, picking_receipt.partner_id) # The picking should be a delivery order wh = picking_receipt.picking_type_id.warehouse_id self.assertEqual(mo.picking_ids.picking_type_id, wh.out_type_id) self.assertEqual(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.assertEqual(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.assertEqual(avail_qty_comp1, -1) self.assertEqual(avail_qty_comp2, -1) self.assertEqual(avail_qty_finished, 1)
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_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.assertEqual(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.assertEqual(picking.picking_type_id, wh.out_type_id) self.assertEqual(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.assertEqual(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.assertEqual(avail_qty_comp1, -1) self.assertEqual(avail_qty_comp2, -1) self.assertEqual(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_product_produce_3(self): """ Check that line are created when the consumed products are tracked by serial and the lot proposed are correct. """ self.stock_location = self.env.ref('stock.stock_location_stock') self.stock_shelf_1 = self.env.ref('stock.stock_location_components') self.stock_shelf_2 = self.env.ref('stock.stock_location_14') mo, _, p_final, p1, p2 = self.generate_mo(tracking_base_1='lot', qty_base_1=10, qty_final=1) self.assertEqual(len(mo), 1, 'MO should have been created') first_lot_for_p1 = self.env['stock.production.lot'].create({ 'name': 'lot1', 'product_id': p1.id, }) second_lot_for_p1 = self.env['stock.production.lot'].create({ 'name': 'lot2', 'product_id': p1.id, }) final_product_lot = self.env['stock.production.lot'].create({ 'name': 'lot1', 'product_id': p_final.id, }) self.env['stock.quant']._update_available_quantity( p1, self.stock_shelf_1, 3, lot_id=first_lot_for_p1) self.env['stock.quant']._update_available_quantity( p1, self.stock_shelf_2, 3, lot_id=first_lot_for_p1) self.env['stock.quant']._update_available_quantity( p1, self.stock_location, 8, lot_id=second_lot_for_p1) self.env['stock.quant']._update_available_quantity( p2, self.stock_location, 5) mo.action_assign() produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': mo.id, 'active_ids': [mo.id], })) produce_form.qty_producing = 1.0 product_produce = produce_form.save() product_produce.final_lot_id = final_product_lot.id # product 1 lot 1 shelf1 # product 1 lot 1 shelf2 # product 1 lot 2 self.assertEqual( len(product_produce.workorder_line_ids), 4, 'You should have 4 produce lines. lot 1 shelf_1, lot 1 shelf_2, lot2 and for product which have tracking None' ) for produce_line in product_produce.workorder_line_ids: produce_line.qty_done = produce_line.qty_to_consume + 1 product_produce.do_produce() move_1 = mo.move_raw_ids.filtered(lambda m: m.product_id == p1) # qty_done/product_uom_qty lot # 3/3 lot 1 shelf 1 # 1/1 lot 1 shelf 2 # 2/2 lot 1 shelf 2 # 2/0 lot 1 other # 5/4 lot 2 ml_to_shelf_1 = move_1.move_line_ids.filtered( lambda ml: ml.lot_id == first_lot_for_p1 and ml.location_id == self .stock_shelf_1) ml_to_shelf_2 = move_1.move_line_ids.filtered( lambda ml: ml.lot_id == first_lot_for_p1 and ml.location_id == self .stock_shelf_2) self.assertEqual(sum(ml_to_shelf_1.mapped('qty_done')), 3.0, '3 units should be took from shelf1 as reserved.') self.assertEqual(sum(ml_to_shelf_2.mapped('qty_done')), 3.0, '3 units should be took from shelf2 as reserved.') self.assertEqual(move_1.quantity_done, 13, 'You should have used the tem units.') mo.button_mark_done() self.assertEqual(mo.state, 'done', "Production order should be in done state.")
def test_basic(self): """ Basic order test: no routing (thus no workorders), no lot """ self.product_1.type = 'product' self.product_2.type = 'product' inventory = self.env['stock.inventory'].create({ 'name': 'Initial inventory', 'filter': 'partial', 'line_ids': [(0, 0, { 'product_id': self.product_1.id, 'product_uom_id': self.product_1.uom_id.id, 'product_qty': 500, 'location_id': self.warehouse_1.lot_stock_id.id }), (0, 0, { 'product_id': self.product_2.id, 'product_uom_id': self.product_2.uom_id.id, 'product_qty': 500, 'location_id': self.warehouse_1.lot_stock_id.id })] }) inventory.action_validate() test_date_planned = Dt.now() - timedelta(days=1) test_quantity = 2.0 self.bom_1.routing_id = False man_order_form = Form(self.env['mrp.production'].sudo( self.user_mrp_user)) man_order_form.product_id = self.product_4 man_order_form.bom_id = self.bom_1 man_order_form.product_uom_id = self.product_4.uom_id man_order_form.product_qty = test_quantity man_order_form.date_planned_start = test_date_planned man_order_form.location_src_id = self.location_1 man_order_form.location_dest_id = self.warehouse_1.wh_output_stock_loc_id man_order = man_order_form.save() self.assertEqual(man_order.state, 'draft', "Production order should be in draft state.") man_order.action_confirm() self.assertEqual(man_order.state, 'confirmed', "Production order should be in confirmed state.") # check production move production_move = man_order.move_finished_ids self.assertEqual(production_move.date, test_date_planned) self.assertEqual(production_move.product_id, self.product_4) self.assertEqual(production_move.product_uom, man_order.product_uom_id) self.assertEqual(production_move.product_qty, man_order.product_qty) self.assertEqual(production_move.location_id, self.product_4.property_stock_production) self.assertEqual(production_move.location_dest_id, man_order.location_dest_id) # check consumption moves for move in man_order.move_raw_ids: self.assertEqual(move.date, test_date_planned) first_move = man_order.move_raw_ids.filtered( lambda move: move.product_id == self.product_2) self.assertEqual( first_move.product_qty, test_quantity / self.bom_1.product_qty * self.product_4.uom_id.factor_inv * 2) first_move = man_order.move_raw_ids.filtered( lambda move: move.product_id == self.product_1) self.assertEqual( first_move.product_qty, test_quantity / self.bom_1.product_qty * self.product_4.uom_id.factor_inv * 4) # waste some material, create a scrap # scrap = self.env['stock.scrap'].with_context( # active_model='mrp.production', active_id=man_order.id # ).create({}) # scrap = self.env['stock.scrap'].create({ # 'production_id': man_order.id, # 'product_id': first_move.product_id.id, # 'product_uom_id': first_move.product_uom.id, # 'scrap_qty': 5.0, # }) # check created scrap # procurements = self.env['procurement.order'].search([('move_dest_id', 'in', man_order.move_raw_ids.ids)]) # print procurements # procurements = self.env['procurement.order'].search([('production_id', '=', man_order.id)]) # print procurements # for proc in self.env['procurement.order'].browse(procurements): # date_planned = self.mrp_production_test1.date_planned # if proc.product_id.type not in ('product', 'consu'): # continue # if proc.product_id.id == order_line.product_id.id: # self.assertEqual(proc.date_planned, date_planned, "Planned date does not correspond") # # procurement state should be `confirmed` at this stage, except if procurement_jit is installed, in which # # case it could already be in `running` or `exception` state (not enough stock) # expected_states = ('confirmed', 'running', 'exception') # self.assertEqual(proc.state in expected_states, 'Procurement state is `%s` for %s, expected one of %s' % (proc.state, proc.product_id.name, expected_states)) # Change production quantity qty_wizard = self.env['change.production.qty'].create({ 'mo_id': man_order.id, 'product_qty': 3.0, }) # qty_wizard.change_prod_qty() # # I check qty after changed in production order. # #self.assertEqual(self.mrp_production_test1.product_qty, 3, "Qty is not changed in order.") # move = self.mrp_production_test1.move_finished_ids[0] # self.assertEqual(move.product_qty, self.mrp_production_test1.product_qty, "Qty is not changed in move line.") # # I run scheduler. # self.env['procurement.order'].run_scheduler() # # The production order is Waiting Goods, will force production which should set consume lines as available # self.mrp_production_test1.button_plan() # # I check that production order in ready state after forcing production. # #self.assertEqual(self.mrp_production_test1.availability, 'assigned', 'Production order availability should be set as available') # produce product produce_form = Form(self.env['mrp.product.produce'].with_context({ 'active_id': man_order.id, 'active_ids': [man_order.id], })) produce_form.qty_producing = 1.0 produce_wizard = produce_form.save() produce_wizard.do_produce() # man_order.button_mark_done() man_order.button_mark_done() self.assertEqual(man_order.state, 'done', "Production order should be in done state.")