From 5cd0bbd32c66e60f3ba9dfe9c42683f9ab095274 Mon Sep 17 00:00:00 2001 From: pilarvargas-tecnativa Date: Wed, 22 Nov 2023 18:00:25 +0100 Subject: [PATCH] [IMP-FIX] loyalty_multi_gift: Continue migration to v16 - Added migration script - Adapt test - Adapt methods and views TT44321 --- loyalty_multi_gift/README.rst | 39 +++-- loyalty_multi_gift/__manifest__.py | 2 +- .../migrations/pre-migration.py | 23 +++ loyalty_multi_gift/models/loyalty_reward.py | 41 +++-- loyalty_multi_gift/readme/CONFIGURE.rst | 2 +- loyalty_multi_gift/readme/CONTEXT.rst | 14 ++ loyalty_multi_gift/readme/CONTRIBUTORS.rst | 1 + .../static/description/index.html | 65 +++++--- loyalty_multi_gift/tests/__init__.py | 2 +- .../tests/loyalty_multi_gift_case.py | 64 -------- .../tests/test_loyalty_multi_gift_case.py | 150 ++++++++++++++++++ .../views/loyalty_program_views.xml | 3 - .../views/loyalty_reward_views.xml | 48 ++++++ 13 files changed, 334 insertions(+), 120 deletions(-) create mode 100644 loyalty_multi_gift/migrations/pre-migration.py create mode 100644 loyalty_multi_gift/readme/CONTEXT.rst delete mode 100644 loyalty_multi_gift/tests/loyalty_multi_gift_case.py create mode 100644 loyalty_multi_gift/tests/test_loyalty_multi_gift_case.py create mode 100644 loyalty_multi_gift/views/loyalty_reward_views.xml diff --git a/loyalty_multi_gift/README.rst b/loyalty_multi_gift/README.rst index f3a3daf72..11f605938 100644 --- a/loyalty_multi_gift/README.rst +++ b/loyalty_multi_gift/README.rst @@ -1,5 +1,5 @@ ================== -Coupons multi gift +Loyalty multi gift ================== .. @@ -7,7 +7,7 @@ Coupons multi gift !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:55e1550e878f90717902833da0b3bcedb492be8f33b0211ee608ecb32f85968b + !! source digest: sha256:f3338dddec7e1ca070ed8a53fe498a1ebbdd1be1578d88d2bd3b72be437188f8 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -17,13 +17,13 @@ Coupons multi gift :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--promotion-lightgray.png?logo=github - :target: https://github.com/OCA/sale-promotion/tree/15.0/coupon_multi_gift + :target: https://github.com/OCA/sale-promotion/tree/16.0/loyalty_multi_gift :alt: OCA/sale-promotion .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/sale-promotion-15-0/sale-promotion-15-0-coupon_multi_gift + :target: https://translation.odoo-community.org/projects/sale-promotion-16-0/sale-promotion-16-0-loyalty_multi_gift :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/sale-promotion&target_branch=15.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/sale-promotion&target_branch=16.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -35,15 +35,33 @@ This module allows to define multiple reward products on promotions. .. contents:: :local: +Use Cases / Context +=================== + +For the 'buy_x_get_y' type promotion, the 'Reward_type' field is restricted to the 'Product' +option only and the possibility to select 'Multigift' is disabled. This restriction is implemented +because, in this scenario, the 'reward_type' field becomes 'readonly'. + +It is crucial to note that modifying the values displayed in this field to set different +values according to the type of promotion may generate conflicts with other modules that +contribute to the configuration of this same field. Therefore, it is recommended not to +alter these values directly, as this may affect the consistency and functionality of other +components of the system. + +To configure similar promotions, it is suggested to modify another type of promotion by +adapting its rules and rewards according to specific needs. This provides a more secure +and consistent way to manage custom configurations without compromising the integrity of +the system. + Configuration ============= To configure multiple product rewards: -#. Go to *Sales > Catalog > Coupon Programs* and select or create a new one. +#. Go to *Sales > Products > Discount & Loyalty* and select or create a new one. #. Choose the criteria of appliance you want to use and the minimum quantities, that will be used to calculate the times the rewards can be applied. -#. On the *Reward Type* field choose *Multi Gift*. +#. On the *Program Type* field choose *Multi Gift*. #. You'll see a now the *Gift list* on which you can add the products you want to give away and the quantities for each of them. @@ -58,7 +76,7 @@ An example: With a minimum quantity of 3, for every 3 units of products that fulfill the domain we'd get 3 units of A and 2 of B. So if the valid products quantities are 11, we'd -get 9 of product A and 6 of product B. +get 3 of product A and 2 of product B. Usage ===== @@ -72,7 +90,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -90,6 +108,7 @@ Contributors * `Tecnativa `_: * David Vidal + * Pilar Vargas * `Domatix `_: @@ -116,6 +135,6 @@ Current `maintainer `__: |maintainer-chienandalu| -This module is part of the `OCA/sale-promotion `_ project on GitHub. +This module is part of the `OCA/sale-promotion `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/loyalty_multi_gift/__manifest__.py b/loyalty_multi_gift/__manifest__.py index 2d4869318..a6e68964e 100644 --- a/loyalty_multi_gift/__manifest__.py +++ b/loyalty_multi_gift/__manifest__.py @@ -11,5 +11,5 @@ "maintainers": ["chienandalu"], "license": "AGPL-3", "depends": ["loyalty"], - "data": ["views/loyalty_program_views.xml", "security/ir.model.access.csv"], + "data": ["views/loyalty_reward_views.xml", "security/ir.model.access.csv"], } diff --git a/loyalty_multi_gift/migrations/pre-migration.py b/loyalty_multi_gift/migrations/pre-migration.py new file mode 100644 index 000000000..fcfdafd2e --- /dev/null +++ b/loyalty_multi_gift/migrations/pre-migration.py @@ -0,0 +1,23 @@ +# Copyright 2023 Tecnativa - Pilar Vargas +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openupgradelib import openupgrade + +_renamed_fields = [ + ( + "loyalty.reward", + "loyalty_reward", + "coupon_multi_gift_ids", + "loyalty_multi_gift_ids", + ), +] + + +@openupgrade.migrate() +def migrate(env, version): + openupgrade.rename_fields(env, _renamed_fields) + openupgrade.rename_models( + env.cr, [("coupon.reward.product_line", "loyalty.reward.product_line")] + ) + openupgrade.rename_tables( + env.cr, [("coupon_reward_product_line", "loyalty_reward_product_line")] + ) diff --git a/loyalty_multi_gift/models/loyalty_reward.py b/loyalty_multi_gift/models/loyalty_reward.py index 2ade5bf11..c17890ea3 100644 --- a/loyalty_multi_gift/models/loyalty_reward.py +++ b/loyalty_multi_gift/models/loyalty_reward.py @@ -11,23 +11,37 @@ class LoyaltyReward(models.Model): inverse_name="reward_id", string="Gift list", ) + multi_gift = fields.Boolean(compute="_compute_multi_gift") reward_type = fields.Selection( selection_add=[("multi_gift", "Multi Gift")], ondelete={"multi_gift": "set default"}, ) - def name_get(self): - """Add complete description for the multi gift reward type.""" - res = super().name_get() - for reward in self.filtered(lambda x: x.program_type == "multi_gift"): - reward_string = _("Free Products - %(name)s") % { - "name": ", ".join( - f"{reward.reward_product_quantity}x " - f"{fields.first(reward.reward_product_ids).name}" - for reward in reward.loyalty_multi_gift_ids + @api.depends("reward_type", "loyalty_multi_gift_ids.reward_product_ids") + def _compute_multi_gift(self): + for reward in self: + reward.multi_gift = ( + reward.reward_type == "multi_gift" + and len(reward.loyalty_multi_gift_ids) > 0 + ) + + @api.depends("loyalty_multi_gift_ids.reward_product_ids") + def _compute_description(self): + res = super()._compute_description() + for reward in self: + if reward.reward_type == "multi_gift": + reward_string = "" + products = self.env["product.product"].browse( + reward.loyalty_multi_gift_ids.reward_default_product_id.ids ) - } - res.append((reward.id, reward_string)) + product_names = products.with_context( + display_default_code=False + ).mapped("display_name") + if len(products) == 0: + reward_string = _("Multi Gift") + else: + reward_string = _("Multi Gift - [%s]") % ", ".join(product_names) + reward.description = reward_string return res @@ -43,7 +57,6 @@ class LoyaltyGift(models.Model): reward_default_product_id = fields.Many2one( comodel_name="product.product", compute="_compute_reward_default_product_id", - inverse="_inverse_reward_default_product_id", readonly=False, ) reward_product_ids = fields.Many2many( @@ -60,10 +73,6 @@ def _compute_reward_default_product_id(self): for line in self: line.reward_default_product_id = fields.first(line.reward_product_ids) - def _inverse_reward_default_product_id(self): - for line in self.filtered("reward_default_product_id"): - line.reward_product_ids = line.reward_default_product_id - @api.onchange("reward_product_ids") def onchange_reward_product_ids(self): self.reward_default_product_id = fields.first(self.reward_product_ids)._origin diff --git a/loyalty_multi_gift/readme/CONFIGURE.rst b/loyalty_multi_gift/readme/CONFIGURE.rst index 504682899..903e8d61e 100644 --- a/loyalty_multi_gift/readme/CONFIGURE.rst +++ b/loyalty_multi_gift/readme/CONFIGURE.rst @@ -18,4 +18,4 @@ An example: With a minimum quantity of 3, for every 3 units of products that fulfill the domain we'd get 3 units of A and 2 of B. So if the valid products quantities are 11, we'd -get 9 of product A and 6 of product B. +get 3 of product A and 2 of product B. diff --git a/loyalty_multi_gift/readme/CONTEXT.rst b/loyalty_multi_gift/readme/CONTEXT.rst new file mode 100644 index 000000000..618f6283f --- /dev/null +++ b/loyalty_multi_gift/readme/CONTEXT.rst @@ -0,0 +1,14 @@ +For the 'buy_x_get_y' type promotion, the 'Reward_type' field is restricted to the 'Product' +option only and the possibility to select 'Multigift' is disabled. This restriction is implemented +because, in this scenario, the 'reward_type' field becomes 'readonly'. + +It is crucial to note that modifying the values displayed in this field to set different +values according to the type of promotion may generate conflicts with other modules that +contribute to the configuration of this same field. Therefore, it is recommended not to +alter these values directly, as this may affect the consistency and functionality of other +components of the system. + +To configure similar promotions, it is suggested to modify another type of promotion by +adapting its rules and rewards according to specific needs. This provides a more secure +and consistent way to manage custom configurations without compromising the integrity of +the system. diff --git a/loyalty_multi_gift/readme/CONTRIBUTORS.rst b/loyalty_multi_gift/readme/CONTRIBUTORS.rst index 994869129..06c2608cd 100644 --- a/loyalty_multi_gift/readme/CONTRIBUTORS.rst +++ b/loyalty_multi_gift/readme/CONTRIBUTORS.rst @@ -1,6 +1,7 @@ * `Tecnativa `_: * David Vidal + * Pilar Vargas * `Domatix `_: diff --git a/loyalty_multi_gift/static/description/index.html b/loyalty_multi_gift/static/description/index.html index 6fb8d7fc7..7ab15d9f4 100644 --- a/loyalty_multi_gift/static/description/index.html +++ b/loyalty_multi_gift/static/description/index.html @@ -4,7 +4,7 @@ -Coupons multi gift +Loyalty multi gift -
-

Coupons multi gift

+
+

Loyalty multi gift

-

Beta License: AGPL-3 OCA/sale-promotion Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/sale-promotion Translate me on Weblate Try me on Runboat

This module allows to define multiple reward products on promotions.

Table of contents

+
+

Use Cases / Context

+

For the ‘buy_x_get_y’ type promotion, the ‘Reward_type’ field is restricted to the ‘Product’ +option only and the possibility to select ‘Multigift’ is disabled. This restriction is implemented +because, in this scenario, the ‘reward_type’ field becomes ‘readonly’.

+

It is crucial to note that modifying the values displayed in this field to set different +values according to the type of promotion may generate conflicts with other modules that +contribute to the configuration of this same field. Therefore, it is recommended not to +alter these values directly, as this may affect the consistency and functionality of other +components of the system.

+

To configure similar promotions, it is suggested to modify another type of promotion by +adapting its rules and rewards according to specific needs. This provides a more secure +and consistent way to manage custom configurations without compromising the integrity of +the system.

+
-

Configuration

+

Configuration

To configure multiple product rewards:

    -
  1. Go to Sales > Catalog > Coupon Programs and select or create a new one.
  2. +
  3. Go to Sales > Products > Discount & Loyalty and select or create a new one.
  4. Choose the criteria of appliance you want to use and the minimum quantities, that will be used to calculate the times the rewards can be applied.
  5. -
  6. On the Reward Type field choose Multi Gift.
  7. +
  8. On the Program Type field choose Multi Gift.
  9. You’ll see a now the Gift list on which you can add the products you want to give away and the quantities for each of them.
@@ -420,34 +436,35 @@

Configuration

With a minimum quantity of 3, for every 3 units of products that fulfill the domain we’d get 3 units of A and 2 of B. So if the valid products quantities are 11, we’d -get 9 of product A and 6 of product B.

+get 3 of product A and 2 of product B.

-

Usage

+

Usage

This module is a base to be used by extra modules that use it in sale orders, PoS orders, etc.

-

Bug Tracker

+

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.

+feedback.

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Tecnativa
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association

OCA, or the Odoo Community Association, is a nonprofit organization whose @@ -465,7 +482,7 @@

Maintainers

promote its widespread use.

Current maintainer:

chienandalu

-

This module is part of the OCA/sale-promotion project on GitHub.

+

This module is part of the OCA/sale-promotion project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/loyalty_multi_gift/tests/__init__.py b/loyalty_multi_gift/tests/__init__.py index b18b957d0..8af1b66e8 100644 --- a/loyalty_multi_gift/tests/__init__.py +++ b/loyalty_multi_gift/tests/__init__.py @@ -1 +1 @@ -from . import loyalty_multi_gift_case +from . import test_loyalty_multi_gift_case diff --git a/loyalty_multi_gift/tests/loyalty_multi_gift_case.py b/loyalty_multi_gift/tests/loyalty_multi_gift_case.py deleted file mode 100644 index 50bcd1fc4..000000000 --- a/loyalty_multi_gift/tests/loyalty_multi_gift_case.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2021 Tecnativa - David Vidal -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo.tests import Form, TransactionCase - - -class LoyaltyMultiGiftCase(TransactionCase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) - cls.pricelist = cls.env["product.pricelist"].create( - { - "name": "Test pricelist", - "item_ids": [ - ( - 0, - 0, - { - "applied_on": "3_global", - "compute_price": "formula", - "base": "list_price", - }, - ) - ], - } - ) - cls.partner = cls.env["res.partner"].create( - {"name": "Mr. Odoo", "property_product_pricelist": cls.pricelist.id} - ) - cls.product_1 = cls.env["product.product"].create( - {"name": "Test 1", "sale_ok": True, "list_price": 50} - ) - cls.product_2 = cls.env["product.product"].create( - {"name": "Test 2", "sale_ok": False, "list_price": 60} - ) - cls.product_3 = cls.env["product.product"].create( - {"name": "Test 3", "sale_ok": False, "list_price": 70} - ) - cls.product_4 = cls.env["product.product"].create( - {"name": "Test 4", "sale_ok": False, "list_price": 80} - ) - loyalty_program_form = Form( - cls.env["loyalty.program"], - view="coupon.coupon_program_view_promo_program_form", - ) - loyalty_program_form.name = "Test Multiplier Program" - loyalty_program_form.promo_code_usage = "no_code_needed" - loyalty_program_form.reward_type = "multi_gift" - # For every two products that fulfill the domain condition, we'd get 2 units - # of product 1 and 3 units of product 3 for free - loyalty_program_form.rule_minimum_amount = 75 - # Every two we'll fulfill the condition - loyalty_program_form.rule_min_quantity = 2 - loyalty_program_form.rule_products_domain = "[('id', '=', %s)]" % ( - cls.product_1.id - ) - with loyalty_program_form.loyalty_multi_gift_ids.new() as reward_line: - reward_line.reward_product_ids.add(cls.product_2) - reward_line.reward_product_quantity = 2 - with loyalty_program_form.loyalty_multi_gift_ids.new() as reward_line: - reward_line.reward_product_ids.add(cls.product_3) - reward_line.reward_product_ids.add(cls.product_4) - reward_line.reward_product_quantity = 3 - cls.loyalty_program = loyalty_program_form.save() diff --git a/loyalty_multi_gift/tests/test_loyalty_multi_gift_case.py b/loyalty_multi_gift/tests/test_loyalty_multi_gift_case.py new file mode 100644 index 000000000..72ea17360 --- /dev/null +++ b/loyalty_multi_gift/tests/test_loyalty_multi_gift_case.py @@ -0,0 +1,150 @@ +# Copyright 2021 Tecnativa - David Vidal +# Copyright 2023 Tecnativa - Pilar Vargas +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo.tests import TransactionCase + + +class LoyaltyMultiGiftCase(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.pricelist = cls.env["product.pricelist"].create( + { + "name": "Test pricelist", + "item_ids": [ + ( + 0, + 0, + { + "applied_on": "3_global", + "compute_price": "formula", + "base": "list_price", + }, + ) + ], + } + ) + cls.partner = cls.env["res.partner"].create( + {"name": "Mr. Odoo", "property_product_pricelist": cls.pricelist.id} + ) + cls.product_1 = cls.env["product.product"].create( + {"name": "Test 1", "sale_ok": True, "list_price": 50} + ) + cls.product_2 = cls.env["product.product"].create( + {"name": "Test 2", "sale_ok": False, "list_price": 60} + ) + cls.product_3 = cls.env["product.product"].create( + {"name": "Test 3", "sale_ok": False, "list_price": 70} + ) + cls.product_4 = cls.env["product.product"].create( + {"name": "Test 4", "sale_ok": False, "list_price": 80} + ) + cls.loyalty_program_form = cls.env["loyalty.program"].create( + { + "name": "Test Multi Gift Program", + "program_type": "promotion", + "trigger": "auto", + "applies_on": "current", + "rule_ids": [ + ( + 0, + 0, + { + "reward_point_mode": "order", + "minimum_qty": 2, + }, + ), + ], + "reward_ids": [ + ( + 0, + 0, + { + "reward_type": "multi_gift", + "required_points": 1, + "loyalty_multi_gift_ids": [ + ( + 0, + 0, + { + "reward_product_ids": [(4, cls.product_2.id)], + "reward_product_quantity": 2, + }, + ), + ( + 0, + 0, + { + "reward_product_ids": [ + (4, cls.product_3.id), + (4, cls.product_4.id), + ], + "reward_product_quantity": 3, + }, + ), + ], + }, + ) + ], + } + ) + + def test_01_loyalty_multi_gift_ids(self): + """Check that the records are being created without duplicates + (Fix in write method of loyalty.program).""" + # Initially the promotion has 2 gifts + gift_options_qty = len( + self.loyalty_program_form.reward_ids[0].loyalty_multi_gift_ids + ) + self.assertEqual(gift_options_qty, 2) + # By modifying the amount of gifts (+1) by typing in the field from reward_ids + # (loyalty.reward), the amount of gifts increases by 1, in total 3. + self.loyalty_program_form.reward_ids[0].write( + { + "loyalty_multi_gift_ids": [ + ( + 0, + 0, + { + "reward_product_ids": [(4, self.product_3.id)], + "reward_product_quantity": 1, + }, + ) + ], + } + ) + gift_options_qty = len( + self.loyalty_program_form.reward_ids[0].loyalty_multi_gift_ids + ) + self.assertEqual(gift_options_qty, 3) + # This will fail. When modifying the amount of gifts from the promotion (as it + # is done in the form) if we increase that gift in 1 more, we should have in total + # 4 gifts, the previous 3 + 1, in this case 2 records are being created for the + # same gift and instead of having 4, there will be 5 (failure). + self.loyalty_program_form.write( + { + "reward_ids": [ + ( + 1, + self.loyalty_program_form.reward_ids[0].id, + { + "loyalty_multi_gift_ids": [ + ( + 0, + 0, + { + "reward_product_ids": [(4, self.product_3.id)], + "reward_product_quantity": 1, + }, + ) + ], + }, + ) + ], + } + ) + gift_options_qty = len( + self.loyalty_program_form.reward_ids[0].loyalty_multi_gift_ids + ) + self.assertEqual(gift_options_qty, 4) diff --git a/loyalty_multi_gift/views/loyalty_program_views.xml b/loyalty_multi_gift/views/loyalty_program_views.xml index 5ff3f08ec..c2fed6e29 100644 --- a/loyalty_multi_gift/views/loyalty_program_views.xml +++ b/loyalty_multi_gift/views/loyalty_program_views.xml @@ -4,9 +4,6 @@ loyalty.reward - - {} - + + + + loyalty.reward + + + + + + + + + + + + + + + + + loyalty.reward + + + +
+
+
+
+
+