diff --git a/product_multi_barcode_constraint_per_company/README.rst b/product_multi_barcode_constraint_per_company/README.rst new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/product_multi_barcode_constraint_per_company/__init__.py b/product_multi_barcode_constraint_per_company/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/product_multi_barcode_constraint_per_company/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_multi_barcode_constraint_per_company/__manifest__.py b/product_multi_barcode_constraint_per_company/__manifest__.py new file mode 100644 index 000000000000..f46c8d3919d2 --- /dev/null +++ b/product_multi_barcode_constraint_per_company/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2023 Cetmix OÜ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Product Multi Barcode Constraint per Company", + "version": "14.0.1.0.0", + "category": "Product", + "summary": """This is a bridge module between "product_multi_barcode" and + "product_barcode_constraint_per_company" """, + "author": "Ooops, Cetmix, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-barcode", + "license": "AGPL-3", + "depends": [ + "product_multi_barcode", + "product_barcode_constraint_per_company", + ], + "installable": True, + "auto_install": True, +} diff --git a/product_multi_barcode_constraint_per_company/models/__init__.py b/product_multi_barcode_constraint_per_company/models/__init__.py new file mode 100644 index 000000000000..940ac3279c6a --- /dev/null +++ b/product_multi_barcode_constraint_per_company/models/__init__.py @@ -0,0 +1 @@ +from . import product_barcode diff --git a/product_multi_barcode_constraint_per_company/models/product_barcode.py b/product_multi_barcode_constraint_per_company/models/product_barcode.py new file mode 100644 index 000000000000..f75b4f711af2 --- /dev/null +++ b/product_multi_barcode_constraint_per_company/models/product_barcode.py @@ -0,0 +1,25 @@ +# Copyright 2023 Cetmix OÜ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, models + + +class ProductBarcode(models.Model): + _inherit = "product.barcode" + + @api.constrains("name") + def _check_duplicates(self): + existing_codes = self.env["product.barcode"] + for record in self: + barcode = self.search( + [("id", "!=", record.id), ("name", "=", record.name)], limit=1 + ) + if barcode and ( + not record.product_id.company_id + or ( + barcode.sudo().product_id.company_id == record.product_id.company_id + ) + ): + existing_codes |= record + if existing_codes: + super(ProductBarcode, existing_codes)._check_duplicates() diff --git a/product_multi_barcode_constraint_per_company/readme/CONTRIBUTORS.rst b/product_multi_barcode_constraint_per_company/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..439b82700daf --- /dev/null +++ b/product_multi_barcode_constraint_per_company/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* Ooops + * Francesco Foresti +* Cetmix + * Dessan Hemrayev diff --git a/product_multi_barcode_constraint_per_company/readme/DESCRIPTION.rst b/product_multi_barcode_constraint_per_company/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..3302bbef697b --- /dev/null +++ b/product_multi_barcode_constraint_per_company/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This is a bridge module between "product_barcode_constraint_per_company" and "product_multi_barcode" diff --git a/product_multi_barcode_constraint_per_company/readme/newsfragmensts/.gitkeep b/product_multi_barcode_constraint_per_company/readme/newsfragmensts/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/product_multi_barcode_constraint_per_company/static/description/icon.png b/product_multi_barcode_constraint_per_company/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/product_multi_barcode_constraint_per_company/static/description/icon.png differ diff --git a/product_multi_barcode_constraint_per_company/tests/__init__.py b/product_multi_barcode_constraint_per_company/tests/__init__.py new file mode 100644 index 000000000000..904f0e14585d --- /dev/null +++ b/product_multi_barcode_constraint_per_company/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_barcode_constraint diff --git a/product_multi_barcode_constraint_per_company/tests/test_product_barcode_constraint.py b/product_multi_barcode_constraint_per_company/tests/test_product_barcode_constraint.py new file mode 100644 index 000000000000..5785ec1882d0 --- /dev/null +++ b/product_multi_barcode_constraint_per_company/tests/test_product_barcode_constraint.py @@ -0,0 +1,146 @@ +# Copyright 2023 Cetmix OÜ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from psycopg2 import IntegrityError + +from odoo import _ +from odoo.exceptions import UserError +from odoo.tools.misc import mute_logger + +from odoo.addons.product_barcode_constraint_per_company.tests.common import ( + CommonProductBarcodeConstraintPerCompany, +) + + +class TestProductBarcodeConstraint(CommonProductBarcodeConstraintPerCompany): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.valid_barcode_1 = "1234567890128123" + cls.valid_barcode2_1 = "0123456789012123" + cls.product_test_1 = cls.product_product_obj.create( + {"name": "Test product 1", "company_id": False} + ) + cls.product_test_2 = cls.product_product_obj.create( + {"name": "Test product 2", "company_id": False} + ) + + def test_create_same_company(self): + """Verifying the Existence of a Product with the Same Barcode within a Single Company""" + # Create the first product in company_1 + product_1 = self._create_product("Product 1", self.company_1.id) + # Check if the company_id of the product matches self.company_1 + self.assertEqual( + product_1.company_id, + self.company_1, + msg="Product company ID must be equal to ID #{company}".format( + company=self.company_1.id + ), + ) + + # Check if the company_id of the product_tmpl_id matches self.company_1 + self.assertEqual( + product_1.product_tmpl_id.company_id, + self.company_1, + msg="Product company ID must be equal to ID # {company}".format( + company=self.company_1.id + ), + ) + + # Try to create a second product with the same barcode in company_1 + # and expect an IntegrityError + with mute_logger("odoo.sql_db"), self.assertRaises( + IntegrityError, + msg="A barcode can only be assigned to one product per company !", + ): + self._create_product("Product 2", self.company_1.id) + + def test_create_different_company(self): + """Verify creating a product with the same barcode for different companies""" + # Create the first product in company_1 + product_1 = self._create_product("Product 1", self.company_1.id) + + # Create the second product in company_2 + product_2 = self._create_product("Product 2", self.company_2.id) + + # Check that the products belong to different companies + self.assertNotEqual( + product_1.company_id, + product_2.company_id, + msg="Products should belong to different companies", + ) + + # Check that the products have the same barcode + self.assertEqual( + product_1.barcode, + product_2.barcode, + msg="Products should have the same barcode", + ) + + def test_barcode_with_same_company(self): + """Checking setting same barcode for same companies""" + self.product_test_1.barcode = self.valid_barcode_1 + self.assertEqual(len(self.product_test_1.barcode_ids), 1) + self.assertEqual( + self.product_test_1.barcode_ids.name, self.product_test_1.barcode + ) + self.product_test_1.company_id = self.company_1.id + + self.product_test_2.company_id = self.company_1.id + with self.assertRaises( + UserError, + msg=_( + 'The Barcode "%(barcode_name)s" already exists for ' + 'product "%(product_name)s" in the company %(company_name)s' + ) + % dict( + barcode_name=self.valid_barcode_1, + product_name=self.product_test_1.name, + company_name=self.product_test_1.company_id.name, + ), + ): + self.product_test_2.barcode = self.valid_barcode_1 + + def test_barcodes(self): + self.product_test_1.barcode = self.valid_barcode_1 + self.product_test_1.company_id = self.company_1.id + message = ( + _( + 'The Barcode "%(barcode_name)s" already exists for ' + 'product "%(product_name)s" in the company %(company_name)s' + ) + % dict( + barcode_name=self.valid_barcode2_1, + product_name=self.product_test_2.name, + company_name=self.product_test_2.company_id.name, + ), + ) + with self.assertRaises(UserError, msg=message): + self.product_test_2.barcode_ids = [ + (0, 0, {"name": self.valid_barcode2_1}), + (0, 0, {"name": self.valid_barcode2_1}), + ] + + self.product_test_2.company_id = self.company_1.id + with self.assertRaises(UserError, msg=message): + self.product_test_2.barcode_ids = [ + (0, 0, {"name": self.valid_barcode2_1}), + (0, 0, {"name": self.valid_barcode2_1}), + ] + self.product_test_2.company_id = self.company_2.id + with self.assertRaises(UserError, msg=message): + self.product_test_2.barcode_ids = [ + (0, 0, {"name": self.valid_barcode2_1}), + (0, 0, {"name": self.valid_barcode2_1}), + ] + with self.assertRaises(UserError, msg=message): + self.product_test_2.barcode_ids = [ + (0, 0, {"name": self.valid_barcode2_1}), + (0, 0, {"name": self.valid_barcode_1}), + ] + + with self.assertRaises(UserError, msg=message): + self.product_test_2.barcode_ids = [ + (0, 0, {"name": self.valid_barcode_1}), + (0, 0, {"name": self.valid_barcode2_1}), + ] diff --git a/setup/product_multi_barcode_constraint_per_company/odoo/addons/product_multi_barcode_constraint_per_company b/setup/product_multi_barcode_constraint_per_company/odoo/addons/product_multi_barcode_constraint_per_company new file mode 120000 index 000000000000..12d7d8bfa10e --- /dev/null +++ b/setup/product_multi_barcode_constraint_per_company/odoo/addons/product_multi_barcode_constraint_per_company @@ -0,0 +1 @@ +../../../../product_multi_barcode_constraint_per_company \ No newline at end of file diff --git a/setup/product_multi_barcode_constraint_per_company/setup.py b/setup/product_multi_barcode_constraint_per_company/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/product_multi_barcode_constraint_per_company/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)