Taxes and totals calculation in party currency

This commit is contained in:
Nabin Hait
2015-02-20 14:40:35 +05:30
parent 81d96fdb60
commit e7679703cf
10 changed files with 2146 additions and 2036 deletions

View File

@@ -38,22 +38,46 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
this.show_item_wise_taxes();
},
validate_conversion_rate: function() {
this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, precision("conversion_rate"));
var conversion_rate_label = frappe.meta.get_label(this.frm.doc.doctype, "conversion_rate",
this.frm.doc.name);
var company_currency = this.get_company_currency();
if(!this.frm.doc.conversion_rate) {
frappe.throw(repl('%(conversion_rate_label)s' +
__(' is mandatory. Maybe Currency Exchange record is not created for ') +
'%(from_currency)s' + __(" to ") + '%(to_currency)s',
{
"conversion_rate_label": conversion_rate_label,
"from_currency": this.frm.doc.currency,
"to_currency": company_currency
}));
}
},
calculate_item_values: function() {
var me = this;
if (!this.discount_amount_applied) {
$.each(this.frm.doc["items"] || [], function(i, item) {
frappe.model.round_floats_in(item);
item.net_rate = item.rate;
item.amount = flt(item.rate * item.qty, precision("amount", item));
item.net_amount = item.amount;
item.item_tax_amount = 0.0;
$.each(["price_list_rate", "rate", "amount"], function(i, f) {
item["base_" + f] = flt(item[f] * me.frm.doc.conversion_rate, precision("base_" + f, item));
})
this.set_in_company_currency(item, ["price_list_rate", "rate", "amount", "net_rate", "net_amount"]);
});
}
},
set_in_company_currency: function(doc, fields) {
$.each(fields, function(i, f) {
doc["base_"+f] = flt(flt(doc[f], precision(f, doc)) * me.frm.doc.conversion_rate, precision("base_" + f, doc));
})
}
initialize_taxes: function() {
var me = this;
@@ -75,7 +99,12 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
},
determine_exclusive_rate: function() {
if(!in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"], this.frm.doc.doctype)) return;
var has_inclusive_tax = false;
$.each(me.frm.doc["taxes"] || [], function(i, row) {
if(cint(row.included_in_print_rate)) has_inclusive_tax = true;
})
if(has_inclusive_tax==false || !in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"], this.frm.doc.doctype))
return;
var me = this;
$.each(me.frm.doc["items"] || [], function(n, item) {
@@ -97,19 +126,21 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
});
if(cumulated_tax_fraction && !me.discount_amount_applied) {
item.base_amount = flt(
item.net_amount = flt(
(item.amount * me.frm.doc.conversion_rate) / (1 + cumulated_tax_fraction),
precision("base_amount", item));
precision("net_amount", item));
item.base_rate = flt(item.base_amount / item.qty, precision("base_rate", item));
item.net_rate = flt(item.net_amount / item.qty, precision("net_rate", item));
if(item.discount_percentage == 100) {
item.base_price_list_rate = item.base_rate;
item.base_rate = 0.0;
} else {
item.base_price_list_rate = flt(item.base_rate / (1 - item.discount_percentage / 100.0),
precision("base_price_list_rate", item));
}
this.set_in_company_currency(item, ["net_rate", "net_amount"]);
// if(item.discount_percentage == 100) {
// item.base_price_list_rate = item.base_rate;
// item.base_rate = 0.0;
// } else {
// item.base_price_list_rate = flt(item.base_rate / (1 - item.discount_percentage / 100.0),
// precision("base_price_list_rate", item));
// }
}
});
},
@@ -140,20 +171,21 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
_get_tax_rate: function(tax, item_tax_map) {
return (keys(item_tax_map).indexOf(tax.account_head) != -1) ?
flt(item_tax_map[tax.account_head], precision("rate", tax)) :
tax.rate;
flt(item_tax_map[tax.account_head], precision("rate", tax)) : tax.rate;
},
calculate_net_total: function() {
var me = this;
this.frm.doc.base_net_total = this.frm.doc.net_total = 0.0;
this.frm.doc.print_total = this.frm.doc.base_print_total = this.frm.doc.net_total = this.frm.doc.base_net_total = 0.0;
$.each(this.frm.doc["items"] || [], function(i, item) {
me.frm.doc.base_net_total += item.base_amount;
me.frm.doc.net_total += item.amount;
me.frm.doc.print_total += item.amount;
me.frm.doc.base_print_total += item.base_amount;
me.frm.doc.net_total += item.net_amount;
me.frm.doc.base_net_total += item.base_net_amount;
});
frappe.model.round_floats_in(this.frm.doc, ["base_net_total", "net_total"]);
frappe.model.round_floats_in(this.frm.doc, ["print_total", "base_print_total", "net_total", "base_net_total"]);
},
calculate_taxes: function() {
@@ -163,7 +195,7 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
// maintain actual tax rate based on idx
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
if (tax.charge_type == "Actual") {
actual_tax_dict[tax.idx] = flt(tax.rate, precision("tax_amount", tax));
actual_tax_dict[tax.idx] = flt(tax.tax_amount, precision("tax_amount", tax));
}
});
@@ -205,12 +237,10 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
// note: grand_total_for_current_item contains the contribution of
// item's amount, previously applied tax and the current tax on that item
if(i==0) {
tax.grand_total_for_current_item = flt(item.base_amount + current_tax_amount,
precision("total", tax));
tax.grand_total_for_current_item = flt(item.base_amount + current_tax_amount);
} else {
tax.grand_total_for_current_item =
flt(me.frm.doc["taxes"][i-1].grand_total_for_current_item + current_tax_amount,
precision("total", tax));
flt(me.frm.doc["taxes"][i-1].grand_total_for_current_item + current_tax_amount);
}
// in tax.total, accumulate grand total for each item
@@ -238,12 +268,12 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
if(tax.charge_type == "Actual") {
// distribute the tax amount proportionally to each item row
var actual = flt(tax.rate, precision("tax_amount", tax));
current_tax_amount = this.frm.doc.base_net_total ?
((item.base_amount / this.frm.doc.base_net_total) * actual) : 0.0;
var actual = flt(tax.tax_amount, precision("tax_amount", tax));
current_tax_amount = this.frm.doc.net_total ?
((item.net_amount / this.frm.doc.net_total) * actual) : 0.0;
} else if(tax.charge_type == "On Net Total") {
current_tax_amount = (tax_rate / 100.0) * item.base_amount;
current_tax_amount = (tax_rate / 100.0) * item.net_amount;
} else if(tax.charge_type == "On Previous Row Amount") {
current_tax_amount = (tax_rate / 100.0) *
@@ -254,14 +284,24 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
this.frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_for_current_item;
}
current_tax_amount = flt(current_tax_amount, precision("tax_amount", tax));
// current_tax_amount = flt(current_tax_amount, precision("tax_amount", tax));
// store tax breakup for each item
tax.item_wise_tax_detail[item.item_code || item.item_name] = [tax_rate, current_tax_amount];
this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount);
return current_tax_amount;
},
set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) {
// store tax breakup for each item
var key = item.item_code || item.item_name;
var item_wise_tax_amount = current_tax_amount * this.frm.doc.conversion_rate;
if (tax.item_wise_tax_detail.get(key))
item_wise_tax_amount += tax.item_wise_tax_detail[key][1]
tax.item_wise_tax_detail[key] = [tax_rate,flt(item_wise_tax_amount, precision("base_tax_amount", tax))]
},
round_off_totals: function(tax) {
tax.total = flt(tax.total, precision("total", tax));
tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax));
@@ -276,9 +316,55 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
tax.total = flt(tax.total + discount_amount_loss, precision("total", tax));
},
calculate_totals: function() {
// Changing sequence can cause roundiing issue and on-screen discrepency
var me = this;
var tax_count = this.frm.doc["taxes"] ? this.frm.doc["taxes"].length : 0;
this.frm.doc.grand_total = flt(tax_count ? this.frm.doc["taxes"][tax_count - 1].total : this.frm.doc.net_total);
if(in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"], this.frm.doc.doctype)) {
this.frm.doc.base_grand_total = (this.frm.doc.base_total_taxes_and_charges) ?
flt(this.frm.doc.grand_total * this.frm.doc.conversion_rate) : this.frm.doc.base_net_total;
} else {
// other charges added/deducted
this.frm.doc.taxes_and_charges_added = this.frm.doc.taxes_and_charges_deducted = 0.0;
if(tax_count) {
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
if in_list(["Valuation and Total", "Total"], tax.category) {
if(tax.add_deduct_tax == "Add") {
me.frm.doc.taxes_and_charges_added += flt(tax.tax_amount);
} else {
me.frm.doc.taxes_and_charges_deducted += flt(tax.tax_amount);
}
}
})
frappe.model.round_floats_in(this.frm.doc, ["taxes_and_charges_added", "taxes_and_charges_deducted"]);
}
this.frm.doc.grand_total = flt((this.frm.doc.taxes_and_charges_added || this.frm.doc.taxes_and_charges_deducted) ?
flt(this.frm.doc.grand_total * this.frm.doc.conversion_rate) : this.frm.doc.base_net_total);
this.set_in_company_currency(this.frm.doc, ["taxes_and_charges_added", "taxes_and_charges_deducted"]);
}
this.frm.doc.total_taxes_and_charges = flt(this.frm.doc.grand_total - this.frm.doc.net_total,
precision("total_taxes_and_charges"));
// Round grand total as per precision
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "base_grand_total"]);
// rounded totals
if(frappe.meta.get_docfield(this.frm.doc.doctype, "rounded_total", this.frm.doc.name)) {
this.frm.doc.rounded_total = Math.round(this.frm.doc.grand_total);
}
if(frappe.meta.get_docfield(this.frm.doc.doctype, "base_rounded_total", this.frm.doc.name)) {
this.frm.doc.base_rounded_total = Math.round(this.frm.doc.base_grand_total);
}
},
_cleanup: function() {
this.frm.doc.base_in_words = this.frm.doc.in_words = this.frm.doc.in_words = "";
this.frm.doc.base_in_words = this.frm.doc.in_words = "";
if(this.frm.doc["items"] && this.frm.doc["items"].length) {
if(!frappe.meta.get_docfield(this.frm.doc["items"][0].doctype, "item_tax_amount", this.frm.doctype)) {
@@ -288,7 +374,6 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
}
}
if(this.frm.doc["taxes"] && this.frm.doc["taxes"].length) {
var temporary_fields = ["tax_amount_for_current_item", "grand_total_for_current_item",
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]
@@ -307,65 +392,6 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
}
},
calculate_totals: function() {
// Changing sequence can cause roundiing issue and on-screen discrepency
var tax_count = this.frm.doc["taxes"] ? this.frm.doc["taxes"].length : 0;
this.frm.doc.base_grand_total = flt(tax_count ? this.frm.doc["taxes"][tax_count - 1].total : this.frm.doc.base_net_total);
this.frm.doc.base_total_taxes_and_charges = flt(this.frm.doc.base_grand_total - this.frm.doc.base_net_total,
precision("base_total_taxes_and_charges"));
if(in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"], this.frm.doc.doctype)) {
this.frm.doc.grand_total = (this.frm.doc.base_total_taxes_and_charges || this.frm.doc.discount_amount) ?
flt(this.frm.doc.base_grand_total / this.frm.doc.conversion_rate) : this.frm.doc.net_total;
this.frm.doc.total_taxes_and_charges = flt(this.frm.doc.grand_total - this.frm.doc.net_total
+ flt(this.frm.doc.discount_amount), precision("total_taxes_and_charges"));
} else {
// other charges added/deducted
this.frm.doc.base_taxes_and_charges_added = 0.0
this.frm.doc.base_taxes_and_charges_deducted = 0.0
if(tax_count) {
this.frm.doc.base_taxes_and_charges_added = frappe.utils.sum($.map(this.frm.doc["taxes"],
function(tax) { return (tax.add_deduct_tax == "Add"
&& in_list(["Valuation and Total", "Total"], tax.category)) ?
tax.tax_amount : 0.0; }));
this.frm.doc.base_taxes_and_charges_deducted = frappe.utils.sum($.map(this.frm.doc["taxes"],
function(tax) { return (tax.add_deduct_tax == "Deduct"
&& in_list(["Valuation and Total", "Total"], tax.category)) ?
tax.tax_amount : 0.0; }));
frappe.model.round_floats_in(this.frm.doc,
["base_taxes_and_charges_added", "base_taxes_and_charges_deducted"]);
}
this.frm.doc.grand_total = flt((this.frm.doc.base_taxes_and_charges_added || this.frm.doc.base_taxes_and_charges_deducted) ?
flt(this.frm.doc.base_grand_total / this.frm.doc.conversion_rate) : this.frm.doc.net_total);
this.frm.doc.total_taxes_and_charges = flt(this.frm.doc.grand_total - this.frm.doc.net_total,
precision("total_taxes_and_charges"));
this.frm.doc.taxes_and_charges_added = flt(this.frm.doc.base_taxes_and_charges_added /
this.frm.doc.conversion_rate, precision("taxes_and_charges_added"));
this.frm.doc.taxes_and_charges_deducted = flt(this.frm.doc.base_taxes_and_charges_deducted /
this.frm.doc.conversion_rate, precision("taxes_and_charges_deducted"));
}
// Round grand total as per precision
this.frm.doc.base_grand_total = flt(this.frm.doc.base_grand_total, precision("base_grand_total"));
this.frm.doc.grand_total = flt(this.frm.doc.grand_total, precision("grand_total"));
// rounded totals
if(frappe.meta.get_docfield(this.frm.doc.doctype, "base_rounded_total", this.frm.doc.name)) {
this.frm.doc.base_rounded_total = Math.round(this.frm.doc.base_grand_total);
}
if(frappe.meta.get_docfield(this.frm.doc.doctype, "rounded_total", this.frm.doc.name)) {
this.frm.doc.rounded_total = Math.round(this.frm.doc.grand_total);
}
},
apply_discount_amount: function() {
var me = this;
var distributed_amount = 0.0;
@@ -374,12 +400,15 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
this.frm.set_value("base_discount_amount",
flt(this.frm.doc.discount_amount * this.frm.doc.conversion_rate, precision("base_discount_amount")))
var grand_total_for_discount_amount = this.get_grand_total_for_discount_amount();
var total_for_discount_amount = this.get_total_for_discount_amount();
// calculate item amount after Discount Amount
if (grand_total_for_discount_amount) {
if (total_for_discount_amount) {
$.each(this.frm.doc["items"] || [], function(i, item) {
distributed_amount = flt(me.frm.doc.base_discount_amount) * item.base_amount / grand_total_for_discount_amount;
item.base_amount = flt(item.base_amount - distributed_amount, precision("base_amount", item));
distributed_amount = flt(me.frm.doc.discount_amount) * item.net_amount / total_for_discount_amount;
item.base_amount = flt(item.net_amount - distributed_amount, precision("base_amount", item));
item.net_rate = flt(item.net_amount / item.qty, precision("net_rate", item));
me.set_in_company_currency(item, ["net_rate", "net_amount"]);
});
this.discount_amount_applied = true;
@@ -390,34 +419,38 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
}
},
get_grand_total_for_discount_amount: function() {
get_total_for_discount_amount: function() {
var me = this;
var total_actual_tax = 0.0;
var actual_taxes_dict = {};
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
if (tax.charge_type == "Actual")
actual_taxes_dict[tax.idx] = tax.tax_amount;
else if (actual_taxes_dict[tax.row_id] !== null) {
actual_tax_amount = flt(actual_taxes_dict[tax.row_id]) * flt(tax.rate) / 100;
actual_taxes_dict[tax.idx] = actual_tax_amount;
}
});
if(this.apply_discount_amount == "Print Total") {
return this.net_total
} else {
var total_actual_tax = 0.0;
var actual_taxes_dict = {};
$.each(actual_taxes_dict, function(key, value) {
if (value)
total_actual_tax += value;
});
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
if (tax.charge_type == "Actual")
actual_taxes_dict[tax.idx] = tax.tax_amount;
else if (actual_taxes_dict[tax.row_id] !== null) {
actual_tax_amount = flt(actual_taxes_dict[tax.row_id]) * flt(tax.rate) / 100;
actual_taxes_dict[tax.idx] = actual_tax_amount;
}
});
grand_total_for_discount_amount = flt(this.frm.doc.base_grand_total - total_actual_tax,
precision("base_grand_total"));
return grand_total_for_discount_amount;
$.each(actual_taxes_dict, function(key, value) {
if (value)
total_actual_tax += value;
});
return flt(this.frm.doc.grand_total - total_actual_tax, precision("grand_total"));
}
},
calculate_total_advance: function(update_paid_amount) {
this.frm.doc.total_advance = flt(frappe.utils.sum(
$.map(this.frm.doc["advances"] || [], function(adv) { return adv.allocated_amount })
), precision("total_advance"));
var total_allocated_amount = frappe.utils.sum($.map(this.frm.doc["advances"] || [], function(adv) {
return flt(adv.allocated_amount, precision("allocated_amount", adv))
}));
this.frm.doc.total_advance = flt(total_allocated_amount, precision("total_advance"));
this.calculate_outstanding_amount(update_paid_amount);
}