# Copyright 2019 Tecnativa - David Vidal # Copyright 2019 Tecnativa - Pedro M. Baeza # Copyright 2020 ACSONE SA/NV # Copyright 2023 Simone Rubino - Aion Tech # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import functools from odoo import api from odoo import fields from odoo import models class TripleDiscountMixin(models.AbstractModel): _name = "triple.discount.mixin" _description = "Triple discount mixin" # core discount field is now a computed field # based on the 3 discounts defined below. # the digits limitation is removed, to make # the computation of the subtotal exact. # For exemple, if discounts are 05%, 09% and 13% # the main discount is 24.7885 % (and not 24.79) discount = fields.Float( string="Total discount", compute="_compute_discount", store=True, readonly=True, digits=None, ) discount1 = fields.Float(string="Discount 1 (%)", digits="Discount") discount2 = fields.Float(string="Discount 2 (%)", digits="Discount") discount3 = fields.Float(string="Discount 3 (%)", digits="Discount") _sql_constraints = [ ( "discount1_limit", "CHECK (discount1 <= 100.0)", "Discount 1 must be lower than 100%.", ), ( "discount2_limit", "CHECK (discount2 <= 100.0)", "Discount 2 must be lower than 100%.", ), ( "discount3_limit", "CHECK (discount3 <= 100.0)", "Discount 3 must be lower than 100%.", ), ] @api.depends(lambda self: self._get_multiple_discount_field_names()) def _compute_discount(self): for line in self: line.discount = line._get_aggregated_multiple_discounts( [line[x] for x in line._get_multiple_discount_field_names()] ) def _get_aggregated_multiple_discounts(self, discounts): """ Returns the aggregate discount corresponding to any number of discounts. For exemple, if discounts is [11.0, 22.0, 33.0] It will return 46.5114 """ discount_values = [] for discount in discounts: discount_values.append(1 - (discount or 0.0) / 100.0) aggregated_discount = ( 1 - functools.reduce((lambda x, y: x * y), discount_values) ) * 100 return aggregated_discount @api.model def _get_multiple_discount_field_names(self): return ["discount1", "discount2", "discount3"] @api.model_create_multi def create(self, vals_list): for vals in vals_list: if vals.get("discount") and not any( vals.get(field) for field in self._get_multiple_discount_field_names() ): vals["discount1"] = vals.pop("discount") return super().create(vals_list) def write(self, vals): discount_fields = self._get_multiple_discount_field_names() if "discount" in vals: vals["discount1"] = vals.pop("discount") vals.update({field: 0 for field in discount_fields[1:]}) return super().write(vals)