From c3e27b5556bc2ffe1c4bd6ab0b3731b8017af04c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 20 Apr 2022 19:07:53 +0530 Subject: [PATCH 1/6] fix: Loan doctypes in bank reconciliation --- .../doctype/bank_clearance/bank_clearance.py | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py index 96779d75be..ed5a699463 100644 --- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py @@ -5,7 +5,10 @@ import frappe from frappe import _, msgprint from frappe.model.document import Document -from frappe.utils import flt, fmt_money, getdate, nowdate +from frappe.query_builder.custom import ConstantColumn +from frappe.utils import flt, fmt_money, getdate + +import erpnext form_grid_templates = {"journal_entries": "templates/form_grid/bank_reconciliation_grid.html"} @@ -76,6 +79,52 @@ class BankClearance(Document): as_dict=1, ) + loan_disbursement = frappe.qb.DocType("Loan Disbursement") + + loan_disbursements = ( + frappe.qb.from_(loan_disbursement) + .select( + ConstantColumn("Loan Disbursement").as_("payment_document"), + loan_disbursement.name.as_("payment_entry"), + loan_disbursement.disbursed_amount.as_("credit"), + ConstantColumn(0).as_("debit"), + loan_disbursement.reference_number.as_("cheque_number"), + loan_disbursement.reference_date.as_("cheque_date"), + loan_disbursement.disbursement_date.as_("posting_date"), + loan_disbursement.applicant.as_("against_account"), + ) + .where(loan_disbursement.docstatus == 1) + .where(loan_disbursement.disbursement_date >= self.from_date) + .where(loan_disbursement.disbursement_date <= self.to_date) + .where(loan_disbursement.clearance_date.isnull()) + .where(loan_disbursement.disbursement_account.isin([self.bank_account, self.account])) + .orderby(loan_disbursement.disbursement_date) + .orderby(loan_disbursement.name, frappe.qb.desc) + ).run(as_dict=1) + + loan_repayment = frappe.qb.DocType("Loan Repayment") + + loan_repayments = ( + frappe.qb.from_(loan_repayment) + .select( + ConstantColumn("Loan Repayment").as_("doctype"), + loan_repayment.name.as_("payment_entry"), + loan_repayment.amount_paid.as_("debit"), + ConstantColumn(0).as_("credit"), + loan_repayment.reference_number.as_("cheque_number"), + loan_repayment.reference_date.as_("cheque_date"), + loan_repayment.applicant.as_("against_account"), + loan_repayment.posting_date, + ) + .where(loan_repayment.docstatus == 1) + .where(loan_repayment.clearance_date.isnull()) + .where(loan_repayment.posting_date >= self.from_date) + .where(loan_repayment.posting_date <= self.to_date) + .where(loan_repayment.payment_account.isin([self.bank_account, self.account])) + .orderby(loan_repayment.posting_date) + .orderby(loan_repayment.name, frappe.qb.desc) + ).run(as_dict=1) + pos_sales_invoices, pos_purchase_invoices = [], [] if self.include_pos_transactions: pos_sales_invoices = frappe.db.sql( @@ -114,18 +163,26 @@ class BankClearance(Document): entries = sorted( list(payment_entries) - + list(journal_entries + list(pos_sales_invoices) + list(pos_purchase_invoices)), - key=lambda k: k["posting_date"] or getdate(nowdate()), + + list(journal_entries) + + list(pos_sales_invoices) + + list(pos_purchase_invoices) + + list(loan_disbursements) + + list(loan_repayments), + key=lambda k: getdate(k["posting_date"]), ) self.set("payment_entries", []) self.total_amount = 0.0 + default_currency = erpnext.get_default_currency() for d in entries: row = self.append("payment_entries", {}) amount = flt(d.get("debit", 0)) - flt(d.get("credit", 0)) + if not d.get("account_currency"): + d.account_currency = default_currency + formatted_amount = fmt_money(abs(amount), 2, d.account_currency) d.amount = formatted_amount + " " + (_("Dr") if amount > 0 else _("Cr")) From 3d0e68acaa82aa0e1a6ab50e835f192297bd7bd2 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 20 Apr 2022 19:49:53 +0530 Subject: [PATCH 2/6] fix: select doctype as payment_document --- erpnext/accounts/doctype/bank_clearance/bank_clearance.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py index ed5a699463..0f617b5dda 100644 --- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py @@ -107,7 +107,7 @@ class BankClearance(Document): loan_repayments = ( frappe.qb.from_(loan_repayment) .select( - ConstantColumn("Loan Repayment").as_("doctype"), + ConstantColumn("Loan Repayment").as_("payment_document"), loan_repayment.name.as_("payment_entry"), loan_repayment.amount_paid.as_("debit"), ConstantColumn(0).as_("credit"), @@ -185,6 +185,7 @@ class BankClearance(Document): formatted_amount = fmt_money(abs(amount), 2, d.account_currency) d.amount = formatted_amount + " " + (_("Dr") if amount > 0 else _("Cr")) + d.posting_date = getdate(d.posting_date) d.pop("credit") d.pop("debit") From 8a8476bb5c9e487a80d0631b685a4a596caa297e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 21 Apr 2022 18:53:18 +0530 Subject: [PATCH 3/6] test: Add test coverage for bank clearance --- .../bank_clearance/test_bank_clearance.py | 121 +++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py index 706fbbe245..fbc44ee312 100644 --- a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py @@ -1,9 +1,126 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -# import frappe import unittest +import frappe +from frappe.utils import add_months, getdate + +from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry +from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice +from erpnext.loan_management.doctype.loan.test_loan import ( + create_loan, + create_loan_accounts, + create_loan_type, + create_repayment_entry, + make_loan_disbursement_entry, +) + class TestBankClearance(unittest.TestCase): - pass + @classmethod + def setUpClass(cls): + make_bank_account() + create_loan_accounts() + create_loan_masters() + add_transactions() + + @classmethod + def tearDownClass(cls): + payment_entry = frappe.get_doc( + "Payment Entry", {"party_name": "_Test Supplier", "paid_from": "_Test Bank Clearance - _TC"} + ) + payment_entry.cancel() + payment_entry.delete() + + loan = frappe.get_doc("Loan", {"applicant": "_Test Customer"}) + + ld_doc = frappe.get_doc("Loan Disbursement", {"against_loan": loan.name}) + ld_doc.cancel() + ld_doc.delete() + + lr_doc = frappe.get_doc("Loan Repayment", {"against_loan": loan.name}) + lr_doc.cancel() + lr_doc.delete() + + lia = frappe.get_doc("Loan Interest Accrual", {"loan": loan.name}) + lia.delete() + + plia = frappe.get_doc("Process Loan Interest Accrual", {"loan": loan.name}) + plia.cancel() + plia.delete() + + loan.load_from_db() + loan.cancel() + loan.flags.ignore_links = True + loan.delete() + + # Basic test case to test if bank clearance tool doesn't break + # Detailed test can be added later + def test_bank_clearance(self): + bank_clearance = frappe.get_doc("Bank Clearance") + bank_clearance.account = "_Test Bank Clearance - _TC" + bank_clearance.from_date = add_months(getdate(), -1) + bank_clearance.to_date = getdate() + bank_clearance.get_payment_entries() + self.assertEqual(len(bank_clearance.payment_entries), 3) + + +def make_bank_account(): + if not frappe.db.get_value("Account", "_Test Bank Clearance - _TC"): + frappe.get_doc( + { + "doctype": "Account", + "account_type": "Bank", + "account_name": "_Test Bank Clearance", + "company": "_Test Company", + "parent_account": "Bank Accounts - _TC", + } + ).insert() + + +def create_loan_masters(): + create_loan_type( + "Clearance Loan", + 2000000, + 13.5, + 25, + 0, + 5, + "Cash", + "_Test Bank Clearance - _TC", + "_Test Bank Clearance - _TC", + "Loan Account - _TC", + "Interest Income Account - _TC", + "Penalty Income Account - _TC", + ) + + +def add_transactions(): + make_payment_entry() + make_loan() + + +def make_loan(): + loan = create_loan( + "_Test Customer", + "Clearance Loan", + 280000, + "Repay Over Number of Periods", + 20, + applicant_type="Customer", + ) + loan.submit() + make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=getdate()) + repayment_entry = create_repayment_entry(loan.name, "_Test Customer", getdate(), loan.loan_amount) + repayment_entry.save() + repayment_entry.submit() + + +def make_payment_entry(): + pi = make_purchase_invoice(supplier="_Test Supplier", qty=1, rate=690) + pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank Clearance - _TC") + pe.reference_no = "Conrad Oct 18" + pe.reference_date = "2018-10-24" + pe.insert() + pe.submit() From 0eacc99ab705af446a0464f09ac92af760f5d9cf Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 23 Apr 2022 12:08:30 +0530 Subject: [PATCH 4/6] test: Fixes in test case --- .../bank_clearance/test_bank_clearance.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py index fbc44ee312..c09aa1c013 100644 --- a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py @@ -30,25 +30,33 @@ class TestBankClearance(unittest.TestCase): payment_entry = frappe.get_doc( "Payment Entry", {"party_name": "_Test Supplier", "paid_from": "_Test Bank Clearance - _TC"} ) - payment_entry.cancel() - payment_entry.delete() + + if payment_entry.docstatus == 1: + payment_entry.cancel() + payment_entry.delete() loan = frappe.get_doc("Loan", {"applicant": "_Test Customer"}) ld_doc = frappe.get_doc("Loan Disbursement", {"against_loan": loan.name}) - ld_doc.cancel() - ld_doc.delete() + + if ld_doc.docstatus == 1: + ld_doc.cancel() + ld_doc.delete() lr_doc = frappe.get_doc("Loan Repayment", {"against_loan": loan.name}) - lr_doc.cancel() - lr_doc.delete() + + if lr_doc.docstatus == 1: + lr_doc.cancel() + lr_doc.delete() lia = frappe.get_doc("Loan Interest Accrual", {"loan": loan.name}) lia.delete() plia = frappe.get_doc("Process Loan Interest Accrual", {"loan": loan.name}) - plia.cancel() - plia.delete() + + if plia.docstatus == 1: + plia.cancel() + plia.delete() loan.load_from_db() loan.cancel() From d4d83f4bb6f34353347f4b613bfe7c9554343425 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 23 Apr 2022 12:33:35 +0530 Subject: [PATCH 5/6] test: Fixes in test case --- .../accounts/doctype/bank_clearance/test_bank_clearance.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py index c09aa1c013..18645c7517 100644 --- a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py @@ -27,6 +27,8 @@ class TestBankClearance(unittest.TestCase): @classmethod def tearDownClass(cls): + frappe.db.set_single_value("Accounts Settings", "delete_linked_ledger_entries", 1) + payment_entry = frappe.get_doc( "Payment Entry", {"party_name": "_Test Supplier", "paid_from": "_Test Bank Clearance - _TC"} ) @@ -63,6 +65,8 @@ class TestBankClearance(unittest.TestCase): loan.flags.ignore_links = True loan.delete() + frappe.db.set_single_value("Accounts Settings", "delete_linked_ledger_entries", 0) + # Basic test case to test if bank clearance tool doesn't break # Detailed test can be added later def test_bank_clearance(self): From c515abc392a8ae6b230ff39e32aae6a8ca4a6dfe Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 24 Apr 2022 19:20:29 +0530 Subject: [PATCH 6/6] test: Remove teardown method --- .../bank_clearance/test_bank_clearance.py | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py index 18645c7517..c1e55f6f72 100644 --- a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py @@ -25,48 +25,6 @@ class TestBankClearance(unittest.TestCase): create_loan_masters() add_transactions() - @classmethod - def tearDownClass(cls): - frappe.db.set_single_value("Accounts Settings", "delete_linked_ledger_entries", 1) - - payment_entry = frappe.get_doc( - "Payment Entry", {"party_name": "_Test Supplier", "paid_from": "_Test Bank Clearance - _TC"} - ) - - if payment_entry.docstatus == 1: - payment_entry.cancel() - payment_entry.delete() - - loan = frappe.get_doc("Loan", {"applicant": "_Test Customer"}) - - ld_doc = frappe.get_doc("Loan Disbursement", {"against_loan": loan.name}) - - if ld_doc.docstatus == 1: - ld_doc.cancel() - ld_doc.delete() - - lr_doc = frappe.get_doc("Loan Repayment", {"against_loan": loan.name}) - - if lr_doc.docstatus == 1: - lr_doc.cancel() - lr_doc.delete() - - lia = frappe.get_doc("Loan Interest Accrual", {"loan": loan.name}) - lia.delete() - - plia = frappe.get_doc("Process Loan Interest Accrual", {"loan": loan.name}) - - if plia.docstatus == 1: - plia.cancel() - plia.delete() - - loan.load_from_db() - loan.cancel() - loan.flags.ignore_links = True - loan.delete() - - frappe.db.set_single_value("Accounts Settings", "delete_linked_ledger_entries", 0) - # Basic test case to test if bank clearance tool doesn't break # Detailed test can be added later def test_bank_clearance(self):