From af27d61bee3d2b6ad6a29c8219549c957900c3a9 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 13 Apr 2020 12:29:00 +0530 Subject: [PATCH] fix: Employee loan test case and other fixes --- erpnext/hooks.py | 2 +- .../payroll_entry/test_payroll_entry.py | 4 +- erpnext/hr/doctype/salary_slip/salary_slip.py | 45 ++++++++++++------- .../doctype/salary_slip/test_salary_slip.py | 4 +- .../loan_management/doctype/loan/test_loan.py | 7 ++- .../test_loan_disbursement.py | 2 +- .../loan_interest_accrual.py | 4 +- .../test_loan_interest_accrual.py | 2 +- .../doctype/loan_repayment/loan_repayment.py | 11 +++-- .../loan_security_shortfall.py | 9 +--- .../doctype/loan_type/loan_type.py | 3 ++ 11 files changed, 52 insertions(+), 41 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index f1881d97dfc..6d02a277a01 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -311,7 +311,7 @@ scheduler_events = { "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms", "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation", "erpnext.hr.utils.generate_leave_encashment", - "erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall.check_for_ltv_shortfall", + "erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall.create_process_loan_security_shortfall", "erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_term_loans" ], "monthly_long": [ diff --git a/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py b/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py index 35f5a57a1c3..49671d5e224 100644 --- a/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py +++ b/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py @@ -13,7 +13,7 @@ from erpnext.hr.doctype.salary_slip.test_salary_slip import get_salary_component make_earning_salary_component, make_deduction_salary_component from erpnext.hr.doctype.salary_structure.test_salary_structure import make_salary_structure from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry -from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import make_accrual_interest_entry_for_term_loans +from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans class TestPayrollEntry(unittest.TestCase): def setUp(self): @@ -81,7 +81,7 @@ class TestPayrollEntry(unittest.TestCase): make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1)) - make_accrual_interest_entry_for_term_loans(posting_date=nowdate()) + process_loan_interest_accrual_for_term_loans(posting_date=nowdate()) dates = get_start_end_dates('Monthly', nowdate()) diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index d03a3dd9a36..4d48fdfbd21 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -755,30 +755,43 @@ class SalarySlip(TransactionBase): d.amount = self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0] def set_loan_repayment(self): - self.set('loans', []) self.total_loan_repayment = 0 self.total_interest_amount = 0 self.total_principal_amount = 0 - for loan in self.get_loan_details(): + if not self.get('loans'): + for loan in self.get_loan_details(): - amounts = calculate_amounts(loan.name, self.posting_date, "Regular Payment") + amounts = calculate_amounts(loan.name, self.posting_date, "Regular Payment") - total_payment = amounts['interest_amount'] + amounts['payable_principal_amount'] + if amounts['interest_amount'] or amounts['payable_principal_amount']: + self.append('loans', { + 'loan': loan.name, + 'total_payment': amounts['interest_amount'] + amounts['payable_principal_amount'], + 'interest_amount': amounts['interest_amount'], + 'principal_amount': amounts['payable_principal_amount'], + 'loan_account': loan.loan_account, + 'interest_income_account': loan.interest_income_account + }) - if total_payment: - self.append('loans', { - 'loan': loan.name, - 'total_payment': total_payment, - 'interest_amount': amounts['interest_amount'], - 'principal_amount': amounts['payable_principal_amount'], - 'loan_account': loan.loan_account, - 'interest_income_account': loan.interest_income_account - }) + for payment in self.get('loans'): + amounts = calculate_amounts(payment.loan, self.posting_date, "Regular Payment") - self.total_loan_repayment += total_payment - self.total_interest_amount += amounts['interest_amount'] - self.total_principal_amount += amounts['payable_principal_amount'] + if payment.interest_amount > amounts['interest_amount']: + frappe.throw(_("""Row {0}: Paid Interest amount {1} is greater than pending interest amount {2} + against loan {3}""").format(payment.idx, frappe.bold(payment.interest_amount), + frappe.bold(amounts['interest_amount']), frappe.bold(payment.loan))) + + if payment.principal_amount > amounts['payable_principal_amount']: + frappe.throw(_("""Row {0}: Paid Principal amount {1} is greater than pending principal amount {2} + against loan {3}""").format(payment.idx, frappe.bold(payment.principal_amount), + frappe.bold(amounts['payable_principal_amount']), frappe.bold(payment.loan))) + + payment.total_payment = payment.interest_amount + payment.principal_amount + self.total_interest_amount += payment.interest_amount + self.total_principal_amount += payment.principal_amount + + self.total_loan_repayment = self.total_interest_amount + self.total_principal_amount def get_loan_details(self): diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py index 9acfd1f5c64..ecccac7d416 100644 --- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py @@ -146,7 +146,7 @@ class TestSalarySlip(unittest.TestCase): def test_loan_repayment_salary_slip(self): from erpnext.loan_management.doctype.loan.test_loan import create_loan_type, create_loan, make_loan_disbursement_entry, create_loan_accounts - from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import make_accrual_interest_entry_for_term_loans + from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans applicant = make_employee("test_loanemployee@salary.com", company="_Test Company") @@ -166,7 +166,7 @@ class TestSalarySlip(unittest.TestCase): make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1)) - make_accrual_interest_entry_for_term_loans(posting_date=nowdate()) + process_loan_interest_accrual_for_term_loans(posting_date=nowdate()) ss = make_employee_salary_slip("test_loanemployee@salary.com", "Monthly") ss.submit() diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py index 34b801b3bef..108672b25ae 100644 --- a/erpnext/loan_management/doctype/loan/test_loan.py +++ b/erpnext/loan_management/doctype/loan/test_loan.py @@ -12,9 +12,8 @@ from erpnext.selling.doctype.customer.test_customer import get_customer_dict from erpnext.hr.doctype.salary_structure.test_salary_structure import make_employee from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (process_loan_interest_accrual_for_demand_loans, process_loan_interest_accrual_for_term_loans) -from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_term_loans, days_in_year) - -from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import check_for_ltv_shortfall +from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year +from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall class TestLoan(unittest.TestCase): def setUp(self): @@ -298,7 +297,7 @@ class TestLoan(unittest.TestCase): frappe.db.sql(""" UPDATE `tabLoan Security Price` SET loan_security_price = 100 where loan_security='Test Security 2'""") - check_for_ltv_shortfall() + create_process_loan_security_shortfall() loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name}) self.assertTrue(loan_security_shortfall) diff --git a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py index 01290d400a3..189b2f5afff 100644 --- a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py +++ b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py @@ -8,7 +8,7 @@ from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_la from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_repayment_entry, make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_security_price) from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans -from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_term_loans, days_in_year) +from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year from erpnext.selling.doctype.customer.test_customer import get_customer_dict class TestLoanDisbursement(unittest.TestCase): diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py index 698b42409ba..094b9c698c7 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py @@ -94,7 +94,7 @@ def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_i 'applicant_type': loan.applicant_type, 'applicant': loan.applicant, 'interest_income_account': loan.interest_income_account, - 'loan_account': loan.loan_acccount, + 'loan_account': loan.loan_account, 'pending_principal_amount': pending_principal_amount, 'interest_amount': payable_interest, 'process_loan_interest': process_loan_interest, @@ -137,7 +137,7 @@ def make_accrual_interest_entry_for_term_loans(posting_date, process_loan_intere 'applicant_type': loan.applicant_type, 'applicant': loan.applicant, 'interest_income_account': loan.interest_income_account, - 'loan_account': loan.loan_acccount, + 'loan_account': loan.loan_account, 'interest_amount': loan.interest_amount, 'payable_principal': loan.principal_amount, 'process_loan_interest': process_loan_interest, diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py index dd4ca367c58..2f19ca1022c 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py @@ -8,7 +8,7 @@ from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_la from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_loan_security_price, make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan) from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans -from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_term_loans, days_in_year) +from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_years from erpnext.selling.doctype.customer.test_customer import get_customer_dict class TestLoanInterestAccrual(unittest.TestCase): diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py index a70e3128808..2d2ca4c2f4e 100644 --- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py +++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py @@ -210,7 +210,7 @@ class LoanRepayment(AccountsController): ) if gle_map: - make_gl_entries(gle_map, cancel=cancel, adv_adj=adv_adj) + make_gl_entries(gle_map, cancel=cancel, adv_adj=adv_adj, merge_entries=False) def create_repayment_entry(loan, applicant, company, posting_date, loan_type, payment_type, interest_payable, payable_principal_amount, amount_paid, penalty_amount=None): @@ -223,7 +223,7 @@ def create_repayment_entry(loan, applicant, company, posting_date, loan_type, "posting_date": posting_date, "applicant": applicant, "penalty_amount": penalty_amount, - "interets_payable": interest_payable, + "interst_payable": interest_payable, "payable_principal_amount": payable_principal_amount, "amount_paid": amount_paid, "loan_type": loan_type @@ -236,7 +236,8 @@ def get_accrued_interest_entries(against_loan): fields=["name", "interest_amount", "posting_date", "payable_principal_amount"], filters = { "loan": against_loan, - "is_paid": 0 + "is_paid": 0, + "docstatus": 1 }, order_by="posting_date") return accrued_interest_entries @@ -272,7 +273,9 @@ def get_amounts(amounts, against_loan, posting_date, payment_type): total_pending_interest += entry.interest_amount payable_principal_amount += entry.payable_principal_amount - pending_accrual_entries.setdefault(entry.name, entry.interest_amount) + pending_accrual_entries.setdefault(entry.name, + flt(entry.interest_amount) + flt(entry.payable_principal_amount)) + final_due_date = due_date pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid - against_loan_doc.total_interest_payable diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py index b7be84f8366..ab040f1d333 100644 --- a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py +++ b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py @@ -37,17 +37,10 @@ def add_security(loan): return loan_security_pledge.as_dict() -def check_for_ltv_shortfall(process_loan_security_shortfall=None): +def check_for_ltv_shortfall(process_loan_security_shortfall): update_time = get_datetime() - if not process_loan_security_shortfall: - process = frappe.new_doc("Process Loan Security Shortfall") - process.update_time = update_time - process.submit() - - process_loan_security_shortfall = process.name - loan_security_price_map = frappe._dict(frappe.get_all("Loan Security Price", fields=["loan_security", "loan_security_price"], filters = { diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.py b/erpnext/loan_management/doctype/loan_type/loan_type.py index 14b18ab57a1..208cb19c88e 100644 --- a/erpnext/loan_management/doctype/loan_type/loan_type.py +++ b/erpnext/loan_management/doctype/loan_type/loan_type.py @@ -19,3 +19,6 @@ class LoanType(Document): frappe.throw(_("Account {0} does not belong to company {1}").format(frappe.bold(self.get(fieldname)), frappe.bold(self.company))) + if self.get('loan_account') == self.get('payment_account'): + frappe.throw(_('Loan Account and Payment Account cannot be same')) +