Merge branch 'master' of github.com:webnotes/erpnext
diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py
index 47e3195..b31d549 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/accounts/doctype/sales_invoice/sales_invoice.py
@@ -8,7 +8,7 @@
 # 
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU General Public License for more details.
 # 
 # You should have received a copy of the GNU General Public License
diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py
index fb290d2..1f165f0 100644
--- a/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -38,72 +38,199 @@
 		si.insert()
 		si.submit()
 		
-		self.assertEquals(webnotes.conn.get_value("Time Log Batch", "_T-Time Log Batch-00001", "status"), 
-			"Billed")
+		self.assertEquals(webnotes.conn.get_value("Time Log Batch", "_T-Time Log Batch-00001",
+		 	"status"), "Billed")
 
 		self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), 
 			"Billed")
 
 		si.cancel()
 
-		self.assertEquals(webnotes.conn.get_value("Time Log Batch", "_T-Time Log Batch-00001", "status"), 
-			"Submitted")
+		self.assertEquals(webnotes.conn.get_value("Time Log Batch", "_T-Time Log Batch-00001", 
+			"status"), "Submitted")
 
 		self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), 
 			"Batched for Billing")
 			
+	def test_sales_invoice_gl_entry_without_aii(self):
+		si = webnotes.bean(webnotes.copy_doclist(test_records[1]))
+		si.insert()
+		si.submit()
 		
+		webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
+		
+		gl_entries = webnotes.conn.sql("""select account, debit, credit
+			from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
+			order by account asc""", si.doc.name, as_dict=1)
+		self.assertTrue(gl_entries)
+		expected_values = sorted([
+			[si.doc.debit_to, 630.0, 0.0],
+			[test_records[1][1]["income_account"], 0.0, 500.0],
+			[test_records[1][2]["account_head"], 0.0, 80.0],
+			[test_records[1][3]["account_head"], 0.0, 50.0],
+		])
+		
+		for i, gle in enumerate(gl_entries):
+			self.assertEquals(expected_values[i][0], gle.account)
+			self.assertEquals(expected_values[i][1], gle.debit)
+			self.assertEquals(expected_values[i][2], gle.credit)
+		
+	def test_sales_invoice_gl_entry_with_aii(self):
+		webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
+		
+		self._insert_purchase_receipt()
+		dn = self._insert_delivery_note()
+		
+		si_against_dn = webnotes.copy_doclist(test_records[1])
+		si_against_dn[1]["delivery_note"] = dn.doc.name
+		si = webnotes.bean(si_against_dn)
+		si.insert()
+		si.submit()
+		
+		gl_entries = webnotes.conn.sql("""select account, debit, credit
+			from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
+			order by account asc""", si.doc.name, as_dict=1)
+		self.assertTrue(gl_entries)
+		
+		expected_values = sorted([
+			[si.doc.debit_to, 630.0, 0.0],
+			[test_records[1][1]["income_account"], 0.0, 500.0],
+			[test_records[1][2]["account_head"], 0.0, 80.0],
+			[test_records[1][3]["account_head"], 0.0, 50.0],
+			["Stock Delivered But Not Billed - _TC", 0.0, 375.0],
+			[test_records[1][1]["expense_account"], 375.0, 0.0]
+		])
+		print expected_values
+		print gl_entries
+		for i, gle in enumerate(gl_entries):
+			self.assertEquals(expected_values[i][0], gle.account)
+			self.assertEquals(expected_values[i][1], gle.debit)
+			self.assertEquals(expected_values[i][2], gle.credit)
+			
+		webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
+		
+		
+	def _insert_purchase_receipt(self):
+		from stock.doctype.purchase_receipt.test_purchase_receipt import test_records \
+			as pr_test_records
+		pr = webnotes.bean(copy=pr_test_records[0])
+		pr.run_method("calculate_taxes_and_totals")
+		pr.insert()
+		pr.submit()
+		
+	def _insert_delivery_note(self):
+		from stock.doctype.delivery_note.test_delivery_note import test_records \
+			as dn_test_records
+		dn = webnotes.bean(copy=dn_test_records[0])
+		dn.insert()
+		dn.submit()
+		return dn
 		
 test_dependencies = ["Journal Voucher"]
 
-test_records = [[
-	{
-		"naming_series": "_T-Sales Invoice-",
-		"company": "_Test Company", 
-		"conversion_rate": 1.0, 
-		"currency": "INR", 
-		"debit_to": "_Test Customer - _TC",
-		"customer": "_Test Customer",
-		"customer_name": "_Test Customer",
-		"doctype": "Sales Invoice", 
-		"due_date": "2013-01-23", 
-		"fiscal_year": "_Test Fiscal Year 2013", 
-		"grand_total": 561.8, 
-		"grand_total_export": 561.8, 
-		"net_total": 500.0, 
-		"plc_conversion_rate": 1.0, 
-		"posting_date": "2013-01-23", 
-		"price_list_currency": "INR", 
-		"price_list_name": "_Test Price List", 
-		"territory": "_Test Territory"
-	}, 
-	{
-		"amount": 500.0, 
-		"basic_rate": 500.0, 
-		"description": "138-CMS Shoe", 
-		"doctype": "Sales Invoice Item", 
-		"export_amount": 500.0, 
-		"export_rate": 500.0, 
-		"income_account": "Sales - _TC",
-		"cost_center": "_Test Cost Center - _TC",
-		"item_name": "138-CMS Shoe", 
-		"parentfield": "entries",
-		"qty": 1.0
-	}, 
-	{
-		"account_head": "_Test Account VAT - _TC", 
-		"charge_type": "On Net Total", 
-		"description": "VAT", 
-		"doctype": "Sales Taxes and Charges", 
-		"parentfield": "other_charges",
-		"tax_amount": 30.0,
-	}, 
-	{
-		"account_head": "_Test Account Service Tax - _TC", 
-		"charge_type": "On Net Total", 
-		"description": "Service Tax", 
-		"doctype": "Sales Taxes and Charges", 
-		"parentfield": "other_charges",
-		"tax_amount": 31.8,
-	}
-]]
\ No newline at end of file
+test_records = [
+	[
+		{
+			"naming_series": "_T-Sales Invoice-",
+			"company": "_Test Company", 
+			"conversion_rate": 1.0, 
+			"currency": "INR", 
+			"debit_to": "_Test Customer - _TC",
+			"customer": "_Test Customer",
+			"customer_name": "_Test Customer",
+			"doctype": "Sales Invoice", 
+			"due_date": "2013-01-23", 
+			"fiscal_year": "_Test Fiscal Year 2013", 
+			"grand_total": 561.8, 
+			"grand_total_export": 561.8, 
+			"net_total": 500.0, 
+			"plc_conversion_rate": 1.0, 
+			"posting_date": "2013-01-23", 
+			"price_list_currency": "INR", 
+			"price_list_name": "_Test Price List", 
+			"territory": "_Test Territory"
+		}, 
+		{
+			"amount": 500.0, 
+			"basic_rate": 500.0, 
+			"description": "138-CMS Shoe", 
+			"doctype": "Sales Invoice Item", 
+			"export_amount": 500.0, 
+			"export_rate": 500.0, 
+			"income_account": "Sales - _TC",
+			"cost_center": "_Test Cost Center - _TC",
+			"item_name": "138-CMS Shoe", 
+			"parentfield": "entries",
+			"qty": 1.0
+		}, 
+		{
+			"account_head": "_Test Account VAT - _TC", 
+			"charge_type": "On Net Total", 
+			"description": "VAT", 
+			"doctype": "Sales Taxes and Charges", 
+			"parentfield": "other_charges",
+			"tax_amount": 30.0,
+		}, 
+		{
+			"account_head": "_Test Account Service Tax - _TC", 
+			"charge_type": "On Net Total", 
+			"description": "Service Tax", 
+			"doctype": "Sales Taxes and Charges", 
+			"parentfield": "other_charges",
+			"tax_amount": 31.8,
+		}
+	],
+	[
+		{
+			"naming_series": "_T-Sales Invoice-",
+			"company": "_Test Company", 
+			"conversion_rate": 1.0, 
+			"currency": "INR", 
+			"debit_to": "_Test Customer - _TC",
+			"customer": "_Test Customer",
+			"customer_name": "_Test Customer",
+			"doctype": "Sales Invoice", 
+			"due_date": "2013-01-23", 
+			"fiscal_year": "_Test Fiscal Year 2013", 
+			"grand_total": 630.0, 
+			"grand_total_export": 630.0, 
+			"net_total": 500.0, 
+			"plc_conversion_rate": 1.0, 
+			"posting_date": "2013-03-07", 
+			"price_list_currency": "INR", 
+			"price_list_name": "_Test Price List", 
+			"territory": "_Test Territory"
+		}, 
+		{
+			"item_code": "_Test Item",
+			"item_name": "_Test Item", 
+			"description": "_Test Item", 
+			"doctype": "Sales Invoice Item", 
+			"parentfield": "entries",
+			"qty": 1.0,
+			"basic_rate": 500.0,
+			"amount": 500.0, 
+			"export_rate": 500.0, 
+			"export_amount": 500.0, 
+			"income_account": "Sales - _TC",
+			"expense_account": "_Test Account Cost for Goods Sold",
+			"cost_center": "_Test Cost Center - _TC",
+		}, 
+		{
+			"account_head": "_Test Account VAT - _TC", 
+			"charge_type": "On Net Total", 
+			"description": "VAT", 
+			"doctype": "Sales Taxes and Charges", 
+			"parentfield": "other_charges",
+			"tax_amount": 80.0,
+		}, 
+		{
+			"account_head": "_Test Account Service Tax - _TC", 
+			"charge_type": "On Net Total", 
+			"description": "Service Tax", 
+			"doctype": "Sales Taxes and Charges", 
+			"parentfield": "other_charges",
+			"tax_amount": 50.0,
+		}
+	],
+]
\ No newline at end of file
diff --git a/accounts/general_ledger.py b/accounts/general_ledger.py
index 215c351..8e0f408 100644
--- a/accounts/general_ledger.py
+++ b/accounts/general_ledger.py
@@ -16,7 +16,7 @@
 
 from __future__ import unicode_literals
 import webnotes
-from webnotes.utils import flt, cstr
+from webnotes.utils import flt, cstr, now
 from webnotes.model.doc import Document
 
 def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, 
@@ -109,5 +109,7 @@
 		 	(total_debit - total_credit), raise_exception=1)
 
 def set_as_cancel(voucher_type, voucher_no):
-	webnotes.conn.sql("""update `tabGL Entry` set is_cancelled='Yes' 
-		where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
\ No newline at end of file
+	webnotes.conn.sql("""update `tabGL Entry` set is_cancelled='Yes',
+		modified=%s, modified_by=%s
+		where voucher_type=%s and voucher_no=%s""", 
+		(now(), webnotes.session.user, voucher_type, voucher_no))
\ No newline at end of file
diff --git a/accounts/page/financial_analytics/financial_analytics.js b/accounts/page/financial_analytics/financial_analytics.js
index f0bafdb..f714549 100644
--- a/accounts/page/financial_analytics/financial_analytics.js
+++ b/accounts/page/financial_analytics/financial_analytics.js
@@ -71,9 +71,11 @@
 	setup_filters: function() {
 		var me = this;
 		this._super();
-		this.filter_inputs.pl_or_bs.change(function() {
-			me.filter_inputs.refresh.click();
-		}).add_options($.map(wn.report_dump.data["Cost Center"], function(v) {return v.name;}));
+		this.trigger_refresh_on_change(["pl_or_bs"]);
+		
+		this.filter_inputs.pl_or_bs
+			.add_options($.map(wn.report_dump.data["Cost Center"], function(v) {return v.name;}));
+
 		this.setup_plot_check();
 	},
 	init_filter_values: function() {
diff --git a/accounts/page/general_ledger/general_ledger.js b/accounts/page/general_ledger/general_ledger.js
index 8f6b598..4a3f21e 100644
--- a/accounts/page/general_ledger/general_ledger.js
+++ b/accounts/page/general_ledger/general_ledger.js
@@ -108,7 +108,7 @@
 		// filter accounts options by company
 		this.filter_inputs.company.change(function() {
 			me.setup_account_filter(this);
-			me.filter_inputs.refresh.click();
+			me.set_route()
 		});
 		
 		this.filter_inputs.account.change(function() {
diff --git a/buying/page/purchase_analytics/purchase_analytics.js b/buying/page/purchase_analytics/purchase_analytics.js
index 7d8171e..fc082ea 100644
--- a/buying/page/purchase_analytics/purchase_analytics.js
+++ b/buying/page/purchase_analytics/purchase_analytics.js
@@ -120,19 +120,9 @@
 	setup_filters: function() {
 		var me = this;
 		this._super();
-
-		this.filter_inputs.value_or_qty.change(function() {
-			me.filter_inputs.refresh.click();
-		});
-
-		this.filter_inputs.tree_type.change(function() {
-			me.filter_inputs.refresh.click();
-		});
 		
-		this.filter_inputs.based_on.change(function() {
-			me.filter_inputs.refresh.click();
-		});
-		
+		this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on"]);
+
 		this.show_zero_check()		
 		this.setup_plot_check();
 	},
diff --git a/selling/doctype/sales_common/sales_common.py b/selling/doctype/sales_common/sales_common.py
index 47d139f..12ae4a8 100644
--- a/selling/doctype/sales_common/sales_common.py
+++ b/selling/doctype/sales_common/sales_common.py
@@ -341,12 +341,10 @@
 	# ========================================================================
 	# it indicates % contribution of sales person in sales
 	def get_allocated_sum(self,obj):
-		sum = 0
-		for d in getlist(obj.doclist,'sales_team'):
-			sum += flt(d.allocated_percentage)
-		if (flt(sum) != 100) and getlist(obj.doclist,'sales_team'):
-			msgprint("Total Allocated % of Sales Persons should be 100%")
-			raise Exception
+		sales_team_list = obj.doclist.get({"parentfield": "sales_team"})
+		total_allocation = sum([flt(d.allocated_percentage) for d in sales_team_list])
+		if sales_team_list and total_allocation != 100.0:
+			msgprint("Total Allocated %% of Sales Persons should be 100%", raise_exception=True)
 			
 	# Check Conversion Rate (i.e. it will not allow conversion rate to be 1 for Currency other than default currency set in Global Defaults)
 	# ===========================================================================
diff --git a/selling/page/sales_analytics/sales_analytics.js b/selling/page/sales_analytics/sales_analytics.js
index 499c6c0..0b35af5 100644
--- a/selling/page/sales_analytics/sales_analytics.js
+++ b/selling/page/sales_analytics/sales_analytics.js
@@ -122,18 +122,8 @@
 	setup_filters: function() {
 		var me = this;
 		this._super();
-
-		this.filter_inputs.value_or_qty.change(function() {
-			me.filter_inputs.refresh.click();
-		});
-
-		this.filter_inputs.tree_type.change(function() {
-			me.filter_inputs.refresh.click();
-		});
 		
-		this.filter_inputs.based_on.change(function() {
-			me.filter_inputs.refresh.click();
-		});
+		this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on"]);
 
 		this.show_zero_check()		
 		this.setup_plot_check();
diff --git a/stock/doctype/delivery_note/test_delivery_note.py b/stock/doctype/delivery_note/test_delivery_note.py
index c2bb5d0..acdf8b9 100644
--- a/stock/doctype/delivery_note/test_delivery_note.py
+++ b/stock/doctype/delivery_note/test_delivery_note.py
@@ -109,7 +109,7 @@
 			"description": "CPU", 
 			"doctype": "Delivery Note Item", 
 			"item_code": "_Test Item", 
-			"item_name": "CPU", 
+			"item_name": "_Test Item", 
 			"parentfield": "delivery_note_details", 
 			"qty": 5.0, 
 			"basic_rate": 100.0,
diff --git a/stock/doctype/stock_ledger/stock_ledger.py b/stock/doctype/stock_ledger/stock_ledger.py
index 05fc0e0..5dff992 100644
--- a/stock/doctype/stock_ledger/stock_ledger.py
+++ b/stock/doctype/stock_ledger/stock_ledger.py
@@ -17,7 +17,7 @@
 from __future__ import unicode_literals
 import webnotes
 
-from webnotes.utils import add_days, cstr, flt, nowdate, cint
+from webnotes.utils import add_days, cstr, flt, nowdate, cint, now
 from webnotes.model.doc import Document
 from webnotes.model.bean import getlist
 from webnotes.model.code import get_obj
@@ -49,7 +49,7 @@
 				serial_nos = get_valid_serial_nos(d.serial_no)
 				for s in serial_nos:
 					s = s.strip()
-					sr_war = sql("select warehouse,name from `tabSerial No` where name = '%s'" % (s))
+					sr_war = webnotes.conn.sql("select warehouse,name from `tabSerial No` where name = '%s'" % (s))
 					if not sr_war:
 						msgprint("Serial No %s does not exists"%s, raise_exception = 1)
 					elif not sr_war[0][0]:
@@ -81,7 +81,7 @@
 				
 
 	def set_pur_serial_no_values(self, obj, serial_no, d, s, new_rec, rejected=None):
-		item_details = sql("""select item_group, warranty_period 
+		item_details = webnotes.conn.sql("""select item_group, warranty_period 
 			from `tabItem` where name = '%s' and (ifnull(end_of_life,'')='' or 
 			end_of_life = '0000-00-00' or end_of_life > now()) """ %(d.item_code), as_dict=1)
 		
@@ -112,7 +112,7 @@
 
 
 	def update_serial_purchase_details(self, obj, d, serial_no, is_submit, purpose = '', rejected=None):
-		exists = sql("select name, status, docstatus from `tabSerial No` where name = '%s'" % (serial_no))
+		exists = webnotes.conn.sql("select name, status, docstatus from `tabSerial No` where name = '%s'" % (serial_no))
 		if is_submit:
 			if exists and exists[0][2] != 2 and purpose not in ['Material Transfer', 'Sales Return']:
 				msgprint("Serial No: %s already %s" % (serial_no, exists and exists[0][1]), raise_exception = 1)
@@ -126,15 +126,15 @@
 			if exists and exists[0][1] == 'Delivered' and exists[0][2] != 2:
 				msgprint("Serial No: %s is already delivered, you can not cancel the document." % serial_no, raise_exception=1)
 			elif purpose == 'Material Transfer':
-				sql("update `tabSerial No` set status = 'In Store', purchase_document_type = '', purchase_document_no = '', warehouse = '%s' where name = '%s'" % (d.s_warehouse, serial_no))				
+				webnotes.conn.sql("update `tabSerial No` set status = 'In Store', purchase_document_type = '', purchase_document_no = '', warehouse = '%s' where name = '%s'" % (d.s_warehouse, serial_no))				
 			elif purpose == 'Sales Return':
-				sql("update `tabSerial No` set status = 'Delivered', purchase_document_type = '', purchase_document_no = '' where name = '%s'" % serial_no)
+				webnotes.conn.sql("update `tabSerial No` set status = 'Delivered', purchase_document_type = '', purchase_document_no = '' where name = '%s'" % serial_no)
 			else:
-				sql("update `tabSerial No` set docstatus = 2, status = 'Not in Use', purchase_document_type = '', purchase_document_no = '', purchase_date = null, purchase_rate = 0, supplier = null, supplier_name = '', supplier_address = '', warehouse = '' where name = '%s'" % serial_no)
+				webnotes.conn.sql("update `tabSerial No` set docstatus = 2, status = 'Not in Use', purchase_document_type = '', purchase_document_no = '', purchase_date = null, purchase_rate = 0, supplier = null, supplier_name = '', supplier_address = '', warehouse = '' where name = '%s'" % serial_no)
 
 
 	def check_serial_no_exists(self, serial_no, item_code):
-		chk = sql("select name, status, docstatus, item_code from `tabSerial No` where name = %s", (serial_no), as_dict=1)
+		chk = webnotes.conn.sql("select name, status, docstatus, item_code from `tabSerial No` where name = %s", (serial_no), as_dict=1)
 		if not chk:
 			msgprint("Serial No: %s does not exists in the system" % serial_no, raise_exception=1)
 		elif chk and chk[0]['item_code'] != item_code:
@@ -169,7 +169,7 @@
 			self.check_serial_no_exists(serial_no, d.item_code)
 			self.set_delivery_serial_no_values(obj, serial_no)
 		else:
-			sql("update `tabSerial No` set docstatus = 0, status = 'In Store', delivery_document_type = '', delivery_document_no = '', delivery_date = null, customer = null, customer_name = '', delivery_address = '', territory = null where name = '%s'" % (serial_no))
+			webnotes.conn.sql("update `tabSerial No` set docstatus = 0, status = 'In Store', delivery_document_type = '', delivery_document_no = '', delivery_date = null, customer = null, customer_name = '', delivery_address = '', territory = null where name = '%s'" % (serial_no))
 
 
 	def update_serial_record(self, obj, fname, is_submit = 1, is_incoming = 0):
@@ -202,8 +202,10 @@
 			if v.get('is_cancelled') == 'Yes':
 				v['actual_qty'] = -flt(v['actual_qty'])
 				# cancel matching entry
-				sql("update `tabStock Ledger Entry` set is_cancelled='Yes' where voucher_no=%s \
-					and voucher_type=%s", (v['voucher_no'], v['voucher_type']))
+				webnotes.conn.sql("""update `tabStock Ledger Entry` set is_cancelled='Yes',
+					modified=%s, modified_by=%s
+					where voucher_no=%s and voucher_type=%s""", 
+					(now(), webnotes.session.user, v['voucher_no'], v['voucher_type']))
 
 			if v.get("actual_qty"):
 				sle_id = self.make_entry(v)
@@ -230,5 +232,5 @@
 		"""
 		Repost everything!
 		"""
-		for wh in sql("select name from tabWarehouse"):
+		for wh in webnotes.conn.sql("select name from tabWarehouse"):
 			get_obj('Warehouse', wh[0]).repost_stock()