From eb3d28fcc048ae67267703a235306e304e41a2a9 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 3 Jan 2022 19:40:47 +0530 Subject: [PATCH 1/8] fix: Deferred revenue booking for multi currency invoices via JV (cherry picked from commit 98f294a8ae983fe9bf9b83127fccbf1f1a397ba1) --- erpnext/accounts/deferred_revenue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py index 7e270601fb5..460d0844a11 100644 --- a/erpnext/accounts/deferred_revenue.py +++ b/erpnext/accounts/deferred_revenue.py @@ -259,7 +259,7 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None): start_date, end_date, last_gl_entry = get_booking_dates(doc, item, posting_date=posting_date) if not (start_date and end_date): return - account_currency = get_account_currency(item.expense_account) + account_currency = get_account_currency(item.expense_account or item.income_account) if doc.doctype == "Sales Invoice": against, project = doc.customer, doc.project credit_account, debit_account = item.income_account, item.deferred_revenue_account From a08b10d5cf395dea48f77964dc599142d70ac183 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 4 Jan 2022 14:04:18 +0530 Subject: [PATCH 2/8] fix: Add test case for multicurrency invoice (cherry picked from commit 094158f287240fd0807ada6eb89dc6874420aed8) --- erpnext/accounts/deferred_revenue.py | 4 -- .../doctype/journal_entry/journal_entry.py | 24 ++++--- .../sales_invoice/test_sales_invoice.py | 63 +++++++++++++++++++ 3 files changed, 80 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py index 460d0844a11..af6dc577a18 100644 --- a/erpnext/accounts/deferred_revenue.py +++ b/erpnext/accounts/deferred_revenue.py @@ -407,8 +407,6 @@ def book_revenue_via_journal_entry(doc, credit_account, debit_account, against, 'account': credit_account, 'credit': base_amount, 'credit_in_account_currency': amount, - 'party_type': 'Customer' if doc.doctype == 'Sales Invoice' else 'Supplier', - 'party': against, 'account_currency': account_currency, 'reference_name': doc.name, 'reference_type': doc.doctype, @@ -421,8 +419,6 @@ def book_revenue_via_journal_entry(doc, credit_account, debit_account, against, 'account': debit_account, 'debit': base_amount, 'debit_in_account_currency': amount, - 'party_type': 'Customer' if doc.doctype == 'Sales Invoice' else 'Supplier', - 'party': against, 'account_currency': account_currency, 'reference_name': doc.name, 'reference_type': doc.doctype, diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 6ec2d4bda03..9c1710217dd 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -397,13 +397,14 @@ class JournalEntry(AccountsController): debit_or_credit = 'Debit' if d.debit else 'Credit' party_account = get_deferred_booking_accounts(d.reference_type, d.reference_detail_no, debit_or_credit) + against_voucher = ['', against_voucher[1]] else: if d.reference_type == "Sales Invoice": party_account = get_party_account_based_on_invoice_discounting(d.reference_name) or against_voucher[1] else: party_account = against_voucher[1] - if (against_voucher[0] != d.party or party_account != d.account): + if (against_voucher[0] != cstr(d.party) or party_account != d.account): frappe.throw(_("Row {0}: Party / Account does not match with {1} / {2} in {3} {4}") .format(d.idx, field_dict.get(d.reference_type)[0], field_dict.get(d.reference_type)[1], d.reference_type, d.reference_name)) @@ -468,13 +469,22 @@ class JournalEntry(AccountsController): def set_against_account(self): accounts_debited, accounts_credited = [], [] - for d in self.get("accounts"): - if flt(d.debit > 0): accounts_debited.append(d.party or d.account) - if flt(d.credit) > 0: accounts_credited.append(d.party or d.account) + if self.voucher_type in ('Deferred Revenue', 'Deferred Expense'): + for d in self.get('accounts'): + if d.reference_type == 'Sales Invoice': + field = 'customer' + else: + field = 'supplier' - for d in self.get("accounts"): - if flt(d.debit > 0): d.against_account = ", ".join(list(set(accounts_credited))) - if flt(d.credit > 0): d.against_account = ", ".join(list(set(accounts_debited))) + d.against_account = frappe.db.get_value(d.reference_type, d.reference_name, field) + else: + for d in self.get("accounts"): + if flt(d.debit > 0): accounts_debited.append(d.party or d.account) + if flt(d.credit) > 0: accounts_credited.append(d.party or d.account) + + for d in self.get("accounts"): + if flt(d.debit > 0): d.against_account = ", ".join(list(set(accounts_credited))) + if flt(d.credit > 0): d.against_account = ", ".join(list(set(accounts_debited))) def validate_debit_credit_amount(self): for d in self.get('accounts'): diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index e2c1f79bd2e..618acb00aea 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2455,6 +2455,69 @@ class TestSalesInvoice(unittest.TestCase): frappe.db.set_value('Accounts Settings', None, 'over_billing_allowance', over_billing_allowance) + def test_multi_currency_deferred_revenue_via_journal_entry(self): + deferred_account = create_account(account_name="Deferred Revenue", + parent_account="Current Liabilities - _TC", company="_Test Company") + + acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') + acc_settings.book_deferred_entries_via_journal_entry = 1 + acc_settings.submit_journal_entries = 1 + acc_settings.save() + + item = create_item("_Test Item for Deferred Accounting") + item.enable_deferred_expense = 1 + item.deferred_revenue_account = deferred_account + item.save() + + si = create_sales_invoice(customer='_Test Customer USD', currency='USD', + item=item.name, qty=1, rate=100, conversion_rate=60, do_not_save=True) + + si.set_posting_time = 1 + si.posting_date = '2019-01-01' + si.items[0].enable_deferred_revenue = 1 + si.items[0].service_start_date = "2019-01-01" + si.items[0].service_end_date = "2019-03-30" + si.items[0].deferred_expense_account = deferred_account + si.save() + si.submit() + + pda1 = frappe.get_doc(dict( + doctype='Process Deferred Accounting', + posting_date=nowdate(), + start_date="2019-01-01", + end_date="2019-03-31", + type="Income", + company="_Test Company" + )) + + pda1.insert() + pda1.submit() + + expected_gle = [ + ["Sales - _TC", 0.0, 2089.89, "2019-01-31"], + [deferred_account, 2089.89, 0.0, "2019-01-31"], + ["Sales - _TC", 0.0, 1887.64, "2019-02-28"], + [deferred_account, 1887.64, 0.0, "2019-02-28"], + ["Sales - _TC", 0.0, 2022.47, "2019-03-15"], + [deferred_account, 2022.47, 0.0, "2019-03-15"] + ] + + gl_entries = gl_entries = frappe.db.sql("""select account, debit, credit, posting_date + from `tabGL Entry` + where voucher_type='Journal Entry' and voucher_detail_no=%s and posting_date <= %s + order by posting_date asc, account asc""", (si.items[0].name, si.posting_date), as_dict=1) + + for i, gle in enumerate(gl_entries): + self.assertEqual(expected_gle[i][0], gle.account) + self.assertEqual(expected_gle[i][1], gle.credit) + self.assertEqual(expected_gle[i][2], gle.debit) + self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date) + + acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') + acc_settings.book_deferred_entries_via_journal_entry = 0 + acc_settings.submit_journal_entriessubmit_journal_entries = 0 + acc_settings.save() + def get_sales_invoice_for_e_invoice(): si = make_sales_invoice_for_ewaybill() si.naming_series = 'INV-2020-.#####' From 38a330b55e47cae0ce73d2db364a456e5e9ad76d Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 4 Jan 2022 16:24:24 +0530 Subject: [PATCH 3/8] fix: Test case (cherry picked from commit e311667a250d112552a115a4b551efdc53cf6099) --- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 618acb00aea..76948652f2b 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2474,6 +2474,7 @@ class TestSalesInvoice(unittest.TestCase): si.set_posting_time = 1 si.posting_date = '2019-01-01' + si.debit_to = '_Test Receivable USD - _TC' si.items[0].enable_deferred_revenue = 1 si.items[0].service_start_date = "2019-01-01" si.items[0].service_end_date = "2019-03-30" From a4e897d30bf302f6a11c0cd101828501a3ecb1ab Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 7 Jan 2022 19:52:38 +0530 Subject: [PATCH 4/8] fix: Handle frozen books while handling (cherry picked from commit 30a647ff8099105a9fdce02bc98d43969985acb3) --- erpnext/accounts/deferred_revenue.py | 6 ++++++ .../accounts/doctype/sales_invoice/test_sales_invoice.py | 8 ++++++-- erpnext/controllers/accounts_controller.py | 2 -- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py index af6dc577a18..4b1535e1000 100644 --- a/erpnext/accounts/deferred_revenue.py +++ b/erpnext/accounts/deferred_revenue.py @@ -255,6 +255,8 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None): enable_check = "enable_deferred_revenue" \ if doc.doctype=="Sales Invoice" else "enable_deferred_expense" + accounts_frozen_upto = frappe.get_cached_value('Accounts Settings', 'None', 'acc_frozen_upto') + def _book_deferred_revenue_or_expense(item, via_journal_entry, submit_journal_entry, book_deferred_entries_based_on): start_date, end_date, last_gl_entry = get_booking_dates(doc, item, posting_date=posting_date) if not (start_date and end_date): return @@ -280,6 +282,10 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None): if not amount: return + # check if books nor frozen till endate: + if getdate(end_date) >= getdate(accounts_frozen_upto): + end_date = get_last_day(add_days(accounts_frozen_upto, 1)) + if via_journal_entry: book_revenue_via_journal_entry(doc, credit_account, debit_account, against, amount, base_amount, end_date, project, account_currency, item.cost_center, item, deferred_process, submit_journal_entry) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 76948652f2b..82c5ab5fc1f 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2482,6 +2482,9 @@ class TestSalesInvoice(unittest.TestCase): si.save() si.submit() + acc_settings.acc_frozen_upto = '2019-01-31' + acc_settings.save() + pda1 = frappe.get_doc(dict( doctype='Process Deferred Accounting', posting_date=nowdate(), @@ -2495,8 +2498,8 @@ class TestSalesInvoice(unittest.TestCase): pda1.submit() expected_gle = [ - ["Sales - _TC", 0.0, 2089.89, "2019-01-31"], - [deferred_account, 2089.89, 0.0, "2019-01-31"], + ["Sales - _TC", 0.0, 2089.89, "2019-01-28"], + [deferred_account, 2089.89, 0.0, "2019-01-28"], ["Sales - _TC", 0.0, 1887.64, "2019-02-28"], [deferred_account, 1887.64, 0.0, "2019-02-28"], ["Sales - _TC", 0.0, 2022.47, "2019-03-15"], @@ -2517,6 +2520,7 @@ class TestSalesInvoice(unittest.TestCase): acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') acc_settings.book_deferred_entries_via_journal_entry = 0 acc_settings.submit_journal_entriessubmit_journal_entries = 0 + acc_settings.acc_frozen_upto = None acc_settings.save() def get_sales_invoice_for_e_invoice(): diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 2a95553fbf2..b7b198eac4c 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -191,8 +191,6 @@ class AccountsController(TransactionBase): frappe.throw(_("Row #{0}: Service Start Date cannot be greater than Service End Date").format(d.idx)) elif getdate(self.posting_date) > getdate(d.service_end_date): frappe.throw(_("Row #{0}: Service End Date cannot be before Invoice Posting Date").format(d.idx)) - elif getdate(self.posting_date) > getdate(d.service_start_date): - frappe.throw(_("Row #{0}: Service Start Date cannot be before Invoice Posting Date").format(d.idx)) def validate_invoice_documents_schedule(self): self.validate_payment_schedule_dates() From 8ed138e3733018a2831eb3ef1e4229adaeef4ea1 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 7 Jan 2022 20:57:15 +0530 Subject: [PATCH 5/8] fix: Test case (cherry picked from commit 18c4ddadf1428133961f3558d7df8eefb7475f40) --- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 82c5ab5fc1f..4bf920ac4e4 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2520,9 +2520,10 @@ class TestSalesInvoice(unittest.TestCase): acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') acc_settings.book_deferred_entries_via_journal_entry = 0 acc_settings.submit_journal_entriessubmit_journal_entries = 0 - acc_settings.acc_frozen_upto = None acc_settings.save() + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', add_days(getdate(), 1)) + def get_sales_invoice_for_e_invoice(): si = make_sales_invoice_for_ewaybill() si.naming_series = 'INV-2020-.#####' From eff48299e4310ad02cb494771b5ab84cb6474927 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 13 Jan 2022 19:44:26 +0530 Subject: [PATCH 6/8] fix: Test case (cherry picked from commit 24bb1e8987c222139884076e4134fe52e3d214f7) --- .../doctype/sales_invoice/test_sales_invoice.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 4bf920ac4e4..d76e655d071 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2459,7 +2459,7 @@ class TestSalesInvoice(unittest.TestCase): deferred_account = create_account(account_name="Deferred Revenue", parent_account="Current Liabilities - _TC", company="_Test Company") - acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') + acc_settings = frappe.get_single('Accounts Settings') acc_settings.book_deferred_entries_via_journal_entry = 1 acc_settings.submit_journal_entries = 1 acc_settings.save() @@ -2474,7 +2474,7 @@ class TestSalesInvoice(unittest.TestCase): si.set_posting_time = 1 si.posting_date = '2019-01-01' - si.debit_to = '_Test Receivable USD - _TC' + # si.debit_to = '_Test Receivable USD - _TC' si.items[0].enable_deferred_revenue = 1 si.items[0].service_start_date = "2019-01-01" si.items[0].service_end_date = "2019-03-30" @@ -2482,8 +2482,7 @@ class TestSalesInvoice(unittest.TestCase): si.save() si.submit() - acc_settings.acc_frozen_upto = '2019-01-31' - acc_settings.save() + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', getdate('2019-01-31')) pda1 = frappe.get_doc(dict( doctype='Process Deferred Accounting', @@ -2517,12 +2516,12 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(expected_gle[i][2], gle.debit) self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date) - acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') + acc_settings = frappe.get_single('Accounts Settings') acc_settings.book_deferred_entries_via_journal_entry = 0 acc_settings.submit_journal_entriessubmit_journal_entries = 0 acc_settings.save() - frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', add_days(getdate(), 1)) + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', getdate('2019-01-31')) def get_sales_invoice_for_e_invoice(): si = make_sales_invoice_for_ewaybill() From 045a505a38f1320736aea8343c287bde4a10e215 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 13 Jan 2022 23:05:27 +0530 Subject: [PATCH 7/8] fix: Remove comment (cherry picked from commit 08f26de3df28eabb93064217f3a67ff9b0ce01b9) --- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index d76e655d071..7a26611b58d 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2474,7 +2474,7 @@ class TestSalesInvoice(unittest.TestCase): si.set_posting_time = 1 si.posting_date = '2019-01-01' - # si.debit_to = '_Test Receivable USD - _TC' + si.debit_to = '_Test Receivable USD - _TC' si.items[0].enable_deferred_revenue = 1 si.items[0].service_start_date = "2019-01-01" si.items[0].service_end_date = "2019-03-30" @@ -2521,7 +2521,7 @@ class TestSalesInvoice(unittest.TestCase): acc_settings.submit_journal_entriessubmit_journal_entries = 0 acc_settings.save() - frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', getdate('2019-01-31')) + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None) def get_sales_invoice_for_e_invoice(): si = make_sales_invoice_for_ewaybill() From ef3e4ee61feffc03b3270c0a18198298ac5917cc Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 15 Jan 2022 18:27:40 +0530 Subject: [PATCH 8/8] fix: Remove unwanted test (cherry picked from commit fd922f1617303d8bf26529b9a9e9d3e919cba011) --- .../sales_invoice/test_sales_invoice.py | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 7a26611b58d..12e00dcac6f 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1789,47 +1789,6 @@ class TestSalesInvoice(unittest.TestCase): check_gl_entries(self, si.name, expected_gle, "2019-01-30") - def test_deferred_revenue_post_account_freeze_upto_by_admin(self): - frappe.set_user("Administrator") - - frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None) - frappe.db.set_value('Accounts Settings', None, 'frozen_accounts_modifier', None) - - deferred_account = create_account(account_name="Deferred Revenue", - parent_account="Current Liabilities - _TC", company="_Test Company") - - item = create_item("_Test Item for Deferred Accounting") - item.enable_deferred_revenue = 1 - item.deferred_revenue_account = deferred_account - item.no_of_months = 12 - item.save() - - si = create_sales_invoice(item=item.name, posting_date="2019-01-10", do_not_save=True) - si.items[0].enable_deferred_revenue = 1 - si.items[0].service_start_date = "2019-01-10" - si.items[0].service_end_date = "2019-03-15" - si.items[0].deferred_revenue_account = deferred_account - si.save() - si.submit() - - frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', getdate('2019-01-31')) - frappe.db.set_value('Accounts Settings', None, 'frozen_accounts_modifier', 'System Manager') - - pda1 = frappe.get_doc(dict( - doctype='Process Deferred Accounting', - posting_date=nowdate(), - start_date="2019-01-01", - end_date="2019-03-31", - type="Income", - company="_Test Company" - )) - - pda1.insert() - self.assertRaises(frappe.ValidationError, pda1.submit) - - frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None) - frappe.db.set_value('Accounts Settings', None, 'frozen_accounts_modifier', None) - def test_fixed_deferred_revenue(self): deferred_account = create_account(account_name="Deferred Revenue", parent_account="Current Liabilities - _TC", company="_Test Company")