Files
tryton/modules/stock_ethanol/product.py
T

229 lines
8.3 KiB
Python
Raw Normal View History

2026-03-28 13:40:06 +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.
2026-03-28 17:54:47 +01:00
from decimal import Decimal
2026-03-28 13:40:06 +01:00
from sql.conditionals import Coalesce
from trytond.model import fields
from trytond.pool import Pool, PoolMeta
2026-03-28 17:54:47 +01:00
from trytond.pyson import Eval, Id, If
2026-03-28 13:40:06 +01:00
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.")
2026-03-28 13:40:06 +01:00
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"
2026-03-28 13:40:06 +01:00
"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."),
2026-03-28 13:40:06 +01:00
'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)
2026-03-28 17:54:47 +01:00
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)