Skip to content

Commit 8cf5147

Browse files
committed
Merge PR OCA#2044 into 17.0
Signed-off-by HaraldPanten
2 parents d9942a4 + f3706e8 commit 8cf5147

20 files changed

+1030
-0
lines changed

product_multi_code/README.rst

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
==================
2+
Product Multi Code
3+
==================
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:7fd619bf8cc112254983e4f42879e3dfea560daa31bc82a0d799f20527df21fb
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Beta
16+
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
18+
:alt: License: AGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproduct--attribute-lightgray.png?logo=github
20+
:target: https://github.com/OCA/product-attribute/tree/17.0/product_multi_code
21+
:alt: OCA/product-attribute
22+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
23+
:target: https://translation.odoo-community.org/projects/product-attribute-17-0/product-attribute-17-0-product_multi_code
24+
:alt: Translate me on Weblate
25+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
26+
:target: https://runboat.odoo-community.org/builds?repo=OCA/product-attribute&target_branch=17.0
27+
:alt: Try me on Runboat
28+
29+
|badge1| |badge2| |badge3| |badge4| |badge5|
30+
31+
This module allows multiple internal references (default_code) per
32+
product.
33+
34+
**Table of contents**
35+
36+
.. contents::
37+
:local:
38+
39+
Usage
40+
=====
41+
42+
To use this module:
43+
44+
1. Go to the Products menu.
45+
2. Open a product.
46+
3. You will see a new section for Internal References where you can add
47+
multiple codes.
48+
49+
The system will automatically link the internal code with the
50+
corresponding product and template. If you try to add a duplicate
51+
internal reference, a validation error will be raised.
52+
53+
Bug Tracker
54+
===========
55+
56+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/product-attribute/issues>`_.
57+
In case of trouble, please check there if your issue has already been reported.
58+
If you spotted it first, help us to smash it by providing a detailed and welcomed
59+
`feedback <https://github.com/OCA/product-attribute/issues/new?body=module:%20product_multi_code%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
60+
61+
Do not contact contributors directly about support or help with technical issues.
62+
63+
Credits
64+
=======
65+
66+
Authors
67+
-------
68+
69+
* Sygel
70+
71+
Contributors
72+
------------
73+
74+
- `Sygel <https://www.sygel.es>`__:
75+
76+
- Ángel Rivas
77+
- Valentín Vinagre
78+
79+
Maintainers
80+
-----------
81+
82+
This module is maintained by the OCA.
83+
84+
.. image:: https://odoo-community.org/logo.png
85+
:alt: Odoo Community Association
86+
:target: https://odoo-community.org
87+
88+
OCA, or the Odoo Community Association, is a nonprofit organization whose
89+
mission is to support the collaborative development of Odoo features and
90+
promote its widespread use.
91+
92+
This module is part of the `OCA/product-attribute <https://github.com/OCA/product-attribute/tree/17.0/product_multi_code>`_ project on GitHub.
93+
94+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

product_multi_code/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
2+
3+
from . import models
4+
from .hooks import post_init_hook
5+
from .hooks import uninstall_hook

product_multi_code/__manifest__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2025 Ángel Rivas <angel.rivas@sygel.es>
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
{
4+
"name": "Product Multi Code",
5+
"summary": "Allow multiple internal references (default_code) per product",
6+
"version": "17.0.1.0.0",
7+
"category": "Product Management",
8+
"website": "https://github.com/OCA/product-attribute",
9+
"author": "Sygel, Odoo Community Association (OCA)",
10+
"license": "AGPL-3",
11+
"application": False,
12+
"installable": True,
13+
"depends": ["product", "stock"],
14+
"data": [
15+
"security/ir.model.access.csv",
16+
"views/product_views.xml",
17+
"views/product_template_views.xml",
18+
],
19+
"post_init_hook": "post_init_hook",
20+
"uninstall_hook": "uninstall_hook",
21+
}

product_multi_code/hooks.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# © 2025 Valentin Vinagre (Sygel)
2+
# © 2025 Ángel Rivas (Sygel)
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
5+
6+
def post_init_hook(env):
7+
Product = env["product.product"]
8+
9+
for product in Product.search([]):
10+
if not product.default_code:
11+
continue
12+
env.cr.execute(
13+
"""
14+
SELECT 1 FROM product_default_code
15+
WHERE product_id = %s AND name = %s
16+
""",
17+
(product.id, product.default_code),
18+
)
19+
if env.cr.fetchone():
20+
continue
21+
env.cr.execute(
22+
"""
23+
INSERT INTO product_default_code
24+
(product_id, product_tmpl_id, name, sequence)
25+
VALUES (%s, %s, %s, %s)
26+
""",
27+
(
28+
product.id,
29+
product.product_tmpl_id.id,
30+
product.default_code,
31+
0,
32+
),
33+
)
34+
35+
36+
def uninstall_hook(env):
37+
env.cr.execute(
38+
"""
39+
UPDATE product_product pp
40+
SET default_code = pp.default_code
41+
"""
42+
)
43+
env.cr.execute("DELETE FROM product_default_code")

product_multi_code/i18n/es.po

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Translation of Odoo Server.
2+
# This file contains the translation of the following modules:
3+
# * product_multi_code
4+
#
5+
msgid ""
6+
msgstr ""
7+
"Project-Id-Version: Odoo Server 17.0\n"
8+
"Report-Msgid-Bugs-To: \n"
9+
"POT-Creation-Date: 2025-08-20 11:42+0000\n"
10+
"PO-Revision-Date: 2025-08-20 13:45+0200\n"
11+
"Last-Translator: \n"
12+
"Language-Team: \n"
13+
"Language: es\n"
14+
"MIME-Version: 1.0\n"
15+
"Content-Type: text/plain; charset=UTF-8\n"
16+
"Content-Transfer-Encoding: 8bit\n"
17+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
18+
"X-Generator: Poedit 3.6\n"
19+
20+
#. module: product_multi_code
21+
#: model:ir.model.fields,field_description:product_multi_code.field_product_default_code__create_uid
22+
msgid "Created by"
23+
msgstr "Creado por"
24+
25+
#. module: product_multi_code
26+
#: model:ir.model.fields,field_description:product_multi_code.field_product_default_code__create_date
27+
msgid "Created on"
28+
msgstr "Creado en"
29+
30+
#. module: product_multi_code
31+
#: model:ir.model.fields,field_description:product_multi_code.field_product_default_code__display_name
32+
msgid "Display Name"
33+
msgstr "Mostrar nombre"
34+
35+
#. module: product_multi_code
36+
#: model:ir.model.fields,field_description:product_multi_code.field_product_default_code__id
37+
msgid "ID"
38+
msgstr "ID"
39+
40+
#. module: product_multi_code
41+
#: model:ir.model.fields,field_description:product_multi_code.field_product_default_code__name
42+
#: model:ir.model.fields,field_description:product_multi_code.field_product_product__default_code
43+
#: model_terms:ir.ui.view,arch_db:product_multi_code.product_search_form_view_multi_default_code
44+
msgid "Internal Reference"
45+
msgstr "Referencia interna"
46+
47+
#. module: product_multi_code
48+
#: model:ir.model.fields,field_description:product_multi_code.field_product_product__default_code_ids
49+
#: model:ir.model.fields,field_description:product_multi_code.field_product_template__default_code_ids
50+
msgid "Internal References"
51+
msgstr "Referencias internas"
52+
53+
#. module: product_multi_code
54+
#: model:ir.model,name:product_multi_code.model_product_default_code
55+
msgid "Internal reference entry for a product"
56+
msgstr "Entrada de referencia interna para un producto"
57+
58+
#. module: product_multi_code
59+
#: model:ir.model.fields,field_description:product_multi_code.field_product_default_code__write_uid
60+
msgid "Last Updated by"
61+
msgstr "Última actualización por"
62+
63+
#. module: product_multi_code
64+
#: model:ir.model.fields,field_description:product_multi_code.field_product_default_code__write_date
65+
msgid "Last Updated on"
66+
msgstr "Última actualización en"
67+
68+
#. module: product_multi_code
69+
#: model:ir.model,name:product_multi_code.model_product_template
70+
#: model:ir.model.fields,field_description:product_multi_code.field_product_default_code__product_id
71+
msgid "Product"
72+
msgstr "Producto"
73+
74+
#. module: product_multi_code
75+
#: model:ir.model.fields,field_description:product_multi_code.field_product_default_code__product_tmpl_id
76+
msgid "Product Tmpl"
77+
msgstr "Plantilla de producto"
78+
79+
#. module: product_multi_code
80+
#: model:ir.model,name:product_multi_code.model_product_product
81+
msgid "Product Variant"
82+
msgstr "Variante de producto"
83+
84+
#. module: product_multi_code
85+
#: model:ir.model.fields,field_description:product_multi_code.field_product_default_code__sequence
86+
msgid "Sequence"
87+
msgstr "Secuencia"
88+
89+
#. module: product_multi_code
90+
#. odoo-python
91+
#: code:addons/product_multi_code/models/product_default_code.py:0
92+
#, python-format
93+
msgid ""
94+
"The Internal Reference \"%(code_name)s\" already exists for product "
95+
"\"%(product_name)s\"."
96+
msgstr ""
97+
"La referencia interna \"%(code_name)s\" ya existe en el producto "
98+
"\"%(product_name)s\"."
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
2+
3+
from . import product_product
4+
from . import product_template
5+
from . import product_default_code
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Copyright 2025 Ángel Rivas <angel.rivas@sygel.es>
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from odoo import api, fields, models
5+
from odoo.exceptions import ValidationError
6+
7+
8+
class ProductDefaultCode(models.Model):
9+
_name = "product.default_code"
10+
_description = "Internal reference entry for a product"
11+
_order = "sequence, id"
12+
13+
name = fields.Char(
14+
string="Internal Reference",
15+
required=True,
16+
)
17+
sequence = fields.Integer(default=10)
18+
19+
product_id = fields.Many2one(
20+
"product.product",
21+
string="Product",
22+
compute="_compute_product",
23+
store=True,
24+
readonly=False,
25+
ondelete="cascade",
26+
)
27+
product_tmpl_id = fields.Many2one(
28+
"product.template",
29+
compute="_compute_product_tmpl",
30+
store=True,
31+
readonly=False,
32+
ondelete="cascade",
33+
)
34+
35+
@api.depends("product_id")
36+
def _compute_product_tmpl(self):
37+
for rec in self.filtered(lambda x: not x.product_tmpl_id and x.product_id):
38+
rec.product_tmpl_id = rec.product_id.product_tmpl_id
39+
40+
@api.depends("product_tmpl_id.product_variant_ids")
41+
def _compute_product(self):
42+
for rec in self.filtered(
43+
lambda x: not x.product_id and x.product_tmpl_id.product_variant_ids
44+
):
45+
rec.product_id = rec.product_tmpl_id.product_variant_ids[0]
46+
47+
def _get_domain_check_duplicates(self):
48+
return [("id", "not in", self.ids), ("name", "in", self.mapped("name"))]
49+
50+
@api.constrains("name")
51+
def _check_duplicates(self):
52+
codes_to_check = self.sudo().search(self._get_domain_check_duplicates())
53+
for record in self:
54+
duplicate = codes_to_check.filtered(
55+
lambda b, rec=record: b.name == rec.name
56+
)
57+
58+
if duplicate:
59+
product = duplicate[0].sudo().product_id
60+
raise ValidationError(
61+
f'The Internal Reference "{record.name}" already exists for '
62+
f'product "{product.name}".'
63+
)
64+
65+
@api.constrains("product_id", "product_tmpl_id")
66+
def _check_required_product(self):
67+
for rec in self:
68+
if not (rec.product_id or rec.product_tmpl_id):
69+
raise ValidationError(
70+
f'You must assign the internal reference "{rec.name}" '
71+
"to a product or a template."
72+
)

0 commit comments

Comments
 (0)