diff --git a/addons/account_anglo_saxon/test/anglo_saxon.yml b/addons/account_anglo_saxon/test/anglo_saxon.yml index 32f5fd12dee..6733f8794a0 100644 --- a/addons/account_anglo_saxon/test/anglo_saxon.yml +++ b/addons/account_anglo_saxon/test/anglo_saxon.yml @@ -198,8 +198,8 @@ product_uom_qty: 1.0 product_uom: product.product_uom_unit location_dest_id: stock.stock_location_customers - invoice_state: 2binvoiced move_type: direct + invoice_state: 2binvoiced picking_type_id: stock.picking_type_out - I need to check the availability of the product, So I make my picking order for processing later. diff --git a/addons/account_anglo_saxon/test/anglo_saxon_avg_fifo.yml b/addons/account_anglo_saxon/test/anglo_saxon_avg_fifo.yml index daeefc09730..5762ee128d1 100644 --- a/addons/account_anglo_saxon/test/anglo_saxon_avg_fifo.yml +++ b/addons/account_anglo_saxon/test/anglo_saxon_avg_fifo.yml @@ -200,7 +200,7 @@ product_id: product_fifo_anglo_saxon product_uom_qty: 1.0 location_dest_id: stock.stock_location_customers - invoice_state: 2binvoiced + invoice_state: 2binvoiced move_type: direct picking_type_id: stock.picking_type_out - diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 9e6afe3cc2c..850f8c22eda 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -230,7 +230,7 @@ class mrp_bom(osv.osv): } _order = "sequence" - def _bom_find(self, cr, uid, product_uom, product_tmpl_id=None, product_id=None, properties=None): + def _bom_find(self, cr, uid, product_uom, product_tmpl_id=None, product_id=None, properties=None, context=None): """ Finds BoM for particular product and product uom. @param product_tmpl_id: Selected product. @param product_uom: Unit of measure of a product. @@ -241,7 +241,7 @@ class mrp_bom(osv.osv): properties = [] if product_id: if not product_tmpl_id: - product_tmpl_id = self.pool['product.product'].browse(cr, uid, product_id).product_tmpl_id.id + product_tmpl_id = self.pool['product.product'].browse(cr, uid, product_id, context=context).product_tmpl_id.id domain = [ '|', ('product_id', '=', product_id), @@ -255,21 +255,21 @@ class mrp_bom(osv.osv): # neither product nor template, makes no sense to search return False if product_uom: - domain += [('product_uom','=',product_uom)] + domain += [('product_uom','=',product_uom)] domain = domain + [ '|', ('date_start', '=', False), ('date_start', '<=', 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 ids = self.search(cr, uid, domain, order='product_id') 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 return False - def _bom_explode(self, cr, uid, bom, product, factor, properties=None, level=0, routing_id=False, previous_products=None, master_bom=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. @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 of product UoM. + @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 @@ -277,6 +277,7 @@ class mrp_bom(osv.osv): @return: result: List of dictionaries containing product details. result2: List of dictionaries containing Work Center details. """ + uom_obj = self.pool.get("product.uom") routing_obj = self.pool.get('mrp.routing') all_prod = [] + (previous_products or []) master_bom = master_bom or bom @@ -312,9 +313,6 @@ class mrp_bom(osv.osv): if bom_line_id.date_start and bom_line_id.date_start > time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) or \ bom_line_id.date_stop and bom_line_id.date_stop > time.strftime(DEFAULT_SERVER_DATETIME_FORMAT): continue - # check properties - if set(map(int,bom_line_id.property_ids or [])) - set(properties or []): - continue # all bom_line_id variant values must be in the product if bom_line_id.attribute_value_ids: if not product or (set(map(int,bom_line_id.attribute_value_ids or [])) - set(map(int,product.attribute_value_ids))): @@ -322,27 +320,32 @@ class mrp_bom(osv.osv): if bom_line_id.product_id.id in all_prod: 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])) - all_prod.append(bom_line_id.product_id.id) - - if bom_line_id.type != "phantom": + + 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) + + #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"): result.append({ 'name': bom_line_id.product_id.name, 'product_id': bom_line_id.product_id.id, - 'product_qty': _factor(bom_line_id.product_qty * factor, bom_line_id.product_efficiency, bom_line_id.product_rounding), + 'product_qty': quantity, 'product_uom': bom_line_id.product_uom.id, - 'product_uos_qty': bom_line_id.product_uos and bom_line_id.product_uos_qty * factor or False, + 'product_uos_qty': bom_line_id.product_uos and _factor(bom_line_id.product_uos_qty * factor, bom_line_id.product_efficiency, bom_line_id.product_rounding) or False, 'product_uos': bom_line_id.product_uos and bom_line_id.product_uos.id or False, }) + elif bom_id: + all_prod.append(bom_line_id.product_id.id) + bom2 = self.browse(cr, uid, bom_id, context=context) + # We need to convert to units/UoM of chosen BoM + factor2 = uom_obj._compute_qty(cr, uid, bom_line_id.product_uom.id, quantity, bom2.product_uom.id) + quantity2 = factor2 / bom2.product_qty + res = self._bom_explode(cr, uid, bom2, bom_line_id.product_id, quantity2, + properties=properties, level=level + 10, previous_products=all_prod, master_bom=master_bom, context=context) + result = result + res[0] + result2 = result2 + res[1] else: - bom_id = self._bom_find(cr, uid, bom_line_id.product_uom.id, product_id=bom_line_id.product_id.id, properties=properties) - if bom_id: - bom2 = self.browse(cr, uid, bom_id) - res = self._bom_explode(cr, uid, bom2, bom_line_id.product_id, factor, - properties=properties, level=level + 10, previous_products=all_prod, master_bom=master_bom) - result = result + res[0] - result2 = result2 + res[1] - else: - raise osv.except_osv(_('Invalid Action!'), _('BoM "%s" contains a phantom BoM line but the product "%s" don\'t have any BoM defined.') % (master_bom.name,bom_line_id.product_id.name_get()[0][1])) + raise osv.except_osv(_('Invalid Action!'), _('BoM "%s" contains a phantom BoM line but the product "%s" don\'t have any BoM defined.') % (master_bom.name,bom_line_id.product_id.name_get()[0][1])) return result, result2 @@ -642,7 +645,7 @@ class mrp_production(osv.osv): }} bom_obj = self.pool.get('mrp.bom') 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=[]) + bom_id = bom_obj._bom_find(cr, uid, product.uom_id and product.uom_id.id, product_id=product.id, properties=[], context=context) routing_id = False if bom_id: bom_point = bom_obj.browse(cr, uid, bom_id, context=context) @@ -691,7 +694,7 @@ class mrp_production(osv.osv): bom_point = production.bom_id bom_id = production.bom_id.id if not bom_point: - bom_id = bom_obj._bom_find(cr, uid, production.product_uom.id, product_id=production.product_id.id, properties=properties) + bom_id = bom_obj._bom_find(cr, uid, production.product_uom.id, product_id=production.product_id.id, properties=properties, context=context) if bom_id: bom_point = bom_obj.browse(cr, uid, bom_id) routing_id = bom_point.routing_id.id or False @@ -703,7 +706,7 @@ class mrp_production(osv.osv): # get components and workcenter_lines from BoM structure factor = uom_obj._compute_qty(cr, uid, production.product_uom.id, production.product_qty, bom_point.product_uom.id) # product_lines, workcenter_lines - results, results2 = bom_obj._bom_explode(cr, uid, bom_point, production.product_id, factor / bom_point.product_qty, properties, routing_id=production.routing_id.id) + results, results2 = bom_obj._bom_explode(cr, uid, bom_point, production.product_id, factor / bom_point.product_qty, properties, routing_id=production.routing_id.id, context=context) # reset product_lines in production order for line in results: line['production_id'] = production.id @@ -1063,15 +1066,32 @@ class mrp_production(osv.osv): ''' When the routing gives a different location than the raw material location of the production order, we should create an extra move from the raw material location to the location of the routing, which - precedes the consumption line (chained) + precedes the consumption line (chained). The picking type depends on the warehouse in which this happens + and the type of locations. ''' + loc_obj = self.pool.get("stock.location") stock_move = self.pool.get('stock.move') + type_obj = self.pool.get('stock.picking.type') + # Need to search for a picking type + move = stock_move.browse(cr, uid, move_id, context=context) + code = stock_move.get_code_from_locs(cr, uid, move, context=context) + if code == 'outgoing': + check_loc_id = source_location_id + else: + check_loc_id = dest_location_id + check_loc = loc_obj.browse(cr, uid, check_loc_id, context=context) + wh = loc_obj.get_warehouse(cr, uid, check_loc, context=context) + domain = [('code', '=', code)] + if wh: + domain += [('warehouse_id', '=', wh)] + types = type_obj.search(cr, uid, domain, context=context) move = stock_move.copy(cr, uid, move_id, default = { 'location_id': source_location_id, 'location_dest_id': dest_location_id, 'procure_method': self._get_raw_material_procure_method(cr, uid, product, context=context), 'raw_material_production_id': False, 'move_dest_id': move_id, + 'picking_type_id': types and types[0] or False, }, context=context) return move @@ -1109,6 +1129,7 @@ class mrp_production(osv.osv): if prev_move: prev_move = self._create_previous_move(cr, uid, move_id, product, prod_location_id, source_location_id, context=context) + stock_move.action_confirm(cr, uid, [prev_move], context=context) return move_id def _make_production_consume_line(self, cr, uid, line, context=None): diff --git a/addons/mrp/procurement.py b/addons/mrp/procurement.py index 06eacc6a1a2..ec175273d10 100644 --- a/addons/mrp/procurement.py +++ b/addons/mrp/procurement.py @@ -63,7 +63,7 @@ class procurement_order(osv.osv): for procurement in self.browse(cr, uid, ids, context=context): properties = [x.id for x in procurement.property_ids] bom_id = self.pool.get('mrp.bom')._bom_find(cr, uid, procurement.product_uom.id, - product_id=procurement.product_id.id, properties=properties) + product_id=procurement.product_id.id, properties=properties, context=context) if not bom_id: return False return True @@ -85,7 +85,7 @@ class procurement_order(osv.osv): else: properties = [x.id for x in procurement.property_ids] bom_id = bom_obj._bom_find(cr, uid, procurement.product_uom.id, - product_id=procurement.product_id.id, properties=properties) + product_id=procurement.product_id.id, properties=properties, context=context) bom = bom_obj.browse(cr, uid, bom_id, context=context) routing_id = bom.routing_id.id diff --git a/addons/mrp/report/bom_structure.py b/addons/mrp/report/bom_structure.py index 1b286feac46..c8a3132a679 100644 --- a/addons/mrp/report/bom_structure.py +++ b/addons/mrp/report/bom_structure.py @@ -59,10 +59,10 @@ class bom_structure(report_sxw.rml_parse): return children -class report_lunchorder(osv.AbstractModel): +class report_mrpbomstructure(osv.AbstractModel): _name = 'report.mrp.report_mrpbomstructure' _inherit = 'report.abstract_report' - _template = 'mpr.report_mrpbomstructure' + _template = 'mrp.report_mrpbomstructure' _wrapped_report_class = bom_structure # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/mrp/report/price.py b/addons/mrp/report/price.py index 0071784eed4..9e818001d15 100644 --- a/addons/mrp/report/price.py +++ b/addons/mrp/report/price.py @@ -144,7 +144,7 @@ class report_custom(report_rml): for product in product_pool.browse(cr, uid, ids, context=context): 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) + bom_id = bom_pool._bom_find(cr, uid, product.uom_id.id, product_id=product.id, context=context) title = "