Files
tryton/uom.py
T

260 lines
10 KiB
Python
Raw Normal View History

2009-02-02 13:11:13 +01:00
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
2009-02-28 17:00:24 +01:00
from trytond.model import ModelView, ModelSQL, fields
2009-02-02 13:11:13 +01:00
from trytond.model.modelstorage import OPERATORS
2008-05-13 13:08:29 +02:00
from decimal import Decimal
2008-03-03 18:36:08 +01:00
STATES = {
'readonly': "(active == False)",
2008-03-03 18:36:08 +01:00
}
2009-02-28 17:00:24 +01:00
class UomCategory(ModelSQL, ModelView):
2008-03-03 18:36:08 +01:00
'Product uom category'
_name = 'product.uom.category'
_description = __doc__
name = fields.Char('Name', required=True, translate=True)
2008-04-08 17:25:39 +02:00
uoms = fields.One2Many('product.uom', 'category', 'Unit of Measures')
2008-03-03 18:36:08 +01:00
2008-04-22 17:49:25 +02:00
def __init__(self):
super(UomCategory, self).__init__()
self._order.insert(0, ('name', 'ASC'))
2008-03-03 18:36:08 +01:00
UomCategory()
2009-02-28 17:00:24 +01:00
class Uom(ModelSQL, ModelView):
2008-03-03 18:36:08 +01:00
'Unit of measure'
_name = 'product.uom'
_description = __doc__
2008-07-16 18:08:48 +02:00
name = fields.Char('Name', size=None, required=True, states=STATES,
translate=True)
symbol = fields.Char('Symbol', size=10, required=True, states=STATES,
translate=True)
2008-03-03 18:36:08 +01:00
category = fields.Many2One('product.uom.category', 'UOM Category',
2009-03-25 12:55:24 +01:00
required=True, ondelete='RESTRICT', states=STATES)
2008-03-03 18:36:08 +01:00
rate = fields.Float('Rate', digits=(12, 6), required=True,
2008-08-26 19:06:12 +02:00
on_change=['rate'], states=STATES,
help='The coefficient for the formula:\n' \
'1 (base unit) = coef (this unit)')
2008-03-13 01:22:57 +01:00
factor = fields.Float('Factor', digits=(12, 6), states=STATES,
2008-08-26 19:06:12 +02:00
on_change=['factor'], required=True,
help='The coefficient for the formula:\n' \
'coef (base unit) = 1 (this unit)')
2008-03-13 01:22:57 +01:00
rounding = fields.Float('Rounding Precision', digits=(12, 6),
2008-08-26 19:06:12 +02:00
required=True, states=STATES)
digits = fields.Integer('Display Digits')
2008-03-03 18:36:08 +01:00
active = fields.Boolean('Active')
2008-08-26 18:18:38 +02:00
def check_xml_record(self, cursor, user, ids, values, context=None):
return True
2008-03-03 18:36:08 +01:00
def default_rate(self, cursor, user, context=None):
return 1.0
def default_factor(self, cursor, user, context=None):
return 1.0
def default_active(self, cursor, user, context=None):
return 1
def default_rounding(self, cursor, user, context=None):
return 0.01
2008-08-26 19:06:12 +02:00
def default_digits(self, cursor, user, context=None):
return 2
2008-11-13 15:18:40 +01:00
def default_category(self, cursor, user, context=None):
category_obj = self.pool.get('product.uom.category')
product_obj = self.pool.get('product.product')
if context is None:
context = {}
if 'category' in context:
if isinstance(context['category'], (tuple, list)) \
and len(context['category']) > 1 \
and context['category'][1] in ('uom.category',
'product.default_uom.category'):
if context['category'][1] == 'uom.category':
if not context['category'][0]:
return False
uom = self.browse(cursor, user, context['category'][0],
context=context)
return uom.category.id
2008-11-13 15:18:40 +01:00
else:
if not context['category'][0]:
return False
product = product_obj.browse(cursor, user,
context['category'][0], context=context)
return product.default_uom.category.id
2008-11-13 15:18:40 +01:00
return False
2008-03-03 18:36:08 +01:00
def on_change_factor(self, cursor, user, ids, value, context=None):
if value.get('factor', 0.0) == 0.0:
2008-03-14 14:08:26 +01:00
return {'rate': 0.0}
2008-03-13 01:22:57 +01:00
return {'rate': round(1.0/value['factor'], 6)}
2008-03-03 18:36:08 +01:00
def on_change_rate(self, cursor, user, ids, value, context=None):
if value.get('rate', 0.0) == 0.0:
2008-03-14 14:08:26 +01:00
return {'factor': 0.0}
2008-03-13 01:22:57 +01:00
return {'factor': round(1.0/value['rate'], 6)}
2008-03-14 14:08:26 +01:00
def __init__(self):
super(Uom, self).__init__()
self._sql_constraints += [
('non_zero_rate_factor', 'CHECK((rate != 0.0) or (factor != 0.0))',
'Rate and factor can not be both equal to zero.')
]
self._order.insert(0, ('name', 'ASC'))
self._error_messages.update({
'change_uom_rate_title':'You cannot change Rate, Factor or '\
'Category on a Unit of Measure. ',
'change_uom_rate': 'If the UOM is still not used, you can '\
'delete it ortherwise you can deactivate it and create a new one.'
})
2008-03-14 14:08:26 +01:00
2008-03-13 01:22:57 +01:00
@staticmethod
def round(number, precision=1.0):
2008-10-29 18:27:08 +01:00
return round(number / precision) * precision
@staticmethod
def check_factor_and_rate(values):
factor = None
rate = None
if ('factor' not in values) and ('rate' not in values):
return values
elif 'factor' in values and 'rate' in values:
if values['rate'] == 0.0 and values['factor'] == 0.0:
return values
elif values['factor'] != 0.0 and \
values['rate'] != 0.0:
2008-03-13 01:22:57 +01:00
if values['rate'] == round(1.0/values['factor'], 6) or \
values['factor'] == round(1.0/values['rate'], 6):
return values
else:
2008-03-13 01:22:57 +01:00
factor = round(1.0/values['rate'], 6)
elif values['rate'] != 0.0 and \
2008-03-13 01:22:57 +01:00
values['factor'] != round(1.0/values['rate'], 6):
factor = round(1.0/values['rate'], 6)
elif values['factor'] != 0.0 and \
2008-03-13 01:22:57 +01:00
values['rate'] != round(1.0/values['factor'], 6):
rate = round(1.0/values['factor'], 6)
else:
return values
elif 'rate' in values:
if values['rate'] != 0.0:
2008-03-13 01:22:57 +01:00
factor = round(1.0/values['rate'], 6)
else:
factor = 0.0
elif 'factor' in values:
if values['factor'] != 0.0:
2008-03-13 01:22:57 +01:00
rate = round(1.0/values['factor'], 6)
else:
rate = 0.0
if rate != None or factor != None:
values = values.copy()
if rate != None: values['rate'] = rate
if factor != None: values['factor'] = factor
return values
2008-03-13 01:22:57 +01:00
def create(self, cursor, user, values, context=None):
values = self.check_factor_and_rate(values)
return super(Uom, self).create(cursor, user, values, context)
2008-03-13 01:22:57 +01:00
def write(self, cursor, user, ids, values, context=None):
if 'rate' in values or 'factor' in values or 'category' in values:
uoms = self.browse(cursor, user, ids, context=context)
for uom in uoms:
if ('rate' in values and values['rate'] != uom.factor) \
or ('factor' in values and values['factor'] != uom.rate) \
or ('category' in values and values['category'] != uom.category.id):
self.raise_user_error(cursor, 'change_uom_rate_title',
error_description='change_uom_rate')
return super(Uom, self).write(cursor, user, ids, values, context)
def compute_qty(self, cursor, user, from_uom, qty, to_uom=False,
2008-11-03 15:39:40 +01:00
round=True, context=None):
"""
Convert quantity for given uom's. from_uom and to_uom should
be browse records.
"""
if not from_uom or not qty or not to_uom:
return qty
if from_uom.category.id <> to_uom.category.id:
return qty
2008-03-13 01:22:57 +01:00
if from_uom.factor >= 1.0: # Choose the more precise field.
amount = qty * from_uom.factor
else:
2008-03-13 01:22:57 +01:00
amount = qty / from_uom.rate
if to_uom:
2008-03-13 01:22:57 +01:00
if to_uom.factor >= 1.0:
2008-11-03 15:39:40 +01:00
amount = amount / to_uom.factor
else:
2008-11-03 15:39:40 +01:00
amount = amount * to_uom.rate
if round:
amount = self.round(amount, to_uom.rounding)
return amount
def compute_price(self, cursor, user, from_uom, price, to_uom=False,
context=None):
"""
Convert price for given uom's. from_uom and to_uom should be
browse records.
"""
if not from_uom or not price or not to_uom:
return price
if from_uom.category.id <> to_uom.category.id:
return price
2008-05-13 13:08:29 +02:00
2008-03-13 01:22:57 +01:00
if from_uom.factor >= 1.0:
2008-05-13 13:08:29 +02:00
new_price = price / Decimal(str(from_uom.factor))
else:
2008-05-13 13:08:29 +02:00
new_price = price * Decimal(str(from_uom.rate))
2008-03-13 01:22:57 +01:00
if to_uom.factor >= 1.0:
2008-05-13 13:08:29 +02:00
new_price = new_price * Decimal(str(to_uom.factor))
else:
2008-05-13 13:08:29 +02:00
new_price = new_price / Decimal(str(to_uom.rate))
2008-03-14 14:08:26 +01:00
return new_price
2008-03-03 18:36:08 +01:00
def search(self, cursor, user, args, offset=0, limit=None, order=None,
context=None, count=False, query_string=False):
product_obj = self.pool.get('product.product')
args = args[:]
def process_args(args):
i = 0
while i < len(args):
2008-09-30 17:10:36 +02:00
#add test for xmlrpc that doesn't handle tuple
if (isinstance(args[i], tuple) \
or (isinstance(args[i], list) and len(args[i]) > 2 \
and args[i][1] in OPERATORS)) \
and args[i][0] == 'category' \
and isinstance(args[i][2], (list, tuple)) \
and len(args[i][2]) == 2 \
2008-09-30 17:10:36 +02:00
and args[i][2][1] in ('product.default_uom.category',
'uom.category'):
if not args[i][2][0]:
args[i] = ('id', '!=', '0')
else:
2008-09-30 17:10:36 +02:00
if args[i][2][1] == 'product.default_uom.category':
product = product_obj.browse(cursor, user,
args[i][2][0], context=context)
category_id = product.default_uom.category.id
else:
uom = self.browse(cursor, user, args[i][2][0],
context=context)
category_id = uom.category.id
args[i] = (args[i][0], args[i][1], category_id)
2008-09-30 17:10:36 +02:00
elif isinstance(args[i], list):
process_args(args[i])
i += 1
process_args(args)
return super(Uom, self).search(cursor, user, args, offset=offset,
limit=limit, order=order, context=context, count=count,
query_string=query_string)
2008-03-03 18:36:08 +01:00
Uom()