From 5b479e6114b618b2f5c4f78873004a29de9821d2 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 21 Apr 2015 14:50:18 +0200 Subject: [PATCH] [FIX] mrp: bom properties The bom related to the product in a sale line order must be filtered by the function _bom_find. If two boms can be applied on a product, the bom with the smallest sequence is applied. opw:632558 --- addons/mrp/mrp.py | 10 +++++----- addons/mrp/mrp_demo.xml | 2 +- addons/mrp/stock.py | 37 +++++++++++++------------------------ addons/sale_mrp/sale_mrp.py | 10 ++++++++++ 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 8c7673a7e3d..fa6f189a262 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -232,16 +232,16 @@ class mrp_bom(osv.osv): domain = domain + [ '|', ('date_start', '=', False), ('date_start', '<=', time.strftime(DEFAULT_SERVER_DATE_FORMAT)), '|', ('date_stop', '=', False), ('date_stop', '>=', time.strftime(DEFAULT_SERVER_DATE_FORMAT))] # order to prioritize bom with product_id over the one without - ids = self.search(cr, uid, domain, order='product_id', context=context) + ids = self.search(cr, uid, domain, order='sequence, product_id', context=context) # Search a BoM which has all properties specified, or if you can not find one, you could - # pass a BoM without any properties + # pass a BoM without any properties with the smallest sequence bom_empty_prop = False for bom in self.pool.get('mrp.bom').browse(cr, uid, ids, context=context): if not set(map(int, bom.property_ids or [])) - set(properties or []): - if properties and not bom.property_ids: - bom_empty_prop = bom.id - else: + if not properties or bom.property_ids: return bom.id + elif not bom_empty_prop: + bom_empty_prop = 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): diff --git a/addons/mrp/mrp_demo.xml b/addons/mrp/mrp_demo.xml index 3af8d7d9c0e..5446d0a6ec0 100644 --- a/addons/mrp/mrp_demo.xml +++ b/addons/mrp/mrp_demo.xml @@ -503,7 +503,7 @@ PC Assemble + 512MB RAM - 5 + 4 phantom diff --git a/addons/mrp/stock.py b/addons/mrp/stock.py index 8aba4fdac38..ed6c5c4049c 100644 --- a/addons/mrp/stock.py +++ b/addons/mrp/stock.py @@ -43,39 +43,27 @@ class StockMove(osv.osv): if move.raw_material_production_id and move.location_dest_id.usage == 'production' and move.raw_material_production_id.product_id.track_production and not move.consumed_for: raise osv.except_osv(_('Warning!'), _("Because the product %s requires it, you must assign a serial number to your raw material %s to proceed further in your production. Please use the 'Produce' button to do so.") % (move.raw_material_production_id.product_id.name, move.product_id.name)) - def _check_phantom_bom(self, cr, uid, move, context=None): - """check if product associated to move has a phantom bom - return list of ids of mrp.bom for that product """ - user_company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id - #doing the search as SUPERUSER because a user with the permission to write on a stock move should be able to explode it - #without giving him the right to read the boms. - domain = [ - '|', ('product_id', '=', move.product_id.id), - '&', ('product_id', '=', False), ('product_tmpl_id.product_variant_ids', '=', move.product_id.id), - ('type', '=', 'phantom'), - '|', ('date_start', '=', False), ('date_start', '<=', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)), - '|', ('date_stop', '=', False), ('date_stop', '>=', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)), - ('company_id', '=', user_company)] - return self.pool.get('mrp.bom').search(cr, SUPERUSER_ID, domain, context=context) - def _action_explode(self, cr, uid, move, context=None): """ Explodes pickings. @param move: Stock moves @return: True """ + if context is None: + context = {} bom_obj = self.pool.get('mrp.bom') move_obj = self.pool.get('stock.move') prod_obj = self.pool.get("product.product") proc_obj = self.pool.get("procurement.order") uom_obj = self.pool.get("product.uom") to_explode_again_ids = [] - processed_ids = [] - bis = self._check_phantom_bom(cr, uid, move, context=context) - if bis: - bom_point = bom_obj.browse(cr, SUPERUSER_ID, bis[0], context=context) + property_ids = context.get('property_ids') or [] + bis = bom_obj._bom_find(cr, SUPERUSER_ID, product_id=move.product_id.id, properties=property_ids) + bom_point = bom_obj.browse(cr, SUPERUSER_ID, bis, context=context) + if bis and bom_point.type == 'phantom': + processed_ids = [] factor = uom_obj._compute_qty(cr, SUPERUSER_ID, move.product_uom.id, move.product_uom_qty, bom_point.product_uom.id) / bom_point.product_qty - res = bom_obj._bom_explode(cr, SUPERUSER_ID, bom_point, move.product_id, factor, [], context=context) - + res = bom_obj._bom_explode(cr, SUPERUSER_ID, bom_point, move.product_id, factor, property_ids, context=context) + for line in res[0]: product = prod_obj.browse(cr, uid, line['product_id'], context=context) if product.type != 'service': @@ -114,7 +102,6 @@ class StockMove(osv.osv): else: proc = proc_obj.create(cr, uid, valdef, context=context) proc_obj.run(cr, uid, [proc], context=context) #could be omitted - #check if new moves needs to be exploded if to_explode_again_ids: @@ -133,8 +120,10 @@ class StockMove(osv.osv): #delete the move with original product which is not relevant anymore move_obj.unlink(cr, SUPERUSER_ID, [move.id], context=context) - #return list of newly created move or the move id otherwise, unless there is no move anymore - return processed_ids or (not bis and [move.id]) or [] + #return list of newly created move + return processed_ids + + return [move.id] def action_confirm(self, cr, uid, ids, context=None): move_ids = [] diff --git a/addons/sale_mrp/sale_mrp.py b/addons/sale_mrp/sale_mrp.py index 082323ad580..acc0db65742 100644 --- a/addons/sale_mrp/sale_mrp.py +++ b/addons/sale_mrp/sale_mrp.py @@ -100,3 +100,13 @@ class stock_move(osv.osv): if res and move.procurement_id and move.procurement_id.property_ids: res['property_ids'] = [(6, 0, [x.id for x in move.procurement_id.property_ids])] return res + + def _action_explode(self, cr, uid, move, context=None): + """ Explodes pickings. + @param move: Stock moves + @return: True + """ + if context is None: + context = {} + property_ids = map(int, move.procurement_id.sale_line_id.property_ids or []) + return super(stock_move, self)._action_explode(cr, uid, move, context=dict(context, property_ids=property_ids))