Files

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)