Files
manufacture/mrp_bom_dismantling/tests/test_bom.py
2016-06-08 16:07:09 +02:00

369 lines
13 KiB
Python

# -*- coding: utf-8 -*-
# © 2016 Cyril Gaudin (Camptocamp)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import exceptions
from openerp.exceptions import UserError
from openerp.tests import TransactionCase
class TestBom(TransactionCase):
def setUp(self):
super(TestBom, self).setUp()
self.product_model = self.env['product.product']
self.bom_model = self.env['mrp.bom']
self.bom_line_model = self.env['mrp.bom.line']
self.mrp_production_model = self.env['mrp.production']
self.config_param_model = self.env['ir.config_parameter']
self.unit_uom = self.browse_ref('product.product_uom_unit')
self.dozen_uom = self.browse_ref('product.product_uom_dozen')
def check_result_and_load_entity(self, model_name, result, context=None):
entity_id = result.pop('res_id')
self.assertEqual({
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': model_name,
'target': 'current',
'context': context or self.env.context,
}, result)
return self.env[model_name].browse(entity_id)
def create_bom(self, product, qty=1, uom=None,
phantom=False, components=None):
bom = self.bom_model.create({
'product_tmpl_id': product.product_tmpl_id.id,
'product_id': product.id,
'product_qty': qty,
'product_uom': self.unit_uom.id if uom is None else uom.id,
'type': 'phantom' if phantom else 'normal',
})
if components:
for component in components:
self.create_bom_line(bom, component)
return bom
def create_bom_line(self, bom, component, qty=1, uom=None):
self.bom_line_model.create({
'bom_id': bom.id,
'product_id': component.id,
'product_qty': qty,
'product_uom': self.unit_uom.id if uom is None else uom.id,
})
def test_dismantling_no_components(self):
p1 = self.product_model.create({'name': 'Test P1'})
p2 = self.product_model.create({'name': 'Test P1'})
p1_bom = self.create_bom(p1)
with self.assertRaises(exceptions.UserError):
p1_bom.create_dismantling_bom()
self.create_bom_line(p1_bom, p2)
p1_bom.create_dismantling_bom()
def test_dismantling_on_dismantling_bom(self):
p1 = self.product_model.create({'name': 'Test P1'})
p2 = self.product_model.create({'name': 'Test P1'})
p1_bom = self.create_bom(p1, components=[p2])
p1_bom.write({
'dismantling': True,
'dismantled_product_id': p2.id
})
with self.assertRaises(exceptions.UserError):
p1_bom.create_dismantling_bom()
def test_dismantling_bom_no_product_id__multiple_vaiants(self):
p1 = self.product_model.create({'name': 'Test P1'})
p1_var = self.product_model.create({
'product_tmpl_id': p1.product_tmpl_id.id,
})
p2 = self.product_model.create({'name': 'Test P2'})
# P1 BoM: Need one P2
p1_bom = self.bom_model.create({
'product_tmpl_id': p1.product_tmpl_id.id,
'product_id': None,
})
self.create_bom_line(p1_bom, p2)
# No variant specified (and template has multiple variants)
with self.assertRaises(exceptions.UserError):
p1_bom.create_dismantling_bom()
# Variant specified
p1_bom.product_id = p1_var
result = p1_bom.create_dismantling_bom()
self.check_result_and_load_entity('mrp.bom', result)
def test_dismantling_bom_no_product_id(self):
# Same tests but BoM only have a product_tmpl_id, no product_id
# (Seems to be the standard case)
p1 = self.product_model.create({'name': 'Test P1'})
p2 = self.product_model.create({'name': 'Test P2'})
# P1 BoM: Need one P2
p1_bom = self.bom_model.create({
'product_tmpl_id': p1.product_tmpl_id.id,
'product_id': None,
})
self.create_bom_line(p1_bom, p2)
result = p1_bom.create_dismantling_bom()
dmtl_bom = self.check_result_and_load_entity('mrp.bom', result)
self.assertEqual(p2.id, dmtl_bom.product_id.id)
self.assertEqual(True, dmtl_bom.dismantling)
self.assertEqual(p1.id, dmtl_bom.dismantled_product_id.id)
self.assertEqual(p2.product_tmpl_id.id, dmtl_bom.product_tmpl_id.id)
# Consume p1
self.assertEqual(1, len(dmtl_bom.bom_line_ids))
self.assertEqual(p1.id, dmtl_bom.bom_line_ids[0].product_id.id)
def test_dismantling_simple_case(self):
p1 = self.product_model.create({'name': 'Test P1'})
p2 = self.product_model.create({'name': 'Test P2'})
p3 = self.product_model.create({'name': 'Test P3'})
# P1 BoM: Need one P2 and one P3
p1_bom = self.create_bom(p1, components=[p2, p3])
result = p1_bom.create_dismantling_bom()
dmtl_bom = self.check_result_and_load_entity('mrp.bom', result)
self.assertEqual(p2.id, dmtl_bom.product_id.id)
self.assertEqual(p2.product_tmpl_id.id, dmtl_bom.product_tmpl_id.id)
self.assertEqual(True, dmtl_bom.dismantling)
self.assertEqual(p1.id, dmtl_bom.dismantled_product_id.id)
# Consume p1
self.assertEqual(1, len(dmtl_bom.bom_line_ids))
self.assertEqual(p1.id, dmtl_bom.bom_line_ids[0].product_id.id)
# P3 in by-products
self.assertEqual(1, len(dmtl_bom.sub_products))
self.assertEqual(p3.id, dmtl_bom.sub_products[0].product_id.id)
def test_phantom_bom(self):
p1 = self.product_model.create({'name': 'Test P1'})
p2 = self.product_model.create({'name': 'Test P2'})
sub_p2 = self.product_model.create({'name': 'Test sub P2'})
p3 = self.product_model.create({'name': 'Test P3'})
sub_p3 = self.product_model.create({'name': 'Test sub P3'})
# P1 BoM: Need one P2 and one P3
# P2 has a phantom BoM which need one sub P2
# P3 has a normal Bom which need one sub p3
p1_bom = self.create_bom(p1, components=[p2, p3])
self.create_bom(p2, phantom=True, components=[sub_p2])
self.create_bom(p3, components=[sub_p3])
result = p1_bom.create_dismantling_bom()
dmtl_bom = self.check_result_and_load_entity('mrp.bom', result)
self.assertEqual(sub_p2.id, dmtl_bom.product_id.id)
self.assertEqual(sub_p2.product_tmpl_id.id,
dmtl_bom.product_tmpl_id.id)
self.assertEqual(True, dmtl_bom.dismantling)
self.assertEqual(p1.id, dmtl_bom.dismantled_product_id.id)
# Consume p1self.assertEqual(1, len(dmtl_bom.bom_line_ids))
self.assertEqual(p1.id, dmtl_bom.bom_line_ids[0].product_id.id)
# Sub P3 in by-products
self.assertEqual(1, len(dmtl_bom.sub_products))
self.assertEqual(p3.id, dmtl_bom.sub_products[0].product_id.id)
def test_multi_unit_components(self):
p1 = self.product_model.create({'name': 'Test P1'})
p2 = self.product_model.create({'name': 'Test P2'})
p3 = self.product_model.create({'name': 'Test P3'})
p4 = self.product_model.create({'name': 'Test P4'})
# P1 BoM (produced 1 dozen): Needs 2 P2, 4 P3 and 2 dozen P4
# P2 has a phantom BoM which need one Dozen of P3
#
# => Dismantling BoM:
# Product: P3 (produced 28 unit)
# Component: 1 dozen P1
p1_bom = self.create_bom(p1, qty=1, uom=self.dozen_uom)
self.create_bom_line(p1_bom, p2, qty=2)
self.create_bom_line(p1_bom, p3, qty=4)
self.create_bom_line(p1_bom, p4, qty=2, uom=self.dozen_uom)
p2_bom = self.create_bom(p2, phantom=True)
self.create_bom_line(p2_bom, p3, qty=1, uom=self.dozen_uom)
result = p1_bom.create_dismantling_bom()
dmtl_bom = self.check_result_and_load_entity('mrp.bom', result)
self.assertEqual(p3.id, dmtl_bom.product_id.id)
self.assertEqual(28, dmtl_bom.product_qty)
self.assertEqual(self.unit_uom, dmtl_bom.product_uom)
self.assertEqual(True, dmtl_bom.dismantling)
self.assertEqual(p1.id, dmtl_bom.dismantled_product_id.id)
# Consume 1 dozen p1
self.assertEqual(1, len(dmtl_bom.bom_line_ids))
dmtl_bom_line = dmtl_bom.bom_line_ids[0]
self.assertEqual(p1.id, dmtl_bom_line.product_id.id)
self.assertEqual(1, dmtl_bom_line.product_qty)
self.assertEqual(self.dozen_uom, dmtl_bom_line.product_uom)
# Byproducts
self.assertEqual(1, len(dmtl_bom.sub_products))
dmtl_sub_product = dmtl_bom.sub_products[0]
self.assertEqual(p4.id, dmtl_sub_product.product_id.id)
self.assertEqual(24, dmtl_sub_product.product_qty)
self.assertEqual(self.unit_uom, dmtl_sub_product.product_uom)
def test_create_mrp_production(self):
p1 = self.product_model.create({'name': 'Test P1'})
p2 = self.product_model.create({'name': 'Test P2'})
bom = self.create_bom(p1, qty=2, uom=self.dozen_uom, components=[p2])
self.assertEqual(
0,
self.mrp_production_model.search_count([('bom_id', '=', bom.id)])
)
result = bom.create_mrp_production()
mrp_prod = self.check_result_and_load_entity('mrp.production', result)
self.assertEqual(bom, mrp_prod.bom_id)
self.assertEqual(p1, mrp_prod.product_id)
self.assertEqual(2, mrp_prod.product_qty)
self.assertEqual(2, mrp_prod.product_qty)
self.assertEqual(self.dozen_uom, mrp_prod.product_uom)
def test_action_create_dismantling_bom(self):
# Set component automatically choosen.
self.config_param_model.set_param(
'mrp.bom.dismantling.product_choice', False
)
p1 = self.product_model.create({'name': 'Test P1'})
p2 = self.product_model.create({'name': 'Test P2'})
p1_bom = self.create_bom(p1, components=[p2])
dismantled_p2_domain = [
('product_id', '=', p2.id),
('dismantling', '=', True),
]
# Non dismantling bom
self.assertEqual(0, self.bom_model.search_count(dismantled_p2_domain))
result = p1_bom.action_create_dismantling_bom()
self.assertEqual(1, self.bom_model.search_count(dismantled_p2_domain))
dmtl_bom = self.check_result_and_load_entity('mrp.bom', result)
self.assertEqual(p2.id, dmtl_bom.product_id.id)
self.assertEqual(True, dmtl_bom.dismantling)
# Component must be choose by user
self.config_param_model.set_param(
'mrp.bom.dismantling.product_choice', '1'
)
result = p1_bom.action_create_dismantling_bom()
# No new dismantling bom created
self.assertEqual(1, self.bom_model.search_count(dismantled_p2_domain))
# Response opened wizard
self.assertEqual({
'type': 'ir.actions.act_window',
'name': 'Choose main compoment',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'mrp.bom.dismantling_product_choice',
'target': 'new',
'context': self.env.context
}, result)
def test_res_config(self):
# Coverage test for res_config methods
self.config_param_model.set_param(
'mrp.bom.dismantling.product_choice', None
)
mrp_config = self.env['mrp.config.settings'].create({
# Bypass default_get bug: https://github.com/odoo/odoo/pull/10373
'group_product_variant': 0
})
self.assertEqual(
False, mrp_config.read(
['dismantling_product_choice']
)[0]['dismantling_product_choice']
)
mrp_config.write({'dismantling_product_choice': 1})
mrp_config.execute()
self.assertEqual('1', self.config_param_model.get_param(
'mrp.bom.dismantling.product_choice'
))
def test_product_choice_wizard(self):
wizard_model = self.env['mrp.bom.dismantling_product_choice']
p1 = self.product_model.create({'name': 'Test P1'})
p2 = self.product_model.create({'name': 'Test P2'})
p3 = self.product_model.create({'name': 'Test P3'})
bom = self.create_bom(p1)
# No active ID
with self.assertRaises(KeyError):
wizard_model.create({})
# Cannot really test full workflow => call methods manually.
wizard = wizard_model.with_context(active_id=bom.id).new({})
self.assertEqual(bom, wizard._get_bom_id())
wizard.bom_id = bom
# No component
with self.assertRaises(UserError):
wizard.on_change_bom_id()
self.create_bom_line(bom, p2)
self.create_bom_line(bom, p3)
bom.refresh()
wizard.bom_id = bom
result = wizard.on_change_bom_id()
self.assertEqual({
'domain': {
'component_id': [('id', 'in', [p2.id, p3.id])],
}
}, result)
wizard.component_id = p3
wizard.write({})
result = wizard.create_bom()
# Dismantling BOM main product is P3
dmtl_bom = self.check_result_and_load_entity(
'mrp.bom', result, context={'active_id': bom.id}
)
self.assertEqual(p3.id, dmtl_bom.product_id.id)
self.assertEqual(True, dmtl_bom.dismantling)