Merge pull request #4205 from nabinhait/expenses_included_in_valuation

Expenses Included in Valuation
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 2e34980..af41ef5 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -317,23 +317,22 @@
 			if auto_accounting_for_stock and self.is_opening == "No" and \
 				item.item_code in stock_items and item.item_tax_amount:
 					# Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt
-					negative_expense_booked_in_pi = None
 					if item.purchase_receipt:
-						negative_expense_booked_in_pi = frappe.db.sql("""select name from `tabGL Entry`
+						negative_expense_booked_in_pr = frappe.db.sql("""select name from `tabGL Entry`
 							where voucher_type='Purchase Receipt' and voucher_no=%s and account=%s""",
 							(item.purchase_receipt, expenses_included_in_valuation))
 
-					if not negative_expense_booked_in_pi:
-						gl_entries.append(
-							self.get_gl_dict({
-								"account": stock_received_but_not_billed,
-								"against": self.supplier,
-								"debit": flt(item.item_tax_amount, self.precision("item_tax_amount", item)),
-								"remarks": self.remarks or "Accounting Entry for Stock"
-							})
-						)
+						if not negative_expense_booked_in_pr:
+							gl_entries.append(
+								self.get_gl_dict({
+									"account": stock_received_but_not_billed,
+									"against": self.supplier,
+									"debit": flt(item.item_tax_amount, self.precision("item_tax_amount", item)),
+									"remarks": self.remarks or "Accounting Entry for Stock"
+								})
+							)
 
-						negative_expense_to_be_booked += flt(item.item_tax_amount, self.precision("item_tax_amount", item))
+							negative_expense_to_be_booked += flt(item.item_tax_amount, self.precision("item_tax_amount", item))
 
 		if self.is_opening == "No" and negative_expense_to_be_booked and valuation_tax:
 			# credit valuation tax amount in "Expenses Included In Valuation"
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 67286db..10e20af 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -49,25 +49,9 @@
 		pi = frappe.copy_doc(test_records[1])
 		pi.insert()
 		pi.submit()
-
-		gl_entries = frappe.db.sql("""select account, debit, credit
-			from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
-			order by account asc""", pi.name, as_dict=1)
-		self.assertTrue(gl_entries)
-
-		expected_values = dict((d[0], d) for d in [
-			["_Test Payable - _TC", 0, 720],
-			["Stock Received But Not Billed - _TC", 750.0, 0],
-			["Expenses Included In Valuation - _TC", 0.0, 250.0],
-			["_Test Account Shipping Charges - _TC", 100.0, 0],
-			["_Test Account VAT - _TC", 120.0, 0],
-		])
-
-		for i, gle in enumerate(gl_entries):
-			self.assertEquals(expected_values[gle.account][0], gle.account)
-			self.assertEquals(expected_values[gle.account][1], gle.debit)
-			self.assertEquals(expected_values[gle.account][2], gle.credit)
-
+		
+		self.check_gle_for_pi(pi.name)
+		
 		set_perpetual_inventory(0)
 
 	def test_gl_entries_with_auto_accounting_for_stock_against_pr(self):
@@ -83,9 +67,14 @@
 		pi.insert()
 		pi.submit()
 
+		self.check_gle_for_pi(pi.name)
+
+		set_perpetual_inventory(0)
+
+	def check_gle_for_pi(self, pi):
 		gl_entries = frappe.db.sql("""select account, debit, credit
 			from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
-			order by account asc""", pi.name, as_dict=1)
+			order by account asc""", pi, as_dict=1)
 		self.assertTrue(gl_entries)
 
 		expected_values = dict((d[0], d) for d in [
@@ -100,8 +89,6 @@
 			self.assertEquals(expected_values[gle.account][1], gle.debit)
 			self.assertEquals(expected_values[gle.account][2], gle.credit)
 
-		set_perpetual_inventory(0)
-
 	def test_gl_entries_with_aia_for_non_stock_items(self):
 		set_perpetual_inventory()
 		self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index bbfebe0..b36f74b 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -224,8 +224,7 @@
 execute:frappe.delete_doc_if_exists("DocType", "Applicable Territory")
 execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Price List")
 execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Taxes and Charges Master")
-
 erpnext.patches.v6_4.set_user_in_contact
 erpnext.patches.v6_4.make_image_thumbnail #2015-10-20
-
 erpnext.patches.v6_5.show_in_website_for_template_item
+erpnext.patches.v6_4.fix_expense_included_in_valuation
diff --git a/erpnext/patches/v6_4/fix_expense_included_in_valuation.py b/erpnext/patches/v6_4/fix_expense_included_in_valuation.py
new file mode 100644
index 0000000..cccfb9b
--- /dev/null
+++ b/erpnext/patches/v6_4/fix_expense_included_in_valuation.py
@@ -0,0 +1,64 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.utils import cstr
+
+def execute():
+	for company in frappe.db.sql("select name, expenses_included_in_valuation from tabCompany", as_dict=1):
+		frozen_date = get_frozen_date(company.name, company.expenses_included_in_valuation)
+	
+		# Purchase Invoices after frozen date 
+		# which are not against Receipt, but valuation related tax is there
+		pi_list = frappe.db.sql("""
+			select distinct pi.name
+			from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item
+			where 
+				pi.name = pi_item.parent
+				and pi.company = %s
+				and pi.posting_date > %s
+				and pi.docstatus = 1
+				and pi.is_opening = 'No'
+				and (pi_item.item_tax_amount is not null and pi_item.item_tax_amount > 0)
+				and (pi_item.purchase_receipt is null or pi_item.purchase_receipt = '')
+				and (pi_item.item_code is not null and pi_item.item_code != '')
+				and exists(select name from `tabItem` where name=pi_item.item_code and is_stock_item=1)
+		""", (company.name, frozen_date), as_dict=1)
+		
+		for pi in pi_list:
+			# Check whether gle exists for Expenses Included in Valuation account against the PI
+			gle_for_expenses_included_in_valuation = frappe.db.sql("""select name from `tabGL Entry` 
+				where voucher_type='Purchase Invoice' and voucher_no=%s and account=%s""", 
+				(pi.name, company.expenses_included_in_valuation))
+				
+			if gle_for_expenses_included_in_valuation:
+				frappe.db.sql("""delete from `tabGL Entry`
+					where voucher_type='Purchase Invoice' and voucher_no=%s""", pi.name)
+
+				purchase_invoice = frappe.get_doc("Purchase Invoice", pi.name)
+				purchase_invoice.make_gl_entries()
+				
+				print pi.name
+		
+def get_frozen_date(company, account):
+	# Accounting frozen upto
+	accounts_frozen_upto = frappe.db.get_single_value("Accounts Settings", "acc_frozen_upto")
+	
+	# Last adjustment entry to correct Expenses Included in Valuation account balance
+	last_adjustment_entry = frappe.db.sql("""select posting_date from `tabGL Entry` 
+		where account=%s and company=%s and voucher_type = 'Journal Entry'
+		order by posting_date desc limit 1""", (account, company))
+		
+	last_adjustment_date = cstr(last_adjustment_entry[0][0]) if last_adjustment_entry else None
+	
+	# Last period closing voucher
+	last_closing_entry = frappe.db.sql("""select posting_date from `tabGL Entry` 
+		where company=%s and voucher_type = 'Period Closing Voucher'
+		order by posting_date desc limit 1""", company)
+		
+	last_closing_date = cstr(last_closing_entry[0][0]) if last_closing_entry else None
+
+	frozen_date = max([accounts_frozen_upto, last_adjustment_date, last_closing_date])
+	
+	return frozen_date or '1900-01-01'
\ No newline at end of file