Fix unit used in SO

- Now convert from the unit define in the product
- Don't convert from unit to unit that are not in the same category
- Fix SO report to print the right quantity
- Improve coding guidelines
- Add more digits to uom's factor

bzr revid: ced-bfdc6625d1f705ff3a6664f4e699aff2ea4ef00d
This commit is contained in:
ced 2007-09-11 14:14:15 +00:00
parent b594c23c14
commit c824d63cc0
4 changed files with 147 additions and 70 deletions

View File

@ -90,6 +90,7 @@ class product_pricelist(osv.osv):
if context and ('partner_id' in context):
partner = context['partner_id']
currency_obj = self.pool.get('res.currency')
product_obj = self.pool.get('product.product')
result = {}
for id in ids:
# XXX add date test to select the pricelist version
@ -166,7 +167,10 @@ class product_pricelist(osv.osv):
price = False
result[id] = price
if 'uom' in context:
result[id] = self.pool.get('product.uom')._compute_price(cr, uid, context['uom'], result[id])
product = product_obj.browse(cr, uid, prod_id)
uom = product.uos_id or product.uom_id
result[id] = self.pool.get('product.uom')._compute_price(cr,
uid, uom.id, result[id], context['uom'])
return result
product_pricelist()

View File

@ -56,7 +56,7 @@ class product_uom(osv.osv):
_columns = {
'name': fields.char('Name', size=64, required=True),
'category_id': fields.many2one('product.uom.categ', 'UOM Category', required=True, ondelete='cascade'),
'factor': fields.float('Factor', required=True),
'factor': fields.float('Factor', digits=(12, 6), required=True),
'rounding': fields.float('Rounding Precision', digits=(16, 3), required=True),
'active': fields.boolean('Active'),
}
@ -68,24 +68,34 @@ class product_uom(osv.osv):
}
def _compute_qty(self, cr, uid, from_uom_id, qty, to_uom_id=False):
if not to_uom_id: to_uom_id = 0
if not from_uom_id or not qty:
if not from_uom_id or not qty or not to_uom_id:
return qty
f = self.read(cr, uid, [from_uom_id, to_uom_id], ['factor','rounding'])
if f[0]['id'] == from_uom_id:
from_unit, to_unit = f[0], f[-1]
uoms = self.browse(cr, uid, [from_uom_id, to_uom_id])
if uoms[0].id == from_uom_id:
from_unit, to_unit = uoms[0], uoms[-1]
else:
from_unit, to_unit = f[-1], f[0]
amount = qty * from_unit['factor']
from_unit, to_unit = uoms[-1], uoms[0]
if from_unit.category_id.id <> to_unit.category_id.id:
return qty
amount = qty / from_unit['factor']
if to_uom_id:
amount = rounding(amount / to_unit['factor'], to_unit['rounding'])
amount = rounding(amount * to_unit['factor'], to_unit['rounding'])
return amount
def _compute_price(self, cr, uid, uom_id, qty, to_uom_id=False):
if not uom_id or not qty:
return qty
f = self.read(cr, uid, [uom_id], ['factor','rounding'])[0]
return qty * f['factor']
def _compute_price(self, cr, uid, from_uom_id, price, to_uom_id=False):
if not from_uom_id or not price or not to_uom_id:
return price
uoms = self.browse(cr, uid, [from_uom_id, to_uom_id])
if uoms[0].id == from_uom_id:
from_unit, to_unit = uoms[0], uoms[-1]
else:
from_unit, to_unit = uoms[-1], uoms[0]
if from_unit.category_id.id <> to_unit.category_id.id:
return price
amount = price / from_unit.factor
if to_uom_id:
amount = amount * to_unit.factor
return amount
product_uom()
@ -254,15 +264,18 @@ class product_product(osv.osv):
_product_outgoing_qty = _get_product_available_func(('confirmed','waiting','assigned'), ('out',))
_product_incoming_qty = _get_product_available_func(('confirmed','waiting','assigned'), ('in',))
def _product_lst_price(self, cr, uid, ids, name, arg, context={}):
def _product_lst_price(self, cr, uid, ids, name, arg, context=None):
res = {}
for p in self.browse(cr, uid, ids, context=context):
res[p.id] = p.list_price
product_uom_obj = self.pool.get('product.uom')
for id in ids:
res.setdefault(id, 0.0)
if 'uom' in context:
for id in ids:
res[id] = self.pool.get('product.uom')._compute_price(cr, uid, context['uom'], res[id])
for product in self.browse(cr, uid, ids, context=context):
if 'uom' in context:
uom = product.uos_id or product.uom_id
res[product.id] = product_uom_obj._compute_price(cr, uid,
uom.id, product.list_price, context['uom'])
else:
res[product.id] = product.list_price
return res
def _get_partner_code_name(self, cr, uid, ids, product_id, partner_id, context={}):
@ -369,15 +382,28 @@ class product_product(osv.osv):
# Could be overrided for variants matrices prices
#
def price_get(self, cr, uid, ids, ptype='list_price', context={}):
result = self.read(cr, uid, ids, [ptype, 'price_extra','price_margin'])
result2 = {}
for res in result:
result2[res['id']] = res[ptype] or 0.0
if ptype=='list_price':
result2[res['id']] = result2[res['id']] * res['price_margin'] + res['price_extra']
res = {}
product_uom_obj = self.pool.get('product.uom')
for product in self.browse(cr, uid, ids, context=context):
res[product.id] = product[ptype] or 0.0
if ptype == 'list_price':
res[product.id] = (res[product.id] * product.price_margin) + \
product.price_extra
if 'uom' in context:
result2[res['id']] = self.pool.get('product.uom')._compute_price(cr, uid, context['uom'], result2[res['id']])
return result2
uom = product.uos_id or product.uom_id
res[product.id] = product_uom_obj._compute_price(cr, uid,
uom.id, res[product.id], context['uom'])
return res
# result = self.read(cr, uid, ids, [ptype, 'price_extra','price_margin'])
# result2 = {}
# for res in result:
# result2[res['id']] = res[ptype] or 0.0
# if ptype=='list_price':
# result2[res['id']] = result2[res['id']] * res['price_margin'] + res['price_extra']
# if 'uom' in context:
# result2[res['id']] = self.pool.get('product.uom')._compute_price(cr, uid, context['uom'], result2[res['id']])
# return result2
def copy(self, cr, uid, id, default=None, context=None):
if not context:

File diff suppressed because one or more lines are too long

View File

@ -496,6 +496,9 @@ class sale_order(osv.osv):
return False
sale_order()
# TODO add a field price_unit_uos
# - update it on change product and unit price
# - use it in report if there is a uos
class sale_order_line(osv.osv):
def copy(self, cr, uid, id, default=None, context={}):
if not default: default = {}
@ -623,16 +626,20 @@ class sale_order_line(osv.osv):
return res
def uos_change(self, cr, uid, ids, product_uos, product_uos_qty=0, product_id=None):
product_obj = self.pool.get('product.product')
if not product_id:
return {'value': {'product_uom': product_uos, 'product_uom_qty': product_uos_qty}, 'domain':{}}
res = self.pool.get('product.product').read(cr, uid, [product_id], ['uom_id', 'uos_id', 'uos_coeff', 'weight'])[0]
return {'value': {'product_uom': product_uos,
'product_uom_qty': product_uos_qty}, 'domain':{}}
product = product_obj.browse(cr, uid, product_id)
value = {
'product_uom' : res['uom_id'],
'product_uom' : product.uom_id,
}
# FIXME must depend on uos/uom of the product and not only of the coeff.
try:
value.update({
'product_uom_qty' : product_uos_qty / res['uos_coeff'],
'th_weight' : product_uos_qty / res['uos_coeff'] * res['weight']
'product_uom_qty' : product_uos_qty / product.uos_coeff,
'th_weight' : product_uos_qty / product.uos_coeff * product.weight
})
except ZeroDivisionError:
pass
@ -644,29 +651,61 @@ class sale_order_line(osv.osv):
default.update({'state':'draft', 'move_ids':[], 'invoiced':False, 'invoice_lines':[]})
return super(sale_order_line, self).copy(cr, uid, id, default, context)
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False, qty_uos=0, uos=False, name='', partner_id=False, lang=False, update_tax=True):
if partner_id:
lang=self.pool.get('res.partner').read(cr, uid, [partner_id])[0]['lang']
context = {'lang':lang}
if not product:
return {'value': {'price_unit': 0.0, 'notes':'', 'th_weight' : 0, 'product_uos_qty': qty}, 'domain':{'product_uom':[]}}
if not pricelist:
raise osv.except_osv('No Pricelist !', 'You have to select a pricelist in the sale form !\nPlease set one before choosing a product.')
price = self.pool.get('product.pricelist').price_get(cr,uid,[pricelist], product, qty or 1.0, partner_id, {'uom': uom})[pricelist]
if price is False:
raise osv.except_osv('No valid pricelist line found !', "Couldn't find a pricelist line matching this product and quantity.\nYou have to change either the product, the quantity or the pricelist.")
res = self.pool.get('product.product').read(cr, uid, [product], context=context)[0]
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
uom=False, qty_uos=0, uos=False, name='', partner_id=False,
lang=False, update_tax=True):
product_uom_obj = self.pool.get('product.uom')
partner_obj = self.pool.get('res.partner')
product_obj = self.pool.get('product.product')
result = {'price_unit': price, 'type':res['procure_method'], 'notes':res['description_sale']}
if partner_id:
lang = partner_obj.browse(cr, uid, partner_id).lang
context = {'lang': lang}
if not product:
return {'value': {'price_unit': 0.0, 'notes':'', 'th_weight' : 0,
'product_uos_qty': qty}, 'domain': {'product_uom': []}}
if not pricelist:
raise osv.except_osv('No Pricelist !',
'You have to select a pricelist in the sale form !\n'
'Please set one before choosing a product.')
price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist],
product, qty or 1.0, partner_id, {'uom': uom})[pricelist]
if price is False:
raise osv.except_osv('No valid pricelist line found !',
"Couldn't find a pricelist line matching this product and quantity.\n"
"You have to change either the product, the quantity or the pricelist.")
product = product_obj.browse(cr, uid, product, context=context)
if uom:
uom2 = product_uom_obj.browse(cr, uid, uom)
if product.uom_id.category_id.id <> uom2.category_id.id:
uom = False
if uos:
if product.uos_id:
uos2 = product_uom_obj.browse(cr, uid, uos)
if product.uos_id.category_id.id <> uos2.category_id.id:
uos = False
else:
uos = False
result = {'price_unit': price, 'type': product.procure_method,
'notes': product.description_sale}
if update_tax: #The quantity only have changed
result['delay'] = (res['sale_delay'] or 0.0)
taxes = self.pool.get('account.tax').browse(cr, uid, res['taxes_id'])
result['delay'] = (product.sale_delay or 0.0)
taxes = self.pool.get('account.tax').browse(cr, uid,
[x.id for x in product.taxes_id])
taxep = None
if partner_id:
taxep = self.pool.get('res.partner').browse(cr, uid, partner_id).property_account_tax
taxep = self.pool.get('res.partner').browse(cr, uid,
partner_id).property_account_tax
if not taxep or not taxep.id:
result['tax_id'] = res['taxes_id']
result['tax_id'] = [x.id for x in product.taxes_id]
else:
res5 = [taxep.id]
for t in taxes:
@ -674,26 +713,34 @@ class sale_order_line(osv.osv):
res5.append(t.id)
result['tax_id'] = res5
result['name'] = res['partner_ref']
result['name'] = product.partner_ref
domain = {}
if not uom and not uos:
result['product_uom'] = res['uom_id'] and res['uom_id'][0]
if result['product_uom']:
result['product_uos'] = res['uos_id']
result['product_uos_qty'] = qty * res['uos_coeff']
result['th_weight'] = qty * res['weight']
res2 = self.pool.get('product.uom').read(cr, uid, [result['product_uom']], ['category_id'])
if res2 and res2[0]['category_id']:
domain = {'product_uom':[('category_id','=',res2[0]['category_id'][0])]}
result['product_uom'] = product.uom_id.id
if product.uos_id:
result['product_uos'] = product.uos_id.id
result['product_uos_qty'] = qty * product.uos_coeff
else:
result['product_uos'] = False
result['product_uos_qty'] = qty
result['th_weight'] = qty * product.weight
domain = {'product_uom':
[('category_id', '=', product.uom_id.category_id.id)]}
elif uom: # whether uos is set or not
default_uom = res['uom_id'] and res['uom_id'][0]
q = self.pool.get('product.uom')._compute_qty(cr, uid, uom, qty, default_uom)
result['product_uos'] = res['uos_id']
result['product_uos_qty'] = q * res['uos_coeff']
result['th_weight'] = q * res['weight']
default_uom = product.uom_id and product.uom_id.id
q = product_uom_obj._compute_qty(cr, uid, uom, qty, default_uom)
if product.uos_id:
result['product_uos'] = product.uos_id.id
result['product_uos_qty'] = q * product.uos_coeff
else:
result['product_uos'] = False
result['product_uos_qty'] = q
result['th_weight'] = q * product.weight
elif uos: # only happens if uom is False
result['product_uom'] = res['uom_id'] and res['uom_id'][0]
result['product_uom_qty'] = qty_uos / res['uos_coeff']
result['th_weight'] = result['product_uom_qty'] * res['weight']
return {'value':result, 'domain':domain}
result['product_uom'] = product.uom_id and product.uom_id.id
result['product_uom_qty'] = qty_uos / product.uos_coeff
result['th_weight'] = result['product_uom_qty'] * product.weight
return {'value': result, 'domain': domain}
sale_order_line()