mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-02 11:49:10 +00:00
fix: improved rounding adjustment when applying discount (backport #46720)
* fix: improved rounding adjustment when applying discount (#46720) * fix: rounding adjustment in apply_discount_amount taxes_and_totals * refactor: minor changes * fix: set the rounding difference while calculating tax total in the last tax row and add test case * fix: failing test case * fix: made changes in get_total_for_discount_amount in taxes_and_totals * fix: failing test cases * fix: changes as per review * refactor: remove unnecessary use of flt * refactor: improve logic * refactor: minor change * refactor: minor changes * fix: add a test case for applying discount with previous row total in taxes * fix: failing test case * refactor: flatter code, remove `flt` usage for accuracy --------- Co-authored-by: Vishakh Desai <78500008+vishakhdesai@users.noreply.github.com> Co-authored-by: Sagar Vora <sagar@resilient.tech>
This commit is contained in:
@@ -343,7 +343,6 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
||||
|
||||
calculate_taxes() {
|
||||
var me = this;
|
||||
this.frm.doc.rounding_adjustment = 0;
|
||||
var actual_tax_dict = {};
|
||||
|
||||
// maintain actual tax rate based on idx
|
||||
@@ -605,7 +604,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
||||
}
|
||||
|
||||
this.frm.doc.total_taxes_and_charges = flt(this.frm.doc.grand_total - this.frm.doc.net_total
|
||||
- flt(this.frm.doc.rounding_adjustment), precision("total_taxes_and_charges"));
|
||||
- flt(this.frm.doc.grand_total_diff), precision("total_taxes_and_charges"));
|
||||
|
||||
this.set_in_company_currency(this.frm.doc, ["total_taxes_and_charges", "rounding_adjustment"]);
|
||||
|
||||
@@ -627,6 +626,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
||||
if (cint(disable_rounded_total)) {
|
||||
this.frm.doc.rounded_total = 0;
|
||||
this.frm.doc.base_rounded_total = 0;
|
||||
this.frm.doc.rounding_adjustment = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -695,22 +695,26 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
||||
return;
|
||||
}
|
||||
|
||||
var total_for_discount_amount = this.get_total_for_discount_amount();
|
||||
var net_total = 0;
|
||||
const total_for_discount_amount = this.get_total_for_discount_amount();
|
||||
let net_total = 0;
|
||||
let expected_net_total = 0;
|
||||
|
||||
// calculate item amount after Discount Amount
|
||||
if (total_for_discount_amount) {
|
||||
$.each(this.frm._items || [], function(i, item) {
|
||||
distributed_amount = flt(me.frm.doc.discount_amount) * item.net_amount / total_for_discount_amount;
|
||||
item.net_amount = flt(item.net_amount - distributed_amount, precision("net_amount", item));
|
||||
|
||||
const adjusted_net_amount = item.net_amount - distributed_amount;
|
||||
expected_net_total += adjusted_net_amount
|
||||
item.net_amount = flt(adjusted_net_amount, precision("net_amount", item));
|
||||
net_total += item.net_amount;
|
||||
|
||||
// discount amount rounding loss adjustment if no taxes
|
||||
if ((!(me.frm.doc.taxes || []).length || total_for_discount_amount==me.frm.doc.net_total || (me.frm.doc.apply_discount_on == "Net Total"))
|
||||
&& i == (me.frm._items || []).length - 1) {
|
||||
var discount_amount_loss = flt(me.frm.doc.net_total - net_total
|
||||
- me.frm.doc.discount_amount, precision("net_total"));
|
||||
item.net_amount = flt(item.net_amount + discount_amount_loss,
|
||||
precision("net_amount", item));
|
||||
// discount amount rounding adjustment
|
||||
// assignment to rounding_difference is intentional
|
||||
const rounding_difference = flt(expected_net_total - net_total, precision("net_total"));
|
||||
if (rounding_difference) {
|
||||
item.net_amount = flt(item.net_amount + rounding_difference, precision("net_amount", item));
|
||||
net_total += rounding_difference;
|
||||
}
|
||||
item.net_rate = item.qty ? flt(item.net_amount / item.qty, precision("net_rate", item)) : 0;
|
||||
me.set_in_company_currency(item, ["net_rate", "net_amount"]);
|
||||
@@ -723,29 +727,38 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
||||
}
|
||||
|
||||
get_total_for_discount_amount() {
|
||||
if(this.frm.doc.apply_discount_on == "Net Total") {
|
||||
if(this.frm.doc.apply_discount_on == "Net Total")
|
||||
return this.frm.doc.net_total;
|
||||
} else {
|
||||
var total_actual_tax = 0.0;
|
||||
var actual_taxes_dict = {};
|
||||
|
||||
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
|
||||
if (["Actual", "On Item Quantity"].includes(tax.charge_type)) {
|
||||
var tax_amount = (tax.category == "Valuation") ? 0.0 : tax.tax_amount;
|
||||
tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
|
||||
actual_taxes_dict[tax.idx] = tax_amount;
|
||||
} else if (actual_taxes_dict[tax.row_id] !== null) {
|
||||
var actual_tax_amount = flt(actual_taxes_dict[tax.row_id]) * flt(tax.rate) / 100;
|
||||
actual_taxes_dict[tax.idx] = actual_tax_amount;
|
||||
}
|
||||
});
|
||||
let total_actual_tax = 0.0;
|
||||
let actual_taxes_dict = {};
|
||||
|
||||
$.each(actual_taxes_dict, function(key, value) {
|
||||
if (value) total_actual_tax += value;
|
||||
});
|
||||
function update_actual_taxes_dict(tax, tax_amount) {
|
||||
if (tax.add_deduct_tax == "Deduct") tax_amount *= -1;
|
||||
if (tax.category != "Valuation") total_actual_tax += tax_amount;
|
||||
|
||||
return flt(this.frm.doc.grand_total - total_actual_tax, precision("grand_total"));
|
||||
actual_taxes_dict[tax.idx] = {
|
||||
tax_amount: tax_amount,
|
||||
cumulative_total: total_actual_tax
|
||||
};
|
||||
}
|
||||
|
||||
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
|
||||
if (["Actual", "On Item Quantity"].includes(tax.charge_type)) {
|
||||
update_actual_taxes_dict(tax, tax.tax_amount);
|
||||
return;
|
||||
}
|
||||
|
||||
const base_row = actual_taxes_dict[tax.row_id];
|
||||
if (!base_row) return;
|
||||
|
||||
// if charge type is 'On Previous Row Amount', calculate tax on previous row amount
|
||||
// else (On Previous Row Total) calculate tax on cumulative total
|
||||
const base_tax_amount = tax.charge_type == "On Previous Row Amount" ? base_row["tax_amount"]: base_row["cumulative_total"];
|
||||
update_actual_taxes_dict(tax, base_tax_amount * tax.rate / 100);
|
||||
});
|
||||
|
||||
return this.frm.doc.grand_total - total_actual_tax;
|
||||
}
|
||||
|
||||
calculate_total_advance(update_paid_amount) {
|
||||
|
||||
Reference in New Issue
Block a user