mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
[IMP] mrp_hook: Provide hooks for _bom_explode method
As we are struggled by the structure of core current code, and https://github.com/odoo/odoo/pull/8885 hasn't been accepted in v8, we need to make this hard move to allow a lot of workarounds like modules not depending this one, but anyway the method itself is not too much inheritable.
This commit is contained in:
29
mrp_hook/README.rst
Normal file
29
mrp_hook/README.rst
Normal file
@@ -0,0 +1,29 @@
|
||||
===============================
|
||||
Hooks for enabling advanced MRP
|
||||
===============================
|
||||
|
||||
Technical module that provides the proper framework infrastructure (hooks,
|
||||
fallback, etc) to enable advanced functionality in the manufacturing area,
|
||||
as https://github.com/odoo/odoo/pull/8885 hasn't been accepted for v8.
|
||||
|
||||
* Hooks in *_bom_explode* method for returning dictionary for consume and
|
||||
workcenter lines.
|
||||
* Provide product and template.
|
||||
|
||||
By itself it doesn't provide anything, but serves as base for others modules
|
||||
to develop its features.
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
* This module fully overwrites _bom_explode method, so any other module
|
||||
inheriting this method should take that into account.
|
||||
* On v9, this module can be removed.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>
|
||||
5
mrp_hook/__init__.py
Normal file
5
mrp_hook/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2015 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
||||
|
||||
from . import models
|
||||
22
mrp_hook/__openerp__.py
Normal file
22
mrp_hook/__openerp__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2015 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
||||
|
||||
{
|
||||
"name": "MRP Hooks",
|
||||
"version": "8.0.1.0.0",
|
||||
"category": "Hidden",
|
||||
"author": "OdooMRP team, "
|
||||
"AvanzOSC, "
|
||||
"Serv. Tecnol. Avanzados - Pedro M. Baeza",
|
||||
"website": "http://www.odoomrp.com",
|
||||
"contributors": [
|
||||
"Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>",
|
||||
],
|
||||
"depends": [
|
||||
"mrp",
|
||||
],
|
||||
"data": [
|
||||
],
|
||||
"installable": True
|
||||
}
|
||||
5
mrp_hook/models/__init__.py
Normal file
5
mrp_hook/models/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2015 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
||||
|
||||
from . import mrp_bom
|
||||
150
mrp_hook/models/mrp_bom.py
Normal file
150
mrp_hook/models/mrp_bom.py
Normal file
@@ -0,0 +1,150 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2015 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
||||
|
||||
from openerp import models, api, tools, _
|
||||
from openerp.exceptions import Warning as UserError
|
||||
from openerp.addons.product import _common
|
||||
|
||||
|
||||
class MrpBom(models.Model):
|
||||
_inherit = 'mrp.bom'
|
||||
|
||||
@api.model
|
||||
def _factor(self, factor, product_efficiency, product_rounding):
|
||||
factor = factor / (product_efficiency or 1.0)
|
||||
factor = _common.ceiling(factor, product_rounding)
|
||||
if factor < product_rounding:
|
||||
factor = product_rounding
|
||||
return factor
|
||||
|
||||
@api.multi
|
||||
def _prepare_wc_line(self, wc_use, level=0, factor=1):
|
||||
self.ensure_one()
|
||||
wc = wc_use.workcenter_id
|
||||
d, m = divmod(factor, wc_use.workcenter_id.capacity_per_cycle)
|
||||
mult = (d + (m and 1.0 or 0.0))
|
||||
cycle = mult * wc_use.cycle_nbr
|
||||
return {
|
||||
'name': (tools.ustr(wc_use.name) + ' - ' +
|
||||
tools.ustr(self.product_tmpl_id.name_get()[0][1])),
|
||||
'workcenter_id': wc.id,
|
||||
'sequence': level + (wc_use.sequence or 0),
|
||||
'cycle': cycle,
|
||||
'hour': float(
|
||||
wc_use.hour_nbr * mult +
|
||||
(wc.time_start or 0.0) +
|
||||
(wc.time_stop or 0.0) +
|
||||
cycle * (wc.time_cycle or 0.0) * (wc.time_efficiency or 1.0)),
|
||||
}
|
||||
|
||||
@api.model
|
||||
def _prepare_consume_line(self, bom_line, quantity, factor=1):
|
||||
uos_qty = (bom_line.product_uos and
|
||||
self._factor(
|
||||
bom_line.product_uos_qty * factor,
|
||||
bom_line.product_efficiency, bom_line.product_rounding))
|
||||
return {
|
||||
'name': bom_line.product_id.name,
|
||||
'product_id': bom_line.product_id.id,
|
||||
'product_qty': quantity,
|
||||
'product_uom': bom_line.product_uom.id,
|
||||
'product_uos_qty': uos_qty or False,
|
||||
'product_uos': bom_line.product_uos.id,
|
||||
}
|
||||
|
||||
@api.model
|
||||
def _bom_find_prepare(self, bom_line, properties=None):
|
||||
return self._bom_find(
|
||||
product_id=bom_line.product_id.id, properties=properties)
|
||||
|
||||
@api.model
|
||||
def _get_bom_product_name(self, bom_line):
|
||||
return bom_line.product_id.name_get()[0][1]
|
||||
|
||||
@api.v7
|
||||
def _bom_explode(self, cr, uid, bom, product, factor, properties=None,
|
||||
level=0, routing_id=False, previous_products=None,
|
||||
master_bom=None, context=None):
|
||||
return bom._bom_explode(
|
||||
product, factor, properties=properties, level=level,
|
||||
routing_id=routing_id, previous_products=previous_products,
|
||||
master_bom=master_bom)
|
||||
|
||||
@api.v8
|
||||
def _bom_explode(self, product, factor, properties=None, level=0,
|
||||
routing_id=False, previous_products=None,
|
||||
master_bom=None):
|
||||
""" Finds Products and Work Centers for related BoM for manufacturing
|
||||
order.
|
||||
@param bom: BoM of particular product template.
|
||||
@param product: Select a particular variant of the BoM. If False use
|
||||
BoM without variants.
|
||||
@param factor: Factor represents the quantity, but in UoM of the BoM,
|
||||
taking into account the numbers produced by the BoM
|
||||
@param properties: A List of properties Ids.
|
||||
@param level: Depth level to find BoM lines starts from 10.
|
||||
@param previous_products: List of product previously use by bom
|
||||
explore to avoid recursion
|
||||
@param master_bom: When recursion, used to display the name of the
|
||||
master bom
|
||||
@return: result: List of dictionaries containing product details.
|
||||
result2: List of dictionaries containing Work Center details.
|
||||
"""
|
||||
self.ensure_one()
|
||||
bom = self
|
||||
uom_obj = self.env["product.uom"]
|
||||
routing_obj = self.env['mrp.routing']
|
||||
master_bom = master_bom or bom
|
||||
factor = self._factor(
|
||||
factor, bom.product_efficiency, bom.product_rounding)
|
||||
result = []
|
||||
result2 = []
|
||||
routing = ((routing_id and routing_obj.browse(routing_id)) or
|
||||
bom.routing_id or False)
|
||||
if routing:
|
||||
for wc_use in routing.workcenter_lines:
|
||||
result2.append(self._prepare_wc_line(
|
||||
wc_use, level=level, factor=factor))
|
||||
for bom_line_id in bom.bom_line_ids:
|
||||
if self._skip_bom_line(bom_line_id, product):
|
||||
continue
|
||||
if (set(map(int, bom_line_id.property_ids or [])) -
|
||||
set(properties or [])):
|
||||
continue
|
||||
product_tmpl_id = bom_line_id.product_id.product_tmpl_id.id
|
||||
if (previous_products and
|
||||
product_tmpl_id in previous_products):
|
||||
raise UserError(
|
||||
_('BoM "%s" contains a BoM line with a product recursion: '
|
||||
'"%s".') % (master_bom.name,
|
||||
bom_line_id.product_id.name_get()[0][1]))
|
||||
quantity = self._factor(
|
||||
bom_line_id.product_qty * factor,
|
||||
bom_line_id.product_efficiency, bom_line_id.product_rounding)
|
||||
bom_id = self._bom_find_prepare(bom_line_id, properties=properties)
|
||||
# If BoM should not behave like PhantoM, just add the product,
|
||||
# otherwise explode further
|
||||
if (bom_line_id.type != "phantom" and
|
||||
(not bom_id or self.browse(bom_id).type != "phantom")):
|
||||
result.append(
|
||||
self._prepare_consume_line(bom_line_id, quantity, factor))
|
||||
elif bom_id:
|
||||
all_prod = [bom.product_tmpl_id.id] + (previous_products or [])
|
||||
bom2 = self.browse(bom_id)
|
||||
# We need to convert to units/UoM of chosen BoM
|
||||
factor2 = uom_obj._compute_qty(
|
||||
bom_line_id.product_uom.id, quantity, bom2.product_uom.id)
|
||||
quantity2 = factor2 / bom2.product_qty
|
||||
res = bom2._bom_explode(
|
||||
bom_line_id.product_id, quantity2, properties=properties,
|
||||
level=level + 10, previous_products=all_prod,
|
||||
master_bom=master_bom)
|
||||
result = result + res[0]
|
||||
result2 = result2 + res[1]
|
||||
else:
|
||||
raise UserError(
|
||||
_('BoM "%s" contains a phantom BoM line but the product '
|
||||
'"%s" does not have any BoM defined.') %
|
||||
(master_bom.name, self._get_bom_product_name(bom_line_id)))
|
||||
return result, result2
|
||||
Reference in New Issue
Block a user