|
| 1 | +# Copyright 2026 Tecnativa - Andrii Kompaniiets |
| 2 | +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). |
| 3 | +from odoo import Command, api, models |
| 4 | +from odoo.exceptions import ValidationError |
| 5 | +from odoo.tools.float_utils import float_compare |
| 6 | +from odoo.tools.safe_eval import safe_eval |
| 7 | + |
| 8 | + |
| 9 | +class LoyaltyReward(models.Model): |
| 10 | + _inherit = "loyalty.reward" |
| 11 | + |
| 12 | + def _get_sale_margin_formula_eval_context(self): |
| 13 | + main_product = self.env["product.product"].new( |
| 14 | + { |
| 15 | + "name": "Main Product", |
| 16 | + "list_price": 35.0, |
| 17 | + "standard_price": 11.52, |
| 18 | + } |
| 19 | + ) |
| 20 | + order = self.env["sale.order"].new( |
| 21 | + { |
| 22 | + "partner_id": self.env.ref("base.partner_admin").id, |
| 23 | + "order_line": [ |
| 24 | + Command.create( |
| 25 | + { |
| 26 | + "product_id": main_product.id, |
| 27 | + "product_uom_qty": 2.0, |
| 28 | + "price_unit": 35.0, |
| 29 | + } |
| 30 | + ) |
| 31 | + ], |
| 32 | + } |
| 33 | + ) |
| 34 | + return { |
| 35 | + "env": self.env, |
| 36 | + "context": self.env.context, |
| 37 | + "user": self.env.user, |
| 38 | + "origin_lines": order.order_line, |
| 39 | + "reward": self, |
| 40 | + "reward_line": order.order_line[0], |
| 41 | + "float_compare": float_compare, |
| 42 | + } |
| 43 | + |
| 44 | + @api.constrains("sale_margin_formula") |
| 45 | + def _check_sale_margin_formula(self): |
| 46 | + res = super()._check_sale_margin_formula() |
| 47 | + main_product = self.env["product.product"].new( |
| 48 | + { |
| 49 | + "name": "Main Product", |
| 50 | + "list_price": 35.0, |
| 51 | + "standard_price": 11.52, |
| 52 | + } |
| 53 | + ) |
| 54 | + order = self.env["sale.order"].new( |
| 55 | + { |
| 56 | + "partner_id": self.env.ref("base.partner_admin").id, |
| 57 | + "order_line": [ |
| 58 | + Command.create( |
| 59 | + { |
| 60 | + "product_id": main_product.id, |
| 61 | + "product_uom_qty": 2.0, |
| 62 | + "price_unit": 35.0, |
| 63 | + } |
| 64 | + ) |
| 65 | + ], |
| 66 | + } |
| 67 | + ) |
| 68 | + fake_eval_context = { |
| 69 | + "env": self.env, |
| 70 | + "context": self.env.context, |
| 71 | + "user": self.env.user, |
| 72 | + "origin_lines": order.order_line, |
| 73 | + "reward_line": order.order_line[0], |
| 74 | + "float_compare": float_compare, |
| 75 | + } |
| 76 | + for reward in self: |
| 77 | + if not reward.sale_margin_formula: |
| 78 | + continue |
| 79 | + fake_eval_context.update({"reward": reward}) |
| 80 | + try: |
| 81 | + safe_eval( |
| 82 | + str(reward.sale_margin_formula).strip(), |
| 83 | + reward._get_sale_margin_formula_eval_context(), |
| 84 | + mode="exec", |
| 85 | + nocopy=True, |
| 86 | + ) |
| 87 | + except Exception as e: |
| 88 | + raise ValidationError( |
| 89 | + self.env._("Invalid sale margin formula:\n%(error)s", error=e) |
| 90 | + ) from e |
| 91 | + return res |
0 commit comments