From 8fa91a2db63dfcaea9d4e32d2453fb0cef81d1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Sun, 21 Jul 2019 22:40:22 +0200 Subject: [PATCH 1/2] [FIX] Fix delete synchronisation When deleting template, product, binding we should be sure to call unlink code of the binding in order to have the synchronisation working Deleting with casade in postgres bypass the ORM --- shopinvader_search_engine/models/__init__.py | 2 + .../models/product_product.py | 16 +++++ .../models/shopinvader_product.py | 16 +++++ shopinvader_search_engine/tests/__init__.py | 1 + .../tests/test_delete_product.py | 61 +++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 shopinvader_search_engine/models/product_product.py create mode 100644 shopinvader_search_engine/models/shopinvader_product.py create mode 100644 shopinvader_search_engine/tests/__init__.py create mode 100644 shopinvader_search_engine/tests/test_delete_product.py diff --git a/shopinvader_search_engine/models/__init__.py b/shopinvader_search_engine/models/__init__.py index 2fe9ae5c82..105515b1ec 100644 --- a/shopinvader_search_engine/models/__init__.py +++ b/shopinvader_search_engine/models/__init__.py @@ -1,4 +1,6 @@ from . import shopinvader_backend +from . import product_product +from . import shopinvader_product from . import shopinvader_variant from . import shopinvader_category from . import se_index diff --git a/shopinvader_search_engine/models/product_product.py b/shopinvader_search_engine/models/product_product.py new file mode 100644 index 0000000000..61d3690c48 --- /dev/null +++ b/shopinvader_search_engine/models/product_product.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Akretion (http://www.akretion.com). +# @author Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + def unlink(self): + # Call unlink manually to be sure to trigger + # shopinvader variant unlink constraint + self.mapped("shopinvader_bind_ids").unlink() + return super(ProductProduct, self).unlink() diff --git a/shopinvader_search_engine/models/shopinvader_product.py b/shopinvader_search_engine/models/shopinvader_product.py new file mode 100644 index 0000000000..41f6337485 --- /dev/null +++ b/shopinvader_search_engine/models/shopinvader_product.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Akretion (http://www.akretion.com). +# @author Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models + + +class ShopinvaderProduct(models.Model): + _inherit = "shopinvader.product" + + def unlink(self): + # Call unlink manually to be sure to trigger + # shopinvader variant unlink constraint + self.mapped("shopinvader_variant_ids").unlink() + return super(ShopinvaderProduct, self).unlink() diff --git a/shopinvader_search_engine/tests/__init__.py b/shopinvader_search_engine/tests/__init__.py new file mode 100644 index 0000000000..018e2cc529 --- /dev/null +++ b/shopinvader_search_engine/tests/__init__.py @@ -0,0 +1 @@ +from . import test_delete_product diff --git a/shopinvader_search_engine/tests/test_delete_product.py b/shopinvader_search_engine/tests/test_delete_product.py new file mode 100644 index 0000000000..bb4bd37be3 --- /dev/null +++ b/shopinvader_search_engine/tests/test_delete_product.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Akretion (http://www.akretion.com). +# @author Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.exceptions import UserError +from odoo.tests.common import TransactionCase + + +class BindingCase(TransactionCase): + def setUp(self): + super(BindingCase, self).setUp() + self.template = self.env["product.template"].create({"name": "Test"}) + self.product = self.template.product_variant_ids + self.shopinvader_product = ( + self.env["shopinvader.product"] + .with_context(map_children=True) + .create( + { + "record_id": self.template.id, + "backend_id": self.ref("shopinvader.backend_1"), + "lang_id": self.ref("base.lang_en"), + } + ) + ) + self.shopinvader_variant = ( + self.shopinvader_product.shopinvader_variant_ids + ) + + +class BindingDoneCase(BindingCase): + def setUp(self): + super(BindingDoneCase, self).setUp() + self.shopinvader_variant.write({"sync_state": "done"}) + + def test_unlink_shopinvader_product(self): + with self.assertRaises(UserError): + self.shopinvader_product.unlink() + + def test_unlink_product_product(self): + with self.assertRaises(UserError): + self.product.unlink() + + def test_unlink_product_template(self): + with self.assertRaises(UserError): + self.template.unlink() + + +class BindingInactiveDoneCase(BindingCase): + def setUp(self): + super(BindingInactiveDoneCase, self).setUp() + self.shopinvader_variant.write({"sync_state": "done", "active": False}) + + def test_unlink_shopinvader_product(self): + self.shopinvader_product.unlink() + + def test_unlink_product_product(self): + self.product.unlink() + + def test_unlink_product_template(self): + self.template.unlink() From ddcf3e4cb8eb7527ed594a99b83bb70281516d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Mon, 20 Apr 2020 18:09:09 +0200 Subject: [PATCH 2/2] [FIX] move unlink code into shopinvader module --- shopinvader/models/product_product.py | 6 +++ shopinvader/models/shopinvader_product.py | 6 +++ shopinvader_search_engine/models/__init__.py | 2 - .../models/product_product.py | 16 ------- .../models/shopinvader_product.py | 16 ------- .../tests/test_delete_product.py | 43 ++++++++++--------- 6 files changed, 35 insertions(+), 54 deletions(-) delete mode 100644 shopinvader_search_engine/models/product_product.py delete mode 100644 shopinvader_search_engine/models/shopinvader_product.py diff --git a/shopinvader/models/product_product.py b/shopinvader/models/product_product.py index 6bc6a3401c..c94816b44f 100644 --- a/shopinvader/models/product_product.py +++ b/shopinvader/models/product_product.py @@ -84,3 +84,9 @@ def _get_invader_variant(self, backend, lang): return self.shopinvader_bind_ids.filtered( lambda x: x.backend_id == backend and x.lang_id.code == lang ) + + def unlink(self): + # Call unlink manually to be sure to trigger + # shopinvader variant unlink constraint + self.mapped("shopinvader_bind_ids").unlink() + return super(ProductProduct, self).unlink() diff --git a/shopinvader/models/shopinvader_product.py b/shopinvader/models/shopinvader_product.py index 89e1954981..ef32627365 100644 --- a/shopinvader/models/shopinvader_product.py +++ b/shopinvader/models/shopinvader_product.py @@ -199,3 +199,9 @@ def _redirect_existing_url(self): } ) return True + + def unlink(self): + # Call unlink manually to be sure to trigger + # shopinvader variant unlink constraint + self.mapped("shopinvader_variant_ids").unlink() + return super(ShopinvaderProduct, self).unlink() diff --git a/shopinvader_search_engine/models/__init__.py b/shopinvader_search_engine/models/__init__.py index 105515b1ec..2fe9ae5c82 100644 --- a/shopinvader_search_engine/models/__init__.py +++ b/shopinvader_search_engine/models/__init__.py @@ -1,6 +1,4 @@ from . import shopinvader_backend -from . import product_product -from . import shopinvader_product from . import shopinvader_variant from . import shopinvader_category from . import se_index diff --git a/shopinvader_search_engine/models/product_product.py b/shopinvader_search_engine/models/product_product.py deleted file mode 100644 index 61d3690c48..0000000000 --- a/shopinvader_search_engine/models/product_product.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2019 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import models - - -class ProductProduct(models.Model): - _inherit = "product.product" - - def unlink(self): - # Call unlink manually to be sure to trigger - # shopinvader variant unlink constraint - self.mapped("shopinvader_bind_ids").unlink() - return super(ProductProduct, self).unlink() diff --git a/shopinvader_search_engine/models/shopinvader_product.py b/shopinvader_search_engine/models/shopinvader_product.py deleted file mode 100644 index 41f6337485..0000000000 --- a/shopinvader_search_engine/models/shopinvader_product.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2019 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import models - - -class ShopinvaderProduct(models.Model): - _inherit = "shopinvader.product" - - def unlink(self): - # Call unlink manually to be sure to trigger - # shopinvader variant unlink constraint - self.mapped("shopinvader_variant_ids").unlink() - return super(ShopinvaderProduct, self).unlink() diff --git a/shopinvader_search_engine/tests/test_delete_product.py b/shopinvader_search_engine/tests/test_delete_product.py index bb4bd37be3..2f76f4814f 100644 --- a/shopinvader_search_engine/tests/test_delete_product.py +++ b/shopinvader_search_engine/tests/test_delete_product.py @@ -1,37 +1,38 @@ -# -*- coding: utf-8 -*- # Copyright 2019 Akretion (http://www.akretion.com). # @author Sébastien BEAU # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo.exceptions import UserError -from odoo.tests.common import TransactionCase +from odoo.tests import SavepointCase -class BindingCase(TransactionCase): - def setUp(self): - super(BindingCase, self).setUp() - self.template = self.env["product.template"].create({"name": "Test"}) - self.product = self.template.product_variant_ids - self.shopinvader_product = ( - self.env["shopinvader.product"] +class BindingCase(SavepointCase): + @classmethod + def setUpClass(cls): + super(BindingCase, cls).setUpClass() + cls.template = cls.env["product.template"].create({"name": "Test"}) + cls.product = cls.template.product_variant_ids + cls.shopinvader_product = ( + cls.env["shopinvader.product"] .with_context(map_children=True) .create( { - "record_id": self.template.id, - "backend_id": self.ref("shopinvader.backend_1"), - "lang_id": self.ref("base.lang_en"), + "record_id": cls.template.id, + "backend_id": cls.env.ref("shopinvader.backend_1").id, + "lang_id": cls.env.ref("base.lang_en").id, } ) ) - self.shopinvader_variant = ( - self.shopinvader_product.shopinvader_variant_ids + cls.shopinvader_variant = ( + cls.shopinvader_product.shopinvader_variant_ids ) class BindingDoneCase(BindingCase): - def setUp(self): - super(BindingDoneCase, self).setUp() - self.shopinvader_variant.write({"sync_state": "done"}) + @classmethod + def setUpClass(cls): + super(BindingDoneCase, cls).setUpClass() + cls.shopinvader_variant.write({"sync_state": "done"}) def test_unlink_shopinvader_product(self): with self.assertRaises(UserError): @@ -47,9 +48,11 @@ def test_unlink_product_template(self): class BindingInactiveDoneCase(BindingCase): - def setUp(self): - super(BindingInactiveDoneCase, self).setUp() - self.shopinvader_variant.write({"sync_state": "done", "active": False}) + @classmethod + def setUpClass(cls): + super(BindingInactiveDoneCase, cls).setUpClass() + cls.shopinvader_variant.active = False + cls.shopinvader_variant.sync_state = "done" def test_unlink_shopinvader_product(self): self.shopinvader_product.unlink()