[FIX] stock_account, purchase: updating the standard price of products in cost method == 'average' on receptions
bzr revid: qdp-launchpad@openerp.com-20130905103435-ch505yi7qyvxz0pz
This commit is contained in:
commit
70d2733d1b
|
@ -685,7 +685,11 @@ class purchase_order(osv.osv):
|
|||
def _prepare_order_line_move(self, cr, uid, order, order_line, picking_id, context=None):
|
||||
''' prepare the stock move data from the PO line '''
|
||||
type_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'picking_type_in')[1]
|
||||
type = self.pool.get("stock.picking.type").browse(cr, uid, type_id, context=context)
|
||||
price_unit = order_line.price_unit
|
||||
if order_line.product_uom.id != order_line.product_id.uom_id.id:
|
||||
price_unit *= order_line.product_uom.factor
|
||||
if order.currency_id.id != order.company_id.currency_id.id:
|
||||
price_unit = self.pool.get('res.currency').compute(cr, uid, order.currency_id.id, order.company_id.currency_id.id, price_unit, context=context)
|
||||
|
||||
return {
|
||||
'name': order_line.name or '',
|
||||
|
@ -704,7 +708,7 @@ class purchase_order(osv.osv):
|
|||
'state': 'draft',
|
||||
'purchase_line_id': order_line.id,
|
||||
'company_id': order.company_id.id,
|
||||
'price_unit': order_line.price_unit,
|
||||
'price_unit': price_unit,
|
||||
'picking_type_id': type_id,
|
||||
}
|
||||
|
||||
|
|
|
@ -26,28 +26,11 @@
|
|||
product_uom: product.product_uom_categ_kgm
|
||||
price_unit: 60.0
|
||||
name: 'Average Ice Cream'
|
||||
-
|
||||
I create a draft Purchase Order for second incoming shipment for 30 pieces at 80€
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_average2}:
|
||||
partner_id: base.res_partner_3
|
||||
location_id: stock.stock_location_stock
|
||||
pricelist_id: 1
|
||||
order_line:
|
||||
- product_id: product_average_icecream
|
||||
product_qty: 30.0
|
||||
product_uom: product.product_uom_categ_kgm
|
||||
price_unit: 80.0
|
||||
name: 'Average Ice Cream'
|
||||
-
|
||||
I confirm the first purchase order
|
||||
-
|
||||
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_average1}
|
||||
-
|
||||
I confirm the second purchase order
|
||||
-
|
||||
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_average2}
|
||||
-
|
||||
I check the "Approved" status of purchase order 1
|
||||
-
|
||||
!assert {model: purchase.order, id: purchase_order_average1}:
|
||||
|
@ -66,6 +49,23 @@
|
|||
assert product.qty_available == 10.0, 'Wrong quantity in stock after first reception'
|
||||
assert product.standard_price == 60.0, 'Standard price should be the price of the first reception!'
|
||||
-
|
||||
I create a draft Purchase Order for second incoming shipment for 30 pieces at 80€
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_average2}:
|
||||
partner_id: base.res_partner_3
|
||||
location_id: stock.stock_location_stock
|
||||
pricelist_id: 1
|
||||
order_line:
|
||||
- product_id: product_average_icecream
|
||||
product_qty: 30.0
|
||||
product_uom: product.product_uom_categ_kgm
|
||||
price_unit: 80.0
|
||||
name: 'Average Ice Cream'
|
||||
-
|
||||
I confirm the second purchase order
|
||||
-
|
||||
!workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_average2}
|
||||
-
|
||||
Process the reception of purchase order 2
|
||||
-
|
||||
!python {model: stock.picking}: |
|
||||
|
@ -88,7 +88,9 @@
|
|||
picking_id: outgoing_average_shipment
|
||||
product_id: product_average_icecream
|
||||
product_uom: product.product_uom_kgm
|
||||
product_qty: 20.0
|
||||
location_id: stock.stock_location_stock
|
||||
location_dest_id: stock.stock_location_customers
|
||||
product_uom_qty: 20.0
|
||||
-
|
||||
I assign this outgoing shipment and process the delivery
|
||||
-
|
||||
|
@ -102,7 +104,7 @@
|
|||
assert self.browse(cr, uid, ref("product_average_icecream")).standard_price == 75.0, 'Standard price should not have changed with outgoing picking!'
|
||||
assert self.browse(cr, uid, ref("product_average_icecream")).qty_available == 20.0, 'Pieces were not picked correctly as the quantity on hand is wrong'
|
||||
-
|
||||
Make a new purchase order with 500 g Average Ice Cream at a price of 100 TODO the unit_price is 1 here
|
||||
Make a new purchase order with 500 g Average Ice Cream at a price of 0.2€/g
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_average3}:
|
||||
partner_id: base.res_partner_3
|
||||
|
@ -112,7 +114,7 @@
|
|||
- product_id: product_average_icecream
|
||||
product_qty: 500.0
|
||||
product_uom: product.product_uom_gram
|
||||
price_unit: 1.0
|
||||
price_unit: 0.2
|
||||
name: 'Average Ice Cream'
|
||||
-
|
||||
I confirm the first purchase order
|
||||
|
@ -125,9 +127,9 @@
|
|||
pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_average3")).picking_ids
|
||||
self.do_partial(cr, uid, [pick_ids[0].id])
|
||||
-
|
||||
Check price is (75.0*20 + 500) / 20.5 = 97.56097561
|
||||
Check price is (75.0*20 + 200*0.5) / 20.5 = 78.04878
|
||||
-
|
||||
!python {model: product.product}: |
|
||||
product = self.browse(cr, uid, ref("product_average_icecream"))
|
||||
assert product.qty_available == 20.5, 'Reception of purchase order in grams leads to wrong quantity in stock'
|
||||
assert round(self.browse(cr, uid, ref("product_average_icecream")).standard_price, 2) == 97.56, 'Standard price as average price of third reception with other UoM incorrect!'
|
||||
assert round(self.browse(cr, uid, ref("product_average_icecream")).standard_price, 2) == 78.05, 'Standard price as average price of third reception with other UoM incorrect! Got %s instead of 78.05' % (round(self.browse(cr, uid, ref("product_average_icecream")).standard_price, 2),)
|
||||
|
|
|
@ -980,13 +980,13 @@ class stock_move(osv.osv):
|
|||
_log_create = False
|
||||
|
||||
def get_price_unit(self, cr, uid, move, context=None):
|
||||
""" Returns the unit price to store on the move """
|
||||
""" Returns the unit price to store on the quant """
|
||||
return move.price_unit or move.product_id.standard_price
|
||||
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
res = []
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
name = line.location_id.name+' > '+line.location_dest_id.name
|
||||
name = line.location_id.name + ' > ' + line.location_dest_id.name
|
||||
if line.product_id.code:
|
||||
name = line.product_id.code + ': ' + name
|
||||
if line.picking_id.origin:
|
||||
|
@ -1126,8 +1126,7 @@ class stock_move(osv.osv):
|
|||
"* Available: When products are reserved, it is set to \'Available\'.\n"\
|
||||
"* Done: When the shipment is processed, the state is \'Done\'."),
|
||||
|
||||
'price_unit': fields.float('Unit Price', help="Technical field used to record the product cost set by the user during a picking confirmation (when average price costing method is used)"), # as it's a technical field, we intentionally don't provide the digits attribute
|
||||
'price_currency_id': fields.many2one('res.currency', 'Currency for average price', help="Technical field used to record the currency chosen by the user during a picking confirmation (when average price costing method is used)"),
|
||||
'price_unit': fields.float('Unit Price', help="Technical field used to record the product cost set by the user during a picking confirmation (when average price costing method is used). Value given in company currency and in product uom."), # as it's a technical field, we intentionally don't provide the digits attribute
|
||||
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True, select=True),
|
||||
'backorder_id': fields.related('picking_id','backorder_id',type='many2one', relation="stock.picking", string="Back Order of", select=True),
|
||||
|
@ -2421,6 +2420,7 @@ class stock_picking_type(osv.osv):
|
|||
'sequence_id': fields.many2one('ir.sequence', 'Sequence', required=True),
|
||||
'default_location_src_id': fields.many2one('stock.location', 'Default Source Location'),
|
||||
'default_location_dest_id': fields.many2one('stock.location', 'Default Destination Location'),
|
||||
#TODO: change field name to "code" as it's not a many2one anymore
|
||||
'code_id': fields.selection([('incoming', 'Suppliers'), ('outgoing', 'Customers'), ('internal', 'Internal')], 'Picking type code', required=True),
|
||||
'return_picking_type_id': fields.many2one('stock.picking.type', 'Picking Type for Returns'),
|
||||
'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse'),
|
||||
|
|
|
@ -206,10 +206,27 @@ class stock_move(osv.osv):
|
|||
|
||||
def product_price_update(self, cr, uid, ids, context=None):
|
||||
'''
|
||||
This method adapts the price on the product when necessary (if the cost_method is 'real'), so that a return or an inventory loss is made using the last value used for an outgoing valuation.
|
||||
This method adapts the price on the product when necessary
|
||||
'''
|
||||
product_obj = self.pool.get('product.product')
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
#adapt standard price on incomming moves if the product cost_method is 'average'
|
||||
if (move.location_id.usage == 'supplier') and (move.product_id.cost_method == 'average'):
|
||||
product = move.product_id
|
||||
company_currency_id = move.company_id.currency_id.id
|
||||
ctx = {'currency_id': company_currency_id}
|
||||
product_avail = product.qty_available
|
||||
if product.qty_available <= 0:
|
||||
new_std_price = move.price_unit
|
||||
else:
|
||||
# Get the standard price
|
||||
amount_unit = product.price_get('standard_price', context=ctx)[product.id]
|
||||
new_std_price = (amount_unit * (product_avail - move.product_qty) + (move.price_unit * move.product_qty)) / product_avail
|
||||
# Write the field according to price type field
|
||||
product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price}, context=context)
|
||||
|
||||
#adapt standard price on outgoing moves if the product cost_method is 'real', so that a return
|
||||
#or an inventory loss is made using the last value used for an outgoing valuation.
|
||||
if move.product_id.cost_method == 'real' and move.location_dest_id.usage != 'internal':
|
||||
if any([q.qty <= 0 for q in move.quant_ids]):
|
||||
#if there is a negative quant, the standard price shouldn't be updated
|
||||
|
|
Loading…
Reference in New Issue