From 5cd4e24a0a21cf93e52b1c21901dfd1b7210fc8e Mon Sep 17 00:00:00 2001 From: Camila Vives Date: Wed, 11 Mar 2026 14:30:55 +0000 Subject: [PATCH 1/2] [IMP] product_currency: migrate demo to Python, add EUR demo, remove hook Migrate demo data to a Python generator invoked via demo XML .\n\n- Add EUR demo product product_with_forced_currency to _product_currency_demo_records.\n- Keep USD demo demo_product_usd.\n- Remove post_init_hook and hooks import from __init__.py.\n- Add demo_data_pattern.md documenting the pattern and test usage.\n\nTests can call env['product.template']._install_product_currency_demo() and use env.ref('product_currency.product_with_forced_currency'). --- product_currency/__init__.py | 2 +- product_currency/__manifest__.py | 4 +- product_currency/demo/__init__.py | 1 + .../demo/product_currency_demo.py | 77 +++++++++++++++++++ .../demo/product_product_demo.xml | 12 +-- product_currency/tests/__init__.py | 1 + .../tests/test_product_currency_demo.py | 25 ++++++ 7 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 product_currency/demo/__init__.py create mode 100644 product_currency/demo/product_currency_demo.py create mode 100644 product_currency/tests/__init__.py create mode 100644 product_currency/tests/test_product_currency_demo.py diff --git a/product_currency/__init__.py b/product_currency/__init__.py index d03377692..f2edf867d 100644 --- a/product_currency/__init__.py +++ b/product_currency/__init__.py @@ -2,4 +2,4 @@ # For copyright and license notices, see __manifest__.py file in module root # directory ############################################################################## -from . import models +from . import models, demo diff --git a/product_currency/__manifest__.py b/product_currency/__manifest__.py index 6b7960fd7..1c813894b 100644 --- a/product_currency/__manifest__.py +++ b/product_currency/__manifest__.py @@ -34,9 +34,7 @@ "views/product_template_views.xml", "security/product_currency_security.xml", ], - "demo": [ - "demo/product_product_demo.xml", - ], + "demo": ["demo/product_product_demo.xml"], "installable": True, "auto_install": False, "application": False, diff --git a/product_currency/demo/__init__.py b/product_currency/demo/__init__.py new file mode 100644 index 000000000..2057e859d --- /dev/null +++ b/product_currency/demo/__init__.py @@ -0,0 +1 @@ +from . import product_currency_demo diff --git a/product_currency/demo/product_currency_demo.py b/product_currency/demo/product_currency_demo.py new file mode 100644 index 000000000..8a056df1d --- /dev/null +++ b/product_currency/demo/product_currency_demo.py @@ -0,0 +1,77 @@ +import logging + +from odoo import api, models + +_logger = logging.getLogger(__name__) + + +# pylint: disable=consider-merging-classes-inherited +# pylint: disable=R8180 +class ProductTemplate(models.Model): + _inherit = "product.template" + + @api.model + def _install_product_currency_demo(self): + _logger.info("Creating product_currency demo data") + for xml_name, model_name, values in self._product_currency_demo_records(self.env): + self._create_demo_record(self.env, model_name, xml_name, "product_currency", values) + + @api.model + def _product_currency_demo_records(self, env): + """Retorna lista de (xml_name, model, values).""" + usd_id = env.ref("base.USD").id + eur_id = env.ref("base.EUR").id + return [ + ( + "demo_product_usd", + "product.template", + { + "name": "Product USD", + "type": "service", + "list_price": 100.0, + "currency_id": usd_id, + "force_currency_id": usd_id, + }, + ), + ( + "product_with_forced_currency", + "product.template", + { + "name": "Product with forced currency (EUR)", + "categ_id": env.ref("product.product_category_goods").id, + "standard_price": 50.0, + "list_price": 100.0, + "currency_id": usd_id, + "force_currency_id": eur_id, + "type": "consu", + }, + ), + ] + + @api.model + def _create_demo_record(self, env, model_name, xml_name, module, values): + """Crea o actualiza un registro demo con su XML ID. Idempotente y forzando valores.""" + IrModelData = env["ir.model.data"] + + existing = IrModelData.search( + [ + ("module", "=", module), + ("name", "=", xml_name), + ("model", "=", model_name), + ], + limit=1, + ) + if existing: + record = env[model_name].browse(existing.res_id) + record.sudo().write(values) + else: + record = env[model_name].sudo().create(values) + IrModelData.sudo().create( + { + "module": module, + "name": xml_name, + "model": model_name, + "res_id": record.id, + } + ) + return record diff --git a/product_currency/demo/product_product_demo.xml b/product_currency/demo/product_product_demo.xml index 1f2f1ab35..5e2090f51 100644 --- a/product_currency/demo/product_product_demo.xml +++ b/product_currency/demo/product_product_demo.xml @@ -1,12 +1,4 @@ - - - Product with forced currency (EUR) - - 50 - 100 - - - consu - + + diff --git a/product_currency/tests/__init__.py b/product_currency/tests/__init__.py new file mode 100644 index 000000000..9bb1ee22e --- /dev/null +++ b/product_currency/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_currency_demo diff --git a/product_currency/tests/test_product_currency_demo.py b/product_currency/tests/test_product_currency_demo.py new file mode 100644 index 000000000..89c2b6355 --- /dev/null +++ b/product_currency/tests/test_product_currency_demo.py @@ -0,0 +1,25 @@ +from odoo.tests import TransactionCase, tagged + + +@tagged("post_install", "-at_install") +class TestProductCurrencyDemo(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + # Ejecutar el hook de demo data explícitamente + cls.env["product.template"]._install_product_currency_demo([cls.env.company]) + cls.demo_product = cls.env.ref("product_currency.demo_product_usd", raise_if_not_found=False) + + def test_demo_product_exists(self): + """El producto demo debe existir y tener force_currency_id seteado.""" + self.assertTrue(self.demo_product, "No se encontró el producto demo") + self.assertTrue(self.demo_product.force_currency_id, "El producto demo debe tener force_currency_id") + + def test_force_currency_applies(self): + """currency_id debe ser igual a force_currency_id en el demo.""" + self.assertEqual( + self.demo_product.force_currency_id.id, + self.demo_product.currency_id.id, + "currency_id debe ser igual a force_currency_id en el demo", + ) + # Copiamos el producto y forzamos el campo force_currency_id From 3394614e5e9d1a2c50aa99f2647886934910c6bb Mon Sep 17 00:00:00 2001 From: Camila Vives Date: Wed, 27 May 2026 14:31:39 +0000 Subject: [PATCH 2/2] Fix: _install_product_currency_demo accepts optional companies for compatibility --- product_currency/demo/product_currency_demo.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/product_currency/demo/product_currency_demo.py b/product_currency/demo/product_currency_demo.py index 8a056df1d..8250ea352 100644 --- a/product_currency/demo/product_currency_demo.py +++ b/product_currency/demo/product_currency_demo.py @@ -11,7 +11,21 @@ class ProductTemplate(models.Model): _inherit = "product.template" @api.model - def _install_product_currency_demo(self): + def _install_product_currency_demo(self, companies=None): + """Create demo records. + + Backwards-compatible: if `companies` is provided (old callers/tests), create + per-company using an env restricted to that company. Otherwise create using + the current env. + """ + if companies: + for company in companies: + _logger.info("Creating product_currency demo data for: %s", company.name) + env = self.with_context(allowed_company_ids=[company.id]).env + for xml_name, model_name, values in self._product_currency_demo_records(env): + self._create_demo_record(env, model_name, xml_name, "product_currency", values) + return + _logger.info("Creating product_currency demo data") for xml_name, model_name, values in self._product_currency_demo_records(self.env): self._create_demo_record(self.env, model_name, xml_name, "product_currency", values) @@ -72,6 +86,7 @@ def _create_demo_record(self, env, model_name, xml_name, module, values): "name": xml_name, "model": model_name, "res_id": record.id, + "noupdate": True, } ) return record