[REF] product, *: clean price computation methods
Old price_get method is now replaced by price_compute and ready for migration. Explicit parameters for unit of measure and currency have been added to ease code understanding.
This commit is contained in:
@@ -35,14 +35,8 @@ class AccountAnalyticLine(models.Model):
|
||||
if not unit or self.product_id.uom_po_id.category_id.id != unit.category_id.id:
|
||||
unit = self.product_id.uom_po_id
|
||||
|
||||
ctx = dict(self._context or {})
|
||||
if unit:
|
||||
# price_get() will respect a 'uom' in its context, in order
|
||||
# to return a default price for those units
|
||||
ctx['uom'] = unit.id
|
||||
|
||||
# Compute based on pricetype
|
||||
amount_unit = self.product_id.with_context(ctx).price_get('standard_price')[self.product_id.id]
|
||||
amount_unit = self.product_id.price_compute('standard_price', uom=unit)[self.product_id.id]
|
||||
amount = amount_unit * self.unit_amount or 0.0
|
||||
result = round(amount, self.currency_id.decimal_places) * -1
|
||||
self.amount = result
|
||||
|
||||
@@ -80,7 +80,7 @@ class HrExpense(models.Model):
|
||||
if self.product_id:
|
||||
if not self.name:
|
||||
self.name = self.product_id.display_name or ''
|
||||
self.unit_amount = self.env['product.template']._price_get(self.product_id, 'standard_price')[self.product_id.id]
|
||||
self.unit_amount = self.product_id.price_compute('standard_price')[self.product_id.id]
|
||||
self.product_uom_id = self.product_id.uom_id
|
||||
self.tax_ids = self.product_id.supplier_taxes_id
|
||||
account = self.product_id.product_tmpl_id._get_product_accounts()['expense']
|
||||
|
||||
@@ -18,7 +18,7 @@ class membership_invoice(osv.osv_memory):
|
||||
"""
|
||||
if not product_id:
|
||||
return {'value': {'member_price': False}}
|
||||
return {'value': {'member_price': self.pool.get('product.product').price_get(cr, uid, [product_id])[product_id]}}
|
||||
return {'value': {'member_price': self.pool.get('product.product').price_compute(cr, uid, [product_id], 'list_price')[product_id]}}
|
||||
|
||||
def membership_invoice(self, cr, uid, ids, context=None):
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
|
||||
@@ -495,12 +495,42 @@ class product_product(osv.osv):
|
||||
result = self.name_get(cr, uid, ids, context=context)
|
||||
return result
|
||||
|
||||
#
|
||||
# Could be overrided for variants matrices prices
|
||||
#
|
||||
@api.multi
|
||||
def price_compute(self, price_type, uom=False, currency=False, company=False):
|
||||
# TDE FIXME: delegate to template or not ? fields are reencoded here ...
|
||||
# compatibility about context keys used a bit everywhere in the code
|
||||
if not uom and self._context.get('uom'):
|
||||
uom = self.env['product.uom'].browse(self._context['uom'])
|
||||
if not currency and self._context.get('currency'):
|
||||
currency = self.env['res.currency'].browse(self._context['currency'])
|
||||
|
||||
products = self
|
||||
if price_type == 'standard_price':
|
||||
# standard_price field can only be seen by users in base.group_user
|
||||
# Thus, in order to compute the sale price from the cost for users not in this group
|
||||
# We fetch the standard price as the superuser
|
||||
products = self.with_context(force_company=company and company.id or self._context.get('force_company', self.env.user.company_id.id)).sudo()
|
||||
|
||||
prices = dict.fromkeys(self.ids, 0.0)
|
||||
for product in products:
|
||||
prices[product.id] = product[price_type] or 0.0
|
||||
if price_type == 'list_price':
|
||||
prices[product.id] += product.price_extra
|
||||
|
||||
if uom:
|
||||
prices[product.id] = product.uom_id._compute_price(product.uom_id.id, prices[product.id], uom.id)
|
||||
|
||||
# Convert from current user company currency to asked one
|
||||
# This is right cause a field cannot be in more than one currency
|
||||
if currency:
|
||||
prices[product.id] = product.currency_id.compute(prices[product.id], currency)
|
||||
|
||||
return prices
|
||||
|
||||
|
||||
# compatibility to remove after v10 - DEPRECATED
|
||||
def price_get(self, cr, uid, ids, ptype='list_price', context=None):
|
||||
products = self.browse(cr, uid, ids, context=context)
|
||||
return self.pool.get("product.template")._price_get(cr, uid, products, ptype=ptype, context=context)
|
||||
return self.browse(cr, uid, ids, context=context).price_compute(ptype)
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
if context is None:
|
||||
|
||||
@@ -183,8 +183,9 @@ class product_pricelist(osv.osv):
|
||||
# Ignored - incompatible UoM in context, use default product UoM
|
||||
pass
|
||||
|
||||
# if Public user try to access standard price from website sale, need to call _price_get.
|
||||
price = self.pool['product.template']._price_get(cr, uid, [product], 'list_price', context=context)[product.id]
|
||||
# if Public user try to access standard price from website sale, need to call price_compute.
|
||||
# TDE SURPRISE: product can actually be a template
|
||||
price = product.price_compute('list_price')[product.id]
|
||||
|
||||
price_uom_id = qty_uom_id
|
||||
for rule in items:
|
||||
@@ -217,8 +218,8 @@ class product_pricelist(osv.osv):
|
||||
price = self.pool['res.currency'].compute(cr, uid, ptype_src, pricelist.currency_id.id, price_tmp, round=False, context=context)
|
||||
else:
|
||||
# if base option is public price take sale price else cost price of product
|
||||
# price_get returns the price in the context UoM, i.e. qty_uom_id
|
||||
price = self.pool['product.template']._price_get(cr, uid, [product], rule.base, context=context)[product.id]
|
||||
# price_compute returns the price in the context UoM, i.e. qty_uom_id
|
||||
price = product.price_compute(rule.base)[product.id]
|
||||
|
||||
convert_to_price_uom = (lambda price: product_uom_obj._compute_price(
|
||||
cr, uid, product.uom_id.id,
|
||||
|
||||
@@ -191,35 +191,39 @@ class product_template(osv.osv):
|
||||
"resized as a 64x64px image, with aspect ratio preserved. "\
|
||||
"Use this field anywhere a small image is required.")
|
||||
|
||||
def _price_get(self, cr, uid, products, ptype='list_price', context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
@api.multi
|
||||
def price_compute(self, price_type, uom=False, currency=False, company=False):
|
||||
# TDE FIXME: delegate to template or not ? fields are reencoded here ...
|
||||
# compatibility about context keys used a bit everywhere in the code
|
||||
if not uom and self._context.get('uom'):
|
||||
uom = self.env['product.uom'].browse(self._context['uom'])
|
||||
if not currency and self._context.get('currency'):
|
||||
currency = self.env['res.currency'].browse(self._context['currency'])
|
||||
|
||||
res = {}
|
||||
product_uom_obj = self.pool.get('product.uom')
|
||||
for product in products:
|
||||
templates = self
|
||||
if price_type == 'standard_price':
|
||||
# standard_price field can only be seen by users in base.group_user
|
||||
# Thus, in order to compute the sale price from the cost for users not in this group
|
||||
# We fetch the standard price as the superuser
|
||||
if ptype != 'standard_price':
|
||||
res[product.id] = product[ptype] or 0.0
|
||||
else:
|
||||
company_id = context.get('force_company') or product.env.user.company_id.id
|
||||
product = product.with_context(force_company=company_id)
|
||||
res[product.id] = res[product.id] = product.sudo()[ptype]
|
||||
if ptype == 'list_price':
|
||||
res[product.id] += product._name == "product.product" and product.price_extra or 0.0
|
||||
if 'uom' in context:
|
||||
uom = product.uom_id
|
||||
res[product.id] = product_uom_obj._compute_price(cr, uid,
|
||||
uom.id, res[product.id], context['uom'])
|
||||
templates = self.with_context(force_company=company and company.id or self._context.get('force_company', self.env.user.company_id.id)).sudo()
|
||||
|
||||
prices = dict.fromkeys(self.ids, 0.0)
|
||||
for template in templates:
|
||||
prices[template.id] = template[price_type] or 0.0
|
||||
|
||||
if uom:
|
||||
prices[template.id] = template.uom_id._compute_price(template.uom_id.id, prices[template.id], uom.id)
|
||||
|
||||
# Convert from current user company currency to asked one
|
||||
if 'currency_id' in context:
|
||||
# Take current user company currency.
|
||||
# This is right cause a field cannot be in more than one currency
|
||||
res[product.id] = self.pool.get('res.currency').compute(cr, uid, product.currency_id.id,
|
||||
context['currency_id'], res[product.id], context=context)
|
||||
return res
|
||||
# This is right cause a field cannot be in more than one currency
|
||||
if currency:
|
||||
prices[template.id] = template.currency_id.compute(prices[template.id], currency)
|
||||
|
||||
return prices
|
||||
|
||||
# compatibility to remove after v10 - DEPRECATED
|
||||
def _price_get(self, cr, uid, products, ptype='list_price', context=None):
|
||||
return products.price_compute(ptype)
|
||||
|
||||
def _get_uom_id(self, cr, uid, *args):
|
||||
return self.pool["product.uom"].search(cr, uid, [], limit=1, order='id')[0]
|
||||
|
||||
@@ -101,7 +101,7 @@ class TestPricelist(TransactionCase):
|
||||
unit_price = self.registry('product.pricelist').price_get(cr, uid, [pricelist_id],
|
||||
spam_id, qty,
|
||||
context={'uom': uom})[pricelist_id]
|
||||
self.assertAlmostEqual(unit_price, expected_unit_price, msg='Computed unit price is wrong')
|
||||
self.assertAlmostEqual(unit_price, expected_unit_price)
|
||||
|
||||
# Test prices - they are *per unit*, the quantity is only here to match the pricelist rules!
|
||||
test_unit_price(2, kg, tonne_price / 1000.0)
|
||||
|
||||
Reference in New Issue
Block a user