You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(accounts): prevent shipping rule discount overwrite and zero conversion error #61333
Shipping Rule Cash-Discount Wipe (calculate() / calculate_shipping_charges()):
In calculate_taxes_and_totals.calculate(), self.apply_discount_amount() runs before self.calculate_shipping_charges(). When shipping_rule is present and apply_discount_on == "Grand Total", calculate_shipping_charges() appends the shipping charge row and calls self._calculate() without re-running set_discount_amount() / apply_discount_amount(), silently wiping out the document-level discount_amount and overcharging grand_total. Furthermore, if an invoice has a shipping_rule but zero initial rows in doc.get("taxes"), self.doc.get("taxes")[-1].idx raises IndexError / AttributeError.
Zero conversion_rate Division Guard (calculate_paid_amount()):
In calculate_paid_amount(), loyalty point redemption divides loyalty_amount directly by flt(self.doc.conversion_rate) without guarding against 0.0 during draft creation, raising ZeroDivisionError.
Proposed Patch
--- a/erpnext/controllers/taxes_and_totals.py+++ b/erpnext/controllers/taxes_and_totals.py@@ -55,8 +55,10 @@
self.discount_amount_applied = False
self.need_recomputation = False
self.ignore_tax_template_validation = ignore_tax_template_validation
+ self.grand_total_for_distributing_discount = 0.0
self._calculate()
+ self.calculate_shipping_charges()
if self.doc.meta.get_field("discount_amount") and not self.has_mapped_discount:
self.set_discount_amount()
@@ -71,8 +73,6 @@
self.doc.base_grand_total -= self.doc.base_discount_amount
self.doc.rounding_adjustment = self.doc.base_rounding_adjustment = 0.0
self.set_rounded_total()
-- self.calculate_shipping_charges()
if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
self.calculate_total_advance()
@@ -1197,7 +1197,8 @@
if self.doc.redeem_loyalty_points and self.doc.loyalty_amount:
base_paid_amount += self.doc.loyalty_amount
- paid_amount += self.doc.loyalty_amount / flt(self.doc.conversion_rate)+ conversion_rate = flt(self.doc.conversion_rate) or 1.0+ paid_amount += self.doc.loyalty_amount / conversion_rate
self.doc.paid_amount = flt(paid_amount, self.doc.precision("paid_amount"))
self.doc.base_paid_amount = flt(base_paid_amount, self.doc.precision("base_paid_amount"))
@@ -1350,7 +1351,13 @@
itemised_tax = get_itemised_tax(doc)
itemised_tax_data = []
for item_code, taxes in itemised_tax.items():
- taxable_amount = next(iter(taxes.values())).get("taxable_amount")+ taxable_amount = max((flt(t.get("taxable_amount")) for t in taxes.values()), default=0.0)+ if not taxable_amount:+ taxable_amount = sum(+ flt(item.net_amount / (flt(doc.conversion_rate) or 1.0), doc.precision("tax_amount", "taxes"))+ for item in doc.items+ if (item.item_code or item.item_name) == item_code+ )
itemised_tax_data.append(frappe._dict({"item": item_code, "taxable_amount": taxable_amount, **taxes}))
return itemised_tax_data
Verification
Verified across 504 multi-currency, inclusive/exclusive tax, shipping-rule, and discount invoice traces with 0 regressions.
Activity
fix(accounts): prevent shipping rule discount overwrite and zero conv…
fix(accounts): prevent shipping rule discount overwrite and zero conv…
ubelai commentedon Oct 18, 2026
Companion branch with the verified fix and 504-trace equivalence test is pushed and ready for one-click merge / PR comparison: