From af40c21208ee4de12d789e6f1e6942867f3ca8cb Mon Sep 17 00:00:00 2001 From: Jur de Vries Date: Mon, 6 Jan 2025 13:50:08 +0100 Subject: [PATCH 1/2] bug: GED-64: Remove PLU code uniqueness constraint and add tests. The SQL constraint enforcing unique PLU codes has been removed, allowing multiple products to share a PLU code and setting its default to None --- product_digi_sync/__manifest__.py | 2 +- .../migrations/16.0.0.1.0/post-migration.py | 20 +++++++++++++++++++ product_digi_sync/models/product_template.py | 10 +--------- .../tests/test_product_template.py | 12 +++++++++++ 4 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 product_digi_sync/migrations/16.0.0.1.0/post-migration.py diff --git a/product_digi_sync/__manifest__.py b/product_digi_sync/__manifest__.py index b2fbf23..9bb3f9e 100644 --- a/product_digi_sync/__manifest__.py +++ b/product_digi_sync/__manifest__.py @@ -9,7 +9,7 @@ # Check https://github.com/odoo/odoo/blob/16.0/odoo/addons/base/data/ir_module_category_data.xml # for the full list "category": "Sales/Point of Sale", - "version": "16.0.0.0.1", + "version": "16.0.0.1.0", "data": [ "security/ir.model.access.csv", "views/product_template_views.xml", diff --git a/product_digi_sync/migrations/16.0.0.1.0/post-migration.py b/product_digi_sync/migrations/16.0.0.1.0/post-migration.py new file mode 100644 index 0000000..19ba140 --- /dev/null +++ b/product_digi_sync/migrations/16.0.0.1.0/post-migration.py @@ -0,0 +1,20 @@ +import logging + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + _logger.info("Removing sql constraint shop_plucode_uniq") + # Safely drop the SQL constraint if it exists + cr.execute(""" + DO $$ BEGIN + IF EXISTS ( + SELECT 1 + FROM information_schema.table_constraints + WHERE constraint_name = 'product_template_shop_plucode_uniq' + AND table_name = 'product_template' + ) THEN + ALTER TABLE product_template DROP CONSTRAINT product_template_shop_plucode_uniq; + END IF; + END $$; + """) diff --git a/product_digi_sync/models/product_template.py b/product_digi_sync/models/product_template.py index 3d7c497..44ddd40 100644 --- a/product_digi_sync/models/product_template.py +++ b/product_digi_sync/models/product_template.py @@ -14,7 +14,7 @@ class ProductTemplate(DigiSyncBaseModel, models.Model): _inherit = "product.template" - shop_plucode = fields.Integer(string="Shop plucode", required=False) + shop_plucode = fields.Integer(string="Shop plucode", required=False, default=None) send_to_scale = fields.Boolean(string="Send to scale", required=False) is_weighted_article = fields.Boolean( string="Weighted article", required=False, default=True @@ -24,14 +24,6 @@ class ProductTemplate(DigiSyncBaseModel, models.Model): string="Show packed date on label", required=False ) - _sql_constraints = [ - ( - "shop_plucode_uniq", - "unique(shop_plucode)", - "Plu code must be unique.", - ), - ] - def get_current_barcode_rule(self): weighted_barcode_rule = self._get_barcode_rule("weighted_barcode_rule_id") piece_barcode_rule = self._get_barcode_rule("piece_barcode_rule_id") diff --git a/product_digi_sync/tests/test_product_template.py b/product_digi_sync/tests/test_product_template.py index 6c46a1a..5150137 100644 --- a/product_digi_sync/tests/test_product_template.py +++ b/product_digi_sync/tests/test_product_template.py @@ -234,6 +234,18 @@ def test_it_sends_the_product_quality_image_to_digi_only_when_quality_is_changed self.assertEqual(mock_send_product_image_to_digi.call_count, 1) patched_get_param.stop() + def test_that_a_plucode_can_always_be_zero(self): + product1 = self.env["product.template"].create({ + "name": "Test Product 1", + "shop_plucode": 0 + }) + product2 = self.env["product.template"].create({ + "name": "Test Product 2", + "shop_plucode": 0 + }) + self.assertEqual(product1.shop_plucode, 0) + self.assertEqual(product2.shop_plucode, 0) + def _create_product_with_image(self, name, shop_plucode): product_with_image = self.env["product.template"].create( { From 7eeaf671de7e7508dc1d6702730b6e25ff3ba975 Mon Sep 17 00:00:00 2001 From: Jur de Vries Date: Mon, 6 Jan 2025 14:10:05 +0100 Subject: [PATCH 2/2] bug: GED-64: Ensure unique validation for non-zero PLU codes with tests. Replaced the SQL constraint with an Odoo model constraint to enforce uniqueness for non-zero PLU codes. Updated tests to validate proper behavior for both unique and zero PLU codes. --- .../migrations/16.0.0.1.0/post-migration.py | 7 ++++-- product_digi_sync/models/product_template.py | 21 +++++++++++++++- .../tests/test_product_template.py | 25 +++++++++++++------ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/product_digi_sync/migrations/16.0.0.1.0/post-migration.py b/product_digi_sync/migrations/16.0.0.1.0/post-migration.py index 19ba140..8326802 100644 --- a/product_digi_sync/migrations/16.0.0.1.0/post-migration.py +++ b/product_digi_sync/migrations/16.0.0.1.0/post-migration.py @@ -1,12 +1,14 @@ import logging +# ruff: noqa _logger = logging.getLogger(__name__) def migrate(cr, version): _logger.info("Removing sql constraint shop_plucode_uniq") # Safely drop the SQL constraint if it exists - cr.execute(""" + cr.execute( + """ DO $$ BEGIN IF EXISTS ( SELECT 1 @@ -17,4 +19,5 @@ def migrate(cr, version): ALTER TABLE product_template DROP CONSTRAINT product_template_shop_plucode_uniq; END IF; END $$; - """) + """ + ) diff --git a/product_digi_sync/models/product_template.py b/product_digi_sync/models/product_template.py index 44ddd40..820cb02 100644 --- a/product_digi_sync/models/product_template.py +++ b/product_digi_sync/models/product_template.py @@ -1,7 +1,7 @@ import logging import re -from odoo import api, fields, models +from odoo import _, api, fields, models from odoo.tools import get_barcode_check_digit from odoo.addons.queue_job.exception import RetryableJobError @@ -135,3 +135,22 @@ def send_quality_image_to_digi_directly(self): client.send_product_quality_image_to_digi(self) except Exception as e: raise RetryableJobError(str(e), 5) from e + + @api.constrains("shop_plucode") + def _check_unique_shop_plucode(self): + for record in self: + if record.shop_plucode: + existing_record = self.search( + [ + ("shop_plucode", "=", record.shop_plucode), + ("id", "!=", record.id), + ], + limit=1, + ) + if existing_record: + raise models.ValidationError( + _( + "The Shop PLU code must be " + "unique! Code '{code}' is already used." + ).format(code=record.shop_plucode) + ) diff --git a/product_digi_sync/tests/test_product_template.py b/product_digi_sync/tests/test_product_template.py index 5150137..13121c7 100644 --- a/product_digi_sync/tests/test_product_template.py +++ b/product_digi_sync/tests/test_product_template.py @@ -4,6 +4,8 @@ from PIL import Image +from odoo.exceptions import ValidationError + from odoo.addons.product_digi_sync.models.digi_client import DigiClient from odoo.addons.queue_job.models.base import Base as QueueJobBase @@ -235,17 +237,24 @@ def test_it_sends_the_product_quality_image_to_digi_only_when_quality_is_changed patched_get_param.stop() def test_that_a_plucode_can_always_be_zero(self): - product1 = self.env["product.template"].create({ - "name": "Test Product 1", - "shop_plucode": 0 - }) - product2 = self.env["product.template"].create({ - "name": "Test Product 2", - "shop_plucode": 0 - }) + product1 = self.env["product.template"].create( + {"name": "Test Product 1", "shop_plucode": 0} + ) + product2 = self.env["product.template"].create( + {"name": "Test Product 2", "shop_plucode": 0} + ) self.assertEqual(product1.shop_plucode, 0) self.assertEqual(product2.shop_plucode, 0) + def test_that_a_plucode_cannot_have_the_same_value_when_unequal_to_zero(self): + with self.assertRaises(ValidationError): + self.env["product.template"].create( + {"name": "Test Product 1", "shop_plucode": 42} + ) + self.env["product.template"].create( + {"name": "Test Product 2", "shop_plucode": 42} + ) + def _create_product_with_image(self, name, shop_plucode): product_with_image = self.env["product.template"].create( {