229 lines
8.3 KiB
Python
229 lines
8.3 KiB
Python
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
|
# this repository contains the full copyright notices and license terms.
|
|
|
|
from decimal import Decimal
|
|
|
|
from sql.conditionals import Coalesce
|
|
|
|
from trytond.model import fields
|
|
from trytond.pool import Pool, PoolMeta
|
|
from trytond.pyson import Eval, Id, If
|
|
|
|
|
|
class Template(metaclass=PoolMeta):
|
|
__name__ = 'product.template'
|
|
|
|
contain_ethanol = fields.Boolean(
|
|
"Contain Alcohol",
|
|
states={
|
|
'invisible': Eval('type', 'goods') != 'goods',
|
|
},
|
|
help="Check if goods contain ethanol/alcohol.")
|
|
ethanol_by_volume = fields.Float(
|
|
"Alcohol By Volume", digits=(1, 4),
|
|
domain=[If(Eval('contain_ethanol'),
|
|
['OR',
|
|
[
|
|
('ethanol_by_volume', '>=', 0),
|
|
('ethanol_by_volume', '<=', 1),
|
|
],
|
|
('ethanol_by_volume', '=', None),
|
|
],
|
|
[('ethanol_by_volume', '=', None)])],
|
|
states={
|
|
'invisible': ~Eval('contain_ethanol'),
|
|
},
|
|
help="How much ethanol/alcohol is contained "
|
|
"in a given volume at 20 degrees Celsius.")
|
|
ethanol_volume = fields.Function(
|
|
fields.Float(
|
|
"Alcohol Volume", digits='ethanol_volume_unit',
|
|
help="The volume of ethanol/alcohol in the location."),
|
|
'sum_product')
|
|
ethanol_volume_unit = fields.Function(
|
|
fields.Many2One(
|
|
'product.uom', "Alcohol Volume UoM",
|
|
states={
|
|
'invisible': ~Eval('ethanol_volume'),
|
|
}),
|
|
'get_ethanol_volume_unit')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super().__setup__()
|
|
cls._modify_no_move += [
|
|
('contain_ethanol',
|
|
'stock_ethanol.msg_product_change_contain_ethanol'),
|
|
('ethanol_by_volume',
|
|
'stock_ethanol.msg_product_change_ethanol_by_volume'),
|
|
]
|
|
|
|
@classmethod
|
|
def get_ethanol_volume_unit(cls, templates, name):
|
|
pool = Pool()
|
|
Configuration = pool.get('stock.configuration')
|
|
configuration = Configuration(1)
|
|
uom = configuration.get_multivalue('ethanol_volume_uom')
|
|
return dict.fromkeys(map(int, templates), uom.id)
|
|
|
|
@classmethod
|
|
def view_attributes(cls):
|
|
return super().view_attributes() + [
|
|
('//page[@id="ethanol"]', 'states', {
|
|
'invisible': ~Eval('contain_ethanol'),
|
|
}),
|
|
]
|
|
|
|
|
|
class Product(metaclass=PoolMeta):
|
|
__name__ = 'product.product'
|
|
|
|
ethanol_by_volume = fields.Float(
|
|
"Alcohol By Volume", digits=(1, 4),
|
|
domain=[If(Eval('contain_ethanol'),
|
|
['OR',
|
|
[
|
|
('ethanol_by_volume', '>=', 0),
|
|
('ethanol_by_volume', '<=', 1),
|
|
],
|
|
('ethanol_by_volume', '=', None),
|
|
],
|
|
[('ethanol_by_volume', '=', None)])],
|
|
states={
|
|
'invisible': ~Eval('contain_ethanol'),
|
|
},
|
|
help="How much ethanol/alcohol is contained "
|
|
"in a given volume at 20 degrees Celsius.\n"
|
|
"Leave empty to use the template value.")
|
|
ethanol_by_volume_used = fields.Function(fields.Float(
|
|
"Alcohol By Volume", digits=(1, 4),
|
|
states={
|
|
'invisible': ~Eval('contain_ethanol'),
|
|
},
|
|
help="How much ethanol/alcohol is contained "
|
|
"in a given volume at 20 degrees Celsius."),
|
|
'get_ethanol_by_volume_used',
|
|
searcher='search_ethanol_by_volume_used')
|
|
|
|
ethanol_volume = fields.Function(
|
|
fields.Float(
|
|
"Alcohol Volume", digits='ethanol_volume_unit',
|
|
help="The volume of ethanol/alcohol in the location."),
|
|
'get_ethanol_volume')
|
|
|
|
def get_ethanol_by_volume_used(self, name):
|
|
if self.contain_ethanol:
|
|
if self.ethanol_by_volume is not None:
|
|
return self.ethanol_by_volume
|
|
else:
|
|
return self.template.ethanol_by_volume
|
|
|
|
@classmethod
|
|
def search_ethanol_by_volume_used(cls, name, clause):
|
|
operator = clause[1]
|
|
if operator.startswith('!') or operator.startswith('not '):
|
|
bool_op = 'AND'
|
|
else:
|
|
bool_op = 'OR'
|
|
return [bool_op, [
|
|
('ethanol_by_volume', '!=', None),
|
|
('ethanol_by_volume', *clause[1:]),
|
|
], [
|
|
('ethanol_by_volume', '=', None),
|
|
('template.ethanol_by_volume', *clause[1:]),
|
|
]]
|
|
|
|
@classmethod
|
|
def order_ethanol_by_volume_used(cls, tables):
|
|
pool = Pool()
|
|
Template = pool.get('product.template')
|
|
product, _ = tables[None]
|
|
if 'template' not in tables:
|
|
template = Template.__table__()
|
|
tables['template'] = {
|
|
None: (template, product.template == template.id),
|
|
}
|
|
else:
|
|
template, _ = tables['template'][None]
|
|
return [
|
|
Coalesce(product.ethanol_by_volume, template.ethanol_by_volume)]
|
|
|
|
def get_ethanol_volume(self, name):
|
|
pool = Pool()
|
|
UoM = pool.get('product.uom')
|
|
|
|
if unit := self.ethanol_volume_unit:
|
|
ethanol_by_volume = self.ethanol_by_volume_used
|
|
if ethanol_by_volume is not None and self.quantity is not None:
|
|
if self.default_uom.category == unit.category:
|
|
quantity = self.quantity * ethanol_by_volume
|
|
return UoM.compute_qty(self.default_uom, quantity, unit)
|
|
elif getattr(self, 'volume', None) is not None:
|
|
quantity = (
|
|
self.quantity * self.volume * ethanol_by_volume)
|
|
return UoM.compute_qty(self.volume_uom, quantity, unit)
|
|
|
|
def compute_ethanol_volume(self, quantity, unit, unit_volume, round=True):
|
|
pool = Pool()
|
|
UoM = pool.get('product.uom')
|
|
assert unit.category == self.default_uom.category
|
|
if (ethanol_by_volume := self.ethanol_by_volume_used) is not None:
|
|
if unit.category == unit_volume.category:
|
|
volume = quantity * ethanol_by_volume
|
|
else:
|
|
if getattr(self, 'volume', None) is not None:
|
|
volume = quantity * self.volume * ethanol_by_volume
|
|
unit = self.volume_uom
|
|
return UoM.compute_qty(unit, volume, unit_volume, round=round)
|
|
|
|
|
|
class PriceList(metaclass=PoolMeta):
|
|
__name__ = 'product.price_list'
|
|
|
|
def get_context_formula(self, product, quantity, uom, pattern=None):
|
|
pool = Pool()
|
|
UoM = pool.get('product.uom')
|
|
ModelData = pool.get('ir.model.data')
|
|
|
|
liter = UoM(ModelData.get_id('product', 'uom_liter'))
|
|
|
|
context = super().get_context_formula(
|
|
product, quantity, uom, pattern=pattern)
|
|
ethanol_volume = None
|
|
if product:
|
|
ethanol_volume = product.compute_ethanol_volume(
|
|
1, product.default_uom, liter, round=False)
|
|
if ethanol_volume is None:
|
|
ethanol_volume = 0
|
|
context['names']['ethanol_volume'] = Decimal(str(ethanol_volume))
|
|
return context
|
|
|
|
|
|
class PriceListLine(metaclass=PoolMeta):
|
|
__name__ = 'product.price_list.line'
|
|
|
|
ethanol_volume_uom = fields.Many2One(
|
|
'product.uom', "AlcoholVolume UoM",
|
|
domain=[('category', '=', Id('product', 'uom_cat_volume'))],
|
|
help="Leave empty for liter.")
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super().__setup__()
|
|
cls.formula.help += ("\n"
|
|
"-ethanol_volume: the volume of alcohol in 1 unit of product")
|
|
|
|
def get_unit_price(self, **context):
|
|
pool = Pool()
|
|
UoM = pool.get('product.uom')
|
|
ModelData = pool.get('ir.model.data')
|
|
|
|
if self.ethanol_volume_uom:
|
|
context['names'] = context['names'].copy()
|
|
liter = UoM(ModelData.get_id('product', 'uom_liter'))
|
|
ethanol_volume = UoM.compute_qty(
|
|
liter, float(context['names']['ethanol_volume']),
|
|
self.ethanol_volume_uom, round=False)
|
|
context['names']['ethanol_volume'] = Decimal(str(ethanol_volume))
|
|
return super().get_unit_price(**context)
|