Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions product_analytic/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,18 @@ Authors
Contributors
------------

- Alexis de Lattre <alexis.delattre@akretion.com>
- Javier Iniesta <javieria@antiun.com>
- Luis M. Ontalba <luis.martinez@tecnativa.com>
- David Vidal <david.vidal@tecnativa.com>
- Thore Baden
- Pimolnat Suntian <pimolnats@ecosoft.co.th>
- Reyes4711
- Denis Roussel <denis.roussel@acsone.eu>
- Darius Žižys <darius@vialaurea.lt>
- Jacques-Etienne Baudoux (BCIM) <je@bcim.be>
- Saran Lim. <saranl@ecosoft.co.th>
- Thiago Mulero <thiago.mulero@forgeflow.com>
- Alexis de Lattre <alexis.delattre@akretion.com>
- Javier Iniesta <javieria@antiun.com>
- Luis M. Ontalba <luis.martinez@tecnativa.com>
- David Vidal <david.vidal@tecnativa.com>
- Thore Baden
- Pimolnat Suntian <pimolnats@ecosoft.co.th>
- Reyes4711
- Denis Roussel <denis.roussel@acsone.eu>
- Darius Žižys <darius@vialaurea.lt>
- Jacques-Etienne Baudoux (BCIM) <je@bcim.be>
- Saran Lim. <saranl@ecosoft.co.th>
- Thiago Mulero <thiago.mulero@forgeflow.com>

Maintainers
-----------
Expand Down
5 changes: 4 additions & 1 deletion product_analytic/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
"author": "Akretion, Tecnativa, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-analytic",
"depends": ["account"],
"data": ["views/product_view.xml"],
"data": [
"views/product_view.xml",
"views/product_template_view.xml",
],
"demo": ["demo/product_demo.xml"],
"installable": True,
}
1 change: 1 addition & 0 deletions product_analytic/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

from . import product
from . import product_category
from . import product_template
45 changes: 45 additions & 0 deletions product_analytic/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from odoo import api, fields, models


class ProductTemplate(models.Model):
_inherit = "product.template"

analytic_distribution_model_ids = fields.One2many(
"account.analytic.distribution.model",
string="Analytic Distribution Models",
compute="_compute_analytic_distribution_models",
inverse="_inverse_analytic_distribution_models",
)

@api.depends(
"product_variant_ids", "product_variant_ids.analytic_distribution_model_ids"
)
def _compute_analytic_distribution_models(self):
for tmpl in self:
tmpl.analytic_distribution_model_ids = (
tmpl.product_variant_id.analytic_distribution_model_ids
)

def _inverse_analytic_distribution_models(self):
for tmpl in self:
if tmpl.product_variant_count > 1:
continue
product_variant = tmpl.product_variant_id
product_variant.analytic_distribution_model_ids = (
tmpl.analytic_distribution_model_ids
)

@api.model_create_multi
def create(self, vals_list):
templates = super().create(vals_list)
for template, vals in zip(templates, vals_list, strict=False):
distribution_cmds = vals.get("analytic_distribution_model_ids", False)
if not distribution_cmds or template.product_variant_count > 1:
continue
product_variant = template.product_variant_id
product_variant.write(
{
"analytic_distribution_model_ids": distribution_cmds,
}
)
return templates
1 change: 1 addition & 0 deletions product_analytic/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import test_account_move
from . import test_product_template
150 changes: 150 additions & 0 deletions product_analytic/tests/test_product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Copyright 2025 Your Name
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import Command
from odoo.tests.common import TransactionCase


class TestProductTemplate(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.default_plan = cls.env["account.analytic.plan"].create(
{"name": "Default Plan", "applicability_ids": False}
)
cls.analytic_account1 = cls.env["account.analytic.account"].create(
{"name": "test analytic_account1", "plan_id": cls.default_plan.id}
)
cls.analytic_account2 = cls.env["account.analytic.account"].create(
{"name": "test analytic_account2", "plan_id": cls.default_plan.id}
)
cls.distribution_model1 = cls.env["account.analytic.distribution.model"].create(
{
"account_prefix": "TEST",
"analytic_distribution": {cls.analytic_account1.id: 100},
}
)
cls.distribution_model2 = cls.env["account.analytic.distribution.model"].create(
{
"account_prefix": "DEMO",
"analytic_distribution": {cls.analytic_account2.id: 100},
}
)

def test_compute_analytic_distribution_models(self):
"""Test that analytic_distribution_model_ids is computed from product variant"""
template = self.env["product.template"].create({"name": "Test Template"})
# Add distribution models to the product variant
template.product_variant_id.write(
{
"analytic_distribution_model_ids": [
Command.set(
[self.distribution_model1.id, self.distribution_model2.id]
)
]
}
)

# Check that template gets the models from variant
self.assertEqual(len(template.analytic_distribution_model_ids), 2)
self.assertIn(
self.distribution_model1, template.analytic_distribution_model_ids
)
self.assertIn(
self.distribution_model2, template.analytic_distribution_model_ids
)

def test_inverse_analytic_distribution_models_single_variant(self):
"""Test inverse method for single variant template"""
template = self.env["product.template"].create({"name": "Test Template"})
# Set distribution models via template
template.write(
{
"analytic_distribution_model_ids": [
Command.set([self.distribution_model1.id])
]
}
)

# Check that variant gets the models
self.assertEqual(
len(template.product_variant_id.analytic_distribution_model_ids), 1
)
self.assertIn(
self.distribution_model1,
template.product_variant_id.analytic_distribution_model_ids,
)

def test_inverse_analytic_distribution_models_multi_variant(self):
"""Test inverse method doesn't affect multi-variant templates"""
template = self.env["product.template"].create(
{
"name": "Test Template",
}
)
# Add a variant to make it multi-variant
self.env["product.product"].create(
{
"product_tmpl_id": template.id,
"name": "Variant 2",
}
)
# Get original variant models
original_models = (
template.product_variant_id.analytic_distribution_model_ids.ids
)
# Try to set distribution models via template (should be ignored)
template.write(
{
"analytic_distribution_model_ids": [
Command.set([self.distribution_model1.id])
]
}
)
# Check that variant models are unchanged
self.assertEqual(
template.product_variant_id.analytic_distribution_model_ids.ids,
original_models,
)

def test_create_with_analytic_distribution_models(self):
"""Test creating template with distribution models"""
template = self.env["product.template"].create(
{
"name": "Test Template",
"analytic_distribution_model_ids": [
Command.link(self.distribution_model1.id),
Command.link(self.distribution_model2.id),
],
}
)
# Check that variant gets the models
self.assertEqual(
len(template.product_variant_id.analytic_distribution_model_ids), 2
)
self.assertIn(
self.distribution_model1,
template.product_variant_id.analytic_distribution_model_ids,
)
self.assertIn(
self.distribution_model2,
template.product_variant_id.analytic_distribution_model_ids,
)

def test_create_multi_variant_with_distribution_models(self):
"""Test creating multi-variant with distribution models (should be ignored)"""
template = self.env["product.template"].create(
{
"name": "Test Template",
}
)
# Add second variant
self.env["product.product"].create(
{
"product_tmpl_id": template.id,
"name": "Variant 2",
}
)
# Check that no distribution models were set on variants
self.assertEqual(
len(template.product_variant_id.analytic_distribution_model_ids), 0
)
48 changes: 48 additions & 0 deletions product_analytic/views/product_template_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version='1.0' encoding='utf-8' ?>
<odoo>
<record id="product_template_only_form_view_inherit" model="ir.ui.view">
<field name="name">product.template.only.form.view.product.analytic</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="account.product_template_form_view" />
<field name="arch" type="xml">
<group name="properties" position="after">
<group
name="analytic"
string="Analytic"
invisible="is_product_variant"
groups="analytic.group_analytic_accounting,!product.group_product_variant"
>
<field
name="analytic_distribution_model_ids"
nolabel="1"
context="{'default_product_id': product_variant_id}"
>
<list editable="top">
<field name="sequence" widget="handle" />
<field name="prefix_placeholder" column_invisible="1" />
<field
name="account_prefix"
optional="show"
widget="char_with_placeholder_field"
options="{'placeholder_field': 'prefix_placeholder'}"
/>
<field name="partner_id" optional="show" />
<field name="partner_category_id" optional="hide" />
<field name="product_categ_id" optional="hide" />
<field
name="company_id"
groups="base.group_multi_company"
optional="show"
/>
<field
name="analytic_distribution"
widget="analytic_distribution"
options="{'force_applicability': 'optional', 'disable_save': true}"
/>
</list>
</field>
</group>
</group>
</field>
</record>
</odoo>
6 changes: 5 additions & 1 deletion product_analytic/views/product_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
<field name="inherit_id" ref="product.product_normal_form_view" />
<field name="arch" type="xml">
<group name="properties" position="after">
<group name="analytic" string="Analytic">
<group
name="analytic"
string="Analytic"
groups="analytic.group_analytic_accounting"
>
<field name="analytic_distribution_model_ids">
<list open_form_view="True" editable="top">
<field name="sequence" widget="handle" />
Expand Down