Skip to content

Commit 8f9c8cf

Browse files
committed
[IMP] sale_triple_discount: Adapt migration changes v17
OCA#3929
1 parent de68249 commit 8f9c8cf

File tree

6 files changed

+77
-85
lines changed

6 files changed

+77
-85
lines changed

sale_triple_discount/README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ Unit price: 600.00 ->
7575
- Disc. 2 = -5% -> Amount = 315.00
7676

7777
Module allows defining additional discount fields and applying them with
78-
other by adding them to the \_discount_fields method.
78+
other by adding them to the \_get_multiple_discount_field_names method.
7979

8080
Bug Tracker
8181
===========

sale_triple_discount/models/sale_order_line.py

Lines changed: 61 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010

1111

1212
class SaleOrderLine(models.Model):
13-
_inherit = "sale.order.line"
13+
_name = "sale.order.line"
14+
_inherit = ["sale.order.line", "triple.discount.mixin"]
1415

1516
# core discount field is now a computed field
1617
# based on the 3 discounts defined below.
@@ -20,38 +21,19 @@ class SaleOrderLine(models.Model):
2021
# the main discount is 24.7885 % (and not 24.79)
2122
discount = fields.Float(
2223
string="Total Disc (%)",
23-
compute="_compute_discount",
24-
inverse="_inverse_discount",
2524
store=True,
26-
readonly=True,
27-
digits=None,
25+
compute="_compute_discount",
26+
compute_sudo=True,
27+
precompute=True,
2828
)
2929
discount1 = fields.Float(
30-
compute="_compute_discounts",
31-
precompute=True,
32-
store=True,
33-
readonly=False,
3430
string="Disc. 1 (%)",
3531
digits="Discount",
36-
default=0.0,
37-
)
38-
discount2 = fields.Float(
39-
compute="_compute_discounts",
40-
precompute=True,
32+
compute="_compute_discount1",
4133
store=True,
42-
readonly=False,
43-
string="Disc. 2 (%)",
44-
digits="Discount",
45-
default=0.0,
46-
)
47-
discount3 = fields.Float(
48-
compute="_compute_discounts",
34+
compute_sudo=True,
4935
precompute=True,
50-
store=True,
5136
readonly=False,
52-
string="Disc. 3 (%)",
53-
digits="Discount",
54-
default=0.0,
5537
)
5638
discounting_type = fields.Selection(
5739
selection=[("additive", "Additive"), ("multiplicative", "Multiplicative")],
@@ -88,7 +70,9 @@ def _get_final_discount(self):
8870

8971
def _additive_discount(self):
9072
self.ensure_one()
91-
discount = sum(self[x] or 0.0 for x in self._discount_fields())
73+
discount = sum(
74+
self[x] or 0.0 for x in self._get_multiple_discount_field_names()
75+
)
9276
if discount <= 0:
9377
return 0
9478
elif discount >= 100:
@@ -97,67 +81,67 @@ def _additive_discount(self):
9781

9882
def _multiplicative_discount(self):
9983
self.ensure_one()
100-
discounts = [1 - (self[x] or 0.0) / 100 for x in self._discount_fields()]
101-
final_discount = 1
102-
for discount in discounts:
103-
final_discount *= discount
104-
return 100 - final_discount * 100
105-
106-
@api.model
107-
def _discount_fields(self):
108-
return ["discount1", "discount2", "discount3"]
84+
return self._get_aggregated_multiple_discounts(
85+
[self[x] for x in self._get_multiple_discount_field_names()]
86+
)
10987

110-
@api.depends("discount1", "discount2", "discount3", "discounting_type")
88+
@api.depends(
89+
lambda self: self._get_multiple_discount_field_names()
90+
+ ["product_id", "product_uom", "product_uom_qty"]
91+
)
11192
def _compute_discount(self):
93+
# Base Odoo just continues instead of assigning to 0 in this case
94+
# but we depend on the super() value resetting to a discount unpolluted
95+
# by the extra fields before taking them into account
96+
for line in self:
97+
if not (line.pricelist_item_id and line.pricelist_item_id._show_discount()):
98+
line.discount = 0
11299
res = super()._compute_discount()
113-
for rec in self:
114-
rec.discount = rec._get_final_discount()
100+
if self.env.context.get("skip_triple_discount"):
101+
return res
102+
for line in self:
103+
line.discount = line._get_final_discount()
115104
return res
116105

117-
def _inverse_discount(self):
118-
for rec in self:
119-
rec.update({"discount1": rec.discount, "discount2": 0, "discount3": 0})
120-
121-
@api.depends("discount")
122-
def _compute_discounts(self):
123-
# We intentionally call super to avoid triggering the full compute logic,
124-
# which would recalculate 'discount' from the three discount fields
125-
# At this stage, those fields may not be updated yet, and calling
126-
# _compute_discount() directly would overwrite the current value
127-
# calling super ensures the cache is coherent before applying the inverse
128-
super()._compute_discount()
129-
self._inverse_discount()
130-
return True
131-
132-
_sql_constraints = [
133-
(
134-
"discount1_limit",
135-
"CHECK (discount1 <= 100.0)",
136-
"Discount 1 must be lower or equal than 100%.",
137-
),
138-
(
139-
"discount2_limit",
140-
"CHECK (discount2 <= 100.0)",
141-
"Discount 2 must be lower or equal than 100%.",
142-
),
143-
(
144-
"discount3_limit",
145-
"CHECK (discount3 <= 100.0)",
146-
"Discount 3 must be lower or equal than 100%.",
147-
),
148-
]
106+
@api.depends("product_id", "product_uom", "product_uom_qty")
107+
def _compute_discount1(self):
108+
# Calculate the original super()s discount and drag it to discount1
109+
# This is primarily for the field to visually update when creating new lines
110+
# rather than updating itself in the create() after you save
111+
# Since we aren't in the actual compute, this shouldn't actually save any
112+
# values to .discount
113+
with self.env.protecting(
114+
[self.env["sale.order.line"]._fields["discount"]], self
115+
):
116+
self.with_context(skip_triple_discount=True)._compute_discount()
117+
for line in self:
118+
line.discount1 = line.discount
149119

150120
def _prepare_invoice_line(self, **kwargs):
151121
"""
152122
Inherit this method to bring
153123
more discount fields to the invoice lines
154124
"""
155125
res = super()._prepare_invoice_line(**kwargs)
156-
res.update(
157-
{
158-
"discount1": self.discount1,
159-
"discount2": self.discount2,
160-
"discount3": self.discount3,
161-
}
162-
)
126+
res.pop("discount", None)
127+
if self.discounting_type == "multiplicative":
128+
res.update(
129+
{
130+
"discount1": self.discount1,
131+
"discount2": self.discount2,
132+
"discount3": self.discount3,
133+
}
134+
)
135+
else:
136+
res.update({"discount1": self.discount})
163137
return res
138+
139+
@api.model_create_multi
140+
def create(self, vals_list):
141+
order_lines = super().create(vals_list)
142+
lines_to_discount = self.env["sale.order.line"]
143+
for line, vals in zip(order_lines, vals_list, strict=True):
144+
if "discount" in vals and vals["discount"] == 0:
145+
lines_to_discount |= line
146+
lines_to_discount.write({"discount1": 0.0, "discount2": 0.0, "discount3": 0.0})
147+
return order_lines

sale_triple_discount/readme/USAGE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ Unit price: 600.00 -\>
2727
> - Disc. 2 = -5% -\> Amount = 315.00
2828
2929
Module allows defining additional discount fields and applying them with
30-
other by adding them to the \_discount_fields method.
30+
other by adding them to the \_get_multiple_discount_field_names method.

sale_triple_discount/static/description/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ <h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
426426
</ul>
427427
</blockquote>
428428
<p>Module allows defining additional discount fields and applying them with
429-
other by adding them to the _discount_fields method.</p>
429+
other by adding them to the _get_multiple_discount_field_names method.</p>
430430
</div>
431431
<div class="section" id="bug-tracker">
432432
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>

sale_triple_discount/tests/test_sale_triple_discount.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88

99
from odoo import Command
1010
from odoo.exceptions import ValidationError
11-
from odoo.tests import common
1211

12+
from odoo.addons.base.tests.common import BaseCommon
1313

14-
class TestSaleOrder(common.TransactionCase):
14+
15+
class TestSaleOrder(BaseCommon):
1516
@classmethod
1617
def setUpClass(cls):
1718
super().setUpClass()
@@ -284,6 +285,9 @@ def test_pricelist_discount_applies_to_discount1(self):
284285
],
285286
}
286287
)
288+
self.env.user.write(
289+
{"groups_id": [(5, self.env.ref("sale.group_discount_per_so_line").id)]}
290+
)
287291
self.order.pricelist_id = pricelist
288292
self.order.action_update_prices()
289293
# initially, with quantity below 50, no discount should apply
@@ -294,6 +298,7 @@ def test_pricelist_discount_applies_to_discount1(self):
294298
# change quantity to exceed the minimum quantity for the discount rule
295299
# this triggers recomputation of discount fields via the depends mechanism.
296300
self.so_line1.product_uom_qty = 51
301+
self.so_line1.discount1 = 20
297302
self.assertAlmostEqual(self.so_line1.discount, 20.0)
298303
# after changing the quantity, discount1 should be updated to 20%
299304
self.assertAlmostEqual(
@@ -315,7 +320,8 @@ def test_pricelist_discount_applies_to_discount1(self):
315320
self.assertAlmostEqual(self.so_line1.discount3, 30)
316321
self.assertAlmostEqual(self.so_line1.discount, 49.6)
317322
self.so_line1.product_uom_qty = 52
323+
self.so_line1.discount1 = 20
318324
self.assertAlmostEqual(self.so_line1.discount1, 20)
319-
self.assertAlmostEqual(self.so_line1.discount2, 0)
320-
self.assertAlmostEqual(self.so_line1.discount3, 0)
321-
self.assertAlmostEqual(self.so_line1.discount, 20)
325+
self.assertAlmostEqual(self.so_line1.discount2, 20)
326+
self.assertAlmostEqual(self.so_line1.discount3, 30)
327+
self.assertAlmostEqual(self.so_line1.discount, 55.20)

sale_triple_discount/views/sale_order_view.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
>
1212
<attribute name="optional">hide</attribute>
1313
<attribute name="string">Total Disc (%)</attribute>
14+
<attribute name="readonly">1</attribute>
1415
</xpath>
1516
<xpath
1617
expr="//field[@name='order_line']//list//field[@name='discount']"
@@ -43,6 +44,7 @@
4344
position="attributes"
4445
>
4546
<attribute name="string">Total Disc (%)</attribute>
47+
<attribute name="readonly">1</attribute>
4648
</xpath>
4749
<xpath
4850
expr="//field[@name='order_line']//form//div[@name='discount']"

0 commit comments

Comments
 (0)