From 1bf259023cb53cc8b7dd0c64be1225cc8b02cb54 Mon Sep 17 00:00:00 2001
From: juancarlosonate-tecnativa
Date: Tue, 29 Jul 2025 11:06:53 +0200
Subject: [PATCH 1/3] [ADD] product_eprel
TT57294
---
product_eprel/README.rst | 101 ++++
product_eprel/__init__.py | 1 +
product_eprel/__manifest__.py | 23 +
product_eprel/data/eprel_cron.xml | 15 +
.../data/eprel_product_categories.xml | 144 ++++++
product_eprel/demo/product_template.xml | 22 +
product_eprel/i18n/es.po | 208 ++++++++
product_eprel/i18n/product_eprel.pot | 205 ++++++++
product_eprel/models/__init__.py | 6 +
product_eprel/models/product_category.py | 11 +
.../models/product_category_eprel.py | 11 +
product_eprel/models/product_product.py | 11 +
product_eprel/models/product_template.py | 121 +++++
product_eprel/models/res_company.py | 9 +
product_eprel/models/res_config_settings.py | 9 +
product_eprel/readme/CONFIGURE.md | 2 +
product_eprel/readme/CONTRIBUTORS.md | 2 +
product_eprel/readme/DESCRIPTION.md | 3 +
product_eprel/readme/USAGE.md | 8 +
product_eprel/security/ir.model.access.csv | 3 +
product_eprel/static/description/index.html | 452 ++++++++++++++++++
product_eprel/tests/__init__.py | 1 +
product_eprel/tests/test_product_eprel.py | 54 +++
.../views/product_category_views.xml | 13 +
.../views/product_template_views.xml | 29 ++
.../views/res_config_settings_views.xml | 29 ++
26 files changed, 1493 insertions(+)
create mode 100644 product_eprel/README.rst
create mode 100644 product_eprel/__init__.py
create mode 100644 product_eprel/__manifest__.py
create mode 100644 product_eprel/data/eprel_cron.xml
create mode 100644 product_eprel/data/eprel_product_categories.xml
create mode 100644 product_eprel/demo/product_template.xml
create mode 100644 product_eprel/i18n/es.po
create mode 100644 product_eprel/i18n/product_eprel.pot
create mode 100644 product_eprel/models/__init__.py
create mode 100644 product_eprel/models/product_category.py
create mode 100644 product_eprel/models/product_category_eprel.py
create mode 100644 product_eprel/models/product_product.py
create mode 100644 product_eprel/models/product_template.py
create mode 100644 product_eprel/models/res_company.py
create mode 100644 product_eprel/models/res_config_settings.py
create mode 100644 product_eprel/readme/CONFIGURE.md
create mode 100644 product_eprel/readme/CONTRIBUTORS.md
create mode 100644 product_eprel/readme/DESCRIPTION.md
create mode 100644 product_eprel/readme/USAGE.md
create mode 100644 product_eprel/security/ir.model.access.csv
create mode 100644 product_eprel/static/description/index.html
create mode 100644 product_eprel/tests/__init__.py
create mode 100644 product_eprel/tests/test_product_eprel.py
create mode 100644 product_eprel/views/product_category_views.xml
create mode 100644 product_eprel/views/product_template_views.xml
create mode 100644 product_eprel/views/res_config_settings_views.xml
diff --git a/product_eprel/README.rst b/product_eprel/README.rst
new file mode 100644
index 00000000000..f45d5fd3c21
--- /dev/null
+++ b/product_eprel/README.rst
@@ -0,0 +1,101 @@
+=============
+Product EPREL
+=============
+
+..
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! source digest: sha256:63acb92eb94cf81305149bf8e5f5b5e8199b65070f2088042db63610b188e6bd
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
+ :target: https://odoo-community.org/page/development-status
+ :alt: Beta
+.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproduct--attribute-lightgray.png?logo=github
+ :target: https://github.com/OCA/product-attribute/tree/14.0/product_eprel
+ :alt: OCA/product-attribute
+.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
+ :target: https://translation.odoo-community.org/projects/product-attribute-14-0/product-attribute-14-0-product_eprel
+ :alt: Translate me on Weblate
+.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
+ :target: https://runboat.odoo-community.org/builds?repo=OCA/product-attribute&target_branch=14.0
+ :alt: Try me on Runboat
+
+|badge1| |badge2| |badge3| |badge4| |badge5|
+
+This module connects Odoo with the EPREL API to fetch energy labels and
+fiches for products that have a model identifier and an EPREL product
+category. It retrieves the EPREL registration number and builds URLs.
+
+**Table of contents**
+
+.. contents::
+ :local:
+
+Configuration
+=============
+
+To configure this module, go to Settings > General Settings. Under the
+Integrations section, enter your EPREL API key.
+
+Usage
+=====
+
+- In the **EPREL** page of the product form you will find:
+
+ - Model Identifier (required).
+ - URLs for product fiche, energy label, and energy arrow.
+
+- Product categories must have a valid **EPREL Category**.
+- Usage options:
+
+ 1. Click **Get EPREL data** in the product form.
+ 2. Enable the scheduled action **EPREL: Sync Product Data** in
+ *Settings > Technical > Scheduled Actions*.
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues `_.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us to smash it by providing a detailed and welcomed
+`feedback `_.
+
+Do not contact contributors directly about support or help with technical issues.
+
+Credits
+=======
+
+Authors
+-------
+
+* Tecnativa
+
+Contributors
+------------
+
+- `Tecnativa `__
+
+ - Juan Carlos Oñate
+
+Maintainers
+-----------
+
+This module is maintained by the OCA.
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: https://odoo-community.org
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
+This module is part of the `OCA/product-attribute `_ project on GitHub.
+
+You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/product_eprel/__init__.py b/product_eprel/__init__.py
new file mode 100644
index 00000000000..0650744f6bc
--- /dev/null
+++ b/product_eprel/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/product_eprel/__manifest__.py b/product_eprel/__manifest__.py
new file mode 100644
index 00000000000..784491fa51a
--- /dev/null
+++ b/product_eprel/__manifest__.py
@@ -0,0 +1,23 @@
+# Copyright 2025 Juan Carlos Oñate - Tecnativa
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+{
+ "name": "Product EPREL",
+ "summary": "Manage EPREL model identifiers and energy label data for products.",
+ "version": "14.0.1.0.0",
+ "author": "Tecnativa, Odoo Community Association (OCA)",
+ "website": "https://github.com/OCA/product-attribute",
+ "license": "AGPL-3",
+ "depends": ["product"],
+ "data": [
+ "security/ir.model.access.csv",
+ "views/product_category_views.xml",
+ "views/product_template_views.xml",
+ "views/res_config_settings_views.xml",
+ "data/eprel_cron.xml",
+ "data/eprel_product_categories.xml",
+ ],
+ "demo": [
+ "demo/product_template.xml",
+ ],
+ "installable": True,
+}
diff --git a/product_eprel/data/eprel_cron.xml b/product_eprel/data/eprel_cron.xml
new file mode 100644
index 00000000000..ffcab32bee8
--- /dev/null
+++ b/product_eprel/data/eprel_cron.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ EPREL: Sync Product Data
+
+ code
+ model._get_eprel_registration_number()
+ 1
+ months
+ -1
+
+
+
+
diff --git a/product_eprel/data/eprel_product_categories.xml b/product_eprel/data/eprel_product_categories.xml
new file mode 100644
index 00000000000..556fb21adef
--- /dev/null
+++ b/product_eprel/data/eprel_product_categories.xml
@@ -0,0 +1,144 @@
+
+
+
+
+ Electronic displays
+ electronicdisplays
+
+
+ Household washing machines
+ washingmachines2019
+
+
+ Household washer-dryers
+ washerdriers2019
+
+
+ Light sources
+ lightsources
+
+
+ Refrigerating appliances
+ refrigeratingappliances2019
+
+
+ Household dishwashers
+ dishwashers2019
+
+
+ Refrigerating appliances with a direct sales function
+ refrigeratingappliancesdirectsalesfunction
+
+
+ Tyres
+ tyres
+
+
+ Smartphones and slate tablets
+ smartphonestablets20231669
+
+
+ Household tumble dryers
+ tumbledryers20232534
+
+
+
+ Air conditioners
+ airconditioners
+
+
+ Domestic Ovens
+ ovens
+
+
+ Range hoods
+ rangehoods
+
+
+ Household tumble driers
+ tumbledriers
+
+
+ Local space heaters
+ localspaceheaters
+
+
+ Professional refrigerating storage cabinets
+ professionalrefrigeratedstoragecabinets
+
+
+ Residential Ventilation Units
+ residentialventilationunits
+
+
+ Solid fuel boilers
+ solidfuelboilers
+
+
+ Packages of solid fuel boilers
+ solidfuelboilerpackages
+
+
+ Space heaters/Combination heaters
+ spaceheaters
+
+
+ Packages of space heaters/combinations heaters
+ spaceheaterpackages
+
+
+ Temperature controls for space heaters
+ spaceheatertemperaturecontrol
+
+
+ Solar devices for space heaters
+ spaceheatersolardevice
+
+
+ Water heaters
+ waterheaters
+
+
+ Packages of water heaters
+ waterheaterpackages
+
+
+ Hot water storage tanks for water heaters
+ hotwaterstoragetanks
+
+
+ Solar devices for water heaters
+ waterheatersolardevices
+
+
+
+ Electrical Lamps
+ lamps
+
+
+ Household combined washer-driers
+ washerdriers
+
+
+ Household dishwashers
+ dishwashers
+
+
+ Household refrigerating appliances
+ refrigeratingappliances
+
+
+ Household washing machines
+ washingmachines
+
+
+ Televisions
+ televisions
+
+
diff --git a/product_eprel/demo/product_template.xml b/product_eprel/demo/product_template.xml
new file mode 100644
index 00000000000..d2249aa3bfb
--- /dev/null
+++ b/product_eprel/demo/product_template.xml
@@ -0,0 +1,22 @@
+
+
+
+ Smartphones and slate tablets
+ smartphonestablets20231669
+
+
+ Smartphones
+
+
+
+ Edge 60 Pro
+
+ edge 60 pro (XT2507-1)
+
+
diff --git a/product_eprel/i18n/es.po b/product_eprel/i18n/es.po
new file mode 100644
index 00000000000..524e4ad8c94
--- /dev/null
+++ b/product_eprel/i18n/es.po
@@ -0,0 +1,208 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * product_eprel
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0\n"
+"Report-Msgid-Bugs-To: \n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_res_company__eprel_api_key
+#: model:ir.model.fields,field_description:product_eprel.field_res_config_settings__eprel_api_key
+msgid "API Key"
+msgstr ""
+
+#. module: product_eprel
+#: model_terms:ir.ui.view,arch_db:product_eprel.res_config_settings_view_form
+msgid "Authentication key for accessing EPREL product data via API"
+msgstr ""
+"Clave de autenticación para acceder a los datos de producto de EPREL "
+"mediante API"
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__code
+msgid "Code"
+msgstr "Código"
+
+#. module: product_eprel
+#: model:ir.model,name:product_eprel.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model,name:product_eprel.model_res_config_settings
+msgid "Config Settings"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__create_uid
+msgid "Created by"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__create_date
+msgid "Created on"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category__display_name
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__display_name
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__display_name
+#: model:ir.model.fields,field_description:product_eprel.field_res_company__display_name
+#: model:ir.model.fields,field_description:product_eprel.field_res_config_settings__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: product_eprel
+#: model_terms:ir.ui.view,arch_db:product_eprel.res_config_settings_view_form
+msgid "Documentation"
+msgstr "Documentación"
+
+#. module: product_eprel
+#: code:addons/product_eprel/models/product_template.py:0
+#, python-format
+msgid "EPREL API Key is not configured."
+msgstr "La clave API de EPREL no está configurada."
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category__eprel_category_id
+msgid "EPREL Category"
+msgstr "Categoría EPREL"
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__eprel_enabled
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__eprel_enabled
+msgid "EPREL Enabled"
+msgstr "EPREL activado"
+
+#. module: product_eprel
+#: model:ir.model,name:product_eprel.model_product_category_eprel
+msgid "EPREL Product Category"
+msgstr "Categoría de producto EPREL"
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__eprel_registration_number
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__eprel_registration_number
+msgid "EPREL Registration Number"
+msgstr "Número de registro EPREL"
+
+#. module: product_eprel
+#: model:ir.actions.server,name:product_eprel.ir_cron_eprel_sync_products_ir_actions_server
+#: model:ir.cron,cron_name:product_eprel.ir_cron_eprel_sync_products
+#: model:ir.cron,name:product_eprel.ir_cron_eprel_sync_products
+msgid "EPREL: Sync Product Data"
+msgstr "EPREL: Sincronizar datos del producto"
+
+#. module: product_eprel
+#: model:product.template,name:product_eprel.product_template_edge_60_pro
+msgid "Edge 60 Pro"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__eprel_energy_class_image
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__eprel_energy_class_image
+msgid "Energy Class Image"
+msgstr "Imagen de clase energética"
+
+#. module: product_eprel
+#: code:addons/product_eprel/models/product_template.py:0
+#, python-format
+msgid "Failed to fetch EPREL data: %s"
+msgstr "Error al obtener datos de EPREL: %s"
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__fiche_url
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__fiche_url
+msgid "Fiche URL"
+msgstr "URL de ficha"
+
+#. module: product_eprel
+#: model_terms:ir.ui.view,arch_db:product_eprel.view_product_template_form_eprel
+msgid "Get EPREL data"
+msgstr "Obtener datos de EPREL"
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category__id
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__id
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__id
+#: model:ir.model.fields,field_description:product_eprel.field_res_company__id
+#: model:ir.model.fields,field_description:product_eprel.field_res_config_settings__id
+msgid "ID"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__label_arrow_url
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__label_arrow_url
+msgid "Label Arrow URL"
+msgstr "URL de la flecha energética"
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__label_url
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__label_url
+msgid "Label URL"
+msgstr "URL de etiqueta"
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category____last_update
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel____last_update
+#: model:ir.model.fields,field_description:product_eprel.field_product_template____last_update
+#: model:ir.model.fields,field_description:product_eprel.field_res_company____last_update
+#: model:ir.model.fields,field_description:product_eprel.field_res_config_settings____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__write_uid
+msgid "Last Updated by"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__write_date
+msgid "Last Updated on"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__eprel_model_identifier
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__eprel_model_identifier
+msgid "Model Identifier"
+msgstr "Identificador del modelo"
+
+#. module: product_eprel
+#: code:addons/product_eprel/models/product_template.py:0
+#, python-format
+msgid "Model Identifier and EPREL Category must be set."
+msgstr "Debe establecerse el identificador del modelo y la categoría EPREL."
+
+#. module: product_eprel
+#: model:ir.model,name:product_eprel.model_product_category
+msgid "Product Category"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model,name:product_eprel.model_product_template
+msgid "Product Template"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__name
+msgid "Product group"
+msgstr "Grupo de producto"
+
+#. module: product_eprel
+#: model:ir.model.fields,help:product_eprel.field_product_product__eprel_registration_number
+#: model:ir.model.fields,help:product_eprel.field_product_template__eprel_registration_number
+msgid "The EPREL registration number fetched from the API."
+msgstr "El número de registro EPREL obtenido desde la API."
+
+#. module: product_eprel
+#: model:product.template,uom_name:product_eprel.product_template_edge_60_pro
+msgid "Units"
+msgstr ""
diff --git a/product_eprel/i18n/product_eprel.pot b/product_eprel/i18n/product_eprel.pot
new file mode 100644
index 00000000000..486fc616628
--- /dev/null
+++ b/product_eprel/i18n/product_eprel.pot
@@ -0,0 +1,205 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * product_eprel
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0\n"
+"Report-Msgid-Bugs-To: \n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_res_company__eprel_api_key
+#: model:ir.model.fields,field_description:product_eprel.field_res_config_settings__eprel_api_key
+msgid "API Key"
+msgstr ""
+
+#. module: product_eprel
+#: model_terms:ir.ui.view,arch_db:product_eprel.res_config_settings_view_form
+msgid "Authentication key for accessing EPREL product data via API"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__code
+msgid "Code"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model,name:product_eprel.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model,name:product_eprel.model_res_config_settings
+msgid "Config Settings"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__create_uid
+msgid "Created by"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__create_date
+msgid "Created on"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category__display_name
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__display_name
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__display_name
+#: model:ir.model.fields,field_description:product_eprel.field_res_company__display_name
+#: model:ir.model.fields,field_description:product_eprel.field_res_config_settings__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: product_eprel
+#: model_terms:ir.ui.view,arch_db:product_eprel.res_config_settings_view_form
+msgid "Documentation"
+msgstr ""
+
+#. module: product_eprel
+#: code:addons/product_eprel/models/product_template.py:0
+#, python-format
+msgid "EPREL API Key is not configured."
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category__eprel_category_id
+msgid "EPREL Category"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__eprel_enabled
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__eprel_enabled
+msgid "EPREL Enabled"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model,name:product_eprel.model_product_category_eprel
+msgid "EPREL Product Category"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__eprel_registration_number
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__eprel_registration_number
+msgid "EPREL Registration Number"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.actions.server,name:product_eprel.ir_cron_eprel_sync_products_ir_actions_server
+#: model:ir.cron,cron_name:product_eprel.ir_cron_eprel_sync_products
+#: model:ir.cron,name:product_eprel.ir_cron_eprel_sync_products
+msgid "EPREL: Sync Product Data"
+msgstr ""
+
+#. module: product_eprel
+#: model:product.template,name:product_eprel.product_template_edge_60_pro
+msgid "Edge 60 Pro"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__eprel_energy_class_image
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__eprel_energy_class_image
+msgid "Energy Class Image"
+msgstr ""
+
+#. module: product_eprel
+#: code:addons/product_eprel/models/product_template.py:0
+#, python-format
+msgid "Failed to fetch EPREL data: %s"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__fiche_url
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__fiche_url
+msgid "Fiche URL"
+msgstr ""
+
+#. module: product_eprel
+#: model_terms:ir.ui.view,arch_db:product_eprel.view_product_template_form_eprel
+msgid "Get EPREL data"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category__id
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__id
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__id
+#: model:ir.model.fields,field_description:product_eprel.field_res_company__id
+#: model:ir.model.fields,field_description:product_eprel.field_res_config_settings__id
+msgid "ID"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__label_arrow_url
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__label_arrow_url
+msgid "Label Arrow URL"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__label_url
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__label_url
+msgid "Label URL"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category____last_update
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel____last_update
+#: model:ir.model.fields,field_description:product_eprel.field_product_template____last_update
+#: model:ir.model.fields,field_description:product_eprel.field_res_company____last_update
+#: model:ir.model.fields,field_description:product_eprel.field_res_config_settings____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__write_uid
+msgid "Last Updated by"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__write_date
+msgid "Last Updated on"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_product__eprel_model_identifier
+#: model:ir.model.fields,field_description:product_eprel.field_product_template__eprel_model_identifier
+msgid "Model Identifier"
+msgstr ""
+
+#. module: product_eprel
+#: code:addons/product_eprel/models/product_template.py:0
+#, python-format
+msgid "Model Identifier and EPREL Category must be set."
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model,name:product_eprel.model_product_category
+msgid "Product Category"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model,name:product_eprel.model_product_template
+msgid "Product Template"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,field_description:product_eprel.field_product_category_eprel__name
+msgid "Product group"
+msgstr ""
+
+#. module: product_eprel
+#: model:ir.model.fields,help:product_eprel.field_product_product__eprel_registration_number
+#: model:ir.model.fields,help:product_eprel.field_product_template__eprel_registration_number
+msgid "The EPREL registration number fetched from the API."
+msgstr ""
+
+#. module: product_eprel
+#: model:product.template,uom_name:product_eprel.product_template_edge_60_pro
+msgid "Units"
+msgstr ""
diff --git a/product_eprel/models/__init__.py b/product_eprel/models/__init__.py
new file mode 100644
index 00000000000..a71285fc91b
--- /dev/null
+++ b/product_eprel/models/__init__.py
@@ -0,0 +1,6 @@
+from . import product_category
+from . import product_category_eprel
+from . import product_template
+from . import res_company
+from . import res_config_settings
+from . import product_product
diff --git a/product_eprel/models/product_category.py b/product_eprel/models/product_category.py
new file mode 100644
index 00000000000..eb44f1eb03e
--- /dev/null
+++ b/product_eprel/models/product_category.py
@@ -0,0 +1,11 @@
+# Copyright 2025 Juan Carlos Oñate - Tecnativa
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+from odoo import fields, models
+
+
+class ProductCategory(models.Model):
+ _inherit = "product.category"
+
+ eprel_category_id = fields.Many2one(
+ comodel_name="product.category.eprel", string="EPREL Category"
+ )
diff --git a/product_eprel/models/product_category_eprel.py b/product_eprel/models/product_category_eprel.py
new file mode 100644
index 00000000000..91b9eb9a63d
--- /dev/null
+++ b/product_eprel/models/product_category_eprel.py
@@ -0,0 +1,11 @@
+# Copyright 2025 Juan Carlos Oñate - Tecnativa
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+from odoo import fields, models
+
+
+class ProductCategoryEprel(models.Model):
+ _name = "product.category.eprel"
+ _description = "EPREL Product Category"
+
+ name = fields.Char(string="Product group", required=True)
+ code = fields.Char(string="Code", required=True)
diff --git a/product_eprel/models/product_product.py b/product_eprel/models/product_product.py
new file mode 100644
index 00000000000..67df627579f
--- /dev/null
+++ b/product_eprel/models/product_product.py
@@ -0,0 +1,11 @@
+# Copyright 2025 Juan Carlos Oñate - Tecnativa
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+from odoo import models
+
+
+class ProductProduct(models.Model):
+ _inherit = "product.product"
+
+ def action_get_eprel_registration_number(self):
+ for product in self:
+ product.product_tmpl_id.action_get_eprel_registration_number()
diff --git a/product_eprel/models/product_template.py b/product_eprel/models/product_template.py
new file mode 100644
index 00000000000..beaa8590819
--- /dev/null
+++ b/product_eprel/models/product_template.py
@@ -0,0 +1,121 @@
+# Copyright 2025 Juan Carlos Oñate - Tecnativa
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+import time
+
+import requests
+
+from odoo import _, api, fields, models
+from odoo.exceptions import UserError
+
+API_URL = "https://eprel.ec.europa.eu/"
+
+
+class ProductTemplate(models.Model):
+ _inherit = "product.template"
+
+ eprel_enabled = fields.Boolean(
+ string="EPREL Enabled", compute="_compute_eprel_enabled"
+ )
+ eprel_model_identifier = fields.Char(string="Model Identifier", copy=False)
+ eprel_energy_class_image = fields.Char(string="Energy Class Image", copy=False)
+ fiche_url = fields.Char(
+ compute="_compute_eprel_url", string="Fiche URL", readonly=True, store=True
+ )
+ label_url = fields.Char(
+ compute="_compute_eprel_url", string="Label URL", readonly=True, store=True
+ )
+ label_arrow_url = fields.Char(
+ compute="_compute_eprel_url",
+ string="Label Arrow URL",
+ readonly=True,
+ store=True,
+ )
+ eprel_registration_number = fields.Char(
+ string="EPREL Registration Number",
+ copy=False,
+ help="The EPREL registration number fetched from the API.",
+ )
+
+ def _compute_eprel_enabled(self):
+ for rec in self:
+ rec.eprel_enabled = bool(rec.env.company.eprel_api_key)
+
+ @api.depends("categ_id.eprel_category_id", "eprel_registration_number")
+ def _compute_eprel_url(self):
+ for rec in self:
+ cat = rec.categ_id.eprel_category_id.code
+ reg_num = rec.eprel_registration_number
+ arrow_image_name = (
+ rec.eprel_energy_class_image.replace(".svg", ".png")
+ if rec.eprel_energy_class_image
+ and isinstance(rec.eprel_energy_class_image, str)
+ else False
+ )
+ lang_code = self.env.company.partner_id.lang.split("_")[0]
+ rec.fiche_url = (
+ f"{API_URL}fiches/{cat}/Fiche_{reg_num}_{lang_code.upper()}.pdf"
+ if cat and reg_num
+ else False
+ )
+ rec.label_url = (
+ f"{API_URL}labels/{cat}/Label_{reg_num}.png"
+ if cat and reg_num
+ else False
+ )
+ rec.label_arrow_url = (
+ "https://ec.europa.eu/assets/move-ener/eprel/"
+ f"EPREL%20Public/Nested-labels%20thumbnails/{arrow_image_name}"
+ if arrow_image_name
+ else False
+ )
+
+ def action_get_eprel_registration_number(self):
+ if not self.env.company.eprel_api_key:
+ raise UserError(_("EPREL API Key is not configured."))
+ min_interval = 0.25
+ last_request_time = 0.0
+ for product in self:
+ # Delay control to respect the API rate limit
+ now = time.time()
+ elapsed = now - last_request_time
+ if elapsed < min_interval:
+ time.sleep(min_interval - elapsed)
+ if (
+ not product.eprel_model_identifier
+ or not product.categ_id.eprel_category_id
+ ):
+ raise UserError(_("Model Identifier and EPREL Category must be set."))
+ identifier = product.eprel_model_identifier
+ category_code = product.categ_id.eprel_category_id.code
+ data = self._request_eprel_data(identifier, category_code)
+ last_request_time = time.time()
+ if data.get("hits"):
+ product.eprel_registration_number = data.get("hits")[0].get(
+ "eprelRegistrationNumber"
+ )
+ product.eprel_energy_class_image = data.get("hits")[0].get(
+ "energyClassImage"
+ )
+
+ @api.model
+ def _get_eprel_registration_number(self):
+ products = self.search(
+ [
+ ("eprel_model_identifier", "!=", False),
+ ("categ_id.eprel_category_id", "!=", False),
+ ]
+ )
+ products.action_get_eprel_registration_number()
+
+ def _request_eprel_data(self, identifier, category_code):
+ url = f"{API_URL}api/products/{category_code}?modelIdentifier={identifier}"
+ headers = {
+ "X-API-KEY": self.env.company.eprel_api_key,
+ "Accept": "application/json",
+ }
+ try:
+ response = requests.get(url, headers=headers, timeout=10)
+ response.raise_for_status()
+ return response.json()
+ except Exception as e:
+ raise UserError(_("Failed to fetch EPREL data: %s") % str(e))
diff --git a/product_eprel/models/res_company.py b/product_eprel/models/res_company.py
new file mode 100644
index 00000000000..e4388c545f3
--- /dev/null
+++ b/product_eprel/models/res_company.py
@@ -0,0 +1,9 @@
+# Copyright 2025 Juan Carlos Oñate - Tecnativa
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+from odoo import fields, models
+
+
+class ResCompany(models.Model):
+ _inherit = "res.company"
+
+ eprel_api_key = fields.Char(string="API Key")
diff --git a/product_eprel/models/res_config_settings.py b/product_eprel/models/res_config_settings.py
new file mode 100644
index 00000000000..bb8e054d4a3
--- /dev/null
+++ b/product_eprel/models/res_config_settings.py
@@ -0,0 +1,9 @@
+# Copyright 2025 Juan Carlos Oñate - Tecnativa
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+from odoo import fields, models
+
+
+class ResConfigSettings(models.TransientModel):
+ _inherit = "res.config.settings"
+
+ eprel_api_key = fields.Char(related="company_id.eprel_api_key", readonly=False)
diff --git a/product_eprel/readme/CONFIGURE.md b/product_eprel/readme/CONFIGURE.md
new file mode 100644
index 00000000000..c576acc7bb6
--- /dev/null
+++ b/product_eprel/readme/CONFIGURE.md
@@ -0,0 +1,2 @@
+To configure this module, go to Settings > General Settings. Under the
+Integrations section, enter your EPREL API key.
diff --git a/product_eprel/readme/CONTRIBUTORS.md b/product_eprel/readme/CONTRIBUTORS.md
new file mode 100644
index 00000000000..18e68214cfb
--- /dev/null
+++ b/product_eprel/readme/CONTRIBUTORS.md
@@ -0,0 +1,2 @@
+- [Tecnativa](https://www.tecnativa.com)
+ - Juan Carlos Oñate
diff --git a/product_eprel/readme/DESCRIPTION.md b/product_eprel/readme/DESCRIPTION.md
new file mode 100644
index 00000000000..f29787a5e90
--- /dev/null
+++ b/product_eprel/readme/DESCRIPTION.md
@@ -0,0 +1,3 @@
+This module connects Odoo with the EPREL API to fetch energy labels and fiches
+for products that have a model identifier and an EPREL product category. It
+retrieves the EPREL registration number and builds URLs.
diff --git a/product_eprel/readme/USAGE.md b/product_eprel/readme/USAGE.md
new file mode 100644
index 00000000000..639e3a54929
--- /dev/null
+++ b/product_eprel/readme/USAGE.md
@@ -0,0 +1,8 @@
+- In the **EPREL** page of the product form you will find:
+ - Model Identifier (required).
+ - URLs for product fiche, energy label, and energy arrow.
+- Product categories must have a valid **EPREL Category**.
+- Usage options:
+ 1. Click **Get EPREL data** in the product form.
+ 2. Enable the scheduled action **EPREL: Sync Product Data** in
+ *Settings > Technical > Scheduled Actions*.
diff --git a/product_eprel/security/ir.model.access.csv b/product_eprel/security/ir.model.access.csv
new file mode 100644
index 00000000000..8ea22b5985c
--- /dev/null
+++ b/product_eprel/security/ir.model.access.csv
@@ -0,0 +1,3 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_product_category_eprel_user,product.category.eprel user,model_product_category_eprel,base.group_user,1,0,0,0
+access_product_category_eprel_admin,product.category.eprel admin,model_product_category_eprel,base.group_system,1,1,1,1
diff --git a/product_eprel/static/description/index.html b/product_eprel/static/description/index.html
new file mode 100644
index 00000000000..a805749ad4c
--- /dev/null
+++ b/product_eprel/static/description/index.html
@@ -0,0 +1,452 @@
+
+
+
+
+
+Product EPREL
+
+
+
+
+
Product EPREL
+
+
+
+
This module connects Odoo with the EPREL API to fetch energy labels and
+fiches for products that have a model identifier and an EPREL product
+category. It retrieves the EPREL registration number and builds URLs.
Bugs are tracked on GitHub Issues.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us to smash it by providing a detailed and welcomed
+feedback.
+
Do not contact contributors directly about support or help with technical issues.
OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+ Authentication key for accessing EPREL product data via API
+
+
+
+
+
+
+
+
+
+
+
From 885883ea3fe3182533db8b4c0fc26ccb5ca13cca Mon Sep 17 00:00:00 2001
From: eduardo
Date: Wed, 22 Oct 2025 16:05:33 +0000
Subject: [PATCH 2/3] [IMP] product_eprel: pre-commit auto fixes
---
product_eprel/README.rst | 10 +++++-----
product_eprel/pyproject.toml | 3 +++
product_eprel/static/description/index.html | 6 +++---
3 files changed, 11 insertions(+), 8 deletions(-)
create mode 100644 product_eprel/pyproject.toml
diff --git a/product_eprel/README.rst b/product_eprel/README.rst
index f45d5fd3c21..939acf742d8 100644
--- a/product_eprel/README.rst
+++ b/product_eprel/README.rst
@@ -17,13 +17,13 @@ Product EPREL
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproduct--attribute-lightgray.png?logo=github
- :target: https://github.com/OCA/product-attribute/tree/14.0/product_eprel
+ :target: https://github.com/OCA/product-attribute/tree/18.0/product_eprel
:alt: OCA/product-attribute
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
- :target: https://translation.odoo-community.org/projects/product-attribute-14-0/product-attribute-14-0-product_eprel
+ :target: https://translation.odoo-community.org/projects/product-attribute-18-0/product-attribute-18-0-product_eprel
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
- :target: https://runboat.odoo-community.org/builds?repo=OCA/product-attribute&target_branch=14.0
+ :target: https://runboat.odoo-community.org/builds?repo=OCA/product-attribute&target_branch=18.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -64,7 +64,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues `_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
-`feedback `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -96,6 +96,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
-This module is part of the `OCA/product-attribute `_ project on GitHub.
+This module is part of the `OCA/product-attribute `_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/product_eprel/pyproject.toml b/product_eprel/pyproject.toml
new file mode 100644
index 00000000000..4231d0cccb3
--- /dev/null
+++ b/product_eprel/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["whool"]
+build-backend = "whool.buildapi"
diff --git a/product_eprel/static/description/index.html b/product_eprel/static/description/index.html
index a805749ad4c..42ead54ad68 100644
--- a/product_eprel/static/description/index.html
+++ b/product_eprel/static/description/index.html
@@ -369,7 +369,7 @@
This module connects Odoo with the EPREL API to fetch energy labels and
fiches for products that have a model identifier and an EPREL product
category. It retrieves the EPREL registration number and builds URLs.
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
-feedback.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.