From be464696cce6ea2c70d209a323542996b7fc91eb Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 21 Oct 2015 12:06:51 +0530 Subject: [PATCH 1/3] [fix][patch] Fix wrong gle for Purchase Invoice against Expenses Included in Valuation account --- .../purchase_invoice/purchase_invoice.py | 23 ++++--- erpnext/patches.txt | 3 +- .../v6_4/fix_expense_included_in_valuation.py | 66 +++++++++++++++++++ 3 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 erpnext/patches/v6_4/fix_expense_included_in_valuation.py diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 2e34980352..af41ef5bd4 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -317,23 +317,22 @@ class PurchaseInvoice(BuyingController): 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/patches.txt b/erpnext/patches.txt index bbfebe0162..b36f74b959 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -224,8 +224,7 @@ erpnext.patches.v6_4.email_digest_update 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 0000000000..94dc533172 --- /dev/null +++ b/erpnext/patches/v6_4/fix_expense_included_in_valuation.py @@ -0,0 +1,66 @@ +# 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.utils import cstr + +def execute(): + stock_items = [r[0] for r in frappe.db.sql("""select name from `tabItem` where is_stock_item=1""")] + + 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 in (%s) + """ % ('%s', '%s', ', '.join(['%s']*len(stock_items))), + tuple([company.name, frozen_date] + stock_items), 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 From 31c51ef914cba8ff394438483625f54ecb0aeecf Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 21 Oct 2015 12:15:15 +0530 Subject: [PATCH 2/3] [fix] test case for purchase invoice gle --- .../purchase_invoice/test_purchase_invoice.py | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 67286db202..10e20afe58 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 @@ class TestPurchaseInvoice(unittest.TestCase): 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 @@ class TestPurchaseInvoice(unittest.TestCase): 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 @@ class TestPurchaseInvoice(unittest.TestCase): 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) From 70b7f7f036af70ea691de6b4f99bb8468422b238 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 21 Oct 2015 17:39:09 +0530 Subject: [PATCH 3/3] minor improvement in patch --- .../patches/v6_4/fix_expense_included_in_valuation.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/erpnext/patches/v6_4/fix_expense_included_in_valuation.py b/erpnext/patches/v6_4/fix_expense_included_in_valuation.py index 94dc533172..cccfb9bb36 100644 --- a/erpnext/patches/v6_4/fix_expense_included_in_valuation.py +++ b/erpnext/patches/v6_4/fix_expense_included_in_valuation.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals @@ -6,8 +6,6 @@ import frappe from frappe.utils import cstr def execute(): - stock_items = [r[0] for r in frappe.db.sql("""select name from `tabItem` where is_stock_item=1""")] - 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) @@ -24,9 +22,9 @@ def execute(): 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 in (%s) - """ % ('%s', '%s', ', '.join(['%s']*len(stock_items))), - tuple([company.name, frozen_date] + stock_items), as_dict=1) + 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