[IMP] Add UoM and currency conversions

bzr revid: jco@openerp.com-20130430091345-oxx3ybwn21c3piv3
This commit is contained in:
Josse Colpaert 2013-04-30 11:13:45 +02:00
parent e1aa0da6a6
commit 1dcd36b3ce
3 changed files with 71 additions and 26 deletions

View File

@ -2628,7 +2628,6 @@ class stock_move(osv.osv):
ctx['force_company'] = move.company_id.id
product = product_obj.browse(cr, uid, move.product_id.id, context=ctx)
cost_method = product.cost_method
product_price = move.price_unit
#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)
@ -2707,7 +2706,7 @@ class stock_move(osv.osv):
#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, contexth=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'):

View File

@ -38,34 +38,59 @@ class product_product (osv.osv):
}
def get_stock_matchings_fifolifo(self, cr, uid, ids, qty, fifo, context=None):
def get_stock_matchings_fifolifo(self, cr, uid, ids, qty, fifo, product_uom_id = False, currency_id = False, context=None):
'''
This method returns a list of tuples for which the stock moves are working fifo/lifo
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
'''
assert len(ids) == 1, 'Only the fifolifo stock matchings of one product can be calculated at a time.'
assert len(ids) == 1, _('Only the fifolifo stock matchings of one product can be calculated at a time.')
uom_obj = self.pool.get('product.uom')
currency_obj = self.pool.get('res.currency')
product = self.browse(cr, uid, ids, context=context)[0]
move_obj = self.pool.get('stock.move')
if not product_uom_id:
product_uom_id = product.uom_id.id
if 'force_company' in context:
company_id = context['force_company']
else:
#Would be better not to have to go here
company_id = product.company_id.id
if not currency_id:
currency_id = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id.id
if fifo:
move_ids = move_obj.search(cr, uid, [('qty_remaining', '>', 0), ('state', '=', 'done'),
move_ids = move_obj.search(cr, uid, [('company_id','=', company_id), ('qty_remaining', '>', 0), ('state', '=', 'done'),
('type', '=', 'in'), ('product_id', '=', product.id)],
order = 'date', context=context)
else:
move_ids = move_obj.search(cr, uid, [('qty_remaining', '>', 0), ('state', '=', 'done'),
move_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)
tuples = []
qty_to_go = qty
for move in move_obj.browse(cr, uid, move_ids, context=context):
# @TODO convert UoM for product quantities?
product_qty = move.product_qty
#Convert to UoM of product each time
uom_from = move.product_uom.id
qty_from = move.product_qty
product_qty = uom_obj._compute_qty(cr, uid, uom_from, qty_from, product_uom_id)
#Convert currency from in move currency id to out move currency
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,
move.price_unit)
else:
new_price = move.price_unit
new_price = uom_obj._compute_price(cr, uid, uom_from, new_price,
product_uom_id)
if qty_to_go - product_qty >= 0:
tuples.append((move.id, product_qty, move.price_unit),)
tuples.append((move.id, product_qty, new_price),)
qty_to_go -= product_qty
else:
tuples.append((move.id, qty_to_go, move.price_unit),)
qty_to_go = 0
tuples.append((move.id, qty_to_go, new_price),)
break
return tuples
@ -89,14 +114,21 @@ class stock_move(osv.osv):
return res
#@TODO overwrite method for price_computation
#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
@ -104,31 +136,45 @@ class stock_move(osv.osv):
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
ctx['force_company'] = company_id
product = product_obj.browse(cr, uid, move.product_id.id, context=ctx)
cost_method = product.cost_method
product_price = move.price_unit
#Still need to see how to handle UoM + check quantity from the partial datas
product_qty = move.product_qty
if move.picking_id.type == 'out' and cost_method in ['fifo', 'lifo'] and not move.move_returned_from:
tuples = product_obj.get_stock_matchings_fifolifo(cr, uid, [product.id], product_qty, cost_method == 'fifo', context=context)
#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.price_currency_id, context=context)
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}
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[1]}, context=context)
price_amount += match[1] * match[2]
amount += match[1]
self.write(cr, uid, move.id, {'price_unit': price_amount / amount}, context=context)
#This price has to be put as the new standard price for the product
product_obj.write(cr, uid, product.id, {'standard_price': price_amount / amount}, context=ctx)
#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
uom_id = product.uom_id.id
product_qty = uom_obj._compute_qty(cr, uid, product_uom, amount, uom_id)
#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
#new_price does not depend on qty as it is the total amount => no conversion needed for uom
product_obj.write(cr, uid, product.id, {'standard_price': new_price / product_qty}, context=ctx)
# When the move is products returned to supplier or return products from customer
# then the price should be the price from the original move
if move.move_returned_from:
if move.move_returned_from and cost_method in ['fifo', 'lifo']:
self.write(cr, uid, move.id, {'price_unit': move.move_returned_from.price_unit}, context=context)
return True

View File

@ -116,32 +116,32 @@
-
Do a delivery of an extra 500 g (delivery order)
-
!record {model: stock.picking, id: outgoing_fifo_shipment}:
!record {model: stock.picking, id: outgoing_fifo_shipment_uom}:
type: out
-
Picking needs movement from stock
-
!record {model: stock.move, id: outgoing_shipment_fifo_icecream_gram}:
picking_id: outgoing_fifo_shipment
picking_id: outgoing_fifo_shipment_uom
product_id: product_fifo_icecream
product_uom: product.product_uom_gram
product_qty: 500.0
type: out
-
I confirm outgoing shipment of 20 kg of FIFO Ice Cream.
I confirm outgoing shipment of 500g of FIFO Ice Cream.
-
!workflow {model: stock.picking, action: button_confirm, ref: outgoing_fifo_shipment}
!workflow {model: stock.picking, action: button_confirm, ref: outgoing_fifo_shipment_uom}
-
Process the delivery of the outgoing shipment
-
!python {model: stock.partial.picking}: |
partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [ref("outgoing_fifo_shipment")], 'default_type':'out'})
partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [ref("outgoing_fifo_shipment_uom")], 'default_type':'out'})
self.do_partial(cr, uid, [partial_id])
-
Check 1 stock move matching was created
-
!python {model: stock.picking}: |
assert len(self.browse(cr, uid, ref("outgoing_fifo_shipment")).move_lines[0].matching_ids_out) == 1, 'Should have created 1 matching'
assert len(self.browse(cr, uid, ref("outgoing_fifo_shipment_uom")).move_lines[0].matching_ids_out) == 1, 'Should have created 1 matching'
-
Check product price changed to 80.0
-