details: https://code.tryton.org/tryton/commit/75a9ec77dd93
branch: default
user: Cédric Krier <[email protected]>
date: Tue Dec 30 17:42:00 2025 +0100
description:
Use Many2One field for product and variant on stock reporting
Closes #14456
diffstat:
modules/stock/stock_reporting.py | 121 +++++++++++-
modules/stock/stock_reporting.xml | 4 +-
modules/stock/tests/scenario_stock_reporting_inventory.rst | 4 +-
modules/stock/view/reporting_inventory_daily_form.xml | 4 +-
modules/stock/view/reporting_inventory_daily_list.xml | 2 +
modules/stock/view/reporting_inventory_form.xml | 4 +-
modules/stock/view/reporting_inventory_list.xml | 2 +
modules/stock/view/reporting_inventory_move_form.xml | 4 +-
modules/stock/view/reporting_inventory_move_list.xml | 2 +
modules/stock/view/reporting_inventory_turnover_form.xml | 4 +-
modules/stock/view/reporting_inventory_turnover_list.xml | 2 +
11 files changed, 125 insertions(+), 28 deletions(-)
diffs (343 lines):
diff -r c6e8d2a3534e -r 75a9ec77dd93 modules/stock/stock_reporting.py
--- a/modules/stock/stock_reporting.py Sun Jan 18 16:51:32 2026 +0100
+++ b/modules/stock/stock_reporting.py Tue Dec 30 17:42:00 2025 +0100
@@ -47,10 +47,36 @@
__slots__ = ()
company = fields.Many2One('company.company', "Company")
- product = fields.Reference("Product", [
+ product_reference = fields.Reference("Product Reference", [
('product.product', "Variant"),
('product.template', "Product"),
- ])
+ ],
+ context={
+ 'company': Eval('company', -1),
+ },
+ depends=['company'])
+ product_template = fields.Many2One(
+ 'product.template', "Product",
+ states={
+ 'invisible': (
+ Eval('context', {}).get('product_type', 'product.template')
+ != 'product.template'),
+ },
+ context={
+ 'company': Eval('company', -1),
+ },
+ depends=['company'])
+ product = fields.Many2One(
+ 'product.product', "Variant",
+ states={
+ 'invisible': (
+ Eval('context', {}).get('product_type', 'product.template')
+ != 'product.product'),
+ },
+ context={
+ 'company': Eval('company', -1),
+ },
+ depends=['company'])
unit = fields.Function(
fields.Many2One('product.uom', "Unit"),
'on_change_with_unit')
@@ -108,9 +134,14 @@
)
if context.get('product_type') == 'product.product':
- product = Concat('product.product,', move.product)
+ product_reference = Concat('product.product,', move.product)
+ product = move.product
+ product_template = Literal(None)
else:
- product = Concat('product.template,', product_table.template)
+ product_reference = Concat(
+ 'product.template,', product_table.template)
+ product = Literal(None)
+ product_template = product_table.template
quantities = (
quantities
.join(product_table,
@@ -149,6 +180,8 @@
quantities = quantities.select(
Min(move.id).as_('id'),
+ product_reference.as_('product_reference'),
+ product_template.as_('product_template'),
product.as_('product'),
date_column.as_('date'),
next_date_column.as_('next_date'),
@@ -173,7 +206,7 @@
+ Coalesce(quantities.input_quantity, 0)
- Coalesce(quantities.output_quantity, 0),
window=Window(
- [quantities.product],
+ [quantities.product_reference],
order_by=[*cls._quantities_order_by(quantities)]))
if period:
@@ -208,7 +241,8 @@
query = quantities.join(cache, 'LEFT',
condition=(
cache.product
- == cls.product.sql_id(quantities.product, cls)))
+ == cls.product_reference.sql_id(
+ quantities.product_reference, cls)))
quantity += Coalesce(cache.quantity, 0)
else:
query = quantities
@@ -217,6 +251,8 @@
.select(
quantities.id.as_('id'),
Literal(company).as_('company'),
+ quantities.product_reference.as_('product_reference'),
+ quantities.product_template.as_('product_template'),
quantities.product.as_('product'),
quantities.input_quantity.as_('input_quantity'),
quantities.output_quantity.as_('output_quantity'),
@@ -261,10 +297,20 @@
& (move.state.in_(['done', 'assigned', 'draft'])))
return state_clause
- @fields.depends('product')
+ @fields.depends('product_reference')
def on_change_with_unit(self, name=None):
- if self.product:
- return self.product.default_uom
+ if self.product_reference:
+ return self.product_reference.default_uom
+
+ @classmethod
+ def view_attributes(cls):
+ return super().view_attributes() + [
+ ('/tree/field[@name="product_template"]', 'tree_invisible',
+ Eval('product_type', 'product.template')
+ != 'product.template'),
+ ('/tree/field[@name="product"]', 'tree_invisible',
+ Eval('product_type', 'product.template') != 'product.product'),
+ ]
class InventoryContext(_InventoryContextMixin):
@@ -459,10 +505,36 @@
__name__ = 'stock.reporting.inventory.turnover'
company = fields.Many2One('company.company', "Company")
- product = fields.Reference("Product", [
+ product_reference = fields.Reference("Product", [
('product.product', "Variant"),
('product.template', "Product"),
- ])
+ ],
+ context={
+ 'company': Eval('company', -1),
+ },
+ depends=['company'])
+ product_template = fields.Many2One(
+ 'product.template', "Product",
+ states={
+ 'invisible': (
+ Eval('context', {}).get('product_type', 'product.template')
+ != 'product.template'),
+ },
+ context={
+ 'company': Eval('company', -1),
+ },
+ depends=['company'])
+ product = fields.Many2One(
+ 'product.product', "Variant",
+ states={
+ 'invisible': (
+ Eval('context', {}).get('product_type', 'product.template')
+ != 'product.product'),
+ },
+ context={
+ 'company': Eval('company', -1),
+ },
+ depends=['company'])
unit = fields.Function(
fields.Many2One('product.uom', "Unit"),
'on_change_with_unit')
@@ -506,8 +578,11 @@
return (inventory
.select(
- cls.product.sql_id(inventory.product, cls).as_('id'),
+ cls.product_reference.sql_id(
+ inventory.product_reference, cls).as_('id'),
Literal(company).as_('company'),
+ inventory.product_reference.as_('product_reference'),
+ inventory.product_template.as_('product_template'),
inventory.product.as_('product'),
round_sql(
output_quantity,
@@ -518,9 +593,23 @@
round_sql(
output_quantity / NullIf(average_quantity, 0),
cls.turnover.digits[1]).as_('turnover'),
- group_by=[inventory.product]))
+ group_by=[
+ inventory.product_reference,
+ inventory.product_template,
+ inventory.product,
+ ]))
- @fields.depends('product')
+ @fields.depends('product_reference')
def on_change_with_unit(self, name=None):
- if self.product:
- return self.product.default_uom
+ if self.product_reference:
+ return self.product_reference.default_uom
+
+ @classmethod
+ def view_attributes(cls):
+ return super().view_attributes() + [
+ ('/tree/field[@name="product_template"]', 'tree_invisible',
+ Eval('product_type', 'product.template')
+ != 'product.template'),
+ ('/tree/field[@name="product"]', 'tree_invisible',
+ Eval('product_type', 'product.template') != 'product.product'),
+ ]
diff -r c6e8d2a3534e -r 75a9ec77dd93 modules/stock/stock_reporting.xml
--- a/modules/stock/stock_reporting.xml Sun Jan 18 16:51:32 2026 +0100
+++ b/modules/stock/stock_reporting.xml Tue Dec 30 17:42:00 2025 +0100
@@ -96,7 +96,7 @@
<field
name="context_model">stock.reporting.inventory.range.context</field>
<field
name="domain"
- eval="[('product', '=', (Eval('active_model',
'product.template'), Eval('active_id', -1)))]"
+ eval="[('product_reference', '=', (Eval('active_model',
'product.template'), Eval('active_id', -1)))]"
pyson="1"/>
<field
name="context"
@@ -177,7 +177,7 @@
<field
name="context_model">stock.reporting.inventory.range.context</field>
<field
name="domain"
- eval="[('product', '=', (Eval('active_model',
'product.template'), Eval('active_id', -1)))]"
+ eval="[('product_reference', '=', (Eval('active_model',
'product.template'), Eval('active_id', -1)))]"
pyson="1"/>
<field
name="context"
diff -r c6e8d2a3534e -r 75a9ec77dd93
modules/stock/tests/scenario_stock_reporting_inventory.rst
--- a/modules/stock/tests/scenario_stock_reporting_inventory.rst Sun Jan
18 16:51:32 2026 +0100
+++ b/modules/stock/tests/scenario_stock_reporting_inventory.rst Tue Dec
30 17:42:00 2025 +0100
@@ -148,7 +148,7 @@
... inventory, = Inventory.find([])
>>> inventory.quantity
9.0
- >>> assertEqual(inventory.product.__class__.__name__, product_type)
+ >>> assertEqual(inventory.product_reference.__class__.__name__,
product_type)
>>> with config.set_context(
... location=warehouse_loc.id,
@@ -236,4 +236,4 @@
5.5
>>> turnover.turnover
0.045
- >>> assertEqual(turnover.product.__class__.__name__, product_type)
+ >>> assertEqual(turnover.product_reference.__class__.__name__,
product_type)
diff -r c6e8d2a3534e -r 75a9ec77dd93
modules/stock/view/reporting_inventory_daily_form.xml
--- a/modules/stock/view/reporting_inventory_daily_form.xml Sun Jan 18
16:51:32 2026 +0100
+++ b/modules/stock/view/reporting_inventory_daily_form.xml Tue Dec 30
17:42:00 2025 +0100
@@ -2,8 +2,8 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
- <label name="product"/>
- <field name="product" colspan="3"/>
+ <label name="product_reference"/>
+ <field name="product_reference" colspan="3"/>
<label name="from_date"/>
<field name="from_date"/>
diff -r c6e8d2a3534e -r 75a9ec77dd93
modules/stock/view/reporting_inventory_daily_list.xml
--- a/modules/stock/view/reporting_inventory_daily_list.xml Sun Jan 18
16:51:32 2026 +0100
+++ b/modules/stock/view/reporting_inventory_daily_list.xml Tue Dec 30
17:42:00 2025 +0100
@@ -2,6 +2,8 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
+ <field name="product_reference" tree_invisible="1"/>
+ <field name="product_template" expand="2"/>
<field name="product" expand="2"/>
<field name="from_date" string="Date"/>
<field name="input_quantity" symbol="unit" optional="1"/>
diff -r c6e8d2a3534e -r 75a9ec77dd93
modules/stock/view/reporting_inventory_form.xml
--- a/modules/stock/view/reporting_inventory_form.xml Sun Jan 18 16:51:32
2026 +0100
+++ b/modules/stock/view/reporting_inventory_form.xml Tue Dec 30 17:42:00
2025 +0100
@@ -2,8 +2,8 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
- <label name="product"/>
- <field name="product" colspan="3"/>
+ <label name="product_reference"/>
+ <field name="product_reference" colspan="3"/>
<label name="quantity"/>
<field name="quantity" symbol="unit"/>
diff -r c6e8d2a3534e -r 75a9ec77dd93
modules/stock/view/reporting_inventory_list.xml
--- a/modules/stock/view/reporting_inventory_list.xml Sun Jan 18 16:51:32
2026 +0100
+++ b/modules/stock/view/reporting_inventory_list.xml Tue Dec 30 17:42:00
2025 +0100
@@ -2,6 +2,8 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
+ <field name="product_reference" tree_invisible="1"/>
+ <field name="product_template" expand="2"/>
<field name="product" expand="2"/>
<field name="quantity" symbol="unit"/>
</tree>
diff -r c6e8d2a3534e -r 75a9ec77dd93
modules/stock/view/reporting_inventory_move_form.xml
--- a/modules/stock/view/reporting_inventory_move_form.xml Sun Jan 18
16:51:32 2026 +0100
+++ b/modules/stock/view/reporting_inventory_move_form.xml Tue Dec 30
17:42:00 2025 +0100
@@ -2,8 +2,8 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
- <label name="product"/>
- <field name="product" colspan="3"/>
+ <label name="product_reference"/>
+ <field name="product_reference" colspan="3"/>
<label name="date"/>
<field name="date"/>
diff -r c6e8d2a3534e -r 75a9ec77dd93
modules/stock/view/reporting_inventory_move_list.xml
--- a/modules/stock/view/reporting_inventory_move_list.xml Sun Jan 18
16:51:32 2026 +0100
+++ b/modules/stock/view/reporting_inventory_move_list.xml Tue Dec 30
17:42:00 2025 +0100
@@ -2,6 +2,8 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
+ <field name="product_reference" tree_invisible="1"/>
+ <field name="product_template" expand="2"/>
<field name="product" expand="2"/>
<field name="date"/>
<field name="origin" expand="1" optional="1"/>
diff -r c6e8d2a3534e -r 75a9ec77dd93
modules/stock/view/reporting_inventory_turnover_form.xml
--- a/modules/stock/view/reporting_inventory_turnover_form.xml Sun Jan 18
16:51:32 2026 +0100
+++ b/modules/stock/view/reporting_inventory_turnover_form.xml Tue Dec 30
17:42:00 2025 +0100
@@ -2,8 +2,8 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
- <label name="product"/>
- <field name="product" colspan="3"/>
+ <label name="product_reference"/>
+ <field name="product_reference" colspan="3"/>
<label name="output_quantity"/>
<field name="output_quantity" symbol="unit"/>
diff -r c6e8d2a3534e -r 75a9ec77dd93
modules/stock/view/reporting_inventory_turnover_list.xml
--- a/modules/stock/view/reporting_inventory_turnover_list.xml Sun Jan 18
16:51:32 2026 +0100
+++ b/modules/stock/view/reporting_inventory_turnover_list.xml Tue Dec 30
17:42:00 2025 +0100
@@ -2,6 +2,8 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
+ <field name="product_reference" tree_invisible="1"/>
+ <field name="product_template" expand="2"/>
<field name="product" expand="2"/>
<field name="output_quantity" symbol="unit" optional="0"/>
<field name="average_quantity" symbol="unit" optional="0"/>