Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 3 additions & 99 deletions sale_triple_discount/models/sale_order_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,12 @@
# Copyright 2018 ~ 2021 Simone Rubino - Agile Business Group
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models
import odoo.addons.decimal_precision as dp
from odoo import api, models


class SaleOrderLine(models.Model):
_inherit = "sale.order.line"

def _get_final_discount(self):
self.ensure_one()
if self.discounting_type == "additive":
return self._additive_discount()
elif self.discounting_type == "multiplicative":
return self._multiplicative_discount()

def _additive_discount(self):
self.ensure_one()
discount = sum(
[getattr(self, x) or 0.0 for x in self._discount_fields()]
)
if discount <= 0:
return 0
elif discount >= 100:
return 100
return discount

def _multiplicative_discount(self):
self.ensure_one()
discounts = [1 - (self[x] or 0.0) / 100
for x in self._discount_fields()]
final_discount = 1
for discount in discounts:
final_discount *= discount
return 100 - final_discount * 100

def _discount_fields(self):
return ['discount', 'discount2', 'discount3']
_name = "sale.order.line"
_inherit = ["line.triple_discount.mixin", "sale.order.line"]

@api.depends('discount2', 'discount3', 'discounting_type')
def _compute_amount(self):
Expand All @@ -48,45 +18,6 @@ def _compute_amount(self):
super(SaleOrderLine, line)._compute_amount()
line.triple_discount_postprocess(prev_values)

discount2 = fields.Float(
'Disc. 2 (%)',
digits=dp.get_precision('Discount'),
default=0.0,
)
discount3 = fields.Float(
'Disc. 3 (%)',
digits=dp.get_precision('Discount'),
default=0.0,
)
discounting_type = fields.Selection(
string="Discounting type",
selection=[
('additive', 'Additive'),
('multiplicative', 'Multiplicative'),
],
default="multiplicative",
required=True,
help="Specifies whether discounts should be additive "
"or multiplicative.\nAdditive discounts are summed first and "
"then applied.\nMultiplicative discounts are applied sequentially.\n"
"Multiplicative discounts are default",
)

_sql_constraints = [
('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%.'),
]

def _get_triple_discount(self):
"""Get the discount that is equivalent to the subsequent application
of discount, discount2 and discount3"""
discount_factor = 1.0
for discount in [self.discount, self.discount2, self.discount3]:
discount_factor *= (100.0 - discount) / 100.0
return 100.0 - (discount_factor * 100.0)

def _prepare_invoice_line(self, qty):
res = super(SaleOrderLine, self)._prepare_invoice_line(qty)
res.update({
Expand All @@ -100,30 +31,3 @@ def _get_price_reduce(self):
prev_values = self.triple_discount_preprocess()
super(SaleOrderLine, self)._get_price_reduce()
self.triple_discount_postprocess(prev_values)

@api.multi
def triple_discount_preprocess(self):
"""Save the values of the discounts in a dictionary,
to be restored in postprocess.
Resetting discount2 and discount3 to 0.0 avoids issues if
this method is called multiple times."""
prev_values = dict()

for line in self:
prev_values[line] = dict(
discount=line.discount,
discount2=line.discount2,
discount3=line.discount3,
)
line.update({
'discount': line._get_final_discount(),
'discount2': 0.0,
'discount3': 0.0
})
return prev_values

@api.model
def triple_discount_postprocess(self, prev_values):
"""Restore the discounts of the lines in the dictionary prev_values."""
for line, prev_vals_dict in list(prev_values.items()):
line.update(prev_vals_dict)
16 changes: 16 additions & 0 deletions sale_triple_discount/tests/test_sale_triple_discount.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,19 @@ def test_05_round_globally(self):
self.assertEqual(self.so_line2.price_subtotal, 300.0)
self.assertEqual(self.order.amount_untaxed, 375.0)
self.assertEqual(self.order.amount_tax, 56.25)

def test_06_discounts(self):
""" Tests discounts in edge case """
order = self.env['sale.order'].create({
'partner_id': self.partner.id,
'order_line': [(0, 0, {
'name': 'Line 1',
'product_id': self.product2.id,
'price_unit': 25.0,
'product_uom_qty': 65,
'discount': 50,
'discount2': 13,
'discount3': 0,
})],
})
self.assertEqual(order.order_line.price_subtotal, 706.88)