Files
manufacture/mrp_bom_dismantling/models/mrp_bom.py
2017-05-29 14:38:07 +02:00

170 lines
5.5 KiB
Python

# -*- coding: utf-8 -*-
# © 2016 Cyril Gaudin (Camptocamp)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import _, api, exceptions, fields, models
class MrpBom(models.Model):
_inherit = 'mrp.bom'
dismantling = fields.Boolean(string='Dismantling', default=False)
dismantled_product_id = fields.Many2one(
comodel_name='product.product',
string='Dismantled product'
)
_sql_constraints = [
('bom_dismantled_product_id',
'CHECK(dismantled_product_id is not null = dismantling)',
"Dismantling BoM should have a dismantled product."),
]
@api.multi
def create_mrp_production(self):
""" Create a manufacturing order from this BoM
"""
self.ensure_one()
product = self._get_bom_product()
production = self.env['mrp.production'].create({
'bom_id': self.id,
'product_id': product.id,
'product_qty': self.product_qty,
'product_uom': self.product_uom.id,
})
return self._get_form_view('mrp.production', production)
@api.multi
def action_create_dismantling_bom(self):
""" Check dismantling_product_choice config and open choice wizard
if needed or directly call create_dismantling_bom.
"""
config_name = 'mrp.bom.dismantling.product_choice'
if self.env['ir.config_parameter'].get_param(config_name):
return {
'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
}
else:
return self.create_dismantling_bom()
@api.multi
def create_dismantling_bom(self, main_component=None):
""" Create a dismantling BoM based on this BoM
If *main_component* is not None, this component will be set as main
product in dismantling bom.
Else first component will be taken (sorted by Id).
:type main_component: product_product
:rtype: dict
"""
self.ensure_one()
self._check_bom_validity(check_dismantling=True)
product = self._get_bom_product()
components = self._get_component_needs()
# If no main component, take first sorted by Id
if not main_component:
main_component = sorted(components.keys(), key=lambda c: c.id)[0]
# Create the BoM on main component
main_component_needs = components.pop(main_component)
dismantling_bom = self.create({
'product_tmpl_id': main_component.product_tmpl_id.id,
'product_id': main_component.id,
'dismantling': True,
'dismantled_product_id': product.id,
'product_qty': main_component_needs,
})
# Create BoM line for self.product_tmpl_id
self.env['mrp.bom.line'].create({
'bom_id': dismantling_bom.id,
'product_id': product.id,
'product_qty': self.product_qty,
'product_uom': self.product_uom.id,
})
# Add others component as By-products
subproduct_model = self.env['mrp.subproduct']
for component, needs in components.items():
subproduct_model.create({
'bom_id': dismantling_bom.id,
'product_id': component.id,
'product_qty': needs,
'product_uom': self.env.ref('product.product_uom_unit').id,
})
return self._get_form_view('mrp.bom', dismantling_bom)
def _get_form_view(self, model_name, entity):
return {
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': model_name,
'target': 'current',
'res_id': entity.id,
'context': self.env.context
}
def _check_bom_validity(self, check_dismantling=False):
""" Ensure this BoM can be use for creating a dismantling BoM
or a manufacturing order.
:type check_dismantling: bool
:raise exceptions.UserError: If this BoM is not valid.
"""
warning = None
if check_dismantling and self.dismantling:
warning = 'This BoM is already a dismantling Bom.'
if not len(self.bom_line_ids):
warning = 'This BoM does not have components.'
if not self.product_id \
and len(self.product_tmpl_id.product_variant_ids) > 1:
warning = 'This product has several variants: ' \
'you need to specify one.'
if warning:
raise exceptions.UserError(_(warning))
def _get_component_needs(self):
""" Return this BoM components and their needed qties.
The result is like {component_1: 1, component_2: 5, ...}
:rtype: dict(product_product, float)
"""
components = self.product_id._get_component_needs(
product=self.product_id, bom=self
)
return dict(components)
def _get_bom_product(self):
""" Get the product of this BoM.
If BoM does not have product_id, return first template variant.
:rtype: product_product
"""
if not self.product_id:
product = self.product_tmpl_id.product_variant_ids[0]
else:
product = self.product_id
return product