diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js index 340b4130f4beec3d07c349d0988f06f8332b74be..b1d3d98dd013a84bf0a641a227a5f69e9b35c502 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.js +++ b/erpnext/accounts/report/general_ledger/general_ledger.js @@ -219,10 +219,15 @@ frappe.query_reports["General Ledger"] = { "fieldtype": "Check" }, { - "fieldname": "ignore_err", - "label": __("Ignore Exchange Rate Revaluation Journals"), - "fieldtype": "Check" - } + fieldname: "ignore_err", + label: __("Ignore Exchange Rate Revaluation Journals"), + fieldtype: "Check", + }, + { + fieldname: "ignore_cr_dr_notes", + label: __("Ignore System Generated Credit / Debit Notes"), + fieldtype: "Check", + }, ], "formatter": function (value, row, column, data, default_formatter) { if (["voucher_type", "party_type", "against_voucher_type", "voucher_subtype"].includes(column.fieldname)) { diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index 3b1bc80cac5ce436da594455f75c31ffad92294d..cd2aa47194f6ceb11104edd0efe7d176b35c676e 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -278,12 +278,28 @@ def get_conditions(filters): "company": filters.get("company"), "docstatus": 1, "voucher_type": ("in", ["Exchange Rate Revaluation", "Exchange Gain Or Loss"]), + "posting_date": ["between", [filters.get("from_date"), filters.get("to_date")]], }, as_list=True, ) if err_journals: filters.update({"voucher_no_not_in": [x[0] for x in err_journals]}) + if filters.get("ignore_cr_dr_notes"): + system_generated_cr_dr_journals = frappe.db.get_all( + "Journal Entry", + filters={ + "company": filters.get("company"), + "docstatus": 1, + "voucher_type": ("in", ["Credit Note", "Debit Note"]), + "is_system_generated": 1, + "posting_date": ["between", [filters.get("from_date"), filters.get("to_date")]], + }, + as_list=True, + ) + if system_generated_cr_dr_journals: + filters.update({"voucher_no_not_in": [x[0] for x in system_generated_cr_dr_journals]}) + if filters.get("voucher_no_not_in"): conditions.append("voucher_no not in %(voucher_no_not_in)s") diff --git a/erpnext/accounts/report/general_ledger/test_general_ledger.py b/erpnext/accounts/report/general_ledger/test_general_ledger.py index 75f94309bccd9a0e1e578dc55fdf707e180473ad..af2c569949ac8cc63879d978d3f2bec72362bda0 100644 --- a/erpnext/accounts/report/general_ledger/test_general_ledger.py +++ b/erpnext/accounts/report/general_ledger/test_general_ledger.py @@ -2,13 +2,32 @@ # MIT License. See license.txt import frappe +from frappe import qb from frappe.tests.utils import FrappeTestCase from frappe.utils import flt, today +from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.report.general_ledger.general_ledger import execute +from erpnext.controllers.sales_and_purchase_return import make_return_doc class TestGeneralLedger(FrappeTestCase): + def setUp(self): + self.company = "_Test Company" + self.clear_old_entries() + + def clear_old_entries(self): + doctype_list = [ + "GL Entry", + "Payment Ledger Entry", + "Sales Invoice", + "Purchase Invoice", + "Payment Entry", + "Journal Entry", + ] + for doctype in doctype_list: + qb.from_(qb.DocType(doctype)).delete().where(qb.DocType(doctype).company == self.company).run() + def test_foreign_account_balance_after_exchange_rate_revaluation(self): """ Checks the correctness of balance after exchange rate revaluation @@ -203,9 +222,7 @@ class TestGeneralLedger(FrappeTestCase): revaluation.extend("accounts", accounts) row = revaluation.accounts[0] row.new_exchange_rate = 83 - row.new_balance_in_base_currency = flt( - row.new_exchange_rate * flt(row.balance_in_account_currency) - ) + row.new_balance_in_base_currency = flt(row.new_exchange_rate * flt(row.balance_in_account_currency)) row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency) revaluation.set_total_gain_loss() revaluation = revaluation.save().submit() @@ -250,3 +267,68 @@ class TestGeneralLedger(FrappeTestCase): ) ) self.assertIn(revaluation_jv.name, set([x.voucher_no for x in data])) + + def test_ignore_cr_dr_notes_filter(self): + si = create_sales_invoice() + + cr_note = make_return_doc(si.doctype, si.name) + cr_note.submit() + + pr = frappe.get_doc("Payment Reconciliation") + pr.company = si.company + pr.party_type = "Customer" + pr.party = si.customer + pr.receivable_payable_account = si.debit_to + + pr.get_unreconciled_entries() + + invoices = [invoice.as_dict() for invoice in pr.invoices if invoice.invoice_number == si.name] + payments = [payment.as_dict() for payment in pr.payments if payment.reference_name == cr_note.name] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.reconcile() + + system_generated_journal = frappe.db.get_all( + "Journal Entry", + filters={ + "docstatus": 1, + "reference_type": si.doctype, + "reference_name": si.name, + "voucher_type": "Credit Note", + "is_system_generated": True, + }, + fields=["name"], + ) + self.assertEqual(len(system_generated_journal), 1) + expected = set([si.name, cr_note.name, system_generated_journal[0].name]) + # Without ignore_cr_dr_notes + columns, data = execute( + frappe._dict( + { + "company": si.company, + "from_date": si.posting_date, + "to_date": si.posting_date, + "account": [si.debit_to], + "group_by": "Group by Voucher (Consolidated)", + "ignore_cr_dr_notes": False, + } + ) + ) + actual = set([x.voucher_no for x in data if x.voucher_no]) + self.assertEqual(expected, actual) + + # Without ignore_cr_dr_notes + expected = set([si.name, cr_note.name]) + columns, data = execute( + frappe._dict( + { + "company": si.company, + "from_date": si.posting_date, + "to_date": si.posting_date, + "account": [si.debit_to], + "group_by": "Group by Voucher (Consolidated)", + "ignore_cr_dr_notes": True, + } + ) + ) + actual = set([x.voucher_no for x in data if x.voucher_no]) + self.assertEqual(expected, actual)