details:   https://code.tryton.org/tryton/commit/3dcd79aff559
branch:    default
user:      Cédric Krier <[email protected]>
date:      Sat Mar 28 17:54:47 2026 +0100
description:
        Add ethanol volume to price list formula
diffstat:

 modules/stock_ethanol/doc/design.rst                        |  13 +++
 modules/stock_ethanol/product.py                            |  55 ++++++++++++-
 modules/stock_ethanol/product.xml                           |   7 +
 modules/stock_ethanol/tests/test_module.py                  |  40 +++++++++-
 modules/stock_ethanol/tryton.cfg                            |   6 +
 modules/stock_ethanol/view/product_price_list_line_form.xml |  10 ++
 6 files changed, 129 insertions(+), 2 deletions(-)

diffs (205 lines):

diff -r 78badbeff5b4 -r 3dcd79aff559 modules/stock_ethanol/doc/design.rst
--- a/modules/stock_ethanol/doc/design.rst      Sat Mar 28 17:50:12 2026 +0100
+++ b/modules/stock_ethanol/doc/design.rst      Sat Mar 28 17:54:47 2026 +0100
@@ -30,3 +30,16 @@
 
    The `Product <product:concept-product>` concept is introduced by the
    :doc:`Product Module <product:index>`.
+
+.. _model-product.price_list:
+
+Price List
+==========
+
+When the *Stock Ethanol Module* is activated, a new parameter based on the
+volume of ethanol is added to the *Price List* formula.
+
+.. seealso::
+
+   The Price List concept is introduced by the :doc:`Product Price List Module
+   <product_price_list:index>`.
diff -r 78badbeff5b4 -r 3dcd79aff559 modules/stock_ethanol/product.py
--- a/modules/stock_ethanol/product.py  Sat Mar 28 17:50:12 2026 +0100
+++ b/modules/stock_ethanol/product.py  Sat Mar 28 17:54:47 2026 +0100
@@ -1,11 +1,13 @@
 # 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, If
+from trytond.pyson import Eval, Id, If
 
 
 class Template(metaclass=PoolMeta):
@@ -173,3 +175,54 @@
                     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)
diff -r 78badbeff5b4 -r 3dcd79aff559 modules/stock_ethanol/product.xml
--- a/modules/stock_ethanol/product.xml Sat Mar 28 17:50:12 2026 +0100
+++ b/modules/stock_ethanol/product.xml Sat Mar 28 17:54:47 2026 +0100
@@ -21,4 +21,11 @@
             <field name="name">product_product_list</field>
         </record>
     </data>
+    <data depends="product_price_list">
+        <record model="ir.ui.view" id="product_price_list_line_view_form">
+            <field name="model">product.price_list.line</field>
+            <field name="inherit" 
ref="product_price_list.price_list_line_view_form"/>
+            <field name="name">product_price_list_line_form</field>
+        </record>
+    </data>
 </tryton>
diff -r 78badbeff5b4 -r 3dcd79aff559 modules/stock_ethanol/tests/test_module.py
--- a/modules/stock_ethanol/tests/test_module.py        Sat Mar 28 17:50:12 
2026 +0100
+++ b/modules/stock_ethanol/tests/test_module.py        Sat Mar 28 17:54:47 
2026 +0100
@@ -1,6 +1,9 @@
 # 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 trytond.modules.company.tests import create_company, set_company
 from trytond.pool import Pool
 from trytond.tests.test_tryton import ModuleTestCase, with_transaction
 
@@ -8,7 +11,10 @@
 class StockEthanolTestCase(ModuleTestCase):
     "Test Stock Ethanol module"
     module = 'stock_ethanol'
-    extras = ['account_stock_eu_excise', 'product_measurements']
+    extras = [
+        'account_stock_eu_excise',
+        'product_measurements',
+        'product_price_list']
 
     @with_transaction()
     def test_convert_quantity(self):
@@ -53,5 +59,37 @@
 
         self.assertEqual(excise_tax.convert_quantity(product, 10), 1)
 
+    @with_transaction()
+    def test_price_list_context_formula(self):
+        "Test price list context formula"
+        pool = Pool()
+        Template = pool.get('product.template')
+        Product = pool.get('product.product')
+        UoM = pool.get('product.uom')
+        PriceList = pool.get('product.price_list')
+
+        unit, = UoM.search([('name', '=', "Liter")])
+        cm3, = UoM.search([('name', '=', "Cubic centimeter")])
+
+        company = create_company()
+        with set_company(company):
+            template = Template(
+                name="Product", default_uom=unit, products=None,
+                list_price=Decimal('100'),
+                contain_ethanol=True, ethanol_by_volume=.2)
+            template.save()
+            product = Product(template=template)
+            product.save()
+
+            price_list = PriceList(
+                name="List", price='list_price',
+                lines=[{
+                        'formula': 'unit_price - .05 * ethanol_volume',
+                        'ethanol_volume_uom': cm3,
+                        }])
+            price_list.save()
+
+            self.assertEqual(price_list.compute(product, 5, unit), Decimal(90))
+
 
 del ModuleTestCase
diff -r 78badbeff5b4 -r 3dcd79aff559 modules/stock_ethanol/tryton.cfg
--- a/modules/stock_ethanol/tryton.cfg  Sat Mar 28 17:50:12 2026 +0100
+++ b/modules/stock_ethanol/tryton.cfg  Sat Mar 28 17:54:47 2026 +0100
@@ -8,6 +8,7 @@
 extras_depend:
     account_stock_eu_excise
     product_measurements
+    product_price_list
 xml:
     product.xml
     stock.xml
@@ -26,3 +27,8 @@
 model:
     account_stock_eu.ExciseTax
     account_stock_eu.ExciseTaxRate
+
+[register product_price_list]
+model:
+    product.PriceList
+    product.PriceListLine
diff -r 78badbeff5b4 -r 3dcd79aff559 
modules/stock_ethanol/view/product_price_list_line_form.xml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/stock_ethanol/view/product_price_list_line_form.xml       Sat Mar 
28 17:54:47 2026 +0100
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<data>
+    <xpath expr="//field[@name='formula']" position="after">
+        <label name="ethanol_volume_uom"/>
+        <field name="ethanol_volume_uom" widget="selection"/>
+        <newline/>
+    </xpath>
+</data>

Reply via email to