[IMP] Update module descriptions of procurement and product_extended + _bom_find and properties
Module description of procurement was deprecated (talking about mrp, ...) and in product_extended it described things not implemented in the module. In _bom_find, we passed a UoM which was not used in Saas-4 and it would not be logical that you need to select a BoM that matches the UoM, so I removed it. In the demo data, there was still a push rule which triggered a move from output to pack. The copy=False is correct for production_id when you would have these push rules. For the properties: we want to allow to take a bom which has no properties, but only when there is no other BoM matching the properties we pass. Update module descriptions [IMP] production_id copy + no round [IMP] _bom_find without uom, property correction
This commit is contained in:
parent
3dcb020373
commit
25d2ed6d4b
|
@ -230,7 +230,7 @@ class mrp_bom(osv.osv):
|
||||||
}
|
}
|
||||||
_order = "sequence"
|
_order = "sequence"
|
||||||
|
|
||||||
def _bom_find(self, cr, uid, product_uom, product_tmpl_id=None, product_id=None, properties=None, context=None):
|
def _bom_find(self, cr, uid, product_tmpl_id=None, product_id=None, properties=None, context=None):
|
||||||
""" Finds BoM for particular product and product uom.
|
""" Finds BoM for particular product and product uom.
|
||||||
@param product_tmpl_id: Selected product.
|
@param product_tmpl_id: Selected product.
|
||||||
@param product_uom: Unit of measure of a product.
|
@param product_uom: Unit of measure of a product.
|
||||||
|
@ -254,16 +254,18 @@ class mrp_bom(osv.osv):
|
||||||
else:
|
else:
|
||||||
# neither product nor template, makes no sense to search
|
# neither product nor template, makes no sense to search
|
||||||
return False
|
return False
|
||||||
if product_uom:
|
|
||||||
domain += [('product_uom','=',product_uom)]
|
|
||||||
domain = domain + [ '|', ('date_start', '=', False), ('date_start', '<=', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)),
|
domain = domain + [ '|', ('date_start', '=', False), ('date_start', '<=', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)),
|
||||||
'|', ('date_stop', '=', False), ('date_stop', '>=', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT))]
|
'|', ('date_stop', '=', False), ('date_stop', '>=', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT))]
|
||||||
# order to prioritize bom with product_id over the one without
|
# order to prioritize bom with product_id over the one without
|
||||||
ids = self.search(cr, uid, domain, order='product_id')
|
ids = self.search(cr, uid, domain, order='product_id')
|
||||||
|
bom_empty_prop = False
|
||||||
for bom in self.pool.get('mrp.bom').browse(cr, uid, ids):
|
for bom in self.pool.get('mrp.bom').browse(cr, uid, ids):
|
||||||
if not set(map(int, bom.property_ids or [])) - set(properties or []):
|
if not set(map(int, bom.property_ids or [])) - set(properties or []):
|
||||||
return bom.id
|
if not bom.property_ids:
|
||||||
return False
|
bom_empty_prop = bom.id
|
||||||
|
else:
|
||||||
|
return bom.id
|
||||||
|
return bom_empty_prop
|
||||||
|
|
||||||
def _bom_explode(self, cr, uid, bom, product, factor, properties=None, level=0, routing_id=False, previous_products=None, master_bom=None, context=None):
|
def _bom_explode(self, cr, uid, bom, product, factor, properties=None, level=0, routing_id=False, previous_products=None, master_bom=None, context=None):
|
||||||
""" Finds Products and Work Centers for related BoM for manufacturing order.
|
""" Finds Products and Work Centers for related BoM for manufacturing order.
|
||||||
|
@ -322,7 +324,7 @@ class mrp_bom(osv.osv):
|
||||||
raise osv.except_osv(_('Invalid Action!'), _('BoM "%s" contains a BoM line with a product recursion: "%s".') % (master_bom.name,bom_line_id.product_id.name_get()[0][1]))
|
raise osv.except_osv(_('Invalid Action!'), _('BoM "%s" contains a BoM line with a product recursion: "%s".') % (master_bom.name,bom_line_id.product_id.name_get()[0][1]))
|
||||||
|
|
||||||
quantity = _factor(bom_line_id.product_qty * factor, bom_line_id.product_efficiency, bom_line_id.product_rounding)
|
quantity = _factor(bom_line_id.product_qty * factor, bom_line_id.product_efficiency, bom_line_id.product_rounding)
|
||||||
bom_id = self._bom_find(cr, uid, bom_line_id.product_uom.id, product_id=bom_line_id.product_id.id, properties=properties, context=context)
|
bom_id = self._bom_find(cr, uid, product_id=bom_line_id.product_id.id, properties=properties, context=context)
|
||||||
|
|
||||||
#If BoM should not behave like PhantoM, just add the product, otherwise explode further
|
#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(cr, uid, bom_id, context=context).type != "phantom"):
|
if bom_line_id.type != "phantom" and (not bom_id or self.browse(cr, uid, bom_id, context=context).type != "phantom"):
|
||||||
|
@ -403,7 +405,7 @@ class mrp_bom_line(osv.osv):
|
||||||
'routing_id': fields.many2one('mrp.routing', 'Routing', help="The list of operations (list of work centers) to produce the finished product. The routing is mainly used to compute work center costs during operations and to plan future loads on work centers based on production planning."),
|
'routing_id': fields.many2one('mrp.routing', 'Routing', help="The list of operations (list of work centers) to produce the finished product. The routing is mainly used to compute work center costs during operations and to plan future loads on work centers based on production planning."),
|
||||||
'product_rounding': fields.float('Product Rounding', help="Rounding applied on the product quantity."),
|
'product_rounding': fields.float('Product Rounding', help="Rounding applied on the product quantity."),
|
||||||
'product_efficiency': fields.float('Manufacturing Efficiency', required=True, help="A factor of 0.9 means a loss of 10% within the production process."),
|
'product_efficiency': fields.float('Manufacturing Efficiency', required=True, help="A factor of 0.9 means a loss of 10% within the production process."),
|
||||||
'property_ids': fields.many2many('mrp.property', string='Properties'),
|
'property_ids': fields.many2many('mrp.property', string='Properties'), #Not used
|
||||||
|
|
||||||
'bom_id': fields.many2one('mrp.bom', 'Parent BoM', ondelete='cascade', select=True, required=True),
|
'bom_id': fields.many2one('mrp.bom', 'Parent BoM', ondelete='cascade', select=True, required=True),
|
||||||
'attribute_value_ids': fields.many2many('product.attribute.value', string='Variants', help="BOM Product Variants needed form apply this line."),
|
'attribute_value_ids': fields.many2many('product.attribute.value', string='Variants', help="BOM Product Variants needed form apply this line."),
|
||||||
|
@ -645,7 +647,7 @@ class mrp_production(osv.osv):
|
||||||
}}
|
}}
|
||||||
bom_obj = self.pool.get('mrp.bom')
|
bom_obj = self.pool.get('mrp.bom')
|
||||||
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
|
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
|
||||||
bom_id = bom_obj._bom_find(cr, uid, product.uom_id and product.uom_id.id, product_id=product.id, properties=[], context=context)
|
bom_id = bom_obj._bom_find(cr, uid, product_id=product.id, properties=[], context=context)
|
||||||
routing_id = False
|
routing_id = False
|
||||||
if bom_id:
|
if bom_id:
|
||||||
bom_point = bom_obj.browse(cr, uid, bom_id, context=context)
|
bom_point = bom_obj.browse(cr, uid, bom_id, context=context)
|
||||||
|
@ -694,7 +696,7 @@ class mrp_production(osv.osv):
|
||||||
bom_point = production.bom_id
|
bom_point = production.bom_id
|
||||||
bom_id = production.bom_id.id
|
bom_id = production.bom_id.id
|
||||||
if not bom_point:
|
if not bom_point:
|
||||||
bom_id = bom_obj._bom_find(cr, uid, production.product_uom.id, product_id=production.product_id.id, properties=properties, context=context)
|
bom_id = bom_obj._bom_find(cr, uid, product_id=production.product_id.id, properties=properties, context=context)
|
||||||
if bom_id:
|
if bom_id:
|
||||||
bom_point = bom_obj.browse(cr, uid, bom_id)
|
bom_point = bom_obj.browse(cr, uid, bom_id)
|
||||||
routing_id = bom_point.routing_id.id or False
|
routing_id = bom_point.routing_id.id or False
|
||||||
|
|
|
@ -62,8 +62,8 @@ class procurement_order(osv.osv):
|
||||||
"""
|
"""
|
||||||
for procurement in self.browse(cr, uid, ids, context=context):
|
for procurement in self.browse(cr, uid, ids, context=context):
|
||||||
properties = [x.id for x in procurement.property_ids]
|
properties = [x.id for x in procurement.property_ids]
|
||||||
bom_id = self.pool.get('mrp.bom')._bom_find(cr, uid, procurement.product_uom.id,
|
bom_id = self.pool.get('mrp.bom')._bom_find(cr, uid, product_id=procurement.product_id.id,
|
||||||
product_id=procurement.product_id.id, properties=properties, context=context)
|
properties=properties, context=context)
|
||||||
if not bom_id:
|
if not bom_id:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
@ -84,8 +84,8 @@ class procurement_order(osv.osv):
|
||||||
routing_id = procurement.bom_id.routing_id.id
|
routing_id = procurement.bom_id.routing_id.id
|
||||||
else:
|
else:
|
||||||
properties = [x.id for x in procurement.property_ids]
|
properties = [x.id for x in procurement.property_ids]
|
||||||
bom_id = bom_obj._bom_find(cr, uid, procurement.product_uom.id,
|
bom_id = bom_obj._bom_find(cr, uid, product_id=procurement.product_id.id,
|
||||||
product_id=procurement.product_id.id, properties=properties, context=context)
|
properties=properties, context=context)
|
||||||
bom = bom_obj.browse(cr, uid, bom_id, context=context)
|
bom = bom_obj.browse(cr, uid, bom_id, context=context)
|
||||||
routing_id = bom.routing_id.id
|
routing_id = bom.routing_id.id
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,7 @@ class report_custom(report_rml):
|
||||||
|
|
||||||
for product in product_pool.browse(cr, uid, ids, context=context):
|
for product in product_pool.browse(cr, uid, ids, context=context):
|
||||||
product_uom_name = to_xml(product.uom_id.name)
|
product_uom_name = to_xml(product.uom_id.name)
|
||||||
bom_id = bom_pool._bom_find(cr, uid, product.uom_id.id, product_id=product.id, context=context)
|
bom_id = bom_pool._bom_find(cr, uid, product_id=product.id, context=context)
|
||||||
title = "<title>%s</title>" %(_("Cost Structure"))
|
title = "<title>%s</title>" %(_("Cost Structure"))
|
||||||
title += "<title>%s</title>" % (to_xml(product.name))
|
title += "<title>%s</title>" % (to_xml(product.name))
|
||||||
xml += "<lines style='header'>" + title + prod_header + "</lines>"
|
xml += "<lines style='header'>" + title + prod_header + "</lines>"
|
||||||
|
|
|
@ -78,7 +78,7 @@ class change_production_qty(osv.osv_memory):
|
||||||
bom_point = prod.bom_id
|
bom_point = prod.bom_id
|
||||||
bom_id = prod.bom_id.id
|
bom_id = prod.bom_id.id
|
||||||
if not bom_point:
|
if not bom_point:
|
||||||
bom_id = bom_obj._bom_find(cr, uid, prod.product_uom.id, product_id=prod.product_id.id, context=context)
|
bom_id = bom_obj._bom_find(cr, uid, product_id=prod.product_id.id, context=context)
|
||||||
if not bom_id:
|
if not bom_id:
|
||||||
raise osv.except_osv(_('Error!'), _("Cannot find bill of material for this product."))
|
raise osv.except_osv(_('Error!'), _("Cannot find bill of material for this product."))
|
||||||
prod_obj.write(cr, uid, [prod.id], {'bom_id': bom_id})
|
prod_obj.write(cr, uid, [prod.id], {'bom_id': bom_id})
|
||||||
|
|
|
@ -62,7 +62,7 @@ class stock_move_consume(osv.osv_memory):
|
||||||
for data in self.browse(cr, uid, ids, context=context):
|
for data in self.browse(cr, uid, ids, context=context):
|
||||||
if move_ids and move_ids[0]:
|
if move_ids and move_ids[0]:
|
||||||
move = move_obj.browse(cr, uid, move_ids[0], context=context)
|
move = move_obj.browse(cr, uid, move_ids[0], context=context)
|
||||||
qty = uom_obj._compute_qty(cr, uid, data['product_uom'].id, data.product_qty, data.product_id.uom_id.id, round=False)
|
qty = uom_obj._compute_qty(cr, uid, data['product_uom'].id, data.product_qty, data.product_id.uom_id.id)
|
||||||
move_obj.action_consume(cr, uid, move_ids,
|
move_obj.action_consume(cr, uid, move_ids,
|
||||||
qty, data.location_id.id, restrict_lot_id=data.restrict_lot_id.id,
|
qty, data.location_id.id, restrict_lot_id=data.restrict_lot_id.id,
|
||||||
context=context)
|
context=context)
|
||||||
|
|
|
@ -123,7 +123,6 @@ class mrp_production_workcenter_line(osv.osv):
|
||||||
else:
|
else:
|
||||||
open_count = self.search_count(cr,uid,[('production_id','=',prod_obj.id), ('state', '!=', 'done')])
|
open_count = self.search_count(cr,uid,[('production_id','=',prod_obj.id), ('state', '!=', 'done')])
|
||||||
flag = not bool(open_count)
|
flag = not bool(open_count)
|
||||||
|
|
||||||
if flag:
|
if flag:
|
||||||
for production in prod_obj_pool.browse(cr, uid, [prod_obj.id], context= None):
|
for production in prod_obj_pool.browse(cr, uid, [prod_obj.id], context= None):
|
||||||
if production.move_lines or production.move_created_ids:
|
if production.move_lines or production.move_created_ids:
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
order = self.browse(cr, uid, ref("mrp.mrp_production_1"), context=context)
|
order = self.browse(cr, uid, ref("mrp.mrp_production_1"), context=context)
|
||||||
order.workcenter_lines[0].signal_workflow('button_cancel')
|
order.workcenter_lines[0].signal_workflow('button_cancel')
|
||||||
-
|
-
|
||||||
I reset first work operation and start after resolving techninal fault of work center.
|
I reset first work operation and start after resolving technical fault of work center.
|
||||||
-
|
-
|
||||||
!python {model: mrp.production}: |
|
!python {model: mrp.production}: |
|
||||||
order = self.browse(cr, uid, ref("mrp.mrp_production_1"), context=context)
|
order = self.browse(cr, uid, ref("mrp.mrp_production_1"), context=context)
|
||||||
|
|
|
@ -31,17 +31,22 @@
|
||||||
This is the module for computing Procurements.
|
This is the module for computing Procurements.
|
||||||
==============================================
|
==============================================
|
||||||
|
|
||||||
In the MRP process, procurements orders are created to launch manufacturing
|
This procurement module only depends on the product module and is not useful
|
||||||
orders, purchase orders, stock allocations. Procurement orders are
|
on itself. Procurements represent needs that need to be solved by a procurement
|
||||||
generated automatically by the system and unless there is a problem, the
|
rule. When a procurement is created, it is confirmed. When a rule is found,
|
||||||
user will not be notified. In case of problems, the system will raise some
|
it will be put in running state. After, it will check if what needed to be done
|
||||||
procurement exceptions to inform the user about blocking problems that need
|
for the rule has been executed. Then it will go to the done state. A procurement
|
||||||
to be resolved manually (like, missing BoM structure or missing supplier).
|
can also go into exception, for example when it can not find a rule and it can be cancelled.
|
||||||
|
|
||||||
The procurement order will schedule a proposal for automatic procurement
|
The mechanism will be extended by several modules. The procurement rule of stock will
|
||||||
for the product which needs replenishment. This procurement will start a
|
create a move and the procurement will be fulfilled when the move is done.
|
||||||
task, either a purchase order form for the supplier, or a production order
|
The procurement rule of sale_service will create a task. Those of purchase or
|
||||||
depending on the product's configuration.
|
mrp will create a purchase order or a manufacturing order.
|
||||||
|
|
||||||
|
The scheduler will check if it can assign a rule to confirmed procurements and if
|
||||||
|
it can put running procurements to done.
|
||||||
|
|
||||||
|
Procurements in exception should be checked manually and can be re-run.
|
||||||
""",
|
""",
|
||||||
'data': [
|
'data': [
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
|
|
|
@ -27,10 +27,8 @@
|
||||||
"category" : "Generic Modules/Inventory Control",
|
"category" : "Generic Modules/Inventory Control",
|
||||||
"description": """
|
"description": """
|
||||||
Product extension. This module adds:
|
Product extension. This module adds:
|
||||||
* Last purchase order for each product supplier
|
* Computes standard price from the BoM of the product with a button on the product variant based
|
||||||
* New functional field: Available stock (real+outgoing stock)
|
on the materials in the BoM and the work centers. It can create the necessary accounting entries when necessary.
|
||||||
* Computes standard price from the BoM of the product (optional for each product)
|
|
||||||
* Standard price is shown in the BoM and it can be computed with a wizard
|
|
||||||
""",
|
""",
|
||||||
"init_xml" : [],
|
"init_xml" : [],
|
||||||
"demo_xml" : [],
|
"demo_xml" : [],
|
||||||
|
|
|
@ -36,7 +36,7 @@ class product_product(osv.osv):
|
||||||
testdict = {}
|
testdict = {}
|
||||||
for prod_id in ids:
|
for prod_id in ids:
|
||||||
bom_obj = self.pool.get('mrp.bom')
|
bom_obj = self.pool.get('mrp.bom')
|
||||||
bom_id = bom_obj._bom_find(cr, uid, False, product_id = prod_id, context=context)
|
bom_id = bom_obj._bom_find(cr, uid, product_id = prod_id, context=context)
|
||||||
if bom_id:
|
if bom_id:
|
||||||
# In recursive mode, it will first compute the prices of child boms
|
# In recursive mode, it will first compute the prices of child boms
|
||||||
if recursive:
|
if recursive:
|
||||||
|
|
|
@ -18,9 +18,3 @@
|
||||||
name: Gate B
|
name: Gate B
|
||||||
usage: internal
|
usage: internal
|
||||||
location_id: location_dispatch_zone
|
location_id: location_dispatch_zone
|
||||||
-
|
|
||||||
!record {model: stock.location.path, id: push_pick}:
|
|
||||||
name: Pick List
|
|
||||||
location_from_id: stock.stock_location_output
|
|
||||||
location_dest_id: location_pack_zone
|
|
||||||
picking_type_id: stock.picking_type_internal
|
|
||||||
|
|
Loading…
Reference in New Issue