diff --git a/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py b/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py index 2764ec5c951..97fc47b01b9 100644 --- a/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py +++ b/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py @@ -40,6 +40,13 @@ class TestProcessDeferredAccounting(IntegrationTestCase): si.save() si.submit() + original_gle = [ + ["Debtors - _TC", 3000.0, 0, "2023-07-01"], + [deferred_account, 0.0, 3000, "2023-07-01"], + ] + + check_gl_entries(self, si.name, original_gle, "2023-07-01") + process_deferred_accounting = frappe.get_doc( dict( doctype="Process Deferred Accounting", @@ -63,6 +70,12 @@ class TestProcessDeferredAccounting(IntegrationTestCase): ] check_gl_entries(self, si.name, expected_gle, "2023-07-01") + + # cancel the process deferred accounting document + process_deferred_accounting.cancel() + + # check if gl entries are cancelled + check_gl_entries(self, si.name, original_gle, "2023-07-01") change_acc_settings() def test_pda_submission_and_cancellation(self): diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 49f27d4de73..d8931694dde 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2483,6 +2483,10 @@ class TestSalesInvoice(ERPNextTestSuite): for gle in gl_entries: self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) + @IntegrationTestCase.change_settings( + "Accounts Settings", + {"book_deferred_entries_based_on": "Days", "book_deferred_entries_via_journal_entry": 0}, + ) def test_deferred_revenue(self): deferred_account = create_account( account_name="Deferred Revenue", @@ -2537,6 +2541,10 @@ class TestSalesInvoice(ERPNextTestSuite): self.assertRaises(frappe.ValidationError, si.save) + @IntegrationTestCase.change_settings( + "Accounts Settings", + {"book_deferred_entries_based_on": "Months", "book_deferred_entries_via_journal_entry": 0}, + ) def test_fixed_deferred_revenue(self): deferred_account = create_account( account_name="Deferred Revenue", @@ -2544,10 +2552,6 @@ class TestSalesInvoice(ERPNextTestSuite): company="_Test Company", ) - acc_settings = frappe.get_doc("Accounts Settings", "Accounts Settings") - acc_settings.book_deferred_entries_based_on = "Months" - acc_settings.save() - item = create_item("_Test Item for Deferred Accounting") item.enable_deferred_revenue = 1 item.deferred_revenue_account = deferred_account @@ -2587,10 +2591,6 @@ class TestSalesInvoice(ERPNextTestSuite): check_gl_entries(self, si.name, expected_gle, "2019-01-30") - acc_settings = frappe.get_doc("Accounts Settings", "Accounts Settings") - acc_settings.book_deferred_entries_based_on = "Days" - acc_settings.save() - def test_validate_inter_company_transaction_address_links(self): def _validate_address_link(address, link_doctype, link_name): return frappe.db.get_value( @@ -2833,7 +2833,9 @@ class TestSalesInvoice(ERPNextTestSuite): self.assertEqual(si.items[0].rate, rate) self.assertEqual(target_doc.items[0].rate, rate) - check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1)) + check_gl_entries( + self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1), voucher_type="Purchase Invoice" + ) def test_internal_transfer_gl_precision_issues(self): # Make a stock queue of an item with two valuations @@ -4561,6 +4563,8 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date, voucher_type=" ) gl_entries = q.run(as_dict=True) + doc.assertGreater(len(gl_entries), 0) + for i, gle in enumerate(gl_entries): doc.assertEqual(expected_gle[i][0], gle.account) doc.assertEqual(expected_gle[i][1], gle.debit) diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index b1eeab9e6f8..8c7ec2795e0 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -703,7 +703,18 @@ def make_reverse_gl_entries( query.run() else: if not immutable_ledger_enabled: - set_as_cancel(gl_entries[0]["voucher_type"], gl_entries[0]["voucher_no"]) + gle_names = [x.get("name") for x in gl_entries] + + # if names are available, cancel only that set of entries + if not all(gle_names): + set_as_cancel(gl_entries[0]["voucher_type"], gl_entries[0]["voucher_no"]) + else: + frappe.db.sql( + """UPDATE `tabGL Entry` SET is_cancelled = 1, + modified=%s, modified_by=%s + where name in %s and is_cancelled = 0""", + (now(), frappe.session.user, tuple(gle_names)), + ) for entry in gl_entries: new_gle = copy.deepcopy(entry) diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py index 561034db0c2..caa464c5447 100644 --- a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py +++ b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py @@ -79,6 +79,14 @@ class Deferred_Item: return - estimated amount to post for given period Calculated based on already booked amount and item service period """ + if self.filters.book_deferred_entries_based_on == "Months": + # if the deferred entries are based on service period, use service start and end date + return self.calculate_monthly_amount(start_date, end_date) + + else: + return self.calculate_days_amount(start_date, end_date) + + def calculate_monthly_amount(self, start_date, end_date): total_months = ( (self.service_end_date.year - self.service_start_date.year) * 12 + (self.service_end_date.month - self.service_start_date.month) @@ -105,6 +113,19 @@ class Deferred_Item: return base_amount + def calculate_days_amount(self, start_date, end_date): + base_amount = 0 + total_days = date_diff(self.service_end_date, self.service_start_date) + 1 + total_booking_days = date_diff(end_date, start_date) + 1 + already_booked_amount = self.get_item_total() + + base_amount = flt(self.base_net_amount * total_booking_days / flt(total_days)) + + if base_amount + already_booked_amount > self.base_net_amount: + base_amount = self.base_net_amount - already_booked_amount + + return base_amount + def make_dummy_gle(self, name, date, amount): """ return - frappe._dict() of a dummy gle entry @@ -245,6 +266,10 @@ class Deferred_Revenue_and_Expense_Report: else: self.filters = frappe._dict(filters) + self.filters.book_deferred_entries_based_on = frappe.db.get_singles_value( + "Accounts Settings", "book_deferred_entries_based_on" + ) + self.period_list = None self.deferred_invoices = [] # holds period wise total for report @@ -289,7 +314,11 @@ class Deferred_Revenue_and_Expense_Report: .join(inv) .on(inv.name == inv_item.parent) .left_join(gle) - .on((inv_item.name == gle.voucher_detail_no) & (deferred_account_field == gle.account)) + .on( + (inv_item.name == gle.voucher_detail_no) + & (deferred_account_field == gle.account) + & (gle.is_cancelled == 0) + ) .select( inv.name.as_("doc"), inv.posting_date,