diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 5f84cdaf730..bc5b7608eec 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 @@ -312,9 +312,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))): @@ -323,26 +320,25 @@ 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) - - quantity = _factor(bom_line_id.product_qty * factor, bom_line_id.product_efficiency, bom_line_id.product_rounding) - bom2 = None - 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) - if bom_line_id.type != "phantom" and (not bom2 or bom2.type != "phantom"): + 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': quantity, + 'product_qty': bom_line_id.product_qty * factor, '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': bom_line_id.product_uos and bom_line_id.product_uos.id or False, }) - elif bom2: + elif bom_id: + bom2 = self.browse(cr, uid, bom_id, context=context) + quantity = _factor(bom_line_id.product_qty * factor, bom_line_id.product_efficiency, bom_line_id.product_rounding) res = self._bom_explode(cr, uid, bom2, bom_line_id.product_id, quantity, - properties=properties, level=level + 10, previous_products=all_prod, master_bom=master_bom) + properties=properties, level=level + 10, previous_products=all_prod, master_bom=master_bom, context=context) result = result + res[0] result2 = result2 + res[1] else: @@ -646,7 +642,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) @@ -695,7 +691,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 @@ -707,7 +703,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,9 +1059,6 @@ class mrp_production(osv.osv): return "make_to_order" return "make_to_stock" - - - def _create_previous_move(self, cr, uid, move_id, product, source_location_id, dest_location_id, context=None): ''' When the routing gives a different location than the raw material location of the production order, @@ -1077,17 +1070,15 @@ class mrp_production(osv.osv): stock_move = self.pool.get('stock.move') type_obj = self.pool.get('stock.picking.type') # Need to search for a picking type - src_loc = loc_obj.browse(cr, uid, source_location_id, context=context) - dest_loc = loc_obj.browse(cr, uid, dest_location_id, context=context) - code = 'internal' - check_loc = dest_loc - if src_loc.usage == 'internal' and dest_loc.usage != 'internal': - code = 'outgoing' - check_loc = src_loc - if src_loc.usage != 'internal' and dest_loc.usage == 'internal': - code = 'incoming' + 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)] + domain = [('code', '=', code)] if wh: domain += [('warehouse_id', '=', wh)] types = type_obj.search(cr, uid, domain, context=context) 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/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 = "%s" %(_("Cost Structure")) title += "%s" % (to_xml(product.name)) xml += "" + title + prod_header + "" @@ -168,7 +168,7 @@ class report_custom(report_rml): else: bom = bom_pool.browse(cr, uid, bom_id, context=context) factor = number * product.uom_id.factor / bom.product_uom.factor - sub_boms = bom_pool._bom_explode(cr, uid, bom, product, factor / bom.product_qty) + sub_boms = bom_pool._bom_explode(cr, uid, bom, product, factor / bom.product_qty, context=context) total = 0 total_strd = 0 parent_bom = { diff --git a/addons/mrp/stock.py b/addons/mrp/stock.py index fcd2ae66cef..f472abe4b71 100644 --- a/addons/mrp/stock.py +++ b/addons/mrp/stock.py @@ -73,7 +73,7 @@ class StockMove(osv.osv): if bis: factor = move.product_qty bom_point = bom_obj.browse(cr, SUPERUSER_ID, bis[0], context=context) - res = bom_obj._bom_explode(cr, SUPERUSER_ID, bom_point, move.product_id, factor, []) + res = bom_obj._bom_explode(cr, SUPERUSER_ID, bom_point, move.product_id, factor, [], context=context) state = 'confirmed' if move.state == 'assigned': diff --git a/addons/mrp/wizard/change_production_qty.py b/addons/mrp/wizard/change_production_qty.py index 6b1c9aaf7e8..44eed63d029 100644 --- a/addons/mrp/wizard/change_production_qty.py +++ b/addons/mrp/wizard/change_production_qty.py @@ -78,7 +78,7 @@ class change_production_qty(osv.osv_memory): bom_point = prod.bom_id bom_id = prod.bom_id.id if not bom_point: - bom_id = bom_obj._bom_find(cr, uid, prod.product_uom.id, product_id=prod.product_id.id) + bom_id = bom_obj._bom_find(cr, uid, prod.product_uom.id, product_id=prod.product_id.id, context=context) if not bom_id: raise osv.except_osv(_('Error!'), _("Cannot find bill of material for this product.")) prod_obj.write(cr, uid, [prod.id], {'bom_id': bom_id}) @@ -89,7 +89,7 @@ class change_production_qty(osv.osv_memory): factor = prod.product_qty * prod.product_uom.factor / bom_point.product_uom.factor product_details, workcenter_details = \ - bom_obj._bom_explode(cr, uid, bom_point, prod.product_id, factor / bom_point.product_qty, []) + bom_obj._bom_explode(cr, uid, bom_point, prod.product_id, factor / bom_point.product_qty, [], context=context) for r in product_details: if r['product_id'] == move.product_id.id: move_obj.write(cr, uid, [move.id], {'product_uom_qty': r['product_qty']}) diff --git a/addons/product/product.py b/addons/product/product.py index 009377c7221..cc8d1affb3a 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -1190,46 +1190,7 @@ class product_supplierinfo(osv.osv): 'delay': 1, 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'product.supplierinfo', context=c), } - def price_get(self, cr, uid, supplier_ids, product_id, product_qty=1, context=None): - """ - Calculate price from supplier pricelist. - @param supplier_ids: Ids of res.partner object. - @param product_id: Id of product. - @param product_qty: specify quantity to purchase. - """ - if type(supplier_ids) in (int,long,): - supplier_ids = [supplier_ids] - res = {} - product_pool = self.pool.get('product.product') - partner_pool = self.pool.get('res.partner') - pricelist_pool = self.pool.get('product.pricelist') - currency_pool = self.pool.get('res.currency') - currency_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id - # Compute price from standard price of product - product_price = product_pool.price_get(cr, uid, [product_id], 'standard_price', context=context)[product_id] - product = product_pool.browse(cr, uid, product_id, context=context) - for supplier in partner_pool.browse(cr, uid, supplier_ids, context=context): - price = product_price - # Compute price from Purchase pricelist of supplier - #FIXME: property_product_pricelist_purchase is defined in purchase - pricelist_id = supplier.property_product_pricelist_purchase.id - if pricelist_id: - price = pricelist_pool.price_get(cr, uid, [pricelist_id], product_id, product_qty, context=context).setdefault(pricelist_id, 0) - price = currency_pool.compute(cr, uid, pricelist_pool.browse(cr, uid, pricelist_id).currency_id.id, currency_id, price) - # Compute price from supplier pricelist which are in Supplier Information - supplier_info_ids = self.search(cr, uid, [('name','=',supplier.id),('product_tmpl_id','=',product.product_tmpl_id.id)]) - if supplier_info_ids: - cr.execute('SELECT * ' \ - 'FROM pricelist_partnerinfo ' \ - 'WHERE suppinfo_id IN %s' \ - 'AND min_quantity <= %s ' \ - 'ORDER BY min_quantity DESC LIMIT 1', (tuple(supplier_info_ids),product_qty,)) - res2 = cr.dictfetchone() - if res2: - price = res2['price'] - res[supplier.id] = price - return res _order = 'sequence' diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 69535f703bb..be2803261e7 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -673,10 +673,9 @@ class purchase_order(osv.osv): return False def wkf_action_cancel(self, cr, uid, ids, context=None): - self.write(cr, uid, ids, {'state': 'cancel'}) + self.write(cr, uid, ids, {'state': 'cancel'}, context=context) self.set_order_line_status(cr, uid, ids, 'cancel', context=context) - def action_cancel(self, cr, uid, ids, context=None): for purchase in self.browse(cr, uid, ids, context=context): for pick in purchase.picking_ids: diff --git a/addons/purchase/stock.py b/addons/purchase/stock.py index c1ccdd998d5..320e35c2ffa 100644 --- a/addons/purchase/stock.py +++ b/addons/purchase/stock.py @@ -71,10 +71,10 @@ class stock_move(osv.osv): return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id else: partner = move.picking_id and move.picking_id.partner_id or False - if partner: - if partner.property_product_pricelist_purchase and move.location_id.usage != 'internal' and move.location_dest_id.usage == 'internal': - currency = partner.property_product_pricelist_purchase.currency_id.id - return partner, uid, currency + code = self.get_code_from_locs(cr, uid, move, context=context) + if partner and partner.property_product_pricelist_purchase and code == 'incoming': + currency = partner.property_product_pricelist_purchase.currency_id.id + return partner, uid, currency return super(stock_move, self)._get_master_data(cr, uid, move, company, context=context) @@ -91,7 +91,8 @@ class stock_move(osv.osv): """ Attribute price to move, important in inter-company moves or receipts with only one partner """ - if not move.purchase_line_id and move.location_id.usage != 'internal' and move.location_dest_id.usage == 'internal' and not move.price_unit: + code = self.get_code_from_locs(cr, uid, move, context=context) + if not move.purchase_line_id and code == 'incoming' and not move.price_unit: partner = move.picking_id and move.picking_id.partner_id or False price = False # If partner given, search price in its purchase pricelist @@ -104,12 +105,10 @@ class stock_move(osv.osv): 'date': move.date, })[pricelist] if price: - self.write(cr, uid, [move.id], {'price_unit': price}, context=context) - return True + return self.write(cr, uid, [move.id], {'price_unit': price}, context=context) super(stock_move, self).attribute_price(cr, uid, move, context=context) - class stock_picking(osv.osv): _inherit = 'stock.picking' @@ -167,7 +166,6 @@ class stock_warehouse(osv.osv): 'route_id': buy_route_id, 'action': 'buy', 'picking_type_id': warehouse.in_type_id.id, - 'propagate': False, 'warehouse_id': warehouse.id, } diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py index 7fef11b7472..0d0a147e324 100644 --- a/addons/sale_stock/sale_stock.py +++ b/addons/sale_stock/sale_stock.py @@ -288,6 +288,7 @@ class sale_order_line(osv.osv): product_uom_obj = self.pool.get('product.uom') product_obj = self.pool.get('product.product') warning = {} + #UoM False due to hack which makes sure uom changes price, ... in product_id_change res = self.product_id_change(cr, uid, ids, pricelist, product, qty=qty, uom=False, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id, lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context) diff --git a/addons/stock/product_view.xml b/addons/stock/product_view.xml index f889f09048c..e3612010a80 100644 --- a/addons/stock/product_view.xml +++ b/addons/stock/product_view.xml @@ -84,8 +84,10 @@ - - + + + + @@ -249,21 +251,5 @@ - - - - - - tree_but_open - stock.location - Products - - diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 9b9d8a5c0d9..815caeb3bb9 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2032,7 +2032,6 @@ class stock_move(osv.osv): price = move.product_id.standard_price self.write(cr, uid, [move.id], {'price_unit': price}) - def action_confirm(self, cr, uid, ids, context=None): """ Confirms stock move or put it in waiting if it's linked to another move. @return: List of ids. @@ -2443,6 +2442,21 @@ class stock_move(osv.osv): return self.action_confirm(cr, uid, [new_move], context=context)[0] + def get_code_from_locs(self, cr, uid, move, context=None): + """ + Returns the code the picking type should have. This can easily be used + to check if a move is internal or not + """ + code = 'internal' + src_loc = move.location_id + dest_loc = move.location_dest_id + if src_loc.usage == 'internal' and dest_loc.usage != 'internal': + code = 'outgoing' + if src_loc.usage != 'internal' and dest_loc.usage == 'internal': + code = 'incoming' + return code + + class stock_inventory(osv.osv): _name = "stock.inventory" _description = "Inventory" @@ -3531,7 +3545,6 @@ class stock_location_path(osv.osv): 'push_rule_id': rule.id, 'warehouse_id': rule.warehouse_id and rule.warehouse_id.id or False, } - def _apply(self, cr, uid, rule, move, context=None): move_obj = self.pool.get('stock.move') diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index 6b72f9976df..2f154b03d92 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -306,6 +306,14 @@ stock.quant + + stock.location.form stock.location @@ -316,6 +324,11 @@ class="oe_stat_button" icon="fa-building-o" name="%(location_open_quants)d" type="action" context="{'search_default_internal_loc': 1}"/> +