From ffde17a6030b1fb17d8b29ae7069a17ca21d998e Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Wed, 15 May 2013 14:44:57 +0200 Subject: [PATCH] [IMP] Clean print, clean unused methods, price update according to currency in stock move adjustment bzr revid: jco@openerp.com-20130515124457-irka898ynrgxt279 --- addons/purchase/stock.py | 6 +- addons/purchase/test/fifo_price.yml | 7 +- addons/stock/report/report_stock_move.py | 2 - addons/stock/stock.py | 102 ++----------------- addons/stock/stock_fifo_lifo.py | 93 +---------------- addons/stock/wizard/stock_partial_picking.py | 27 +++-- 6 files changed, 28 insertions(+), 209 deletions(-) diff --git a/addons/purchase/stock.py b/addons/purchase/stock.py index e64c12a2359..ed11e5b7666 100644 --- a/addons/purchase/stock.py +++ b/addons/purchase/stock.py @@ -128,8 +128,10 @@ class stock_partial_picking(osv.osv_memory): # incoming pickings. def _product_cost_for_average_update(self, cr, uid, move): if move.picking_id.purchase_id: - return {'cost': move.purchase_line_id.price_unit, - 'currency': move.picking_id.purchase_id.pricelist_id.currency_id.id} + currency_obj = self.pool.get("res.currency") + new_price = currency_obj.compute(cr, uid, move.picking_id.purchase_id.pricelist_id.currency_id.id, move.company_id.currency_id.id, + move.purchase_line_id.price_unit, round=False) + return {'cost': new_price} return super(stock_partial_picking, self)._product_cost_for_average_update(cr, uid, move) # Redefinition of the new field in order to update the model stock.picking.in in the orm diff --git a/addons/purchase/test/fifo_price.yml b/addons/purchase/test/fifo_price.yml index 918b007b108..9d0b5484c5b 100644 --- a/addons/purchase/test/fifo_price.yml +++ b/addons/purchase/test/fifo_price.yml @@ -172,7 +172,7 @@ version_id: - name: v1.0 items_id: - - name: 20% Discount given by my supplier + - name: First version sequence: 1 price_min_margin: 2 price_max_margin: 5 @@ -186,16 +186,17 @@ !record {model: purchase.order, id: purchase_order_fifo_usd}: partner_id: base.res_partner_3 location_id: stock.stock_location_stock + pricelist_id: supplier_pricelist_usd order_line: - product_id: product_fifo_icecream product_qty: 30.0 product_uom: product.product_uom_kgm - price_unit: 116.88 + price_unit: 150.0 name: 'FIFO Ice Cream' - product_id: product_fifo_icecream product_qty: 10.0 product_uom: product.product_uom_kgm - price_unit: 116.877045348 + price_unit: 150.0 - I confirm the purchase order in USD - diff --git a/addons/stock/report/report_stock_move.py b/addons/stock/report/report_stock_move.py index 2b93bb416ba..1a4f7105753 100644 --- a/addons/stock/report/report_stock_move.py +++ b/addons/stock/report/report_stock_move.py @@ -52,8 +52,6 @@ class report_stock_move(osv.osv): 'day_diff1':fields.float('Planned Lead Time (Days)',readonly=True, digits_compute=dp.get_precision('Shipping Delay'), group_operator="avg"), 'day_diff':fields.float('Execution Lead Time (Days)',readonly=True, digits_compute=dp.get_precision('Shipping Delay'), group_operator="avg"), 'stock_journal': fields.many2one('stock.journal','Stock Journal', select=True), - - } diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 6d2f3ad7c97..18e10e8c5e8 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -675,6 +675,7 @@ class stock_picking(osv.osv): ('name_uniq', 'unique(name, company_id)', 'Reference must be unique per Company!'), ] + def action_process(self, cr, uid, ids, context=None): if context is None: context = {} @@ -1225,10 +1226,8 @@ class stock_picking(osv.osv): for pick in self.browse(cr, uid, ids, context=context): new_picking = None complete, too_many, too_few = [], [], [] - move_product_qty, prodlot_ids, product_avail, partial_qty, product_uoms = {}, {}, {}, {}, {} - - move_ids = [x.id for x in pick.move_lines] - #move_obj.price_computation(cr, uid, move_ids, partial_datas, context=context) + move_product_qty, prodlot_ids, partial_qty, product_uoms = {}, {}, {}, {} + for move in pick.move_lines: if move.state in ('done', 'cancel'): @@ -1238,7 +1237,6 @@ class stock_picking(osv.osv): move_product_qty[move.id] = product_qty product_uom = partial_data.get('product_uom',False) product_price = partial_data.get('product_price',0.0) - product_currency = partial_data.get('product_currency',False) prodlot_id = partial_data.get('prodlot_id') prodlot_ids[move.id] = prodlot_id product_uoms[move.id] = product_uom @@ -1272,7 +1270,7 @@ class stock_picking(osv.osv): 'picking_id' : new_picking, 'state': 'assigned', 'move_dest_id': False, - 'price_unit': move.price_unit, + 'price_unit': product_price, 'product_uom': product_uoms[move.id] } prodlot_id = prodlot_ids[move.id] @@ -2687,7 +2685,7 @@ class stock_move(osv.osv): fifo = (cost_method != 'lifo') tuples = product_obj.get_stock_matchings_fifolifo(cr, uid, [product.id], product_qty, fifo, - product_uom, move.company_id.currency_id.id, context=ctx) + product_uom, move.company_id.currency_id.id, context=ctx) #TODO Would be better to use price_currency_id for migration? price_amount = 0.0 amount = 0.0 #Write stock matchings @@ -2740,89 +2738,6 @@ class stock_move(osv.osv): product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price}, context=ctx) product_avail[product.id] -= product_uom_qty - def price_computation(self, cr, uid, ids, partial_datas, context=None): - ''' - This method will update the price of the products according to the stock moves - If multiple stock moves have the same product, it will take into account - the fact that the other was already processed with the product_avail list - ''' - product_obj = self.pool.get('product.product') - currency_obj = self.pool.get('res.currency') - uom_obj = self.pool.get('product.uom') - - product_avail = {} - for move in self.browse(cr, uid, ids, context=context): - partial_data = partial_datas.get('move%s'%(move.id), {}) - product_qty = partial_data.get('product_qty',0.0) - product_uom = partial_data.get('product_uom',False) - product_price = partial_data.get('product_price',0.0) - product_currency = partial_data.get('product_currency',False) - product = product_obj.browse(cr, uid, move.product_id.id, context=context) - - #Check we are using the right company - company_id = move.company_id.id - ctx = context.copy() - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - if company_id != user.company_id.id: - ctx['force_company'] = move.company_id.id - product = product_obj.browse(cr, uid, move.product_id.id, context=ctx) - cost_method = product.cost_method - #Check if cost_method used needs update - avg_in_update = (move.picking_id.type == 'in') and (cost_method == 'average') - avg_out_update = (move.picking_id.type == 'out') and (cost_method == 'average') and (move.move_returned_from) - if avg_in_update or avg_out_update: - - # If no price from picking, use cost price from product - if product_price == 0.0: - product_price = product.price_get('standard_price', context=ctx)[product.id] - - move_currency_id = move.company_id.currency_id.id - ctx['currency_id'] = move_currency_id - qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id) - - if not product.id in product_avail: - product_avail[product.id] = product.qty_available - - if qty > 0: - if avg_in_update: - new_price = currency_obj.compute(cr, uid, product_currency, - move_currency_id, product_price) - new_price = uom_obj._compute_price(cr, uid, product_uom, new_price, - product.uom_id.id) - if product.qty_available <= 0: - new_std_price = new_price - else: - amount_unit = product.price_get('standard_price', context=ctx)[product.id] - new_std_price = ((amount_unit * product_avail[product.id])\ - + (new_price * qty))/(product_avail[product.id] + qty) - elif avg_out_update: - move_orig = move.move_returned_from - new_price = currency_obj.compute(cr, uid, product_currency, - move_currency_id, move_orig.price_unit) - new_price = uom_obj._compute_price(cr, uid, product_uom, new_price, - product.uom_id.id) - if (product_avail[product.id]- qty) > 0: - amount_unit = product.price_get('standard_price', context=ctx)[product.id] - new_std_price = ((amount_unit * product_avail[product.id])\ - - (new_price * qty))/(product_avail[product.id] - qty) - - #Adjust product available with the right amount - - if avg_out_update: - product_avail[product.id] -= qty - else: - product_avail[product.id] += qty - - # Write the field according to price type field, company dependence in ctx - product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price}, context=ctx) - - # Record the values that were chosen in the wizard, so they can be - # used for inventory valuation if real-time valuation is enabled. - self.write(cr, uid, [move.id], - {'price_unit': product_price, - 'price_currency_id': product_currency}) - return True - # FIXME: needs refactoring, this code is partially duplicated in stock_picking.do_partial()! def do_partial(self, cr, uid, ids, partial_datas, context=None): @@ -2841,11 +2756,8 @@ class stock_move(osv.osv): context = {} complete, too_many, too_few = [], [], [] - move_product_qty, prodlot_ids, product_avail, partial_qty, product_uoms = {}, {}, {}, {}, {} + move_product_qty, prodlot_ids, partial_qty, product_uoms = {}, {}, {}, {} - #Let us do the price calculation - move_ids = [x.id for x in self.browse(cr, uid, ids, context=context)] - #self.price_computation(cr, uid, move_ids, partial_datas, context=context) for move in self.browse(cr, uid, ids, context=context): if move.state in ('done', 'cancel'): @@ -2876,7 +2788,7 @@ class stock_move(osv.osv): 'picking_id' : move.picking_id.id, 'state': 'assigned', 'move_dest_id': False, - 'price_unit': move.price_unit, + 'price_unit': product_price, } prodlot_id = prodlot_ids[move.id] if prodlot_id: diff --git a/addons/stock/stock_fifo_lifo.py b/addons/stock/stock_fifo_lifo.py index 33882d9441c..4d34ff634b3 100644 --- a/addons/stock/stock_fifo_lifo.py +++ b/addons/stock/stock_fifo_lifo.py @@ -36,9 +36,9 @@ class product_product (osv.osv): (move_in_id, qty in uom of move out, price (converted to move out), qty in uom of move in This should be called for only one product at a time UoMs and currencies from the corresponding moves are converted towards that given in the params + It is good to use force_company in the header ''' assert len(ids) == 1, _('Only the fifolifo stock matchings of one product can be calculated at a time.') - print uid, ids, qty, fifo, product_uom_id, currency_id, context uom_obj = self.pool.get('product.uom') currency_obj = self.pool.get('res.currency') @@ -56,8 +56,6 @@ class product_product (osv.osv): if not currency_id: currency_id = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id.id - print fifo - print company_id, product.id if fifo: move_in_ids = move_obj.search(cr, uid, [('company_id','=', company_id), ('qty_remaining', '>', 0), ('state', '=', 'done'), ('type', '=', 'in'), ('product_id', '=', product.id)], @@ -66,7 +64,6 @@ class product_product (osv.osv): move_in_ids = move_obj.search(cr, uid, [('company_id','=', company_id), ('qty_remaining', '>', 0), ('state', '=', 'done'), ('type', '=', 'in'), ('product_id', '=', product.id)], order = 'date desc', context=context) - print move_in_ids tuples = [] qty_to_go = qty for move in move_obj.browse(cr, uid, move_in_ids, context=context): @@ -110,94 +107,6 @@ class stock_move(osv.osv): return res - - - #Overwrites method for FIFO computation - def price_computation(self, cr, uid, ids, partial_datas, context=None): - super(stock_move, self).price_computation(cr, uid, ids, partial_datas, context=context) - product_obj = self.pool.get('product.product') - matching_obj = self.pool.get('stock.move.matching') - currency_obj = self.pool.get('res.currency') - uom_obj = self.pool.get('product.uom') - - #Find stock moves working in fifo/lifo price -> find stock moves out - for move in self.browse(cr, uid, ids, context=context): - partial_data = partial_datas.get('move%s'%(move.id), {}) - product_qty = partial_data.get('product_qty',0.0) - product_uom = partial_data.get('product_uom',False) - product_price = partial_data.get('product_price',0.0) - product_currency = partial_data.get('product_currency',False) - product = product_obj.browse(cr, uid, move.product_id.id, context=context) - - #Check we are using the right company - company_id = move.company_id.id - ctx = context.copy() - ctx['force_company'] = company_id - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - if company_id != user.company_id.id: - product = product_obj.browse(cr, uid, move.product_id.id, context=ctx) - cost_method = product.cost_method - uom_id = product.uom_id.id - if move.picking_id.type == 'out' and cost_method in ['fifo', 'lifo']: - #This price has to be put as the new standard price for the product, but needs to be converted to product UoM and currency - #convert uom of qty - - product_uom_qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, uom_id) - - #get_stock_matchings will convert to currency and UoM of this stock move - tuples = product_obj.get_stock_matchings_fifolifo(cr, uid, [product.id], product_qty, cost_method == 'fifo', - product_uom, move.company_id.currency_id.id, context=ctx) #Always currency of the company - print "TUPLES:", tuples - price_amount = 0.0 - amount = 0.0 - move_currency_id = move.company_id.currency_id.id - ctx['currency_id'] = move_currency_id - for match in tuples: - matchvals = {'move_in_id': match[0], 'qty': match[1], - 'move_out_id': move.id, 'price_unit_out': match[2]} - match_id = matching_obj.create(cr, uid, matchvals, context=context) - move_in = self.browse(cr, uid, match[0], context=context) - #Reduce remaining quantity - self.write(cr, uid, match[0], { 'qty_remaining': move_in.qty_remaining - match[3]}, context=context) - price_amount += match[1] * match[2] - amount += match[1] - if product.qty_available >= product_uom_qty: - self.write(cr, uid, move.id, {'price_unit': price_amount / amount}, context=context) - else: - standard_price = product.standard_price - self.write(cr, uid, move.id, {'price_unit': standard_price}, context=context) - - #convert price, no need of UoM conversion as it is the total price - currency_id = move.company_id.currency_id.id - currency_from = move.price_currency_id - if move.price_currency_id and (move.price_currency_id.id != currency_id): - new_price = currency_obj.compute(cr, uid, move.price_currency_id, currency_id, - price_amount) - else: - new_price = price_amount - - if product.qty_available >= product_uom_qty: - product_obj.write(cr, uid, product.id, {'standard_price': new_price / product_uom_qty}, context=ctx) - # When the move is products returned to supplier or return products from customer, - # it should be treated as a normal in or out, so for every in - elif cost_method in ['fifo', 'lifo']: - #The currency in the stock move should be the currency of the company - if product_price > 0.0: - if product_currency != move.company_id.currency_id.id: - new_price = currency_obj.compute(cr, uid, product_currency, move.company_id.currency_id.id, - product_price, round=False) - else: - new_price = product_price - else: - if product_uom != uom_id: - new_price = uom_obj._compute_price(cr, uid, uom_id, new_price, product_uom) - else: - new_price = product.standard_price - self.write(cr, uid, [move.id], - {'price_unit': new_price, - 'price_currency_id': move.company_id.currency_id.id}) - return True - class stock_move_matching(osv.osv): _name = "stock.move.matching" _description = "Stock move matchings" diff --git a/addons/stock/wizard/stock_partial_picking.py b/addons/stock/wizard/stock_partial_picking.py index b471b5e64b0..a9bc4e65457 100644 --- a/addons/stock/wizard/stock_partial_picking.py +++ b/addons/stock/wizard/stock_partial_picking.py @@ -127,19 +127,21 @@ class stock_partial_picking(osv.osv_memory): def _product_cost_for_average_update(self, cr, uid, move): """Returns product cost and currency ID for the given move, suited for re-computing the average product cost. - + :return: map of the form:: - + {'cost': 123.34, 'currency': 42} """ # Currently, the cost on the product form is supposed to be expressed in the currency # of the company owning the product. If not set, we fall back to the picking's company, # which should work in simple cases. - product_currency_id = move.product_id.company_id.currency_id and move.product_id.company_id.currency_id.id - picking_currency_id = move.picking_id.company_id.currency_id and move.picking_id.company_id.currency_id.id - return {'cost': move.product_id.standard_price, - 'currency': product_currency_id or picking_currency_id or False} + + # need to take the standard_price from the correct company + move2 = self.pool.get("stock.move").browse(cr, uid, move.id, context={'force_company': move.company_id.id}) + + return {'cost': move2.product_id.standard_price, + 'currency': False} def _partial_move_for(self, cr, uid, move): partial_move = { @@ -169,7 +171,7 @@ class stock_partial_picking(osv.osv_memory): line_uom = wizard_line.product_uom move_id = wizard_line.move_id.id - #Quantiny must be Positive + #Quantity must be Positive if wizard_line.quantity < 0: raise osv.except_osv(_('Warning!'), _('Please provide proper Quantity.')) @@ -190,6 +192,7 @@ class stock_partial_picking(osv.osv_memory): without_rounding_qty = (wizard_line.quantity / line_uom.factor) * initial_uom.factor if float_compare(qty_in_initial_uom, without_rounding_qty, precision_rounding=initial_uom.rounding) != 0: raise osv.except_osv(_('Warning!'), _('The rounding of the initial uom does not allow you to ship "%s %s", as it would let a quantity of "%s %s" to ship and only roundings of "%s %s" is accepted by the uom.') % (wizard_line.quantity, line_uom.name, wizard_line.move_id.product_qty - without_rounding_qty, initial_uom.name, initial_uom.rounding, initial_uom.name)) + stock_move.write(cr, uid, [move_id], {'price_unit': wizard_line.cost, 'price_currency_id': False}) else: seq_obj_name = 'stock.picking.' + picking_type move_id = stock_move.create(cr,uid,{'name' : self.pool.get('ir.sequence').get(cr, uid, seq_obj_name), @@ -200,6 +203,7 @@ class stock_partial_picking(osv.osv_memory): 'location_id' : wizard_line.location_id.id, 'location_dest_id' : wizard_line.location_dest_id.id, 'picking_id': partial.picking_id.id, + 'price_unit': wizard_line.cost, },context=context) stock_move.action_confirm(cr, uid, [move_id], context) partial_data['move%s' % (move_id)] = { @@ -211,14 +215,7 @@ class stock_partial_picking(osv.osv_memory): if (picking_type == 'in') and (wizard_line.product_id.cost_method != 'standard'): #TODO Maybe better ways to get company or main currency #TODO Should not this currency be calculated at the date of the purchase order? (not the case now?) - if wizard_line.location_id.company_id: - company = wizard_line.location_id.company_id - else: - company = wizard_line.location_dest_id.company_id - currency_obj = self.pool.get("res.currency") - new_price = currency_obj.compute(cr, uid, wizard_line.currency.id, company.currency_id.id, - wizard_line.cost, round=False) - partial_data['move%s' % (wizard_line.move_id.id)].update(product_price=new_price,) + partial_data['move%s' % (wizard_line.move_id.id)].update(product_price=wizard_line.cost,) stock_picking.do_partial(cr, uid, [partial.picking_id.id], partial_data, context=context) return {'type': 'ir.actions.act_window_close'}