From 088c1f740d92e493ffd455195f9c01170ab7c259 Mon Sep 17 00:00:00 2001 From: pilarvargas-tecnativa Date: Thu, 23 Nov 2023 12:10:55 +0100 Subject: [PATCH] [MIG] sale_coupon_multi_gift>sale_loyalty_multi_gift: Migration to 16.0 TT44348 --- sale_loyalty_multi_gift/README.rst | 19 +- sale_loyalty_multi_gift/__manifest__.py | 6 +- sale_loyalty_multi_gift/models/__init__.py | 2 +- .../models/coupon_program.py | 39 ----- sale_loyalty_multi_gift/models/sale_order.py | 165 ++++++------------ .../readme/CONTRIBUTORS.rst | 1 + .../security/ir.model.access.csv | 4 +- .../static/description/index.html | 15 +- sale_loyalty_multi_gift/tests/__init__.py | 2 +- .../tests/test_sale_coupon_multi_gift.py | 124 ------------- .../tests/test_sale_loyalty_multi_gift.py | 147 ++++++++++++++++ .../odoo/addons/sale_coupon_multi_gift | 1 - .../odoo/addons/sale_loyalty_multi_gift | 1 + .../setup.py | 0 14 files changed, 228 insertions(+), 298 deletions(-) delete mode 100644 sale_loyalty_multi_gift/models/coupon_program.py delete mode 100644 sale_loyalty_multi_gift/tests/test_sale_coupon_multi_gift.py create mode 100644 sale_loyalty_multi_gift/tests/test_sale_loyalty_multi_gift.py delete mode 120000 setup/sale_coupon_multi_gift/odoo/addons/sale_coupon_multi_gift create mode 120000 setup/sale_loyalty_multi_gift/odoo/addons/sale_loyalty_multi_gift rename setup/{sale_coupon_multi_gift => sale_loyalty_multi_gift}/setup.py (100%) diff --git a/sale_loyalty_multi_gift/README.rst b/sale_loyalty_multi_gift/README.rst index c1fc069a5..d933f156e 100644 --- a/sale_loyalty_multi_gift/README.rst +++ b/sale_loyalty_multi_gift/README.rst @@ -1,13 +1,13 @@ -=========================== -Coupons multi gift in sales -=========================== +======================= +Sale Loyalty Multi Gift +======================= .. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:7f3497a24d35eeb0b15943041a8537f46b4eb32153e9451598ca64a9e5bf4e54 + !! source digest: sha256:28e58ffa1dce31e6123f0ae20b41b27ef347e241906cf2a913f9d9163e5673bf !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -17,13 +17,13 @@ Coupons multi gift in sales :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/sale_coupon_multi_gift + :target: https://github.com/OCA/sale-promotion/tree/16.0/sale_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-sale_coupon_multi_gift + :target: https://translation.odoo-community.org/projects/sale-promotion-16-0/sale-promotion-16-0-sale_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| @@ -56,7 +56,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. @@ -74,6 +74,7 @@ Contributors * `Tecnativa `_: * David Vidal + * Pilar Vargas * `Domatix `_: @@ -100,6 +101,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/sale_loyalty_multi_gift/__manifest__.py b/sale_loyalty_multi_gift/__manifest__.py index a08745331..12643d3c2 100644 --- a/sale_loyalty_multi_gift/__manifest__.py +++ b/sale_loyalty_multi_gift/__manifest__.py @@ -1,15 +1,15 @@ # Copyright 2021 Tecnativa - David Vidal # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). { - "name": "Coupons multi gift in sales", + "name": "Sale Loyalty Multi Gift", "summary": "Allows to configure multiple gift rewards per promotion in sales", - "version": "15.0.1.0.0", + "version": "16.0.1.0.0", "development_status": "Beta", "category": "Sale", "website": "https://github.com/OCA/sale-promotion", "author": "Tecnativa, Odoo Community Association (OCA)", "maintainers": ["chienandalu"], "license": "AGPL-3", - "depends": ["sale_coupon_order_line_link", "coupon_multi_gift"], + "depends": ["sale_loyalty_order_line_link", "loyalty_multi_gift"], "data": ["security/ir.model.access.csv"], } diff --git a/sale_loyalty_multi_gift/models/__init__.py b/sale_loyalty_multi_gift/models/__init__.py index b1f0c3480..7578fe454 100644 --- a/sale_loyalty_multi_gift/models/__init__.py +++ b/sale_loyalty_multi_gift/models/__init__.py @@ -1,2 +1,2 @@ -from . import coupon_program +# from . import coupon_program from . import sale_order diff --git a/sale_loyalty_multi_gift/models/coupon_program.py b/sale_loyalty_multi_gift/models/coupon_program.py deleted file mode 100644 index 020dd6aad..000000000 --- a/sale_loyalty_multi_gift/models/coupon_program.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2021 Tecnativa - David Vidal -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import models - - -class CouponProgram(models.Model): - _inherit = "coupon.program" - - def _compute_order_count(self): - """Relay on the order line link for these programs instead of the discount - products""" - multi_gift_programs = self.filtered(lambda x: x.reward_type == "multi_gift") - res = super(CouponProgram, self - multi_gift_programs)._compute_order_count() - for program in multi_gift_programs: - orders = self.env["sale.order.line"].read_group( - [ - ("state", "not in", ["draft", "sent", "cancel"]), - ("coupon_program_id", "=", program.id), - ], - ["order_id"], - ["order_id"], - ) - program.order_count = len(orders) - return res - - def action_view_sales_orders(self): - res = super().action_view_sales_orders() - if self.reward_type != "multi_gift": - return res - orders = ( - self.env["sale.order.line"] - .search([("coupon_program_id", "=", self.id)]) - .mapped("order_id") - ) - res["domain"] = [ - ("id", "in", orders.ids), - ("state", "not in", ["draft", "sent", "cancel"]), - ] - return res diff --git a/sale_loyalty_multi_gift/models/sale_order.py b/sale_loyalty_multi_gift/models/sale_order.py index 8ee67c712..6c86bf489 100644 --- a/sale_loyalty_multi_gift/models/sale_order.py +++ b/sale_loyalty_multi_gift/models/sale_order.py @@ -1,26 +1,16 @@ # Copyright 2021 Tecnativa - David Vidal # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import random + from odoo import _, fields, models -from odoo.fields import first +from odoo.fields import Command, first +from odoo.tools.float_utils import float_round class SaleOrder(models.Model): _inherit = "sale.order" - def _get_paid_order_lines(self): - """Add reward lines produced by multi gift promotions""" - lines = super()._get_paid_order_lines() - free_reward_products = ( - self.env["coupon.program"] - .search([("reward_type", "=", "multi_gift")]) - .mapped("coupon_multi_gift_ids.reward_product_ids") - ) - free_reward_product_lines = self.order_line.filtered( - lambda x: x.is_reward_line and x.product_id in free_reward_products - ) - return lines | free_reward_product_lines - - def _get_reward_values_multi_gift_line(self, reward_line, program): + def _get_reward_values_multi_gift_line(self, reward_line, reward, coupon): """Multi Gift reward rules. For every gift reward rule, we'll create a new sale order line flagged as reward line with a 100% discount""" @@ -40,6 +30,24 @@ def _execute_onchanges(records, field_name): & reward_line.reward_product_ids ) reward_product_id = optional_product or first(reward_line.reward_product_ids) + taxes = self.fiscal_position_id.map_tax( + reward_product_id.taxes_id.filtered( + lambda t: t.company_id == self.company_id + ) + ) + points = self._get_real_points_for_coupon(coupon) + claimable_count = ( + float_round( + points / reward.required_points, + precision_rounding=1, + rounding_method="DOWN", + ) + if not reward.clear_wallet + else 1 + ) + cost = ( + points if reward.clear_wallet else claimable_count * reward.required_points + ) # We prepare a new line and trigger the proper onchanges to ensure we get the # right line values (price unit according to the customer pricelist, taxes, ect) order_line = self.order_line.new( @@ -52,30 +60,50 @@ def _execute_onchanges(records, field_name): vals.update( { "is_reward_line": True, - "name": _("Free Product") + " - " + reward_product_id.name, + "name": _( + "Free Product - %(product)s", + product=reward_product_id.with_context( + display_default_code=False + ).display_name, + ), + "price_unit": reward_product_id.list_price, "discount": 100, - "coupon_program_id": program.id, + "reward_id": reward.id, + "coupon_id": coupon.id, + "points_cost": cost, + "reward_identifier_code": str(random.getrandbits(32)), + "product_uom": reward_product_id.uom_id.id, + "sequence": max( + self.order_line.filtered(lambda x: not x.is_reward_line).mapped( + "sequence" + ), + default=10, + ) + + 1, + "tax_id": [(Command.CLEAR, 0, 0)] + + [(Command.LINK, tax.id, False) for tax in taxes], + "loyalty_program_id": reward.program_id.id, "multi_gift_reward_line_id": reward_line.id, "multi_gift_reward_line_id_option_product_id": reward_product_id.id, } ) return vals - def _get_reward_values_multi_gift(self, program): + def _get_reward_values_multi_gift(self, reward, coupon, **kwargs): """Wrapper to create the reward lines for a multi gift promotion""" return [ - self._get_reward_values_multi_gift_line(reward_line, program) - for reward_line in program.coupon_multi_gift_ids + self._get_reward_values_multi_gift_line(reward_line, reward, coupon) + for reward_line in reward.loyalty_multi_gift_ids ] - def _get_reward_line_values(self, program): + def _get_reward_line_values(self, reward, coupon, **kwargs): """Hook into the core method considering multi gift rewards""" self.ensure_one() self = self.with_context(lang=self.partner_id.lang) - program = program.with_context(lang=self.partner_id.lang) - if program.reward_type == "multi_gift": - return self._get_reward_values_multi_gift(program) - return super()._get_reward_line_values(program) + reward = reward.with_context(lang=self.partner_id.lang) + if reward.reward_type == "multi_gift": + return self._get_reward_values_multi_gift(reward, coupon, **kwargs) + return super()._get_reward_line_values(reward, coupon, **kwargs) def _get_applicable_programs_multi_gift(self): """Wrapper to avoid long method name limitations""" @@ -87,100 +115,15 @@ def _get_applicable_programs_multi_gift(self): ) return programs - def _remove_invalid_reward_lines(self): - """We have to put some logic redundancy here as the main method doesn't have - enough granularity to avoid deleting the lines belonging to the multi gift - programs when the promotions are updated. So the main module expects that the - promotion lines products match with the promotion discount product - (https://git.io/JWpoU) , which is not the approach in this module, where we add - extra lines with the reward products themselves and the proper price tag and - discount. So in this method override, we'll save those correct lines from the - pyre via context that the unlink method will properly catch. We also have to - remove the proper invalid lines that wouldn't be detected""" - self.ensure_one() - # This part is a repetition of the logic so we can get the right programs - applied_programs = self._get_applied_programs() - applicable_programs = self.env["coupon.program"] - if applied_programs: - applicable_programs = self._get_applicable_programs_multi_gift() - programs_to_remove = applied_programs - applicable_programs - # We're only interested in the Multi Gift programs - multi_gift_applied_programs = applied_programs.filtered( - lambda x: x.reward_type == "multi_gift" - ) - # These will be the ones to keep - valid_lines = self.order_line.filtered( - lambda x: x.is_reward_line - and x.coupon_program_id in multi_gift_applied_programs - ) - multi_gift_programs_to_remove = programs_to_remove.filtered( - lambda x: x.reward_type == "multi_gift" - ) - if multi_gift_programs_to_remove: - # Invalidate the generated coupons which we are not eligible anymore - self.generated_coupon_ids.filtered( - lambda x: x.program_id in multi_gift_programs_to_remove - ).write({"state": "expired"}) - # Detect and remove the proper unvalid program order lines - self.order_line.filtered( - lambda x: x.is_reward_line - and x.coupon_program_id in multi_gift_programs_to_remove - ).unlink() - # We'll catch the context in the subsequent unlink() method - return super( - SaleOrder, self.with_context(valid_multi_gift_lines=valid_lines.ids) - )._remove_invalid_reward_lines() - - def _update_existing_reward_lines(self): - """We need to match `multi gift` programs with their discount product""" - self.ensure_one() - res = super( - SaleOrder, self.with_context(only_reward_lines=True) - )._update_existing_reward_lines() - applied_programs = self._get_applied_programs_with_rewards_on_current_order() - for program in applied_programs.filtered( - lambda x: x.reward_type == "multi_gift" - ): - for reward_line in program.coupon_multi_gift_ids: - lines = self.order_line.filtered( - lambda line: line.multi_gift_reward_line_id == reward_line - and line.is_reward_line - and line.coupon_program_id == program - ) - applied_product = lines.multi_gift_reward_line_id_option_product_id - for product in applied_product: - reward_line_options = {reward_line.id: product.id} - values = self.with_context( - reward_line_options=reward_line_options - )._get_reward_values_multi_gift_line(reward_line, program) - # Remove reward line if price or qty equal to 0 - if values.get("product_uom_qty") and values.get("price_unit"): - lines.write(values) - else: - lines.unlink() - return res - class SaleOrderLine(models.Model): _inherit = "sale.order.line" multi_gift_reward_line_id = fields.Many2one( - comodel_name="coupon.reward.product_line", + comodel_name="loyalty.reward.product_line", readonly=True, ) multi_gift_reward_line_id_option_product_id = fields.Many2one( comodel_name="product.product", readonly=True, ) - - def unlink(self): - """Avoid unlinking valid multi gift lines since they aren't linked to the - discount product of the promotion program""" - if not self.env.context.get("valid_multi_gift_lines"): - return super().unlink() - return super( - SaleOrderLine, - self.filtered( - lambda x: x.id not in self.env.context.get("valid_multi_gift_lines") - ), - ).unlink() diff --git a/sale_loyalty_multi_gift/readme/CONTRIBUTORS.rst b/sale_loyalty_multi_gift/readme/CONTRIBUTORS.rst index 994869129..06c2608cd 100644 --- a/sale_loyalty_multi_gift/readme/CONTRIBUTORS.rst +++ b/sale_loyalty_multi_gift/readme/CONTRIBUTORS.rst @@ -1,6 +1,7 @@ * `Tecnativa `_: * David Vidal + * Pilar Vargas * `Domatix `_: diff --git a/sale_loyalty_multi_gift/security/ir.model.access.csv b/sale_loyalty_multi_gift/security/ir.model.access.csv index 502d309e9..b221c8d7d 100644 --- a/sale_loyalty_multi_gift/security/ir.model.access.csv +++ b/sale_loyalty_multi_gift/security/ir.model.access.csv @@ -1,3 +1,3 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink -access_multi_gift_salesman,salesman,coupon_multi_gift.model_coupon_reward_product_line,sales_team.group_sale_salesman,1,0,0,0 -access_multi_gift_manager,multi_gift manager,coupon_multi_gift.model_coupon_reward_product_line,sales_team.group_sale_manager,1,1,1,1 +access_multi_gift_salesman,salesman,loyalty_multi_gift.model_loyalty_reward_product_line,sales_team.group_sale_salesman,1,0,0,0 +access_multi_gift_manager,multi_gift manager,loyalty_multi_gift.model_loyalty_reward_product_line,sales_team.group_sale_manager,1,1,1,1 diff --git a/sale_loyalty_multi_gift/static/description/index.html b/sale_loyalty_multi_gift/static/description/index.html index fc57a1328..80ebb2fa9 100644 --- a/sale_loyalty_multi_gift/static/description/index.html +++ b/sale_loyalty_multi_gift/static/description/index.html @@ -4,7 +4,7 @@ -Coupons multi gift in sales +Sale Loyalty Multi Gift -
-

Coupons multi gift in sales

+
+

Sale 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 on sale orders.

Table of contents

@@ -405,7 +405,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.

@@ -421,6 +421,7 @@

Contributors

diff --git a/sale_loyalty_multi_gift/tests/__init__.py b/sale_loyalty_multi_gift/tests/__init__.py index e9e2e2373..34744a87c 100644 --- a/sale_loyalty_multi_gift/tests/__init__.py +++ b/sale_loyalty_multi_gift/tests/__init__.py @@ -1 +1 @@ -from . import test_sale_coupon_multi_gift +from . import test_sale_loyalty_multi_gift diff --git a/sale_loyalty_multi_gift/tests/test_sale_coupon_multi_gift.py b/sale_loyalty_multi_gift/tests/test_sale_coupon_multi_gift.py deleted file mode 100644 index 1a453a7f5..000000000 --- a/sale_loyalty_multi_gift/tests/test_sale_coupon_multi_gift.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright 2021 Tecnativa - David Vidal -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo.tests import Form - -from odoo.addons.coupon_multi_gift.tests.coupon_multi_gift_case import ( - CouponMultiGiftCase, -) - - -class TestSaleCouponMultiGift(CouponMultiGiftCase): - @classmethod - def setUpClass(cls): - super().setUpClass() - sale_form = Form(cls.env["sale.order"]) - sale_form.partner_id = cls.partner - with sale_form.order_line.new() as line_form: - line_form.product_id = cls.product_1 - line_form.product_uom_qty = 2 - cls.sale = sale_form.save() - - def test_sale_coupon_test_multi_gift(self): - """As we fulfill the proper product qties, we get the proper free product""" - line = self.sale.order_line - self.sale.recompute_coupon_lines() - # As set up, we should one discount line for every reward line in the promotion - discount_line_product_2 = self.sale.order_line.filtered( - lambda x: x.product_id == self.product_2 and x.is_reward_line - ) - discount_line_product_3 = self.sale.order_line.filtered( - lambda x: x.product_id == self.product_3 and x.is_reward_line - ) - self.assertEqual(2, discount_line_product_2.product_uom_qty) - self.assertEqual(3, discount_line_product_3.product_uom_qty) - self.assertEqual(0, discount_line_product_2.price_reduce) - self.assertEqual(0, discount_line_product_3.price_reduce) - self.assertEqual(60, discount_line_product_2.price_unit) - self.assertEqual(70, discount_line_product_3.price_unit) - line_form = Form(line, view="sale.view_order_line_tree") - line_form.product_uom_qty = 7 - line_form.save() - self.sale.recompute_coupon_lines() - discount_line_product_2 = self.sale.order_line.filtered( - lambda x: x.product_id == self.product_2 and x.is_reward_line - ) - discount_line_product_3 = self.sale.order_line.filtered( - lambda x: x.product_id == self.product_3 and x.is_reward_line - ) - # The promotion will only be applied once whatever the min quantity - self.assertEqual(2, discount_line_product_2.product_uom_qty) - self.assertEqual(3, discount_line_product_3.product_uom_qty) - self.assertEqual(0, discount_line_product_2.price_reduce) - self.assertEqual(0, discount_line_product_3.price_reduce) - # Now it can't be applied anymore so the discount lines will dissapear - line_form.product_uom_qty = 1 - line_form.save() - self.sale.recompute_coupon_lines() - discount_line = self.sale.order_line.filtered("is_reward_line") - # The discount goes away - self.assertFalse(bool(discount_line)) - # Optional rewards - line_form.product_uom_qty = 2 - line_form.save() - reward_line_options = { - self.coupon_program.coupon_multi_gift_ids[1].id: self.product_4.id - } - self.sale.with_context( - reward_line_options=reward_line_options - ).recompute_coupon_lines() - discount_line_product_2 = self.sale.order_line.filtered( - lambda x: x.product_id == self.product_2 and x.is_reward_line - ) - discount_line_product_3 = self.sale.order_line.filtered( - lambda x: x.product_id == self.product_3 and x.is_reward_line - ) - discount_line_product_4 = self.sale.order_line.filtered( - lambda x: x.product_id == self.product_4 and x.is_reward_line - ) - self.assertEqual(2, discount_line_product_2.product_uom_qty) - self.assertEqual(3, discount_line_product_4.product_uom_qty) - self.assertFalse(discount_line_product_3) - # The original gift options are kept - self.sale.recompute_coupon_lines() - discount_line_product_4 = self.sale.order_line.filtered( - lambda x: x.product_id == self.product_4 and x.is_reward_line - ) - self.assertEqual(3, discount_line_product_4.product_uom_qty) - self.assertEqual( - discount_line_product_4.multi_gift_reward_line_id_option_product_id, - self.product_4, - "The product should be kept after updating recomputing the promotions", - ) - # The regular options are ok as well - discount_line_product_2 = self.sale.order_line.filtered( - lambda x: x.product_id == self.product_2 and x.is_reward_line - ) - discount_line_product_3 = self.sale.order_line.filtered( - lambda x: x.product_id == self.product_3 and x.is_reward_line - ) - self.assertEqual(2, discount_line_product_2.product_uom_qty) - self.assertEqual(3, discount_line_product_4.product_uom_qty) - - def test_sale_coupon_multi_gift_count(self): - """We have to count the orders in a different manner than the core method""" - self.assertEqual(self.coupon_program.order_count, 0) - self.sale.recompute_coupon_lines() - self.sale.action_confirm() - self.coupon_program._compute_order_count() - self.assertEqual(self.coupon_program.order_count, 1) - # Let's place a second order - sale_form = Form(self.env["sale.order"]) - sale_form.partner_id = self.partner - with sale_form.order_line.new() as line_form: - line_form.product_id = self.product_1 - line_form.product_uom_qty = 2 - sale_2 = sale_form.save() - sale_2.recompute_coupon_lines() - sale_2.action_confirm() - self.coupon_program._compute_order_count() - self.assertEqual(self.coupon_program.order_count, 2) - # We should get our order when we click in the orders smart button - action_domain = self.coupon_program.action_view_sales_orders()["domain"] - self.assertEqual( - self.env["sale.order"].search(action_domain), self.sale + sale_2 - ) diff --git a/sale_loyalty_multi_gift/tests/test_sale_loyalty_multi_gift.py b/sale_loyalty_multi_gift/tests/test_sale_loyalty_multi_gift.py new file mode 100644 index 000000000..39880e95c --- /dev/null +++ b/sale_loyalty_multi_gift/tests/test_sale_loyalty_multi_gift.py @@ -0,0 +1,147 @@ +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo.exceptions import ValidationError +from odoo.tests import Form + +from odoo.addons.loyalty_multi_gift.tests.loyalty_multi_gift_case import ( + LoyaltyMultiGiftCase, +) + + +class TestSaleLoyaltyMultiGift(LoyaltyMultiGiftCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + sale_form = Form(cls.env["sale.order"]) + sale_form.partner_id = cls.partner + with sale_form.order_line.new() as line_form: + line_form.product_id = cls.product_1 + line_form.product_uom_qty = 2 + cls.sale = sale_form.save() + + def _action_apply_program(self, sale, program): + sale._update_programs_and_rewards() + wizard = ( + self.env["sale.loyalty.reward.wizard"] + .with_context(active_id=sale) + .create({"selected_reward_id": program.reward_ids.id}) + ) + wizard.action_apply() + + def test_01_sale_coupon_test_multi_gift(self): + """As we fulfill the proper product qties, we get the proper free product""" + self._action_apply_program(self.sale, self.loyalty_program_form) + # As set up, we should one discount line for every reward line in the promotion + discount_line_product_2 = self.sale.order_line.filtered( + lambda x: x.product_id == self.product_2 and x.is_reward_line + ) + discount_line_product_3 = self.sale.order_line.filtered( + lambda x: x.product_id == self.product_3 and x.is_reward_line + ) + self.assertEqual(2, discount_line_product_2.product_uom_qty) + self.assertEqual(3, discount_line_product_3.product_uom_qty) + self.assertEqual(0, discount_line_product_2.price_reduce) + self.assertEqual(0, discount_line_product_3.price_reduce) + self.assertEqual(60, discount_line_product_2.price_unit) + self.assertEqual(70, discount_line_product_3.price_unit) + + def test_02_test_sale_coupon_test_multi_gift(self): + line = self.sale.order_line + line_form = Form(line, view="sale.view_order_line_tree") + # import wdb; wdb.set_trace() + line_form.product_uom_qty = 7 + line_form.save() + self._action_apply_program(self.sale, self.loyalty_program_form) + discount_line_product_2 = self.sale.order_line.filtered( + lambda x: x.product_id == self.product_2 and x.is_reward_line + ) + discount_line_product_3 = self.sale.order_line.filtered( + lambda x: x.product_id == self.product_3 and x.is_reward_line + ) + # The promotion will only be applied once whatever the min quantity + self.assertEqual(2, discount_line_product_2.product_uom_qty) + self.assertEqual(3, discount_line_product_3.product_uom_qty) + self.assertEqual(0, discount_line_product_2.price_reduce) + self.assertEqual(0, discount_line_product_3.price_reduce) + + def test_03_test_sale_coupon_test_multi_gift(self): + line = self.sale.order_line + line_form = Form(line, view="sale.view_order_line_tree") + # Now it can't be applied anymore so the discount lines will dissapear + line_form.product_uom_qty = 1 + line_form.save() + with self.assertRaises(ValidationError): + self._action_apply_program(self.sale, self.loyalty_program_form) + discount_line = self.sale.order_line.filtered("is_reward_line") + # The discount goes away + self.assertFalse(bool(discount_line)) + # Optional rewards + line_form.product_uom_qty = 2 + line_form.save() + # TODO: Continue when the wizard functionality for selecting rewards is adapted. + # reward_line_options = { + # self.loyalty_program_form.reward_ids[0].loyalty_multi_gift_ids[ + # 1 + # ]: self.product_4.id + # } + # self._action_apply_program( + # self.sale.with_context(reward_line_options=reward_line_options), + # self.loyalty_program_form, + # ) + # discount_line_product_2 = self.sale.order_line.filtered( + # lambda x: x.product_id == self.product_2 and x.is_reward_line + # ) + # discount_line_product_3 = self.sale.order_line.filtered( + # lambda x: x.product_id == self.product_3 and x.is_reward_line + # ) + # discount_line_product_4 = self.sale.order_line.filtered( + # lambda x: x.product_id == self.product_4 and x.is_reward_line + # ) + # self.assertEqual(2, discount_line_product_2.product_uom_qty) + # self.assertEqual(3, discount_line_product_4.product_uom_qty) + # self.assertFalse(discount_line_product_3) + + # # The original gift options are kept + # self._action_apply_program(self.sale, self.loyalty_program_form) + # discount_line_product_4 = self.sale.order_line.filtered( + # lambda x: x.product_id == self.product_4 and x.is_reward_line + # ) + # self.assertEqual(3, discount_line_product_4.product_uom_qty) + # self.assertEqual( + # discount_line_product_4.multi_gift_reward_line_id_option_product_id, + # self.product_4, + # "The product should be kept after updating recomputing the promotions", + # ) + # # The regular options are ok as well + # discount_line_product_2 = self.sale.order_line.filtered( + # lambda x: x.product_id == self.product_2 and x.is_reward_line + # ) + # discount_line_product_3 = self.sale.order_line.filtered( + # lambda x: x.product_id == self.product_3 and x.is_reward_line + # ) + # self.assertEqual(2, discount_line_product_2.product_uom_qty) + # self.assertEqual(3, discount_line_product_4.product_uom_qty) + + # def test_sale_loyalty_multi_gift_count(self): + # """We have to count the orders in a different manner than the core method""" + # self.assertEqual(self.loyalty_program_form.order_count, 0) + # self._action_apply_program(self.sale, self.loyalty_program_form) + # self.sale.action_confirm() + # self.loyalty_program_form._compute_order_count() + # self.assertEqual(self.loyalty_program_form.order_count, 1) + # # Let's place a second order + # sale_form = Form(self.env["sale.order"]) + # sale_form.partner_id = self.partner + # with sale_form.order_line.new() as line_form: + # line_form.product_id = self.product_1 + # line_form.product_uom_qty = 2 + # sale_2 = sale_form.save() + # self._action_apply_program(self.sale, self.loyalty_program_form) + # sale_2.action_confirm() + # self.loyalty_program_form._compute_order_count() + # self.assertEqual(self.loyalty_program_form.order_count, 2) + # # We should get our order when we click in the orders smart button + # action_domain = self.loyalty_program_form.action_view_sales_orders()["domain"] + # self.assertEqual( + # self.env["sale.order"].search(action_domain), self.sale + sale_2 + # ) diff --git a/setup/sale_coupon_multi_gift/odoo/addons/sale_coupon_multi_gift b/setup/sale_coupon_multi_gift/odoo/addons/sale_coupon_multi_gift deleted file mode 120000 index e283a9421..000000000 --- a/setup/sale_coupon_multi_gift/odoo/addons/sale_coupon_multi_gift +++ /dev/null @@ -1 +0,0 @@ -../../../../sale_coupon_multi_gift \ No newline at end of file diff --git a/setup/sale_loyalty_multi_gift/odoo/addons/sale_loyalty_multi_gift b/setup/sale_loyalty_multi_gift/odoo/addons/sale_loyalty_multi_gift new file mode 120000 index 000000000..7a23f9b7f --- /dev/null +++ b/setup/sale_loyalty_multi_gift/odoo/addons/sale_loyalty_multi_gift @@ -0,0 +1 @@ +../../../../sale_loyalty_multi_gift \ No newline at end of file diff --git a/setup/sale_coupon_multi_gift/setup.py b/setup/sale_loyalty_multi_gift/setup.py similarity index 100% rename from setup/sale_coupon_multi_gift/setup.py rename to setup/sale_loyalty_multi_gift/setup.py