From 5e81b3e3d2f8678124a383813e50e133dbba2db3 Mon Sep 17 00:00:00 2001 From: "Pedram (PEBR)" Date: Tue, 22 Aug 2023 09:59:03 +0000 Subject: [PATCH] [FIX] pos_loyalty: handle many2one field in reward product domain Before this commit, if you added a domain to a loyalty reward with one of many2one fields like [("categ_id", "ilike", "test")], it wasn't possible to open the PoS. This commit addresses this limitation by replacing the many2one fields with their corresponding value. To do this the product's field type is loaded to ensure that this improvement applies exclusively to many2one fields. However, it's important to note that this improvement currently handles only "one-level" of related many2one fields. Any domain that appears like ("categ_id.foo", "ilike", "foo-val") won't function as expected. opw-3473103 closes odoo/odoo#134811 X-original-commit: d0a6ab8d1f89f0dd2aa6641c63b6973ae7c753ad Signed-off-by: Joseph Caburnay (jcb) Signed-off-by: Pedram Bi Ria (pebr) --- addons/pos_loyalty/models/pos_session.py | 4 ++ .../static/src/overrides/models/pos_store.js | 10 ++++ .../tests/tours/PosLoyaltyRewardButtonTour.js | 22 +++++++ addons/pos_loyalty/tests/test_frontend.py | 58 +++++++++++++++++++ 4 files changed, 94 insertions(+) diff --git a/addons/pos_loyalty/models/pos_session.py b/addons/pos_loyalty/models/pos_session.py index f91d384012c..f8819443bcc 100644 --- a/addons/pos_loyalty/models/pos_session.py +++ b/addons/pos_loyalty/models/pos_session.py @@ -115,6 +115,10 @@ class PosSession(models.Model): product_id_to_program_ids[product['id']].append(program['id']) loaded_data['product_id_to_program_ids'] = product_id_to_program_ids + product_product_fields = self.env['product.product'].fields_get(self._loader_params_product_product()['search_params']['fields']) + loaded_data['field_types'] = { + 'product.product': {f:v['type'] for f, v in product_product_fields.items()} + } def _loader_params_product_product(self): params = super()._loader_params_product_product() diff --git a/addons/pos_loyalty/static/src/overrides/models/pos_store.js b/addons/pos_loyalty/static/src/overrides/models/pos_store.js index c9b25a62224..9bcadb9756d 100644 --- a/addons/pos_loyalty/static/src/overrides/models/pos_store.js +++ b/addons/pos_loyalty/static/src/overrides/models/pos_store.js @@ -207,6 +207,7 @@ patch(PosStore.prototype, { reward.all_discount_product_ids = new Set(reward.all_discount_product_ids); } + this.fieldTypes = loadedData['field_types']; await super._processData(loadedData); this.productId2ProgramIds = loadedData["product_id_to_program_ids"]; this.programs = loadedData["loyalty.program"] || []; //TODO: rename to `loyaltyPrograms` etc @@ -234,6 +235,15 @@ patch(PosStore.prototype, { try { products + .map(product => { + const modifiedProduct = { ...product }; + Object.keys(modifiedProduct).forEach(key => { + if (this.fieldTypes['product.product'][key] === 'many2one') { + modifiedProduct[key] = modifiedProduct[key][1]; + } + }); + return modifiedProduct; + }) .filter((product) => domain.contains(product)) .forEach((product) => reward.all_discount_product_ids.add(product.id)); } catch (error) { diff --git a/addons/pos_loyalty/static/tests/tours/PosLoyaltyRewardButtonTour.js b/addons/pos_loyalty/static/tests/tours/PosLoyaltyRewardButtonTour.js index aea3766ea04..64587de4e7e 100644 --- a/addons/pos_loyalty/static/tests/tours/PosLoyaltyRewardButtonTour.js +++ b/addons/pos_loyalty/static/tests/tours/PosLoyaltyRewardButtonTour.js @@ -198,3 +198,25 @@ registry.category("web_tour.tours").add("PosLoyaltySpecificDiscountWithFreeProdu return getSteps(); }, }); + +registry + .category("web_tour.tours") + .add("PosLoyaltySpecificDiscountWithRewardProductDomainTour", { + test: true, + url: "/pos/web", + steps: () => { + startSteps(); + + ProductScreen.do.confirmOpeningPopup(); + ProductScreen.do.clickHomeCategory(); + + ProductScreen.do.clickDisplayedProduct('Product A'); + ProductScreen.check.selectedOrderlineHas('Product A', '1.00', '15.00'); + PosLoyalty.check.orderTotalIs('15.00'); + + ProductScreen.do.clickDisplayedProduct('Product B'); + ProductScreen.check.selectedOrderlineHas('Product B', '1.00', '50.00'); + PosLoyalty.check.orderTotalIs('40.00'); + return getSteps(); + } + }); diff --git a/addons/pos_loyalty/tests/test_frontend.py b/addons/pos_loyalty/tests/test_frontend.py index 1e963b3ce1c..0b52d21d569 100644 --- a/addons/pos_loyalty/tests/test_frontend.py +++ b/addons/pos_loyalty/tests/test_frontend.py @@ -1122,3 +1122,61 @@ class TestUi(TestPointOfSaleHttpCommon): "PosLoyaltyTour7", login="pos_user", ) + + def test_discount_with_reward_product_domain(self): + self.env['loyalty.program'].search([]).write({'active': False}) + + product_category_base = self.env.ref('product.product_category_1') + product_category_1 = self.env['product.category'].create({ + 'name': 'Office furnitures', + 'parent_id': product_category_base.id + }) + + self.productA = self.env['product.product'].create( + { + 'name': 'Product A', + 'type': 'product', + 'list_price': 15, + 'available_in_pos': True, + 'taxes_id': False, + 'categ_id': product_category_base.id + } + ) + + self.productB = self.env['product.product'].create( + { + 'name': 'Product B', + 'type': 'product', + 'list_price': 50, + 'available_in_pos': True, + 'taxes_id': False, + 'categ_id': product_category_1.id + } + ) + + self.env['loyalty.program'].create({ + 'name': 'Discount on Specific Products', + 'program_type': 'promotion', + 'trigger': 'auto', + 'applies_on': 'current', + 'rule_ids': [(0, 0, { + 'reward_point_mode': 'order', + 'minimum_qty': 1, + })], + 'reward_ids': [(0, 0, { + 'reward_type': 'discount', + 'required_points': 1, + 'discount': 50, + 'discount_mode': 'percent', + 'discount_applicability': 'specific', + 'discount_product_domain': '[("categ_id", "ilike", "office")]', + })], + 'pos_config_ids': [Command.link(self.main_pos_config.id)], + }) + + self.main_pos_config.open_ui() + self.start_tour( + "/pos/web?config_id=%d" % self.main_pos_config.id, + "PosLoyaltySpecificDiscountWithRewardProductDomainTour", + login="pos_user", + )