fix: get total without rounding off tax amounts for distributing discount (backport #47155)

Co-authored-by: Sagar Vora <16315650+sagarvora@users.noreply.github.com>
This commit is contained in:
mergify[bot]
2025-04-22 17:53:10 +05:30
committed by GitHub
parent 2ba6c78e5e
commit 8050e653ab
3 changed files with 102 additions and 68 deletions

View File

@@ -377,20 +377,22 @@ class calculate_taxes_and_totals:
self._calculate()
def calculate_taxes(self):
self.grand_total_diff = 0
doc = self.doc
if not doc.get("taxes"):
return
# maintain actual tax rate based on idx
actual_tax_dict = dict(
[
[tax.idx, flt(tax.tax_amount, tax.precision("tax_amount"))]
for tax in self.doc.get("taxes")
for tax in doc.taxes
if tax.charge_type == "Actual"
]
)
for n, item in enumerate(self._items):
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
for i, tax in enumerate(self.doc.get("taxes")):
for i, tax in enumerate(doc.taxes):
# tax_amount represents the amount of tax for the current step
current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map)
if frappe.flags.round_row_wise_tax:
@@ -425,30 +427,39 @@ class calculate_taxes_and_totals:
tax.grand_total_for_current_item = flt(item.net_amount + current_tax_amount)
else:
tax.grand_total_for_current_item = flt(
self.doc.get("taxes")[i - 1].grand_total_for_current_item + current_tax_amount
doc.taxes[i - 1].grand_total_for_current_item + current_tax_amount
)
# set precision in the last item iteration
if n == len(self._items) - 1:
self.round_off_totals(tax)
self._set_in_company_currency(tax, ["tax_amount", "tax_amount_after_discount_amount"])
discount_amount_applied = self.discount_amount_applied
if doc.apply_discount_on == "Grand Total" and (
discount_amount_applied or doc.discount_amount or doc.additional_discount_percentage
):
tax_amount_precision = doc.taxes[0].precision("tax_amount")
self.round_off_base_values(tax)
self.set_cumulative_total(i, tax)
for i, tax in enumerate(doc.taxes):
if discount_amount_applied:
tax.tax_amount_after_discount_amount = flt(
tax.tax_amount_after_discount_amount, tax_amount_precision
)
self._set_in_company_currency(tax, ["total"])
self.set_cumulative_total(i, tax)
# adjust Discount Amount loss in last tax iteration
if (
i == (len(self.doc.get("taxes")) - 1)
and self.discount_amount_applied
and self.doc.discount_amount
and self.doc.apply_discount_on == "Grand Total"
):
self.grand_total_diff = flt(
self.doc.grand_total - flt(self.doc.discount_amount) - tax.total,
self.doc.precision("rounding_adjustment"),
)
if not discount_amount_applied:
self.grand_total_for_distributing_discount = doc.taxes[-1].total
else:
self.grand_total_diff = flt(
self.grand_total_for_distributing_discount - doc.discount_amount - doc.taxes[-1].total,
doc.precision("grand_total"),
)
for i, tax in enumerate(doc.taxes):
self.round_off_totals(tax)
self._set_in_company_currency(tax, ["tax_amount", "tax_amount_after_discount_amount"])
self.round_off_base_values(tax)
self.set_cumulative_total(i, tax)
self._set_in_company_currency(tax, ["total"])
def get_tax_amount_if_for_valuation_or_deduction(self, tax_amount, tax):
# if just for valuation, do not add the tax amount in total
@@ -571,16 +582,20 @@ class calculate_taxes_and_totals:
if diff and abs(diff) <= (5.0 / 10 ** last_tax.precision("tax_amount")):
self.grand_total_diff = diff
else:
self.grand_total_diff = 0
def calculate_totals(self):
grand_total_diff = getattr(self, "grand_total_diff", 0)
if self.doc.get("taxes"):
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + self.grand_total_diff
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + grand_total_diff
else:
self.doc.grand_total = flt(self.doc.net_total)
if self.doc.get("taxes"):
self.doc.total_taxes_and_charges = flt(
self.doc.grand_total - self.doc.net_total - self.grand_total_diff,
self.doc.grand_total - self.doc.net_total - grand_total_diff,
self.doc.precision("total_taxes_and_charges"),
)
else:
@@ -725,7 +740,8 @@ class calculate_taxes_and_totals:
self.doc.base_discount_amount = 0
def get_total_for_discount_amount(self):
if self.doc.apply_discount_on == "Net Total":
doc = self.doc
if doc.apply_discount_on == "Net Total" or not doc.get("taxes"):
return self.doc.net_total
total_actual_tax = 0
@@ -745,7 +761,7 @@ class calculate_taxes_and_totals:
"cumulative_tax_amount": total_actual_tax,
}
for tax in self.doc.get("taxes"):
for tax in doc.taxes:
if tax.charge_type in ["Actual", "On Item Quantity"]:
update_actual_tax_dict(tax, tax.tax_amount)
continue
@@ -764,7 +780,7 @@ class calculate_taxes_and_totals:
)
update_actual_tax_dict(tax, base_tax_amount * tax.rate / 100)
return self.doc.grand_total - total_actual_tax
return getattr(self, "grand_total_for_distributing_discount", doc.grand_total) - total_actual_tax
def calculate_total_advance(self):
if not self.doc.docstatus.is_cancelled():