From beb0458d24ef8e612f911b3cf7416ff2caf12508 Mon Sep 17 00:00:00 2001 From: david Date: Fri, 23 Jul 2021 12:42:41 +0200 Subject: [PATCH 01/23] [ADD] sale_coupon_order_line_link: New module Technical module linking order lines with programs TT30850 --- sale_loyalty_order_line_link/README.rst | 85 ++++ sale_loyalty_order_line_link/__init__.py | 2 + sale_loyalty_order_line_link/__manifest__.py | 16 + .../i18n/sale_coupon_order_line_link.pot | 41 ++ .../models/__init__.py | 1 + .../models/sale_order.py | 32 ++ .../readme/CONTRIBUTORS.rst | 3 + .../readme/DESCRIPTION.rst | 3 + .../reports/__init__.py | 1 + .../reports/sale_report.py | 27 ++ .../reports/sale_report_views.xml | 25 + .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 426 ++++++++++++++++++ .../tests/__init__.py | 1 + .../tests/test_coupon_order_line_link.py | 57 +++ 15 files changed, 720 insertions(+) create mode 100644 sale_loyalty_order_line_link/README.rst create mode 100644 sale_loyalty_order_line_link/__init__.py create mode 100644 sale_loyalty_order_line_link/__manifest__.py create mode 100644 sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot create mode 100644 sale_loyalty_order_line_link/models/__init__.py create mode 100644 sale_loyalty_order_line_link/models/sale_order.py create mode 100644 sale_loyalty_order_line_link/readme/CONTRIBUTORS.rst create mode 100644 sale_loyalty_order_line_link/readme/DESCRIPTION.rst create mode 100644 sale_loyalty_order_line_link/reports/__init__.py create mode 100644 sale_loyalty_order_line_link/reports/sale_report.py create mode 100644 sale_loyalty_order_line_link/reports/sale_report_views.xml create mode 100644 sale_loyalty_order_line_link/static/description/icon.png create mode 100644 sale_loyalty_order_line_link/static/description/index.html create mode 100644 sale_loyalty_order_line_link/tests/__init__.py create mode 100644 sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py diff --git a/sale_loyalty_order_line_link/README.rst b/sale_loyalty_order_line_link/README.rst new file mode 100644 index 000000000..2bc3bdc6d --- /dev/null +++ b/sale_loyalty_order_line_link/README.rst @@ -0,0 +1,85 @@ +=========================== +Link coupons to order lines +=========================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png + :target: https://odoo-community.org/page/development-status + :alt: Production/Stable +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :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/13.0/sale_coupon_order_line_link + :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-13-0/sale-promotion-13-0-sale_coupon_order_line_link + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/296/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds a link in the sale order line to the program used in a discount, so +it can be easily tracked afterwards. Also eases the implementation of coupon modules +that don't necessarily use the discount product as product for the discount line. + +**Table of contents** + +.. contents:: + :local: + +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 smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Tecnativa + +Contributors +~~~~~~~~~~~~ + +* `Tecnativa `_: + + * David Vidal + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-chienandalu| image:: https://github.com/chienandalu.png?size=40px + :target: https://github.com/chienandalu + :alt: chienandalu + +Current `maintainer `__: + +|maintainer-chienandalu| + +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_order_line_link/__init__.py b/sale_loyalty_order_line_link/__init__.py new file mode 100644 index 000000000..55ec7fc9a --- /dev/null +++ b/sale_loyalty_order_line_link/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import reports diff --git a/sale_loyalty_order_line_link/__manifest__.py b/sale_loyalty_order_line_link/__manifest__.py new file mode 100644 index 000000000..4e10cb696 --- /dev/null +++ b/sale_loyalty_order_line_link/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Link coupons to order lines", + "summary": "Adds a link between coupons and their generated order lines for easing " + "tracking", + "version": "13.0.1.0.0", + "development_status": "Production/Stable", + "category": "Sale", + "website": "https://github.com/OCA/sale-promotion", + "author": "Tecnativa, Odoo Community Association (OCA)", + "maintainers": ["chienandalu"], + "license": "AGPL-3", + "depends": ["sale_coupon"], + "data": ["reports/sale_report_views.xml"], +} diff --git a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot new file mode 100644 index 000000000..4911c33da --- /dev/null +++ b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot @@ -0,0 +1,41 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_coupon_order_line_link +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__coupon_program_id +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report__coupon_program_id +#: model_terms:ir.ui.view,arch_db:sale_coupon_order_line_link.view_order_product_search +msgid "Coupon Program" +msgstr "" + +#. module: sale_coupon_order_line_link +#: model_terms:ir.ui.view,arch_db:sale_coupon_order_line_link.view_order_product_search +msgid "Promotion Lines" +msgstr "" + +#. module: sale_coupon_order_line_link +#: model:ir.model,name:sale_coupon_order_line_link.model_sale_report +msgid "Sales Analysis Report" +msgstr "" + +#. module: sale_coupon_order_line_link +#: model:ir.model,name:sale_coupon_order_line_link.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: sale_coupon_order_line_link +#: model:ir.model,name:sale_coupon_order_line_link.model_sale_order_line +msgid "Sales Order Line" +msgstr "" diff --git a/sale_loyalty_order_line_link/models/__init__.py b/sale_loyalty_order_line_link/models/__init__.py new file mode 100644 index 000000000..6aacb7531 --- /dev/null +++ b/sale_loyalty_order_line_link/models/__init__.py @@ -0,0 +1 @@ +from . import sale_order diff --git a/sale_loyalty_order_line_link/models/sale_order.py b/sale_loyalty_order_line_link/models/sale_order.py new file mode 100644 index 000000000..36f5c057c --- /dev/null +++ b/sale_loyalty_order_line_link/models/sale_order.py @@ -0,0 +1,32 @@ +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + def _get_reward_values_product(self, program): + """Add the link to the program in the discount line""" + res = super()._get_reward_values_product(program) + res["coupon_program_id"] = program.id + return res + + def _get_reward_values_discount(self, program): + """Add the link to the program in the discount line""" + res = super()._get_reward_values_discount(program) + # The original method returns a dict.values(), which is weird: + # https://git.io/J88As + vals = [r for r in res][0] + vals["coupon_program_id"] = program.id + return {"x": vals}.values() + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + coupon_program_id = fields.Many2one( + comodel_name="sale.coupon.program", + ondelete="restrict", + string="Coupon Program", + ) diff --git a/sale_loyalty_order_line_link/readme/CONTRIBUTORS.rst b/sale_loyalty_order_line_link/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..94b6ba953 --- /dev/null +++ b/sale_loyalty_order_line_link/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `Tecnativa `_: + + * David Vidal diff --git a/sale_loyalty_order_line_link/readme/DESCRIPTION.rst b/sale_loyalty_order_line_link/readme/DESCRIPTION.rst new file mode 100644 index 000000000..3946c003a --- /dev/null +++ b/sale_loyalty_order_line_link/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module adds a link in the sale order line to the program used in a discount, so +it can be easily tracked afterwards. Also eases the implementation of coupon modules +that don't necessarily use the discount product as product for the discount line. diff --git a/sale_loyalty_order_line_link/reports/__init__.py b/sale_loyalty_order_line_link/reports/__init__.py new file mode 100644 index 000000000..cd23411b8 --- /dev/null +++ b/sale_loyalty_order_line_link/reports/__init__.py @@ -0,0 +1 @@ +from . import sale_report diff --git a/sale_loyalty_order_line_link/reports/sale_report.py b/sale_loyalty_order_line_link/reports/sale_report.py new file mode 100644 index 000000000..72f6e1b28 --- /dev/null +++ b/sale_loyalty_order_line_link/reports/sale_report.py @@ -0,0 +1,27 @@ +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class SaleReport(models.Model): + _inherit = "sale.report" + + coupon_program_id = fields.Many2one( + comodel_name="sale.coupon.program", string="Coupon Program", + ) + + def _query(self, with_clause="", fields=None, groupby="", from_clause=""): + if fields is None: + fields = {} + select_str = """ , + l.coupon_program_id as coupon_program_id + """ + fields.update({"coupon_program_id": select_str}) + groupby += ", l.coupon_program_id" + return super()._query( + with_clause=with_clause, + fields=fields, + groupby=groupby, + from_clause=from_clause, + ) diff --git a/sale_loyalty_order_line_link/reports/sale_report_views.xml b/sale_loyalty_order_line_link/reports/sale_report_views.xml new file mode 100644 index 000000000..73113c1b5 --- /dev/null +++ b/sale_loyalty_order_line_link/reports/sale_report_views.xml @@ -0,0 +1,25 @@ + + + + + sale.report + + + + + + + + + + + + diff --git a/sale_loyalty_order_line_link/static/description/icon.png b/sale_loyalty_order_line_link/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/sale_loyalty_order_line_link/static/description/index.html b/sale_loyalty_order_line_link/static/description/index.html new file mode 100644 index 000000000..78263d19a --- /dev/null +++ b/sale_loyalty_order_line_link/static/description/index.html @@ -0,0 +1,426 @@ + + + + + + +Link coupons to order lines + + + + + + diff --git a/sale_loyalty_order_line_link/tests/__init__.py b/sale_loyalty_order_line_link/tests/__init__.py new file mode 100644 index 000000000..7722fcce2 --- /dev/null +++ b/sale_loyalty_order_line_link/tests/__init__.py @@ -0,0 +1 @@ +from . import test_coupon_order_line_link diff --git a/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py b/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py new file mode 100644 index 000000000..0e881c958 --- /dev/null +++ b/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py @@ -0,0 +1,57 @@ +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo.tests import Form, common + + +class TestSaleCouponCriteriaMultiProduct(common.SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + product_obj = cls.env["product.product"] + 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_a = product_obj.create({"name": "Product A", "list_price": 50}) + coupon_program_form = Form( + cls.env["sale.coupon.program"], + view="sale_coupon.sale_coupon_program_view_promo_program_form", + ) + coupon_program_form.name = "Test Program" + coupon_program_form.promo_code_usage = "no_code_needed" + coupon_program_form.reward_type = "discount" + coupon_program_form.discount_apply_on = "on_order" + coupon_program_form.discount_type = "percentage" + coupon_program_form.discount_percentage = 10 + coupon_program_form.rule_products_domain = "[('id', '=', %s)]" % ( + cls.product_a.id + ) + cls.coupon_program = coupon_program_form.save() + # We'll be using this sale order + 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_a + line_form.product_uom_qty = 1 + cls.sale = sale_form.save() + + def test_coupon_order_line_link(self): + """The coupon program gets correctly linked to the line""" + self.sale.recompute_coupon_lines() + discount_line = self.sale.order_line.filtered("is_reward_line") + self.assertEqual(discount_line.coupon_program_id, self.coupon_program) From fd6a22907187e6a6a12ae7a1f764a818b62ced72 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 14 Sep 2021 18:15:42 +0200 Subject: [PATCH 02/23] [IMP] sale_coupon_order_line_link: link sale lines to rewards Filter lines that are related to a reward: either they genereted it or the reward is applied to them. For example: - A promotion product domain could be: ("id", "=" product_a.id) - The same promotion has a reward product B - On a sale order with products A, B and C: - A reward line will be generated to discount B's amount and will be linked to the promotion. - Line A will have a link to the reward line as it was the condition for the promotion. - Line B will also have a link to the reward line as it's the line over which the discount is made. TT31755 --- sale_loyalty_order_line_link/README.rst | 14 ++ .../i18n/sale_coupon_order_line_link.pot | 20 +++ .../models/sale_order.py | 147 +++++++++++++++++- .../readme/DESCRIPTION.rst | 8 + .../readme/ROADMAP.rst | 2 + .../static/description/index.html | 41 +++-- .../tests/test_coupon_order_line_link.py | 132 ++++++++++++++-- 7 files changed, 338 insertions(+), 26 deletions(-) create mode 100644 sale_loyalty_order_line_link/readme/ROADMAP.rst diff --git a/sale_loyalty_order_line_link/README.rst b/sale_loyalty_order_line_link/README.rst index 2bc3bdc6d..b8e793d45 100644 --- a/sale_loyalty_order_line_link/README.rst +++ b/sale_loyalty_order_line_link/README.rst @@ -29,11 +29,25 @@ This module adds a link in the sale order line to the program used in a discount it can be easily tracked afterwards. Also eases the implementation of coupon modules that don't necessarily use the discount product as product for the discount line. +It also links the reward lines to: + - The order lines that generated them, so we can follow which order lines produced + which discounts. + - The order lines over which the reward is applied: + + - In a discount promo: the cheapest product, specific products or the whole order. + - In a product promo: the product lines over which the reward is discounted. + **Table of contents** .. contents:: :local: +Known issues / Roadmap +====================== + +* Rename to `sale_coupon_traceability` in v14 as it fits better the broad features + of the module. + Bug Tracker =========== diff --git a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot index 4911c33da..d72121dc1 100644 --- a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot +++ b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot @@ -20,11 +20,31 @@ msgstr "" msgid "Coupon Program" msgstr "" +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,help:sale_coupon_order_line_link.field_sale_order_line__reward_line_ids +msgid "Link on the reward lines applied from this one" +msgstr "" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,help:sale_coupon_order_line_link.field_sale_order_line__reward_generated_line_ids +msgid "Link on the reward lines generated meeting this line as criteria" +msgstr "" + #. module: sale_coupon_order_line_link #: model_terms:ir.ui.view,arch_db:sale_coupon_order_line_link.view_order_product_search msgid "Promotion Lines" msgstr "" +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__reward_generated_line_ids +msgid "Reward Generated lines" +msgstr "" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__reward_line_ids +msgid "Reward lines" +msgstr "" + #. module: sale_coupon_order_line_link #: model:ir.model,name:sale_coupon_order_line_link.model_sale_report msgid "Sales Analysis Report" diff --git a/sale_loyalty_order_line_link/models/sale_order.py b/sale_loyalty_order_line_link/models/sale_order.py index 36f5c057c..15d4e13c7 100644 --- a/sale_loyalty_order_line_link/models/sale_order.py +++ b/sale_loyalty_order_line_link/models/sale_order.py @@ -1,6 +1,7 @@ # Copyright 2021 Tecnativa - David Vidal # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import fields, models +from odoo.tools.safe_eval import safe_eval class SaleOrder(models.Model): @@ -13,13 +14,105 @@ def _get_reward_values_product(self, program): return res def _get_reward_values_discount(self, program): - """Add the link to the program in the discount line""" - res = super()._get_reward_values_discount(program) - # The original method returns a dict.values(), which is weird: - # https://git.io/J88As - vals = [r for r in res][0] - vals["coupon_program_id"] = program.id - return {"x": vals}.values() + """Add the link to the program in the discount line. The original method returns + a dict.values() to support multiple taxes. We can safely return a list instead + as the main method just iterates over the result of these auxiliar products to + write vals. https://git.io/J88As + """ + res = list(super()._get_reward_values_discount(program)) + [r.update(coupon_program_id=program.id) for r in res] + return res + + def write(self, vals): + """We're looking for reward lines set in the write, from those, we'll get + the proper ids to write them into the related lines""" + res = super().write(vals) + reward_lines = [ + x[2] + for x in vals.get("order_line", []) + if len(x) > 2 and x[0] == 0 and x[2].get("is_reward_line") + ] + if not reward_lines: + return res + programs = self.env["sale.coupon.program"].browse( + list({x.get("coupon_program_id") for x in reward_lines}) + ) + for order in self: + order._link_reward_lines(programs) + order._link_reward_generated_lines(programs) + return res + + def _link_reward_discount_lines(self, program): + """Assign reward lines depending on the discount scope of the promotion: + - A discount on order, will apply to every line. + - A discount on the cheapest product just to the cheapest line. + - A discount on specific products only on those products defined in the + promotion and available in the order lines. + Thes filters are the same the core methods use. + """ + reward_lines = self.order_line.filtered( + lambda x: x.coupon_program_id == program + ) + # TODO: Should we add the lines that meet the criteria even if they aren't + # on the filtered lines? + if program.discount_apply_on == "on_order": + lines = self.order_line.filtered(lambda x: not x.is_reward_line) + elif program.discount_apply_on == "cheapest_product": + lines = self._get_cheapest_line() + elif program.discount_apply_on == "specific_products": + lines = self.order_line.filtered( + lambda x: x.product_id in program.discount_specific_product_ids + ) + # Distribute different tax reward lines with their correspondant order lines. + # We use a dictionary so we can compare taxes even if they are composed. + tax_reward_map = {} + for reward_line in reward_lines: + tax_reward_map.setdefault(reward_line.tax_id, self.env["sale.order.line"]) + tax_reward_map[reward_line.tax_id] |= reward_line + for tax, tax_reward_lines in tax_reward_map.items(): + lines.filtered(lambda x: x.tax_id == tax).write( + {"reward_line_ids": [(4, rl.id) for rl in tax_reward_lines]} + ) + + def _link_reward_product_lines(self, program): + """We want to link to the reward those lines that generated it as well as + the rewarded product, that could be not in the original domain""" + reward_lines = self.order_line.filtered( + lambda x: x.coupon_program_id == program + ) + lines_with_reward_product_id = self.order_line.filtered( + lambda x: x.product_id == program.reward_product_id + ) + # We'll just consider as many lines as the reward quantity can cover. + lines = self.env["sale.order.line"] + reward_qty = program.reward_product_quantity + for line in lines_with_reward_product_id: + lines |= line + if line.product_uom_qty >= reward_qty: + break + reward_qty -= line.product_uom_qty + lines.write({"reward_line_ids": [(4, rl.id) for rl in reward_lines]}) + + def _link_reward_lines(self, programs): + """We want to filter the lines that generated a condition and link them to + the generated rewards. Every reward type has it's own cases depending on + how's applied. Another reward types (e.g: sale_coupon_delivey) should extend + this method adding its cases. Also to be noted that a single line could + generate several rewards coming from different promotions.""" + for program in programs.filtered(lambda x: x.reward_type == "discount"): + self._link_reward_discount_lines(program) + for program in programs.filtered(lambda x: x.reward_type == "product"): + self._link_reward_product_lines(program) + + def _link_reward_generated_lines(self, programs): + """Link the lines that generated reward lines to those lines""" + for program in programs: + reward_lines = self.order_line.filtered( + lambda x: x.coupon_program_id == program + ) + self.order_line._filter_related_program_lines(program).write( + {"reward_generated_line_ids": [(4, rl.id) for rl in reward_lines]} + ) class SaleOrderLine(models.Model): @@ -30,3 +123,43 @@ class SaleOrderLine(models.Model): ondelete="restrict", string="Coupon Program", ) + reward_line_ids = fields.Many2many( + comodel_name="sale.order.line", + relation="sale_line_reward_line_rel", + column1="sale_line_id", + column2="reward_line_id", + string="Reward lines", + help="Link on the reward lines applied from this one", + ) + reward_generated_line_ids = fields.Many2many( + comodel_name="sale.order.line", + relation="sale_line_reward_generated_line_rel", + column1="sale_line_id", + column2="reward_generated_line_id", + string="Reward Generated lines", + help="Link on the reward lines generated meeting this line as criteria", + ) + + def write(self, vals): + """When the reward line is update we should refresh the line links as well""" + res = super().write(vals) + if vals.get("is_reward_line") and vals.get("coupon_program_id"): + program = self.env["sale.coupon.program"].browse( + vals.get("coupon_program_id") + ) + for order in self.mapped("order_id"): + order._link_reward_lines(program) + return res + + def _filter_related_program_lines(self, program): + """Discard those lines not in the program domain. With other modules changing + the product criteria rules, we can extend this method to return the proper + records.""" + # No domain means that any product meets the promotion rules + if not program.rule_products_domain: + return self + domain = safe_eval(program.rule_products_domain) + products = self.mapped("product_id").filtered_domain(domain) + return self.filtered( + lambda x: x.product_id in products and not x.is_reward_line + ) diff --git a/sale_loyalty_order_line_link/readme/DESCRIPTION.rst b/sale_loyalty_order_line_link/readme/DESCRIPTION.rst index 3946c003a..db4a98513 100644 --- a/sale_loyalty_order_line_link/readme/DESCRIPTION.rst +++ b/sale_loyalty_order_line_link/readme/DESCRIPTION.rst @@ -1,3 +1,11 @@ This module adds a link in the sale order line to the program used in a discount, so it can be easily tracked afterwards. Also eases the implementation of coupon modules that don't necessarily use the discount product as product for the discount line. + +It also links the reward lines to: + - The order lines that generated them, so we can follow which order lines produced + which discounts. + - The order lines over which the reward is applied: + + - In a discount promo: the cheapest product, specific products or the whole order. + - In a product promo: the product lines over which the reward is discounted. diff --git a/sale_loyalty_order_line_link/readme/ROADMAP.rst b/sale_loyalty_order_line_link/readme/ROADMAP.rst new file mode 100644 index 000000000..27ddcb1b2 --- /dev/null +++ b/sale_loyalty_order_line_link/readme/ROADMAP.rst @@ -0,0 +1,2 @@ +* Rename to `sale_coupon_traceability` in v14 as it fits better the broad features + of the module. diff --git a/sale_loyalty_order_line_link/static/description/index.html b/sale_loyalty_order_line_link/static/description/index.html index 78263d19a..72a0112cc 100644 --- a/sale_loyalty_order_line_link/static/description/index.html +++ b/sale_loyalty_order_line_link/static/description/index.html @@ -371,20 +371,41 @@

Link coupons to order lines

This module adds a link in the sale order line to the program used in a discount, so it can be easily tracked afterwards. Also eases the implementation of coupon modules that don’t necessarily use the discount product as product for the discount line.

+
+
It also links the reward lines to:
+
    +
  • The order lines that generated them, so we can follow which order lines produced +which discounts.
  • +
  • The order lines over which the reward is applied:
      +
    • In a discount promo: the cheapest product, specific products or the whole order.
    • +
    • In a product promo: the product lines over which the reward is discounted.
    • +
    +
  • +
+
+

Table of contents

+
+

Known issues / Roadmap

+
    +
  • Rename to sale_coupon_traceability in v14 as it fits better the broad features +of the module.
  • +
+
-

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 smashing it by providing a detailed and welcomed @@ -392,15 +413,15 @@

Bug Tracker

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 diff --git a/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py b/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py index 0e881c958..ce27a913a 100644 --- a/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py +++ b/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py @@ -28,19 +28,29 @@ def setUpClass(cls): {"name": "Mr. Odoo", "property_product_pricelist": cls.pricelist.id} ) cls.product_a = product_obj.create({"name": "Product A", "list_price": 50}) + cls.product_b = product_obj.create({"name": "Product B", "list_price": 10}) + cls.product_c = product_obj.create({"name": "Product C", "list_price": 70}) + cls.tax_1 = cls.env["account.tax"].create( + {"name": "Tax 10", "type_tax_use": "sale", "amount": 10} + ) + cls.tax_2 = cls.env["account.tax"].create( + {"name": "Tax 4", "type_tax_use": "sale", "amount": 4} + ) coupon_program_form = Form( cls.env["sale.coupon.program"], view="sale_coupon.sale_coupon_program_view_promo_program_form", ) - coupon_program_form.name = "Test Program" + coupon_program_form.name = "Test Coupon Line Link Program" coupon_program_form.promo_code_usage = "no_code_needed" coupon_program_form.reward_type = "discount" - coupon_program_form.discount_apply_on = "on_order" + coupon_program_form.discount_apply_on = "specific_products" coupon_program_form.discount_type = "percentage" coupon_program_form.discount_percentage = 10 - coupon_program_form.rule_products_domain = "[('id', '=', %s)]" % ( - cls.product_a.id - ) + coupon_program_form.rule_products_domain = [ + ("id", "in", (cls.product_a | cls.product_b | cls.product_c).ids) + ] + coupon_program_form.discount_specific_product_ids.add(cls.product_a) + coupon_program_form.discount_specific_product_ids.add(cls.product_c) cls.coupon_program = coupon_program_form.save() # We'll be using this sale order sale_form = Form(cls.env["sale.order"]) @@ -48,10 +58,114 @@ def setUpClass(cls): with sale_form.order_line.new() as line_form: line_form.product_id = cls.product_a line_form.product_uom_qty = 1 + line_form.tax_id.clear() + line_form.tax_id.add(cls.tax_1) + with sale_form.order_line.new() as line_form: + line_form.product_id = cls.product_b + line_form.product_uom_qty = 1 + line_form.tax_id.clear() + line_form.tax_id.add(cls.tax_1) + with sale_form.order_line.new() as line_form: + line_form.product_id = cls.product_c + line_form.product_uom_qty = 1 + line_form.tax_id.clear() + line_form.tax_id.add(cls.tax_2) cls.sale = sale_form.save() - def test_coupon_order_line_link(self): - """The coupon program gets correctly linked to the line""" + def test_01_coupon_order_line_link_discount(self): + """The reward lines always get the coupon program that applied it. For the order + lines, three main cases are covered: + - Discount on specific products. Only those lines get link to the reward lines. + - Global discount. All the order lines get the link to the reward lines. + """ + self.sale.recompute_coupon_lines() + lines = self.sale.order_line + discount_line_1 = lines.filtered( + lambda x: x.is_reward_line and x.tax_id == self.tax_1 + ) + discount_line_2 = lines.filtered( + lambda x: x.is_reward_line and x.tax_id == self.tax_2 + ) + line_a = lines.filtered(lambda x: x.product_id == self.product_a) + line_b = lines.filtered(lambda x: x.product_id == self.product_b) + line_c = lines.filtered(lambda x: x.product_id == self.product_c) + # Two discount are created from the program + self.assertEqual(discount_line_1.coupon_program_id, self.coupon_program) + self.assertEqual(discount_line_2.coupon_program_id, self.coupon_program) + # Only the program specific products get the link to the reward lines + self.assertEqual(line_a.reward_line_ids, discount_line_1) + self.assertFalse(line_b.reward_line_ids) + self.assertEqual(line_c.reward_line_ids, discount_line_2) + # All the lines apply on the domain + self.assertEqual( + line_a.reward_generated_line_ids, discount_line_1 | discount_line_2 + ) + self.assertEqual( + line_b.reward_generated_line_ids, discount_line_1 | discount_line_2 + ) + self.assertEqual( + line_c.reward_generated_line_ids, discount_line_1 | discount_line_2 + ) + # Change the program discount type to a global discount. Now all the lines + # have a link to the coupon reward lines + self.coupon_program.discount_apply_on = "on_order" + self.sale.recompute_coupon_lines() + self.assertEqual(line_a.reward_line_ids, discount_line_1) + self.assertEqual(line_b.reward_line_ids, discount_line_1) + self.assertEqual(line_c.reward_line_ids, discount_line_2) + + def test_02_coupon_order_line_link_discount_cheapest(self): + """Change the program discount type to a cheapest product. Now only the chepest + line will get the reward.""" + self.coupon_program.discount_apply_on = "cheapest_product" + self.sale.recompute_coupon_lines() + lines = self.sale.order_line + discount_line_1 = lines.filtered( + lambda x: x.is_reward_line and x.tax_id == self.tax_1 + ) + discount_line_2 = lines.filtered( + lambda x: x.is_reward_line and x.tax_id == self.tax_2 + ) + line_a = lines.filtered(lambda x: x.product_id == self.product_a) + line_b = lines.filtered(lambda x: x.product_id == self.product_b) + line_c = lines.filtered(lambda x: x.product_id == self.product_c) + self.assertEqual(discount_line_1.coupon_program_id, self.coupon_program) + self.assertEqual(line_b.reward_line_ids, discount_line_1) + self.assertFalse(line_a.reward_line_ids) + self.assertFalse(line_c.reward_line_ids) + discount_line_2 = self.sale.order_line.filtered( + lambda x: x.is_reward_line and x.tax_id == self.tax_2 + ) + self.assertFalse(discount_line_2, "There shouldn't be a reward for tax 2") + + def test_03_coupon_order_line_link_product(self): + """The reward lines are linked to the coupon programs and the lines that + genereate the reward line are linked to that + """ + # Let's set up the program for product rewards + self.coupon_program.reward_type = "product" + self.coupon_program.reward_product_id = self.product_c + self.coupon_program.reward_product_quantity = 5 + self.coupon_program.rule_products_domain = [("id", "=", self.product_a.id)] + sale_form = Form(self.sale) + with sale_form.order_line.new() as line_form: + line_form.product_id = self.product_c + line_form.product_uom_qty = 6 + line_form.tax_id.clear() + line_form.tax_id.add(self.tax_2) + sale_form.save() + # Refresh the order coupons self.sale.recompute_coupon_lines() - discount_line = self.sale.order_line.filtered("is_reward_line") - self.assertEqual(discount_line.coupon_program_id, self.coupon_program) + lines = self.sale.order_line + reward_line = self.sale.order_line.filtered(lambda x: x.is_reward_line) + line_a = lines.filtered(lambda x: x.product_id == self.product_a) + line_b = lines.filtered(lambda x: x.product_id == self.product_b) + lines_c = lines.filtered(lambda x: x.product_id == self.product_c) + self.assertEqual(reward_line.coupon_program_id, self.coupon_program) + self.assertFalse(line_a.reward_line_ids) + self.assertFalse(line_b.reward_line_ids) + for line in lines_c: + self.assertEqual(line.reward_line_ids, reward_line) + self.assertFalse(line.reward_generated_line_ids) + self.assertEqual(line_a.reward_generated_line_ids, reward_line) + self.assertFalse(line_b.reward_generated_line_ids) From 8080614cc868accbde75446ca3698b4df7a62c97 Mon Sep 17 00:00:00 2001 From: david Date: Wed, 20 Oct 2021 13:30:22 +0200 Subject: [PATCH 03/23] [IMP] sale_coupon_order_line_link: link on reward lines to origin lines On the reward lines we can just invert the relation comlumns to have the lines that generated them. TT31755 --- sale_loyalty_order_line_link/__manifest__.py | 2 +- .../i18n/sale_coupon_order_line_link.pot | 11 +++++++++++ sale_loyalty_order_line_link/models/sale_order.py | 8 ++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/sale_loyalty_order_line_link/__manifest__.py b/sale_loyalty_order_line_link/__manifest__.py index 4e10cb696..598c4629d 100644 --- a/sale_loyalty_order_line_link/__manifest__.py +++ b/sale_loyalty_order_line_link/__manifest__.py @@ -4,7 +4,7 @@ "name": "Link coupons to order lines", "summary": "Adds a link between coupons and their generated order lines for easing " "tracking", - "version": "13.0.1.0.0", + "version": "13.0.1.1.0", "development_status": "Production/Stable", "category": "Sale", "website": "https://github.com/OCA/sale-promotion", diff --git a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot index d72121dc1..794bb49ea 100644 --- a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot +++ b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot @@ -30,6 +30,17 @@ msgstr "" msgid "Link on the reward lines generated meeting this line as criteria" msgstr "" +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,help:sale_coupon_order_line_link.field_sale_order_line__reward_origin_generated_line_ids +msgid "" +"Origin Link on the reward lines generated meeting this line as criteria" +msgstr "" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__reward_origin_generated_line_ids +msgid "Origin Reward Generated lines" +msgstr "" + #. module: sale_coupon_order_line_link #: model_terms:ir.ui.view,arch_db:sale_coupon_order_line_link.view_order_product_search msgid "Promotion Lines" diff --git a/sale_loyalty_order_line_link/models/sale_order.py b/sale_loyalty_order_line_link/models/sale_order.py index 15d4e13c7..75871ff58 100644 --- a/sale_loyalty_order_line_link/models/sale_order.py +++ b/sale_loyalty_order_line_link/models/sale_order.py @@ -139,6 +139,14 @@ class SaleOrderLine(models.Model): string="Reward Generated lines", help="Link on the reward lines generated meeting this line as criteria", ) + reward_origin_generated_line_ids = fields.Many2many( + comodel_name="sale.order.line", + relation="sale_line_reward_generated_line_rel", + column1="reward_generated_line_id", + column2="sale_line_id", + string="Origin Reward Generated lines", + help="Origin Link on the reward lines generated meeting this line as criteria", + ) def write(self, vals): """When the reward line is update we should refresh the line links as well""" From 86e1fa0ae685d06f17ee6efcbad4edcb64733504 Mon Sep 17 00:00:00 2001 From: david Date: Wed, 30 Mar 2022 14:08:23 +0200 Subject: [PATCH 04/23] [IMP] sale_coupon_order_line_link: view applied promotions We can now view which promotions are applied visually. TT35401 --- sale_loyalty_order_line_link/__manifest__.py | 4 +- .../i18n/sale_coupon_order_line_link.pot | 5 + .../views/sale_order_views.xml | 113 ++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 sale_loyalty_order_line_link/views/sale_order_views.xml diff --git a/sale_loyalty_order_line_link/__manifest__.py b/sale_loyalty_order_line_link/__manifest__.py index 598c4629d..496697e32 100644 --- a/sale_loyalty_order_line_link/__manifest__.py +++ b/sale_loyalty_order_line_link/__manifest__.py @@ -4,7 +4,7 @@ "name": "Link coupons to order lines", "summary": "Adds a link between coupons and their generated order lines for easing " "tracking", - "version": "13.0.1.1.0", + "version": "13.0.1.2.0", "development_status": "Production/Stable", "category": "Sale", "website": "https://github.com/OCA/sale-promotion", @@ -12,5 +12,5 @@ "maintainers": ["chienandalu"], "license": "AGPL-3", "depends": ["sale_coupon"], - "data": ["reports/sale_report_views.xml"], + "data": ["reports/sale_report_views.xml", "views/sale_order_views.xml"], } diff --git a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot index 794bb49ea..0e4b67384 100644 --- a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot +++ b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot @@ -46,6 +46,11 @@ msgstr "" msgid "Promotion Lines" msgstr "" +#. module: sale_coupon_order_line_link +#: model_terms:ir.ui.view,arch_db:sale_coupon_order_line_link.view_order_form +msgid "Promotions" +msgstr "" + #. module: sale_coupon_order_line_link #: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__reward_generated_line_ids msgid "Reward Generated lines" diff --git a/sale_loyalty_order_line_link/views/sale_order_views.xml b/sale_loyalty_order_line_link/views/sale_order_views.xml new file mode 100644 index 000000000..940c87145 --- /dev/null +++ b/sale_loyalty_order_line_link/views/sale_order_views.xml @@ -0,0 +1,113 @@ + + + + sale.order + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sale.order.line + + + + + + + + + + + From a44b081e97cb8bd9fb9a984c125c3610fee05165 Mon Sep 17 00:00:00 2001 From: Ilyas Date: Fri, 6 May 2022 18:11:15 +0700 Subject: [PATCH 05/23] [IMP] : black, isort, prettier --- sale_loyalty_order_line_link/reports/sale_report.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sale_loyalty_order_line_link/reports/sale_report.py b/sale_loyalty_order_line_link/reports/sale_report.py index 72f6e1b28..008640889 100644 --- a/sale_loyalty_order_line_link/reports/sale_report.py +++ b/sale_loyalty_order_line_link/reports/sale_report.py @@ -8,7 +8,8 @@ class SaleReport(models.Model): _inherit = "sale.report" coupon_program_id = fields.Many2one( - comodel_name="sale.coupon.program", string="Coupon Program", + comodel_name="sale.coupon.program", + string="Coupon Program", ) def _query(self, with_clause="", fields=None, groupby="", from_clause=""): From e3667810df9a90faaef3ef11004aad4a34f52d9e Mon Sep 17 00:00:00 2001 From: Ilyas Date: Fri, 6 May 2022 18:14:24 +0700 Subject: [PATCH 06/23] [MIG] sale_coupon_order_line_link: Migration to 14.0 --- sale_loyalty_order_line_link/README.rst | 14 +++++++---- sale_loyalty_order_line_link/__manifest__.py | 2 +- .../i18n/sale_coupon_order_line_link.pot | 23 ++++++++++++++++++- .../models/sale_order.py | 8 +++---- .../readme/CONTRIBUTORS.rst | 4 ++++ .../reports/sale_report.py | 2 +- .../static/description/index.html | 10 +++++--- .../tests/test_coupon_order_line_link.py | 2 +- 8 files changed, 48 insertions(+), 17 deletions(-) diff --git a/sale_loyalty_order_line_link/README.rst b/sale_loyalty_order_line_link/README.rst index b8e793d45..ea2b90f4d 100644 --- a/sale_loyalty_order_line_link/README.rst +++ b/sale_loyalty_order_line_link/README.rst @@ -14,13 +14,13 @@ Link coupons to order lines :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/13.0/sale_coupon_order_line_link + :target: https://github.com/OCA/sale-promotion/tree/14.0/sale_coupon_order_line_link :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-13-0/sale-promotion-13-0-sale_coupon_order_line_link + :target: https://translation.odoo-community.org/projects/sale-promotion-14-0/sale-promotion-14-0-sale_coupon_order_line_link :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/296/13.0 + :target: https://runbot.odoo-community.org/runbot/296/14.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -54,7 +54,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 smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -73,6 +73,10 @@ Contributors * David Vidal +* `Ooops404 `_: + + * Ilyas + Maintainers ~~~~~~~~~~~ @@ -94,6 +98,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_order_line_link/__manifest__.py b/sale_loyalty_order_line_link/__manifest__.py index 496697e32..2ca911174 100644 --- a/sale_loyalty_order_line_link/__manifest__.py +++ b/sale_loyalty_order_line_link/__manifest__.py @@ -4,7 +4,7 @@ "name": "Link coupons to order lines", "summary": "Adds a link between coupons and their generated order lines for easing " "tracking", - "version": "13.0.1.2.0", + "version": "14.0.1.0.0", "development_status": "Production/Stable", "category": "Sale", "website": "https://github.com/OCA/sale-promotion", diff --git a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot index 0e4b67384..d78b9f4de 100644 --- a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot +++ b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 13.0\n" +"Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -20,6 +20,27 @@ msgstr "" msgid "Coupon Program" msgstr "" +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order__display_name +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__display_name +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report__display_name +msgid "Display Name" +msgstr "" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order__id +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__id +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report__id +msgid "ID" +msgstr "" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order____last_update +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line____last_update +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report____last_update +msgid "Last Modified on" +msgstr "" + #. module: sale_coupon_order_line_link #: model:ir.model.fields,help:sale_coupon_order_line_link.field_sale_order_line__reward_line_ids msgid "Link on the reward lines applied from this one" diff --git a/sale_loyalty_order_line_link/models/sale_order.py b/sale_loyalty_order_line_link/models/sale_order.py index 75871ff58..1706f552f 100644 --- a/sale_loyalty_order_line_link/models/sale_order.py +++ b/sale_loyalty_order_line_link/models/sale_order.py @@ -34,7 +34,7 @@ def write(self, vals): ] if not reward_lines: return res - programs = self.env["sale.coupon.program"].browse( + programs = self.env["coupon.program"].browse( list({x.get("coupon_program_id") for x in reward_lines}) ) for order in self: @@ -119,7 +119,7 @@ class SaleOrderLine(models.Model): _inherit = "sale.order.line" coupon_program_id = fields.Many2one( - comodel_name="sale.coupon.program", + comodel_name="coupon.program", ondelete="restrict", string="Coupon Program", ) @@ -152,9 +152,7 @@ def write(self, vals): """When the reward line is update we should refresh the line links as well""" res = super().write(vals) if vals.get("is_reward_line") and vals.get("coupon_program_id"): - program = self.env["sale.coupon.program"].browse( - vals.get("coupon_program_id") - ) + program = self.env["coupon.program"].browse(vals.get("coupon_program_id")) for order in self.mapped("order_id"): order._link_reward_lines(program) return res diff --git a/sale_loyalty_order_line_link/readme/CONTRIBUTORS.rst b/sale_loyalty_order_line_link/readme/CONTRIBUTORS.rst index 94b6ba953..3ea30a085 100644 --- a/sale_loyalty_order_line_link/readme/CONTRIBUTORS.rst +++ b/sale_loyalty_order_line_link/readme/CONTRIBUTORS.rst @@ -1,3 +1,7 @@ * `Tecnativa `_: * David Vidal + +* `Ooops404 `_: + + * Ilyas diff --git a/sale_loyalty_order_line_link/reports/sale_report.py b/sale_loyalty_order_line_link/reports/sale_report.py index 008640889..25c5b1a11 100644 --- a/sale_loyalty_order_line_link/reports/sale_report.py +++ b/sale_loyalty_order_line_link/reports/sale_report.py @@ -8,7 +8,7 @@ class SaleReport(models.Model): _inherit = "sale.report" coupon_program_id = fields.Many2one( - comodel_name="sale.coupon.program", + comodel_name="coupon.program", string="Coupon Program", ) diff --git a/sale_loyalty_order_line_link/static/description/index.html b/sale_loyalty_order_line_link/static/description/index.html index 72a0112cc..c60543c80 100644 --- a/sale_loyalty_order_line_link/static/description/index.html +++ b/sale_loyalty_order_line_link/static/description/index.html @@ -367,7 +367,7 @@

Link coupons to order lines

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Production/Stable License: AGPL-3 OCA/sale-promotion Translate me on Weblate Try me on Runbot

+

Production/Stable License: AGPL-3 OCA/sale-promotion Translate me on Weblate Try me on Runbot

This module adds a link in the sale order line to the program used in a discount, so it can be easily tracked afterwards. Also eases the implementation of coupon modules that don’t necessarily use the discount product as product for the discount line.

@@ -409,7 +409,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 smashing it by providing a detailed and welcomed -feedback.

+feedback.

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

@@ -427,6 +427,10 @@

Contributors

  • David Vidal
  • +
  • Ooops404:
      +
    • Ilyas
    • +
    +
  • @@ -438,7 +442,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/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py b/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py index ce27a913a..dacac27bb 100644 --- a/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py +++ b/sale_loyalty_order_line_link/tests/test_coupon_order_line_link.py @@ -37,7 +37,7 @@ def setUpClass(cls): {"name": "Tax 4", "type_tax_use": "sale", "amount": 4} ) coupon_program_form = Form( - cls.env["sale.coupon.program"], + cls.env["coupon.program"], view="sale_coupon.sale_coupon_program_view_promo_program_form", ) coupon_program_form.name = "Test Coupon Line Link Program" From 6d532e39ff9c85540f6a315563fc43266482e4a9 Mon Sep 17 00:00:00 2001 From: Francesco Foresti Date: Tue, 31 May 2022 08:08:50 +0000 Subject: [PATCH 07/23] Added translation using Weblate (Italian) --- sale_loyalty_order_line_link/i18n/it.po | 105 ++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 sale_loyalty_order_line_link/i18n/it.po diff --git a/sale_loyalty_order_line_link/i18n/it.po b/sale_loyalty_order_line_link/i18n/it.po new file mode 100644 index 000000000..d6e4cdf09 --- /dev/null +++ b/sale_loyalty_order_line_link/i18n/it.po @@ -0,0 +1,105 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_coupon_order_line_link +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-05-31 11:05+0000\n" +"Last-Translator: Francesco Foresti \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__coupon_program_id +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report__coupon_program_id +#: model_terms:ir.ui.view,arch_db:sale_coupon_order_line_link.view_order_product_search +msgid "Coupon Program" +msgstr "Programma Coupon" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order__display_name +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__display_name +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order__id +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__id +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report__id +msgid "ID" +msgstr "ID" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order____last_update +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line____last_update +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,help:sale_coupon_order_line_link.field_sale_order_line__reward_line_ids +msgid "Link on the reward lines applied from this one" +msgstr "Collegamento alle righe ricompensa applicate da questa" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,help:sale_coupon_order_line_link.field_sale_order_line__reward_generated_line_ids +msgid "Link on the reward lines generated meeting this line as criteria" +msgstr "" +"Collegamento alle righe ricompensa create che rispondono ai criteri di " +"questa riga" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,help:sale_coupon_order_line_link.field_sale_order_line__reward_origin_generated_line_ids +msgid "" +"Origin Link on the reward lines generated meeting this line as criteria" +msgstr "" +"Collegamento originario alle righe ricompensa create che rispondono ai " +"criteri di questa riga" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__reward_origin_generated_line_ids +msgid "Origin Reward Generated lines" +msgstr "Righe originarie ricompensa create" + +#. module: sale_coupon_order_line_link +#: model_terms:ir.ui.view,arch_db:sale_coupon_order_line_link.view_order_product_search +msgid "Promotion Lines" +msgstr "Righe promozione" + +#. module: sale_coupon_order_line_link +#: model_terms:ir.ui.view,arch_db:sale_coupon_order_line_link.view_order_form +msgid "Promotions" +msgstr "Promozioni" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__reward_generated_line_ids +msgid "Reward Generated lines" +msgstr "Righe ricompense create" + +#. module: sale_coupon_order_line_link +#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__reward_line_ids +msgid "Reward lines" +msgstr "Righe ricompense" + +#. module: sale_coupon_order_line_link +#: model:ir.model,name:sale_coupon_order_line_link.model_sale_report +msgid "Sales Analysis Report" +msgstr "Report analitico vendite" + +#. module: sale_coupon_order_line_link +#: model:ir.model,name:sale_coupon_order_line_link.model_sale_order +msgid "Sales Order" +msgstr "Ordine di vendita" + +#. module: sale_coupon_order_line_link +#: model:ir.model,name:sale_coupon_order_line_link.model_sale_order_line +msgid "Sales Order Line" +msgstr "Riga ordine di vendita" From c7de6da462009d9dd612b7c6ae07af0ad78a86ef Mon Sep 17 00:00:00 2001 From: david Date: Tue, 31 May 2022 17:09:04 +0200 Subject: [PATCH 08/23] [IMP] sale_coupon_order_line_link: hook method for extra discounts If a third module adds an extra discount scope, we should: - Allow integration returning always at least an empty object - Allow compatibility by inheritance hooking into the method that defines the scoped lines. TT36131 --- sale_loyalty_order_line_link/__manifest__.py | 2 +- .../models/sale_order.py | 27 ++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/sale_loyalty_order_line_link/__manifest__.py b/sale_loyalty_order_line_link/__manifest__.py index 2ca911174..8299864cd 100644 --- a/sale_loyalty_order_line_link/__manifest__.py +++ b/sale_loyalty_order_line_link/__manifest__.py @@ -4,7 +4,7 @@ "name": "Link coupons to order lines", "summary": "Adds a link between coupons and their generated order lines for easing " "tracking", - "version": "14.0.1.0.0", + "version": "14.0.1.0.1", "development_status": "Production/Stable", "category": "Sale", "website": "https://github.com/OCA/sale-promotion", diff --git a/sale_loyalty_order_line_link/models/sale_order.py b/sale_loyalty_order_line_link/models/sale_order.py index 1706f552f..e8e48f5f2 100644 --- a/sale_loyalty_order_line_link/models/sale_order.py +++ b/sale_loyalty_order_line_link/models/sale_order.py @@ -42,6 +42,22 @@ def write(self, vals): order._link_reward_generated_lines(programs) return res + def _get_discounted_lines(self, program): + """Hook method that allows to link lines from extra discount reward options""" + # TODO: Should we add the lines that meet the criteria even if they aren't + # on the filtered lines? + if program.discount_apply_on == "on_order": + return self.order_line.filtered(lambda x: not x.is_reward_line) + elif program.discount_apply_on == "cheapest_product": + return self._get_cheapest_line() + elif program.discount_apply_on == "specific_products": + return self.order_line.filtered( + lambda x: x.product_id in program.discount_specific_product_ids + ) + # An extra discount scope could not depend no this module. For integration + # purposes, allways return at least an empty object + return self.env["sale.order.line"] + def _link_reward_discount_lines(self, program): """Assign reward lines depending on the discount scope of the promotion: - A discount on order, will apply to every line. @@ -53,16 +69,7 @@ def _link_reward_discount_lines(self, program): reward_lines = self.order_line.filtered( lambda x: x.coupon_program_id == program ) - # TODO: Should we add the lines that meet the criteria even if they aren't - # on the filtered lines? - if program.discount_apply_on == "on_order": - lines = self.order_line.filtered(lambda x: not x.is_reward_line) - elif program.discount_apply_on == "cheapest_product": - lines = self._get_cheapest_line() - elif program.discount_apply_on == "specific_products": - lines = self.order_line.filtered( - lambda x: x.product_id in program.discount_specific_product_ids - ) + lines = self._get_discounted_lines(program) # Distribute different tax reward lines with their correspondant order lines. # We use a dictionary so we can compare taxes even if they are composed. tax_reward_map = {} From 2933c80f8081e2b0c7bb5039399d7206ca57ad58 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 28 Oct 2022 17:18:17 +0200 Subject: [PATCH 09/23] [FIX] sale_coupon_order_line_link: missing links In some cases the `recompute_coupon_lines` method could lead to miss the previously created links. We want to ensure those links at the end of such method. TT40205 --- sale_loyalty_order_line_link/models/sale_order.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sale_loyalty_order_line_link/models/sale_order.py b/sale_loyalty_order_line_link/models/sale_order.py index e8e48f5f2..c33688d4a 100644 --- a/sale_loyalty_order_line_link/models/sale_order.py +++ b/sale_loyalty_order_line_link/models/sale_order.py @@ -121,6 +121,13 @@ def _link_reward_generated_lines(self, programs): {"reward_generated_line_ids": [(4, rl.id) for rl in reward_lines]} ) + def _create_new_no_code_promo_reward_lines(self): + """Ensure that the links remain""" + res = super()._create_new_no_code_promo_reward_lines() + for order in self: + order._link_reward_generated_lines(order.order_line.coupon_program_id) + return res + class SaleOrderLine(models.Model): _inherit = "sale.order.line" From 6fa2ec3fc57502721aca80edb9240aad75e57cdb Mon Sep 17 00:00:00 2001 From: David Date: Wed, 18 Jan 2023 12:23:56 +0100 Subject: [PATCH 10/23] [MIG] sale_coupon_order_line_link: Migration to 15.0 TT37311 --- sale_loyalty_order_line_link/README.rst | 23 +++++----- sale_loyalty_order_line_link/__manifest__.py | 2 +- .../i18n/sale_coupon_order_line_link.pot | 23 +--------- .../static/description/index.html | 44 ++++++++++--------- .../tests/test_coupon_order_line_link.py | 4 +- 5 files changed, 40 insertions(+), 56 deletions(-) diff --git a/sale_loyalty_order_line_link/README.rst b/sale_loyalty_order_line_link/README.rst index ea2b90f4d..d1c905ab8 100644 --- a/sale_loyalty_order_line_link/README.rst +++ b/sale_loyalty_order_line_link/README.rst @@ -2,10 +2,13 @@ Link coupons to order lines =========================== -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:48825c029f35b6de6644b4af46bb75003501eeea6212c0ff81dcb59db4429d02 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png :target: https://odoo-community.org/page/development-status @@ -14,16 +17,16 @@ Link coupons to order lines :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/14.0/sale_coupon_order_line_link + :target: https://github.com/OCA/sale-promotion/tree/15.0/sale_coupon_order_line_link :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-14-0/sale-promotion-14-0-sale_coupon_order_line_link + :target: https://translation.odoo-community.org/projects/sale-promotion-15-0/sale-promotion-15-0-sale_coupon_order_line_link :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/296/14.0 - :alt: Try me on Runbot +.. |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 + :alt: Try me on Runboat -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| This module adds a link in the sale order line to the program used in a discount, so it can be easily tracked afterwards. Also eases the implementation of coupon modules @@ -53,8 +56,8 @@ 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 smashing it by providing a detailed and welcomed -`feedback `_. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -98,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_order_line_link/__manifest__.py b/sale_loyalty_order_line_link/__manifest__.py index 8299864cd..c6a922523 100644 --- a/sale_loyalty_order_line_link/__manifest__.py +++ b/sale_loyalty_order_line_link/__manifest__.py @@ -4,7 +4,7 @@ "name": "Link coupons to order lines", "summary": "Adds a link between coupons and their generated order lines for easing " "tracking", - "version": "14.0.1.0.1", + "version": "15.0.1.0.0", "development_status": "Production/Stable", "category": "Sale", "website": "https://github.com/OCA/sale-promotion", diff --git a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot index d78b9f4de..c786ed612 100644 --- a/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot +++ b/sale_loyalty_order_line_link/i18n/sale_coupon_order_line_link.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 14.0\n" +"Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -20,27 +20,6 @@ msgstr "" msgid "Coupon Program" msgstr "" -#. module: sale_coupon_order_line_link -#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order__display_name -#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__display_name -#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report__display_name -msgid "Display Name" -msgstr "" - -#. module: sale_coupon_order_line_link -#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order__id -#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line__id -#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report__id -msgid "ID" -msgstr "" - -#. module: sale_coupon_order_line_link -#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order____last_update -#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_order_line____last_update -#: model:ir.model.fields,field_description:sale_coupon_order_line_link.field_sale_report____last_update -msgid "Last Modified on" -msgstr "" - #. module: sale_coupon_order_line_link #: model:ir.model.fields,help:sale_coupon_order_line_link.field_sale_order_line__reward_line_ids msgid "Link on the reward lines applied from this one" diff --git a/sale_loyalty_order_line_link/static/description/index.html b/sale_loyalty_order_line_link/static/description/index.html index c60543c80..58f5ac625 100644 --- a/sale_loyalty_order_line_link/static/description/index.html +++ b/sale_loyalty_order_line_link/static/description/index.html @@ -1,20 +1,20 @@ - + - + Link coupons to order lines -