diff --git a/product_unique_internal_reference/README.rst b/product_unique_internal_reference/README.rst new file mode 100644 index 000000000..5431e0424 --- /dev/null +++ b/product_unique_internal_reference/README.rst @@ -0,0 +1,66 @@ +================================= +Product unique internal reference +================================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:976812157684886bd583c3621ad271c233ae90a365cbb84fa272c9c9fc0f9075 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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-NuoBiT%2Fodoo--addons-lightgray.png?logo=github + :target: https://github.com/NuoBiT/odoo-addons/tree/18.0/product_unique_internal_reference + :alt: NuoBiT/odoo-addons + +|badge1| |badge2| |badge3| + +- This module ensures that you enter a 'Unique' Internal Reference + (default_code) for your Products. +- Multi company aware + +**Table of contents** + +.. contents:: + :local: + +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 +------- + +* NuoBiT Solutions SL + +Contributors +------------ + +- `NuoBiT `__: + + - Eric Antones eantones@nuobit.com + - Bijaya Kumal bkumal@nuobit.com + - Deniz Gallo dgallo@nuobit.com + +Maintainers +----------- + +This module is part of the `NuoBiT/odoo-addons `_ project on GitHub. + +You are welcome to contribute. diff --git a/product_unique_internal_reference/__init__.py b/product_unique_internal_reference/__init__.py new file mode 100644 index 000000000..43e266a34 --- /dev/null +++ b/product_unique_internal_reference/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import internal_reference_duplicate_check diff --git a/product_unique_internal_reference/__manifest__.py b/product_unique_internal_reference/__manifest__.py new file mode 100644 index 000000000..f32efc43a --- /dev/null +++ b/product_unique_internal_reference/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright NuoBiT - Eric Antones +# Copyright NuoBiT 2025 - Bijaya Kumal +# Copyright NuoBiT 2025 - Deniz Gallo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +{ + "name": "Product unique internal reference", + "summary": "This module ensures that you enter a " + "Unique Internal Reference (default_code) for your Products", + "version": "18.0.1.0.0", + "category": "Sales", + "author": "NuoBiT Solutions SL", + "website": "https://github.com/NuoBiT/odoo-addons", + "license": "AGPL-3", + "depends": [ + "product", + ], + "pre_init_hook": "internal_reference_duplicate_check", +} diff --git a/product_unique_internal_reference/hooks.py b/product_unique_internal_reference/hooks.py new file mode 100644 index 000000000..4caa29b80 --- /dev/null +++ b/product_unique_internal_reference/hooks.py @@ -0,0 +1,36 @@ +# Copyright NuoBiT - Eric Antones +# Copyright NuoBiT 2025 - Deniz Gallo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + + +from odoo import _ +from odoo.exceptions import ValidationError + + +def internal_reference_duplicate_check(env): + """This hook will look to see if any conflicting internal references exist before + the module is installed + :param Odoo env: Odoo environment + """ + with env.cr.savepoint(): + env.cr.execute( + """ + SELECT p0.id, p0.default_code, t0.company_id + FROM product_product p0, product_template t0 + WHERE p0.product_tmpl_id = t0.id AND + EXISTS ( + SELECT 1 + FROM product_product p1, product_template t1 + WHERE p1.product_tmpl_id = t1.id AND + (t1.company_id is null OR t0.company_id is null OR + t1.company_id = t0.company_id) AND + p1.default_code = p0.default_code AND p1.id != p0.id + )""" + ) + products = sorted(["[%i] %s (%i)" % p for p in env.cr.fetchall()]) + if products: + raise ValidationError( + _("Conflicting internal references exist: {}").format( + ", ".join(products) + ) + ) diff --git a/product_unique_internal_reference/i18n/es.po b/product_unique_internal_reference/i18n/es.po new file mode 100644 index 000000000..c494b278d --- /dev/null +++ b/product_unique_internal_reference/i18n/es.po @@ -0,0 +1,122 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_unique_internal_reference +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-12-16 14:21+0000\n" +"PO-Revision-Date: 2021-12-16 14:21+0000\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_unique_internal_reference +#: code:addons/product_unique_internal_reference/hooks.py:0 +#, python-format +msgid "Conflicting internal references exist: %s, " +msgstr "Existe un conflicto de referencias internas: %s, " + +#. module: product_unique_internal_reference +#: model:ir.model.fields,field_description:product_unique_internal_reference.field_product_product__display_name +#: model:ir.model.fields,field_description:product_unique_internal_reference.field_product_template__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: product_unique_internal_reference +#: code:addons/product_unique_internal_reference/models/product_product.py:0 +#, python-format +msgid "" +"Error! The Default Code %s already exists. Check also the archived ones." +msgstr "" +"Error! La referencia interna %s ya existe. Comprobar también los productos " +"archivados." + +#. module: product_unique_internal_reference +#: model:ir.model.fields,field_description:product_unique_internal_reference.field_product_product__id +#: model:ir.model.fields,field_description:product_unique_internal_reference.field_product_template__id +msgid "ID" +msgstr "" + +#. module: product_unique_internal_reference +#: code:addons/product_unique_internal_reference/tests/test_product_unique_internal_reference.py:0 +#, python-format +msgid "" +"It has been possible to change the template Internal Reference existing a " +"variant with the same one" +msgstr "" +"Ha sido posible cambiar la referencia interna de la plantilla existiendo una " +"variante con la misma" + +#. module: product_unique_internal_reference +#: code:addons/product_unique_internal_reference/tests/test_product_unique_internal_reference.py:0 +#, python-format +msgid "" +"It has been possible to create a product template on one company and another" +" without company with the same Internal Reference" +msgstr "" +"Ha sido posible crear una plantilla de producto en una compañía y otra sin " +"compañía con la misma referencia interna" + +#. module: product_unique_internal_reference +#: code:addons/product_unique_internal_reference/tests/test_product_unique_internal_reference.py:0 +#, python-format +msgid "" +"It has been possible to create a product template when a variant of another " +"template has the same Internal Reference" +msgstr "" +"Ha sido posible crear una plantilla de producto cuando una variante de otra " +"plantilla tiene la misma referencia interna" + +#. module: product_unique_internal_reference +#: code:addons/product_unique_internal_reference/tests/test_product_unique_internal_reference.py:0 +#: code:addons/product_unique_internal_reference/tests/test_product_unique_internal_reference.py:0 +#, python-format +msgid "" +"It has been possible to create a product variant when a variant of another " +"template has the same Internal Reference" +msgstr "" +"Ha sido posible crear una variante de producto cuando una variante de otra " +"plantilla tiene la misma referencia interna" + +#. module: product_unique_internal_reference +#: code:addons/product_unique_internal_reference/tests/test_product_unique_internal_reference.py:0 +#, python-format +msgid "" +"It has been possible to create two product templates with the same Internal " +"Reference" +msgstr "" +"Ha sido posible crear dos plantillas de producto con la misma referencia " +"interna" + +#. module: product_unique_internal_reference +#: model:ir.model.fields,field_description:product_unique_internal_reference.field_product_product____last_update +#: model:ir.model.fields,field_description:product_unique_internal_reference.field_product_template____last_update +msgid "Last Modified on" +msgstr "Última modificación el" + +#. module: product_unique_internal_reference +#: model:ir.model,name:product_unique_internal_reference.model_product_product +msgid "Product" +msgstr "Producto" + +#. module: product_unique_internal_reference +#: model:ir.model,name:product_unique_internal_reference.model_product_template +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: product_unique_internal_reference +#: code:addons/product_unique_internal_reference/tests/test_product_unique_internal_reference.py:0 +#: code:addons/product_unique_internal_reference/tests/test_product_unique_internal_reference.py:0 +#: code:addons/product_unique_internal_reference/tests/test_product_unique_internal_reference.py:0 +#, python-format +msgid "" +"The Internal References are not equal, this should have not raised an " +"Exception" +msgstr "" +"Las referencias internas no son iguales, esto no debería haber lanzado una " +"excepción" diff --git a/product_unique_internal_reference/models/__init__.py b/product_unique_internal_reference/models/__init__.py new file mode 100644 index 000000000..18b37e853 --- /dev/null +++ b/product_unique_internal_reference/models/__init__.py @@ -0,0 +1,2 @@ +from . import product_product +from . import product_template diff --git a/product_unique_internal_reference/models/product_product.py b/product_unique_internal_reference/models/product_product.py new file mode 100644 index 000000000..287ade360 --- /dev/null +++ b/product_unique_internal_reference/models/product_product.py @@ -0,0 +1,46 @@ +# Copyright NuoBiT - Eric Antones +# Copyright NuoBiT 2025 - Deniz Gallo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + + +from odoo import api, models +from odoo.exceptions import ValidationError +from odoo.tools.translate import _ + + +class ProductProduct(models.Model): + _inherit = "product.product" + + @api.constrains("default_code") + def _check_default_code(self): + for record in self: + if record.default_code: + domain = [ + ("default_code", "=", record.default_code), + ("id", "!=", record.id), + ] + if record.product_tmpl_id.company_id: + domain += [ + "|", + ( + "product_tmpl_id.company_id", + "=", + record.product_tmpl_id.company_id.id, + ), + ("product_tmpl_id.company_id", "=", False), + ] + product = ( + self.sudo() + .with_context(active_test=False) + .search( + domain, + limit=1, + ) + ) + if product: + raise ValidationError( + _( + "Error! The Default Code {} already exists. " + "Check also the archived ones." + ).format(record.default_code) + ) diff --git a/product_unique_internal_reference/models/product_template.py b/product_unique_internal_reference/models/product_template.py new file mode 100644 index 000000000..5342797ec --- /dev/null +++ b/product_unique_internal_reference/models/product_template.py @@ -0,0 +1,46 @@ +# Copyright NuoBiT - Eric Antones +# Copyright NuoBiT 2025 - Deniz Gallo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + + +from odoo import _, api, models +from odoo.exceptions import ValidationError + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + @api.constrains("default_code", "company_id") + def _check_default_code(self): + for record in self: + if record.default_code: + # all products with the same default_code + products_all = ( + self.env["product.product"] + .sudo() + .with_context(active_test=False) + .search( + [ + ("default_code", "=", record.default_code), + ] + ) + ) + # products inside the same template + products_inside = products_all.filtered( + lambda p, record=record: p.product_tmpl_id == record + ) + # products outside the same template + products_outside = products_all - products_inside + if record.company_id: + products_outside = products_outside.filtered( + lambda p, record=record: not p.product_tmpl_id.company_id + or p.product_tmpl_id.company_id == record.company_id + ) + # check if the default code is used in other templates + if len(products_inside) > 1 or products_outside: + raise ValidationError( + _( + "Error! The Default Code {} already exists. " + "Check also the archived ones." + ).format(record.default_code) + ) diff --git a/product_unique_internal_reference/pyproject.toml b/product_unique_internal_reference/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/product_unique_internal_reference/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_unique_internal_reference/readme/CONTRIBUTORS.md b/product_unique_internal_reference/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..325bee193 --- /dev/null +++ b/product_unique_internal_reference/readme/CONTRIBUTORS.md @@ -0,0 +1,4 @@ +- [NuoBiT](https://www.nuobit.com): + - Eric Antones + - Bijaya Kumal + - Deniz Gallo diff --git a/product_unique_internal_reference/readme/DESCRIPTION.md b/product_unique_internal_reference/readme/DESCRIPTION.md new file mode 100644 index 000000000..7b3ac697a --- /dev/null +++ b/product_unique_internal_reference/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +* This module ensures that you enter a 'Unique' Internal Reference (default_code) + for your Products. +* Multi company aware diff --git a/product_unique_internal_reference/static/description/icon.png b/product_unique_internal_reference/static/description/icon.png new file mode 100644 index 000000000..1cd641e79 Binary files /dev/null and b/product_unique_internal_reference/static/description/icon.png differ diff --git a/product_unique_internal_reference/static/description/index.html b/product_unique_internal_reference/static/description/index.html new file mode 100644 index 000000000..1afa609d7 --- /dev/null +++ b/product_unique_internal_reference/static/description/index.html @@ -0,0 +1,425 @@ + + + + + +Product unique internal reference + + + +
+

Product unique internal reference

+ + +

Beta License: AGPL-3 NuoBiT/odoo-addons

+
    +
  • This module ensures that you enter a ‘Unique’ Internal Reference +(default_code) for your Products.
  • +
  • Multi company aware
  • +
+

Table of contents

+ +
+

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

+
    +
  • NuoBiT Solutions SL
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is part of the NuoBiT/odoo-addons project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/product_unique_internal_reference/tests/__init__.py b/product_unique_internal_reference/tests/__init__.py new file mode 100644 index 000000000..d5fb3a44d --- /dev/null +++ b/product_unique_internal_reference/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_unique_internal_reference diff --git a/product_unique_internal_reference/tests/test_product_unique_internal_reference.py b/product_unique_internal_reference/tests/test_product_unique_internal_reference.py new file mode 100644 index 000000000..dae3dbfba --- /dev/null +++ b/product_unique_internal_reference/tests/test_product_unique_internal_reference.py @@ -0,0 +1,566 @@ +# Copyright NuoBiT - Eric Antones +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import logging + +from odoo import _ +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase + +_logger = logging.getLogger(__name__) + + +class TestProductUniqueInternalReference(TransactionCase): + def test_01_template_vs_template_ok_same_company(self): + """ + PRE: - template1 exists + - template1 has default_code 'sku1' + - template1 has company1 + ACT: - create template2 + - template2 has default_code 'sku2' + POST: - template2 is created correctly + """ + # ARRANGE + company1 = self.env["res.company"].create( + { + "name": "Company 1", + "email": "email1@company1.com", + } + ) + self.env["product.template"].create( + { + "name": "Product 1", + "default_code": "sku1", + "company_id": company1.id, + } + ) + # ACT & ASSERT + try: + self.env["product.template"].create( + { + "name": "Product 2", + "default_code": "sku2", + "company_id": company1.id, + } + ) + except ValidationError: + self.fail( + _( + "The Internal References are not equal, " + "this should have not raised an Exception" + ) + ) + + def test_02_template_vs_template_ok_diff_company(self): + """ + PRE: - template1 exists + - template1 has default_code 'sku1' + - template1 has company1 + ACT: - create template2 + - template2 has company2 + - template2 has default_code 'sku2' + POST: - template2 is created correctly + """ + # ARRANGE + company1 = self.env["res.company"].create( + { + "name": "Company 1", + "email": "email1@company1.com", + } + ) + self.env["product.template"].create( + { + "name": "Product 1", + "default_code": "sku1", + "company_id": company1.id, + } + ) + company2 = self.env["res.company"].create( + { + "name": "Company 2", + "email": "email1@company2.com", + } + ) + # ACT & ASSERT + try: + self.env["product.template"].create( + { + "name": "Product 2", + "default_code": "sku2", + "company_id": company2.id, + } + ) + except ValidationError: + self.fail( + _( + "The Internal References are not equal, " + "this should have not raised an Exception" + ) + ) + + def test_03_template_vs_template_dup_same_company(self): + """ + PRE: - template1 exists + - template1 has default_code 'sku1' + - template1 has company1 + ACT: - create template2 + - template2 has default_code 'sku1' + - template2 has company1 + POST: - template2 is not created because exists + template1 with same default_code 'sku1' + on the same company1 + """ + # ARRANGE + company1 = self.env["res.company"].create( + { + "name": "Company 1", + "email": "email1@company1.com", + } + ) + self.env["product.template"].create( + { + "name": "Product 1", + "default_code": "sku1", + "company_id": company1.id, + } + ) + # ACT & ASSERT + try: + with self.assertRaises(ValidationError): + self.env["product.template"].create( + { + "name": "Product 2", + "default_code": "sku1", + "company_id": company1.id, + } + ) + except AssertionError: + self.fail( + _( + "It has been possible to create two product templates " + "with the same Internal Reference" + ) + ) + + def test_04_template_vs_template_dup_diff_company(self): + """ + PRE: - template1 exists + - template1 has default_code 'sku1' + - template1 has company1 + ACT: - create template2 + - template2 has default_code 'sku1' + - template2 has company2 + POST: - template2 is created correctly + """ + # ARRANGE + company1 = self.env["res.company"].create( + { + "name": "Company 1", + "email": "email1@company1.com", + } + ) + self.env["product.template"].create( + { + "name": "Product 1", + "default_code": "sku1", + "company_id": company1.id, + } + ) + company2 = self.env["res.company"].create( + { + "name": "Company 2", + "email": "email1@company2.com", + } + ) + # ACT & ASSERT + try: + self.env["product.template"].create( + { + "name": "Product 2", + "default_code": "sku1", + "company_id": company2.id, + } + ) + except ValidationError: + self.fail( + _( + "The Internal References are not equal, " + "this should have not raised an Exception" + ) + ) + + def test_05_template_vs_template_dup_company_vs_nocompany(self): + """ + PRE: - template1 exists + - template1 has default_code 'sku1' + - template1 has company1 + ACT: - create template2 + - template2 has default_code 'sku1' + - template2 has no company + POST: - template2 is not created because exists + template1 with same default_code 'sku1' + on company1 and template2 has no company + which means 'all companies' + """ + # ARRANGE + company1 = self.env["res.company"].create( + { + "name": "Company 1", + "email": "email1@company1.com", + } + ) + self.env["product.template"].create( + { + "name": "Product 1", + "default_code": "sku1", + "company_id": company1.id, + } + ) + # ACT & ASSERT + try: + with self.assertRaises(ValidationError): + self.env["product.template"].create( + { + "name": "Product 2", + "default_code": "sku1", + "company_id": False, + } + ) + except AssertionError: + self.fail( + _( + "It has been possible to create a product template on " + "one company and another without company with the same " + "Internal Reference" + ) + ) + + def test_06_product_vs_template_uniq_same_company(self): + """ + PRE: - template1 exists + - template1 has variant11 and variant12 + - variant11 has default_code 'sku1' + - variant12 has default_code 'sku2' + - template1 has company1 + ACT: - create template2 + - template2 has default_code 'sku2' + - template2 has company1 + POST: - template2 is not created because exists + variant12 with same default_code 'sku1' + on the same company1 + """ + # ARRANGE + company1 = self.env["res.company"].create( + { + "name": "Company 1", + "email": "email1@company1.com", + } + ) + attribute = self.env["product.attribute"].create( + { + "name": "Attribute 1", + "create_variant": "always", + "value_ids": [ + (0, 0, {"name": "Attribute Value 1"}), + (0, 0, {"name": "Attribute Value 2"}), + ], + } + ) + template = self.env["product.template"].create( + { + "name": "Product 1", + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": attribute.id, + "value_ids": [(6, 0, attribute.value_ids.ids)], + }, + ) + ], + "company_id": company1.id, + } + ) + template.product_variant_ids[0].default_code = "sku1" + template.product_variant_ids[1].default_code = "sku2" + # ACT & ASSERT + try: + with self.assertRaises(ValidationError): + self.env["product.template"].create( + { + "name": "Product 2", + "default_code": "sku2", + "company_id": company1.id, + } + ) + except AssertionError: + self.fail( + _( + "It has been possible to create a product template " + "when a variant of another template has the same " + "Internal Reference" + ) + ) + + def test_07_product_vs_product_uniq_same_company(self): + """ + PRE: - template1 exists + - template1 has variant11 and variant12 + - variant11 has default_code 'sku1' + - variant12 has default_code 'sku2' + - template1 has company1 + ACT: - create template2 + - template2 has company1 + - template2 has variant21 and variant22 and variant23 + - variant21 has default_code 'sku4' + - variant22 has default_code 'sku3' + - variant23 has default_code 'sku2' + POST: - template2 is not created because exists + variant23 with same default_code 'sku1' + as variant12 on the same company1 + """ + # ARRANGE + company1 = self.env["res.company"].create( + { + "name": "Company 1", + "email": "email1@company1.com", + } + ) + attribute1 = self.env["product.attribute"].create( + { + "name": "Attribute 1", + "create_variant": "always", + "value_ids": [ + (0, 0, {"name": "Attribute Value 1"}), + (0, 0, {"name": "Attribute Value 2"}), + ], + } + ) + template1 = self.env["product.template"].create( + { + "name": "Product 1", + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": attribute1.id, + "value_ids": [(6, 0, attribute1.value_ids.ids)], + }, + ) + ], + "company_id": company1.id, + } + ) + template1.product_variant_ids[0].default_code = "sku1" + template1.product_variant_ids[1].default_code = "sku2" + + attribute2 = self.env["product.attribute"].create( + { + "name": "Attribute 2", + "create_variant": "always", + "value_ids": [ + (0, 0, {"name": "Attribute Value 3"}), + (0, 0, {"name": "Attribute Value 4"}), + (0, 0, {"name": "Attribute Value 5"}), + ], + } + ) + template2 = self.env["product.template"].create( + { + "name": "Product 2", + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": attribute2.id, + "value_ids": [(6, 0, attribute2.value_ids.ids)], + }, + ) + ], + "company_id": company1.id, + } + ) + + # ACT & ASSERT + try: + with self.assertRaises(ValidationError): + template2.product_variant_ids[0].default_code = "sku4" + template2.product_variant_ids[1].default_code = "sku3" + template2.product_variant_ids[2].default_code = "sku2" + except AssertionError: + self.fail( + _( + "It has been possible to create a product variant " + "when a variant of another template has the same " + "Internal Reference" + ) + ) + + def test_08_product_vs_product_dup_company_vs_nocompany(self): + """ + PRE: - template1 exists + - template1 has variant11 and variant12 + - variant11 has default_code 'sku1' + - variant12 has default_code 'sku2' + - template1 has company1 + - template2 exists + - template2 has no company + - template2 has variant21 and variant22 and variant23 + - variant21, variant22, variant23 has no default_code + ACT: - change variant21 default_code to 'sku4' + - change variant22 default_code to 'sku3' + - change variant23 default_code to 'sku2' + POST: - variant default_code are not updated because + variant23 has the same default_code as variant12 'sku2' + and they belong to the same company1 because + template2 has no company and it means 'all companies' + """ + # ARRANGE + company1 = self.env["res.company"].create( + { + "name": "Company 1", + "email": "email1@company1.com", + } + ) + attribute1 = self.env["product.attribute"].create( + { + "name": "Attribute 1", + "create_variant": "always", + "value_ids": [ + (0, 0, {"name": "Attribute Value 1"}), + (0, 0, {"name": "Attribute Value 2"}), + ], + } + ) + template1 = self.env["product.template"].create( + { + "name": "Product 1", + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": attribute1.id, + "value_ids": [(6, 0, attribute1.value_ids.ids)], + }, + ) + ], + "company_id": company1.id, + } + ) + template1.product_variant_ids[0].default_code = "sku1" + template1.product_variant_ids[1].default_code = "sku2" + + attribute2 = self.env["product.attribute"].create( + { + "name": "Attribute 2", + "create_variant": "always", + "value_ids": [ + (0, 0, {"name": "Attribute Value 3"}), + (0, 0, {"name": "Attribute Value 4"}), + (0, 0, {"name": "Attribute Value 5"}), + ], + } + ) + template2 = self.env["product.template"].create( + { + "name": "Product 2", + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": attribute2.id, + "value_ids": [(6, 0, attribute2.value_ids.ids)], + }, + ) + ], + "company_id": False, + } + ) + + # ACT & ASSERT + try: + with self.assertRaises(ValidationError): + template2.product_variant_ids[0].default_code = "sku4" + template2.product_variant_ids[1].default_code = "sku3" + template2.product_variant_ids[2].default_code = "sku2" + except AssertionError: + self.fail( + _( + "It has been possible to create a product variant " + "when a variant of another template has the same " + "Internal Reference" + ) + ) + + def test_09_template_vs_product_dup_archived(self): + """ + PRE: - template1 exists + - template1 has variant11 and variant12 and variant13 + - variant11 has default_code 'sku1' + - variant12 has default_code 'sku2' and is archived + - variant13 has default_code 'sku3' and is archived + ACT: - change template1 default_code to 'sku2' + POST: - template1 is not updated because + variant12 has the same default_code 'sku1' + """ + # ARRANGE + company1 = self.env["res.company"].create( + { + "name": "Company 1", + "email": "email1@company1.com", + } + ) + attribute1 = self.env["product.attribute"].create( + { + "name": "Attribute 1", + "create_variant": "always", + "value_ids": [ + (0, 0, {"name": "Attribute Value 1"}), + (0, 0, {"name": "Attribute Value 2"}), + (0, 0, {"name": "Attribute Value 3"}), + ], + } + ) + template1 = self.env["product.template"].create( + { + "name": "Product 1", + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": attribute1.id, + "value_ids": [(6, 0, attribute1.value_ids.ids)], + }, + ) + ], + "company_id": company1.id, + } + ) + variant1 = template1.product_variant_ids[0] + variant2 = template1.product_variant_ids[1] + variant3 = template1.product_variant_ids[2] + + variant1.default_code = "sku1" + variant2.default_code = "sku2" + variant3.default_code = "sku3" + + variant2.active = False + variant3.active = False + + # ACT & ASSERT + try: + with self.assertRaises(ValidationError): + template1.default_code = "sku2" + except AssertionError: + self.fail( + _( + "It has been possible to change the template " + "Internal Reference existing a variant with the same one" + ) + )