In a few words, it allows to send components to a subcontractor partner and receive a finished product. The production is managed through classical manufacturing orders where the raw and finished location is the subcontracting location. When creating a receipt picking for a subcontractor partner, the location_id of the moves will be set to the subcontracting locations by using the property_stock_customer and property_stock_supplier of the partner. An override of _action_confirm will create the manufacturing order. When a subcontracted bom contains tracking, the produce wizard is available from the picking to record which lots were produced/consumed. New type on the BoM: subcontract New type on res.partner: subcontactor New location per company (we still own the components stored at the subcontractor so they're still valued) New routes created to resupply the subcontracting location on order or not (through a reordering rule). Override of res.partner to set the property_stock_customer/supplier on subcontactor partners. Proper tests were added too. Joint work with: Arnaud Baes <arb@odoo.com> task 1831382
526 lines
25 KiB
Python
526 lines
25 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo.tests import Form
|
|
from odoo.tests.common import TransactionCase
|
|
|
|
from odoo.tests import tagged
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestSubcontractingBasic(TransactionCase):
|
|
def test_partner_1(self):
|
|
""" Checks the `display_name` of subcontracted partners. """
|
|
main_partner = self.env['res.partner'].create({'name': 'main_partner'})
|
|
|
|
# When a name is set to the subcontracted partner.
|
|
subcontractor_partner1 = self.env['res.partner'].create({
|
|
'name': 'subcontractor_partner',
|
|
'type': 'subcontractor',
|
|
'parent_id': main_partner.id,
|
|
})
|
|
self.assertEqual(subcontractor_partner1.display_name, "main_partner, subcontractor_partner, Subcontractor")
|
|
|
|
# When a name is not set to the subcontracted partner.
|
|
subcontractor_partner1 = self.env['res.partner'].create({
|
|
'name': '',
|
|
'type': 'subcontractor',
|
|
'parent_id': main_partner.id,
|
|
})
|
|
self.assertEqual(subcontractor_partner1.display_name, "main_partner, Subcontractor")
|
|
|
|
def test_partner_2(self):
|
|
""" Open an existing partner and add a contact of type subcontractor (simple form view).
|
|
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(that_company)
|
|
with partner_form.child_ids.new() as partner:
|
|
partner.name = 'That Guy'
|
|
partner.type = 'subcontractor'
|
|
partner_form.save()
|
|
subcontractor = that_company.child_ids
|
|
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_partner_3(self):
|
|
""" Create a new partner, select a parent company, and choose type subcontractor (debug
|
|
active). Checks the onchange correctly set the customer and supplier locations to the
|
|
subcontracting ones. Change them to another one, save, checks they are rightly applied.
|
|
"""
|
|
# FIXME sle: this field should not be writeable without the debug mode but it is. ask xmo
|
|
group_no_one = self.env.ref('base.group_no_one')
|
|
self.env.user.write({'groups_id': [(3, group_no_one.id)]})
|
|
partner_form = Form(self.env['res.partner'])
|
|
partner_form.name = 'subcontractor partner'
|
|
self.assertNotEqual(partner_form.property_stock_supplier, self.env.user.company_id.subcontracting_location_id)
|
|
self.assertNotEqual(partner_form.property_stock_customer, self.env.user.company_id.subcontracting_location_id)
|
|
partner_form.type = 'subcontractor'
|
|
self.assertEqual(partner_form.property_stock_supplier, self.env.user.company_id.subcontracting_location_id)
|
|
self.assertEqual(partner_form.property_stock_customer, self.env.user.company_id.subcontracting_location_id)
|
|
subcontracting_location2 = self.env.user.company_id.subcontracting_location_id.copy()
|
|
partner_form.property_stock_supplier = subcontracting_location2
|
|
partner_form.property_stock_customer = subcontracting_location2
|
|
partner = partner_form.save()
|
|
self.assertEqual(partner.property_stock_supplier, subcontracting_location2)
|
|
self.assertEqual(partner.property_stock_customer, subcontracting_location2)
|
|
|
|
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_partner_5(self):
|
|
""" Create a new partner with a child partner of type contact,
|
|
then write the type 'subcontractor' on it
|
|
"""
|
|
that_company = self.env['res.partner'].create({
|
|
'is_company': True,
|
|
'name': "That Company",
|
|
})
|
|
partner_form = Form(that_company)
|
|
with partner_form.child_ids.new() as partner:
|
|
partner.name = 'That Guy'
|
|
partner.type = 'contact'
|
|
partner_form.save()
|
|
|
|
# We write a new type on the created child partner
|
|
subcontractor = that_company.child_ids
|
|
self.assertEquals(len(that_company.child_ids), 1)
|
|
subcontractor.type = 'subcontractor'
|
|
|
|
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_subcontracting_location_1(self):
|
|
""" Checks the creation and presence of the subcontracting location. """
|
|
self.assertTrue(self.env.user.company_id.subcontracting_location_id)
|
|
self.assertTrue(self.env.user.company_id.subcontracting_location_id.active)
|
|
company2 = self.env['res.company'].create({'name': 'Test Company'})
|
|
self.assertTrue(company2.subcontracting_location_id)
|
|
|
|
|
|
class TestSubcontractingFlows(TransactionCase):
|
|
def setUp(self):
|
|
super(TestSubcontractingFlows, self).setUp()
|
|
# 1: Create a subcontracting partner
|
|
main_partner = self.env['res.partner'].create({'name': 'main_partner'})
|
|
self.subcontractor_partner1 = self.env['res.partner'].create({
|
|
'name': 'subcontractor_partner',
|
|
'type': 'subcontractor',
|
|
'parent_id': main_partner.id,
|
|
})
|
|
|
|
# 2. Create a BOM of subcontracting type
|
|
self.comp1 = self.env['product.product'].create({
|
|
'name': 'Component1',
|
|
'type': 'product',
|
|
'categ_id': self.env.ref('product.product_category_all').id,
|
|
})
|
|
self.comp2 = self.env['product.product'].create({
|
|
'name': 'Component2',
|
|
'type': 'product',
|
|
'categ_id': self.env.ref('product.product_category_all').id,
|
|
})
|
|
self.finished = self.env['product.product'].create({
|
|
'name': 'finished',
|
|
'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 = self.comp2
|
|
bom_line.product_qty = 1
|
|
self.bom = bom_form.save()
|
|
|
|
# Create a BoM for self.comp2
|
|
self.comp2comp = self.env['product.product'].create({
|
|
'name': 'component for Component2',
|
|
'type': 'product',
|
|
'categ_id': self.env.ref('product.product_category_all').id,
|
|
})
|
|
bom_form = Form(self.env['mrp.bom'])
|
|
bom_form.product_tmpl_id = self.comp2.product_tmpl_id
|
|
with bom_form.bom_line_ids.new() as bom_line:
|
|
bom_line.product_id = self.comp2comp
|
|
bom_line.product_qty = 1
|
|
self.comp2_bom = bom_form.save()
|
|
|
|
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_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.
|
|
"""
|
|
# 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 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)
|
|
|
|
picking = mo.picking_ids
|
|
wh = picking.picking_type_id.warehouse_id
|
|
|
|
# The picking should be a delivery order
|
|
self.assertEquals(picking.picking_type_id, wh.out_type_id)
|
|
|
|
self.assertEquals(mo.picking_type_id, wh.subcontracting_type_id)
|
|
self.assertFalse(mo.picking_type_id.active)
|
|
|
|
# No manufacturing order for `self.comp2`
|
|
comp2mo = self.env['mrp.production'].search([('bom_id', '=', self.comp2_bom.id)])
|
|
self.assertEqual(len(comp2mo), 0)
|
|
|
|
picking_receipt.move_lines.quantity_done = 1
|
|
picking_receipt.button_validate()
|
|
self.assertEquals(mo.state, 'done')
|
|
|
|
# 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_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_flow_4(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',
|
|
'type': 'subcontractor',
|
|
'parent_id': main_partner_2.id,
|
|
})
|
|
|
|
# We create a different BoM for the same product
|
|
comp3 = self.env['product.product'].create({
|
|
'name': 'Component1',
|
|
'type': 'product',
|
|
'categ_id': self.env.ref('product.product_category_all').id,
|
|
})
|
|
|
|
bom_form = Form(self.env['mrp.bom'])
|
|
bom_form.type = 'subcontract'
|
|
bom_form.product_tmpl_id = self.finished.product_tmpl_id
|
|
with bom_form.bom_line_ids.new() as bom_line:
|
|
bom_line.product_id = self.comp1
|
|
bom_line.product_qty = 1
|
|
with bom_form.bom_line_ids.new() as bom_line:
|
|
bom_line.product_id = comp3
|
|
bom_line.product_qty = 1
|
|
bom2 = bom_form.save()
|
|
|
|
# We assign the second BoM to the new partner
|
|
self.bom.write({'subcontractor_ids': [(4, self.subcontractor_partner1.id, None)]})
|
|
bom2.write({'subcontractor_ids': [(4, subcontractor_partner2.id, None)]})
|
|
|
|
# Create a receipt picking from the subcontractor1
|
|
picking_form = Form(self.env['stock.picking'])
|
|
picking_form.picking_type_id = self.env.ref('stock.picking_type_in')
|
|
picking_form.partner_id = self.subcontractor_partner1
|
|
with picking_form.move_ids_without_package.new() as move:
|
|
move.product_id = self.finished
|
|
move.product_uom_qty = 1
|
|
picking_receipt1 = picking_form.save()
|
|
picking_receipt1.action_confirm()
|
|
|
|
# Create a receipt picking from the subcontractor2
|
|
picking_form = Form(self.env['stock.picking'])
|
|
picking_form.picking_type_id = self.env.ref('stock.picking_type_in')
|
|
picking_form.partner_id = subcontractor_partner2
|
|
with picking_form.move_ids_without_package.new() as move:
|
|
move.product_id = self.finished
|
|
move.product_uom_qty = 1
|
|
picking_receipt2 = picking_form.save()
|
|
picking_receipt2.action_confirm()
|
|
|
|
mo_pick1 = picking_receipt1.move_lines.mapped('move_orig_ids.production_id')
|
|
mo_pick2 = picking_receipt2.move_lines.mapped('move_orig_ids.production_id')
|
|
self.assertEquals(len(mo_pick1), 1)
|
|
self.assertEquals(len(mo_pick2), 1)
|
|
self.assertEquals(mo_pick1.bom_id, self.bom)
|
|
self.assertEquals(mo_pick2.bom_id, bom2)
|
|
|
|
|
|
class TestSubcontractingTracking(TransactionCase):
|
|
def setUp(self):
|
|
super(TestSubcontractingTracking, self).setUp()
|
|
# 1: Create a subcontracting partner
|
|
main_company_1 = self.env['res.partner'].create({'name': 'main_partner'})
|
|
self.subcontractor_partner1 = self.env['res.partner'].create({
|
|
'name': 'Subcontractor 1',
|
|
'type': 'subcontractor',
|
|
'parent_id': main_company_1.id,
|
|
})
|
|
|
|
# 2. Create a BOM of subcontracting type
|
|
# 2.1. Comp1 has tracking by lot
|
|
self.comp1_sn = self.env['product.product'].create({
|
|
'name': 'Component1',
|
|
'type': 'product',
|
|
'categ_id': self.env.ref('product.product_category_all').id,
|
|
'tracking': 'serial'
|
|
})
|
|
self.comp2 = self.env['product.product'].create({
|
|
'name': 'Component2',
|
|
'type': 'product',
|
|
'categ_id': self.env.ref('product.product_category_all').id,
|
|
})
|
|
|
|
# 2.2. Finished prodcut has tracking by serial number
|
|
self.finished_lot = self.env['product.product'].create({
|
|
'name': 'finished',
|
|
'type': 'product',
|
|
'categ_id': self.env.ref('product.product_category_all').id,
|
|
'tracking': 'lot'
|
|
})
|
|
bom_form = Form(self.env['mrp.bom'])
|
|
bom_form.type = 'subcontract'
|
|
bom_form.product_tmpl_id = self.finished_lot.product_tmpl_id
|
|
with bom_form.bom_line_ids.new() as bom_line:
|
|
bom_line.product_id = self.comp1_sn
|
|
bom_line.product_qty = 1
|
|
with bom_form.bom_line_ids.new() as bom_line:
|
|
bom_line.product_id = self.comp2
|
|
bom_line.product_qty = 1
|
|
self.bom_tracked = bom_form.save()
|
|
|
|
def test_flow_tracked_1(self):
|
|
""" This test mimics test_flow_1 but with a BoM that has tracking included in it.
|
|
"""
|
|
# Create a receipt picking from the subcontractor
|
|
picking_form = Form(self.env['stock.picking'])
|
|
picking_form.picking_type_id = self.env.ref('stock.picking_type_in')
|
|
picking_form.partner_id = self.subcontractor_partner1
|
|
with picking_form.move_ids_without_package.new() as move:
|
|
move.product_id = self.finished_lot
|
|
move.product_uom_qty = 1
|
|
picking_receipt = picking_form.save()
|
|
picking_receipt.action_confirm()
|
|
|
|
# We should be able to call the 'record_components' button
|
|
self.assertTrue(picking_receipt.display_action_record_components)
|
|
self.assertFalse(picking_receipt.display_view_subcontracted_move_lines)
|
|
|
|
# Check the created manufacturing order
|
|
mo = self.env['mrp.production'].search([('bom_id', '=', self.bom_tracked.id)])
|
|
self.assertEqual(len(mo), 1)
|
|
self.assertEquals(mo.state, 'confirmed')
|
|
self.assertEqual(len(mo.picking_ids), 0)
|
|
wh = picking_receipt.picking_type_id.warehouse_id
|
|
self.assertEquals(mo.picking_type_id, wh.subcontracting_type_id)
|
|
self.assertFalse(mo.picking_type_id.active)
|
|
|
|
# Create a RR
|
|
pg1 = self.env['procurement.group'].create({})
|
|
self.env['stock.warehouse.orderpoint'].create({
|
|
'name': 'xxx',
|
|
'product_id': self.comp1_sn.id,
|
|
'product_min_qty': 0,
|
|
'product_max_qty': 0,
|
|
'location_id': self.env.user.company_id.subcontracting_location_id.id,
|
|
'group_id': pg1.id,
|
|
})
|
|
|
|
# Run the scheduler and check the created picking
|
|
self.env['procurement.group'].run_scheduler()
|
|
picking = self.env['stock.picking'].search([('group_id', '=', pg1.id)])
|
|
self.assertEqual(len(picking), 1)
|
|
self.assertEquals(picking.picking_type_id, wh.out_type_id)
|
|
|
|
lot_id = self.env['stock.production.lot'].create({
|
|
'name': 'lot1',
|
|
'product_id': self.finished_lot.id
|
|
})
|
|
serial_id = self.env['stock.production.lot'].create({
|
|
'name': 'lot1',
|
|
'product_id': self.comp1_sn.id
|
|
})
|
|
produce_form = Form(self.env['mrp.product.produce'].with_context({
|
|
'active_id': mo.id,
|
|
'active_ids': [mo.id],
|
|
}))
|
|
produce_form.final_lot_id = lot_id
|
|
produce_form.workorder_line_ids._records[0]['lot_id'] = serial_id.id
|
|
wiz_produce = produce_form.save()
|
|
wiz_produce.do_produce()
|
|
|
|
# We should not be able to call the 'record_components' button
|
|
self.assertFalse(picking_receipt.display_action_record_components)
|
|
# We should see the move lines stat button
|
|
self.assertTrue(picking_receipt.display_view_subcontracted_move_lines)
|
|
|
|
picking_receipt.move_lines.quantity_done = 1
|
|
picking_receipt.move_lines.move_line_ids.lot_name = 'lot00001test'
|
|
picking_receipt.button_validate()
|
|
self.assertEquals(mo.state, 'done')
|
|
|
|
# Available quantities should be negative at the subcontracting location for each components
|
|
avail_qty_comp1 = self.env['stock.quant']._get_available_quantity(self.comp1_sn, self.subcontractor_partner1.property_stock_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_lot, wh.lot_stock_id)
|
|
self.assertEquals(avail_qty_comp1, -1)
|
|
self.assertEquals(avail_qty_comp2, -1)
|
|
self.assertEquals(avail_qty_finished, 1)
|