33# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
44
55from odoo import _ , api , exceptions , fields , models
6+ from odoo .tools .misc import formatLang
67
78
89class SaleOrder (models .Model ):
@@ -14,6 +15,9 @@ class SaleOrder(models.Model):
1415 domain = "[('discount_scope', '=', 'sale'), "
1516 "('account_id', '!=', False), '|', "
1617 "('company_id', '=', company_id), ('company_id', '=', False)]" ,
18+ compute = "_compute_global_discount_ids" ,
19+ store = True ,
20+ readonly = False ,
1721 )
1822 # HACK: Looks like UI doesn't behave well with Many2many fields and
1923 # negative groups when the same field is shown. In this case, we want to
@@ -68,7 +72,7 @@ def _check_global_discounts_sanity(self):
6872 return True
6973 taxes_keys = {}
7074 for line in self .order_line .filtered (
71- lambda l : not l .display_type and l .product_id
75+ lambda _line : not _line .display_type and _line .product_id
7276 ):
7377 if not line .tax_id :
7478 raise exceptions .UserError (
@@ -135,20 +139,92 @@ def _compute_amounts(self):
135139 return res
136140
137141 def _compute_tax_totals (self ):
138- return super (
139- SaleOrder , self .with_context (from_tax_calculation = True )
140- )._compute_tax_totals ()
142+ res = super ()._compute_tax_totals ()
143+ for order in self :
144+ amount_discount_by_group = {}
145+ cumulative_discount_rate = 1.0
146+ # Calculate the total discount amount and discount by tax group
147+ for line in order .order_line :
148+ if (
149+ line .display_type
150+ or not line .product_id
151+ or line .product_id .bypass_global_discount
152+ ):
153+ continue
141154
142- @api .onchange ("partner_id" )
143- def onchange_partner_id_set_gbl_disc (self ):
144- self .global_discount_ids = (
145- self .partner_id .customer_global_discount_ids .filtered (
146- lambda d : d .company_id == self .company_id
155+ cumulative_discount_rate = 1.0
156+ for gbl_disc in order .global_discount_ids :
157+ discount_rate = gbl_disc .discount / 100
158+ cumulative_discount_rate *= 1 - discount_rate
159+ discounted_price_subtotal = (
160+ line .price_subtotal * cumulative_discount_rate
161+ )
162+ # Calculate tax amounts for each tax group based on the discounted subtotal
163+ for tax in line .tax_id :
164+ tax_group_id = tax .tax_group_id .id
165+ if tax_group_id not in amount_discount_by_group :
166+ amount_discount_by_group [tax_group_id ] = 0.0
167+ # Compute taxes on the discounted subtotal
168+ discounted_tax_vals = tax .compute_all (
169+ discounted_price_subtotal ,
170+ order .currency_id ,
171+ 1.0 ,
172+ product = line .product_id ,
173+ partner = order .partner_shipping_id ,
174+ )
175+ total_discounted_tax = sum (
176+ t .get ("amount" , 0.0 )
177+ for t in discounted_tax_vals .get ("taxes" , [])
178+ )
179+ amount_discount_by_group [tax_group_id ] += total_discounted_tax
180+ # Update tax totals
181+ amount_untaxed = (
182+ order .amount_untaxed_before_global_discounts * cumulative_discount_rate
183+ )
184+ amount_total = amount_untaxed + sum (amount_discount_by_group .values ())
185+ order .tax_totals ["amount_untaxed" ] = amount_untaxed
186+ order .tax_totals ["amount_total" ] = amount_total
187+ order .tax_totals ["formatted_amount_untaxed" ] = formatLang (
188+ self .env , amount_untaxed , currency_obj = order .currency_id
147189 )
148- or self . partner_id . commercial_partner_id . customer_global_discount_ids . filtered (
149- lambda d : d . company_id == self . company_id
190+ order . tax_totals [ "formatted_amount_total" ] = formatLang (
191+ self . env , amount_total , currency_obj = order . currency_id
150192 )
151- )
193+ # Update groups by subtotal
194+ for group in order .tax_totals ["groups_by_subtotal" ].values ():
195+ for tax_group in group :
196+ tax_group_id = tax_group ["tax_group_id" ]
197+ discount_for_group = amount_discount_by_group .get (tax_group_id , 0.0 )
198+ tax_group ["tax_group_amount" ] = discount_for_group
199+ tax_group ["formatted_tax_group_amount" ] = formatLang (
200+ self .env ,
201+ tax_group ["tax_group_amount" ],
202+ currency_obj = order .currency_id ,
203+ )
204+ # Update subtotals
205+ for subtotal in order .tax_totals ["subtotals" ]:
206+ subtotal ["amount" ] = amount_untaxed
207+ subtotal ["formatted_amount" ] = formatLang (
208+ self .env , amount_untaxed , currency_obj = order .currency_id
209+ )
210+ return res
211+
212+ @api .depends ("partner_id" , "company_id" )
213+ def _compute_global_discount_ids (self ):
214+ for order in self :
215+ commercial = order .partner_id .commercial_partner_id
216+ commercial_global_disc = commercial .customer_global_discount_ids
217+ partner_global_disc = order .partner_id .customer_global_discount_ids
218+ discounts = self .env ["global.discount" ]
219+ _discounts = self .env ["global.discount" ]
220+ if partner_global_disc :
221+ _discounts = partner_global_disc
222+ else :
223+ _discounts = commercial_global_disc
224+ for discount in _discounts :
225+ if discount .company_id == order .company_id :
226+ discounts |= discount
227+ order .global_discount_ids = discounts
152228
153229 def _prepare_invoice (self ):
154230 invoice_vals = super ()._prepare_invoice ()
0 commit comments