Merge pull request #3767 from nabinhait/tax_calc

[fix] Tax calculation while discount applied on net total
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 2e64f99..6c67379 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -790,6 +790,58 @@
 		
 		set_perpetual_inventory(0)
 		
+	def test_discount_on_net_total(self):
+		si = frappe.copy_doc(test_records[2])
+		si.apply_discount_on = "Net Total"
+		si.discount_amount = 625
+		si.insert()
+
+		expected_values = {
+			"keys": ["price_list_rate", "discount_percentage", "rate", "amount",
+				"base_price_list_rate", "base_rate", "base_amount", 
+				"net_rate", "base_net_rate", "net_amount", "base_net_amount"],
+			"_Test Item Home Desktop 100": [50, 0, 50, 500, 50, 50, 500, 25, 25, 250, 250],
+			"_Test Item Home Desktop 200": [150, 0, 150, 750, 150, 150, 750, 75, 75, 375, 375],
+		}
+
+		# check if children are saved
+		self.assertEquals(len(si.get("items")),
+			len(expected_values)-1)
+
+		# check if item values are calculated
+		for d in si.get("items"):
+			for i, k in enumerate(expected_values["keys"]):
+				self.assertEquals(d.get(k), expected_values[d.item_code][i])
+
+		# check net total
+		self.assertEquals(si.base_total, 1250)
+		self.assertEquals(si.total, 1250)
+		self.assertEquals(si.base_net_total, 625)
+		self.assertEquals(si.net_total, 625)
+
+		# check tax calculation
+		expected_values = {
+			"keys": ["tax_amount", "tax_amount_after_discount_amount", 
+				"base_tax_amount_after_discount_amount"],
+			"_Test Account Shipping Charges - _TC": [100, 100, 100],
+			"_Test Account Customs Duty - _TC": [62.5, 62.5, 62.5],
+			"_Test Account Excise Duty - _TC": [70, 70, 70],
+			"_Test Account Education Cess - _TC": [1.4, 1.4, 1.4],
+			"_Test Account S&H Education Cess - _TC": [.7, 0.7, 0.7],
+			"_Test Account CST - _TC": [17.2, 17.2, 17.2],
+			"_Test Account VAT - _TC": [78.13, 78.13, 78.13],
+			"_Test Account Discount - _TC": [-95.49, -95.49, -95.49]
+		}
+
+		for d in si.get("taxes"):
+			for i, k in enumerate(expected_values["keys"]):
+				self.assertEquals(d.get(k), expected_values[d.account_head][i])
+				
+		
+		self.assertEquals(si.total_taxes_and_charges, 234.44)
+		self.assertEquals(si.base_grand_total, 859.44)
+		self.assertEquals(si.grand_total, 859.44)
+		
 
 def create_sales_invoice(**args):
 	si = frappe.new_doc("Sales Invoice")
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 6b59cea..d526f66 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -219,7 +219,7 @@
 
 					# 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.discount_amount and self.doc.apply_discount_on == "Grand Total":
 							self.adjust_discount_amount_loss(tax)
 
 
@@ -303,9 +303,9 @@
 			for tax in self.doc.get("taxes"):
 				if tax.category in ["Valuation and Total", "Total"]:
 					if tax.add_deduct_tax == "Add":
-						self.doc.taxes_and_charges_added += flt(tax.tax_amount)
+						self.doc.taxes_and_charges_added += flt(tax.tax_amount_after_discount_amount)
 					else:
-						self.doc.taxes_and_charges_deducted += flt(tax.tax_amount)
+						self.doc.taxes_and_charges_deducted += flt(tax.tax_amount_after_discount_amount)
 
 			self.doc.round_floats_in(self.doc, ["taxes_and_charges_added", "taxes_and_charges_deducted"])
 
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 78e1609..de26ff3 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -184,4 +184,5 @@
 erpnext.patches.v5_4.fix_reserved_qty_and_sle_for_packed_items # 30-07-2015
 execute:frappe.reload_doctype("Leave Type")
 execute:frappe.db.sql("update `tabLeave Type` set include_holiday=0")
-erpnext.patches.v5_4.set_root_and_report_type
\ No newline at end of file
+erpnext.patches.v5_4.set_root_and_report_type
+erpnext.patches.v5_4.notify_system_managers_regarding_wrong_tax_calculation
diff --git a/erpnext/patches/v5_4/notify_system_managers_regarding_wrong_tax_calculation.py b/erpnext/patches/v5_4/notify_system_managers_regarding_wrong_tax_calculation.py
new file mode 100644
index 0000000..8096a37
--- /dev/null
+++ b/erpnext/patches/v5_4/notify_system_managers_regarding_wrong_tax_calculation.py
@@ -0,0 +1,39 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.email import sendmail_to_system_managers
+from frappe.utils import get_url_to_form
+
+def execute():
+	wrong_records = []
+	for dt in ("Quotation", "Sales Order", "Delivery Note", "Sales Invoice", 
+		"Purchase Order", "Purchase Receipt", "Purchase Invoice"):
+			records = frappe.db.sql_list("""select name from `tab{0}` 
+				where apply_discount_on = 'Net Total' and ifnull(discount_amount, 0) != 0
+				and modified >= '2015-02-17' and docstatus=1""".format(dt))
+		
+			if records:
+				records = [get_url_to_form(dt, d) for d in records]
+				wrong_records.append([dt, records])
+				
+	if wrong_records:
+		content = """Dear System Manager,
+
+Due to an error related to Discount Amount on Net Total, tax calculation might be wrong in the following records. We did not fix the tax amount automatically because it can corrupt the entries, so we request you to check these records and amend if you found the calculation wrong.
+
+Please check following Entries:
+
+%s
+
+
+Regards,
+
+Administrator""" % "\n".join([(d[0] + ": " + ", ".join(d[1])) for d in wrong_records])
+
+		sendmail_to_system_managers("[Important] [ERPNext] Tax calculation might be wrong, please check.", content)
+		
+		print "="*50
+		print content
+		print "="*50
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 1e238d6..0b3ca7f 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -256,7 +256,8 @@
 					me.round_off_totals(tax);
 
 					// adjust Discount Amount loss in last tax iteration
-					if ((i == me.frm.doc["taxes"].length - 1) && me.discount_amount_applied && me.frm.doc.apply_discount_on == "Grand Total")
+					if ((i == me.frm.doc["taxes"].length - 1) && me.discount_amount_applied 
+							&& me.frm.doc.apply_discount_on == "Grand Total" && me.frm.doc.discount_amount)
 						me.adjust_discount_amount_loss(tax);
 				}
 			});
@@ -365,9 +366,9 @@
 				$.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);
+							me.frm.doc.taxes_and_charges_added += flt(tax.tax_amount_after_discount_amount);
 						} else {
-							me.frm.doc.taxes_and_charges_deducted += flt(tax.tax_amount);
+							me.frm.doc.taxes_and_charges_deducted += flt(tax.tax_amount_after_discount_amount);
 						}
 					}
 				})