FINERACT-1806: Charge-off validation
This commit is contained in:
+261
-40
@@ -69,9 +69,11 @@ import org.apache.fineract.client.models.PostGLAccountsRequest;
|
||||
import org.apache.fineract.client.models.PostGLAccountsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
|
||||
import org.apache.fineract.client.models.PutChargeTransactionChangesRequest;
|
||||
import org.apache.fineract.client.util.CallFailedRuntimeException;
|
||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
||||
@@ -6954,54 +6956,263 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void chargeOff() {
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
|
||||
String randomText = Utils.randomStringGenerator("en", 5) + Utils.randomNumberGenerator(6) + Utils.randomStringGenerator("is", 5);
|
||||
Integer chargeOffReasonId = CodeHelper.createChargeOffCodeValue(requestSpec, responseSpec, randomText, 1);
|
||||
final Integer loanProductID = createLoanProductWithPeriodicAccrualAccountingNoInterest(assetAccount, incomeAccount, expenseAccount,
|
||||
overpaymentAccount);
|
||||
try {
|
||||
GlobalConfigurationHelper.updateIsAutomaticExternalIdGenerationEnabled(this.requestSpec, this.responseSpec, true);
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(this.requestSpec, this.responseSpec, true);
|
||||
businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
|
||||
.date("2022.09.30").dateFormat("yyyy.MM.dd").locale("en"));
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
|
||||
String randomText = Utils.randomStringGenerator("en", 5) + Utils.randomNumberGenerator(6)
|
||||
+ Utils.randomStringGenerator("is", 5);
|
||||
Integer chargeOffReasonId = CodeHelper.createChargeOffCodeValue(requestSpec, responseSpec, randomText, 1);
|
||||
final Integer loanProductID = createLoanProductWithPeriodicAccrualAccountingNoInterestMultiDisbursement(assetAccount,
|
||||
incomeAccount, expenseAccount, overpaymentAccount);
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2011");
|
||||
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2011");
|
||||
|
||||
final Integer loanID = applyForLoanApplication(clientID, loanProductID);
|
||||
final Integer loanID = applyForLoanApplication(clientID, loanProductID);
|
||||
|
||||
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||
|
||||
loanStatusHashMap = this.loanTransactionHelper.approveLoan("02 September 2022", loanID);
|
||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||
ResponseSpecification errorResponseSpec = new ResponseSpecBuilder().expectStatusCode(403).build();
|
||||
LoanTransactionHelper errorLoanTransactionHelper = new LoanTransactionHelper(this.requestSpec, errorResponseSpec);
|
||||
|
||||
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("03 September 2022", loanID, "1000");
|
||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.chargeOffLoan((long) loanID,
|
||||
new PostLoansLoanIdTransactionsRequest().transactionDate("4 September 2022").locale("en").dateFormat("dd MMMM yyyy")
|
||||
.externalId(UUID.randomUUID().toString()).chargeOffReasonId((long) chargeOffReasonId));
|
||||
});
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID);
|
||||
assertTrue(loanDetails.getStatus().getActive());
|
||||
assertEquals(1000.0, loanDetails.getSummary().getTotalOutstanding());
|
||||
assertFalse(loanDetails.getChargedOff());
|
||||
assertNull(loanDetails.getSummary().getChargeOffReasonId());
|
||||
assertNull(loanDetails.getSummary().getChargeOffReason());
|
||||
assertNull(loanDetails.getTimeline().getChargedOffOnDate());
|
||||
assertNull(loanDetails.getTimeline().getChargedOffByUsername());
|
||||
assertNull(loanDetails.getTimeline().getChargedOffByFirstname());
|
||||
assertNull(loanDetails.getTimeline().getChargedOffByLastname());
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.is.not.active"));
|
||||
|
||||
String transactionExternalId = UUID.randomUUID().toString();
|
||||
this.loanTransactionHelper.chargeOffLoan((long) loanID, new PostLoansLoanIdTransactionsRequest().transactionDate("4 September 2022")
|
||||
.locale("en").dateFormat("dd MMMM yyyy").externalId(transactionExternalId).chargeOffReasonId((long) chargeOffReasonId));
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
this.loanTransactionHelper.undoChargeOffLoan((long) loanID, new PostLoansLoanIdTransactionsRequest());
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.is.not.active"));
|
||||
|
||||
loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID);
|
||||
assertTrue(loanDetails.getStatus().getActive());
|
||||
assertEquals(1000.0, loanDetails.getSummary().getTotalOutstanding());
|
||||
assertTrue(loanDetails.getChargedOff());
|
||||
assertEquals((long) chargeOffReasonId, loanDetails.getSummary().getChargeOffReasonId());
|
||||
assertEquals(randomText, loanDetails.getSummary().getChargeOffReason());
|
||||
assertEquals(LocalDate.of(2022, 9, 4), loanDetails.getTimeline().getChargedOffOnDate());
|
||||
assertEquals("mifos", loanDetails.getTimeline().getChargedOffByUsername());
|
||||
assertEquals("App", loanDetails.getTimeline().getChargedOffByFirstname());
|
||||
assertEquals("Administrator", loanDetails.getTimeline().getChargedOffByLastname());
|
||||
loanStatusHashMap = this.loanTransactionHelper.approveLoan("02 September 2022", loanID);
|
||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||
|
||||
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithTransactionAmount("02 September 2022", loanID, "1000");
|
||||
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithTransactionAmount("03 September 2022", loanID, "1000");
|
||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID);
|
||||
assertTrue(loanDetails.getStatus().getActive());
|
||||
assertEquals(2000.0, loanDetails.getSummary().getTotalOutstanding());
|
||||
assertFalse(loanDetails.getChargedOff());
|
||||
assertNull(loanDetails.getSummary().getChargeOffReasonId());
|
||||
assertNull(loanDetails.getSummary().getChargeOffReason());
|
||||
assertNull(loanDetails.getTimeline().getChargedOffOnDate());
|
||||
assertNull(loanDetails.getTimeline().getChargedOffByUsername());
|
||||
assertNull(loanDetails.getTimeline().getChargedOffByFirstname());
|
||||
assertNull(loanDetails.getTimeline().getChargedOffByLastname());
|
||||
|
||||
Integer flatPenaltySpecifiedDueDate = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "3", true));
|
||||
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper
|
||||
.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flatPenaltySpecifiedDueDate), "04 September 2022", "3"));
|
||||
Integer chargeId = this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper
|
||||
.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flatPenaltySpecifiedDueDate), "04 September 2022", "5"));
|
||||
|
||||
PostLoansLoanIdChargesChargeIdResponse waiveChargeResponse = this.loanTransactionHelper.waiveLoanCharge((long) loanID,
|
||||
(long) chargeId, new PostLoansLoanIdChargesChargeIdRequest());
|
||||
|
||||
String transactionExternalId = UUID.randomUUID().toString();
|
||||
this.loanTransactionHelper.chargeOffLoan((long) loanID,
|
||||
new PostLoansLoanIdTransactionsRequest().transactionDate("4 September 2022").locale("en").dateFormat("dd MMMM yyyy")
|
||||
.externalId(transactionExternalId).chargeOffReasonId((long) chargeOffReasonId));
|
||||
|
||||
loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID);
|
||||
assertTrue(loanDetails.getStatus().getActive());
|
||||
assertEquals(2003.0, loanDetails.getSummary().getTotalOutstanding());
|
||||
assertTrue(loanDetails.getChargedOff());
|
||||
assertEquals((long) chargeOffReasonId, loanDetails.getSummary().getChargeOffReasonId());
|
||||
assertEquals(randomText, loanDetails.getSummary().getChargeOffReason());
|
||||
assertEquals(LocalDate.of(2022, 9, 4), loanDetails.getTimeline().getChargedOffOnDate());
|
||||
assertEquals("mifos", loanDetails.getTimeline().getChargedOffByUsername());
|
||||
assertEquals("App", loanDetails.getTimeline().getChargedOffByFirstname());
|
||||
assertEquals("Administrator", loanDetails.getTimeline().getChargedOffByLastname());
|
||||
|
||||
GetLoansLoanIdTransactions chargeOffTransaction = loanDetails.getTransactions().get(loanDetails.getTransactions().size() - 1);
|
||||
|
||||
assertEquals(2003.0, chargeOffTransaction.getAmount());
|
||||
assertEquals(2000.0, chargeOffTransaction.getPrincipalPortion());
|
||||
assertEquals(3.0, chargeOffTransaction.getPenaltyChargesPortion());
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.chargeOffLoan((long) loanID,
|
||||
new PostLoansLoanIdTransactionsRequest().transactionDate("4 September 2022").locale("en").dateFormat("dd MMMM yyyy")
|
||||
.externalId(UUID.randomUUID().toString()).chargeOffReasonId((long) chargeOffReasonId));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.is.already.charged.off"));
|
||||
|
||||
HashMap chargeAddingError = errorLoanTransactionHelper.addChargesForLoanGetFullResponse(loanID, LoanTransactionHelper
|
||||
.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flatPenaltySpecifiedDueDate), "04 September 2022", "3"));
|
||||
|
||||
assertEquals("error.msg.loan.is.charged.off",
|
||||
((Map) ((List) chargeAddingError.get("errors")).get(0)).get("userMessageGlobalisationCode"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.undoWaiveLoanCharge((long) loanID, waiveChargeResponse.getSubResourceId(),
|
||||
new PutChargeTransactionChangesRequest());
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date"));
|
||||
|
||||
this.loanTransactionHelper.undoChargeOffLoan((long) loanID, new PostLoansLoanIdTransactionsRequest());
|
||||
|
||||
loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID);
|
||||
assertFalse(loanDetails.getChargedOff());
|
||||
assertNull(loanDetails.getSummary().getChargeOffReasonId());
|
||||
assertNull(loanDetails.getSummary().getChargeOffReason());
|
||||
assertNull(loanDetails.getTimeline().getChargedOffOnDate());
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.undoChargeOffLoan((long) loanID, new PostLoansLoanIdTransactionsRequest());
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.is.not.charged.off"));
|
||||
|
||||
PostLoansLoanIdTransactionsResponse loanRepaymentResponse = this.loanTransactionHelper.makeLoanRepayment((long) loanID,
|
||||
new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("05 September 2022").locale("en")
|
||||
.transactionAmount(5.0));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.chargeOffLoan((long) loanID,
|
||||
new PostLoansLoanIdTransactionsRequest().transactionDate("04 September 2022").locale("en")
|
||||
.dateFormat("dd MMMM yyyy").externalId(UUID.randomUUID().toString())
|
||||
.chargeOffReasonId((long) chargeOffReasonId));
|
||||
});
|
||||
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.charge.off.is.before.than.the.last.user.transaction"));
|
||||
|
||||
this.loanTransactionHelper.chargeOffLoan((long) loanID,
|
||||
new PostLoansLoanIdTransactionsRequest().transactionDate("06 September 2022").locale("en").dateFormat("dd MMMM yyyy")
|
||||
.externalId(UUID.randomUUID().toString()).chargeOffReasonId((long) chargeOffReasonId));
|
||||
|
||||
loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID);
|
||||
chargeOffTransaction = loanDetails.getTransactions().get(loanDetails.getTransactions().size() - 1);
|
||||
|
||||
assertEquals(1998.0, chargeOffTransaction.getAmount());
|
||||
assertEquals(1998.0, chargeOffTransaction.getPrincipalPortion());
|
||||
|
||||
this.loanTransactionHelper.makeLoanRepayment((long) loanID, new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy")
|
||||
.transactionDate("07 September 2022").locale("en").transactionAmount(5.0));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.undoChargeOffLoan((long) loanID, new PostLoansLoanIdTransactionsRequest());
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.charge.off.is.not.the.last.user.transaction"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.adjustLoanTransaction((long) loanID, loanRepaymentResponse.getResourceId(),
|
||||
new PostLoansLoanIdTransactionsTransactionIdRequest().transactionDate("06 September 2022").locale("en")
|
||||
.dateFormat("dd MMMM yyyy").transactionAmount(0.0));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.adjusted.transaction.date.cannot.be.earlier.than.charge.off.date"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.makeWriteoff((long) loanID, new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy")
|
||||
.transactionDate("05 September 2022").locale("en"));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.closeLoan((long) loanID, new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy")
|
||||
.transactionDate("05 September 2022").locale("en"));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.forecloseLoan((long) loanID, new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy")
|
||||
.transactionDate("05 September 2022").locale("en"));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.closeRescheduledLoan((long) loanID, new PostLoansLoanIdTransactionsRequest()
|
||||
.dateFormat("dd MMMM yyyy").transactionDate("05 September 2022").locale("en"));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.is.charged.off"));
|
||||
|
||||
HashMap disbursementDetailREsponse = (HashMap) errorLoanTransactionHelper.addAndDeleteDisbursementDetail(loanID, "1000",
|
||||
"03 September 2022", List.of(this.loanTransactionHelper.createTrancheDetail(null, "05 September 2022", "200")), "");
|
||||
|
||||
assertEquals("error.msg.loan.is.charged.off",
|
||||
((Map) ((List) disbursementDetailREsponse.get("errors")).get(0)).get("userMessageGlobalisationCode"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.undoLastDisbursalLoan((long) loanID, new PostLoansLoanIdRequest());
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.is.charged.off"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.undoDisbursalLoan((long) loanID, new PostLoansLoanIdRequest());
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.is.charged.off"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.makeLoanRepayment((long) loanID, new PostLoansLoanIdTransactionsRequest()
|
||||
.dateFormat("dd MMMM yyyy").transactionDate("05 September 2022").locale("en").transactionAmount(5.0));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.makeLoanRepayment((long) loanID, new PostLoansLoanIdTransactionsRequest()
|
||||
.dateFormat("dd MMMM yyyy").transactionDate("05 September 2022").locale("en").transactionAmount(5.0));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.makeCreditBalanceRefund((long) loanID, new PostLoansLoanIdTransactionsRequest()
|
||||
.dateFormat("dd MMMM yyyy").transactionDate("05 September 2022").locale("en").transactionAmount(5.0));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.disburseLoan((long) loanID,
|
||||
new PostLoansLoanIdRequest().actualDisbursementDate("4 September 2022").transactionAmount(new BigDecimal("10"))
|
||||
.locale("en").dateFormat("dd MMMM yyyy"));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date"));
|
||||
|
||||
this.loanTransactionHelper.makeLoanRepayment((long) loanID, new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy")
|
||||
.transactionDate("07 September 2022").locale("en").transactionAmount(5000.0));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> {
|
||||
errorLoanTransactionHelper.makeRefundByCash((long) loanID, new PostLoansLoanIdTransactionsRequest()
|
||||
.dateFormat("dd MMMM yyyy").transactionDate("05 September 2022").locale("en").transactionAmount(5.0));
|
||||
});
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date"));
|
||||
|
||||
this.loanTransactionHelper.makeCreditBalanceRefund((long) loanID, new PostLoansLoanIdTransactionsRequest()
|
||||
.dateFormat("dd MMMM yyyy").transactionDate("08 September 2022").locale("en").transactionAmount(3007.0));
|
||||
} finally {
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -7480,6 +7691,16 @@ public class ClientLoanIntegrationTest {
|
||||
return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
|
||||
}
|
||||
|
||||
private Integer createLoanProductWithPeriodicAccrualAccountingNoInterestMultiDisbursement(final Account... accounts) {
|
||||
LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
|
||||
final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
|
||||
.withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
|
||||
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
|
||||
.withAccountingRulePeriodicAccrual(accounts).withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30")
|
||||
.withDaysInYear("365").withMoratorium("0", "0").withMultiDisburse().withDisallowExpectedDisbursements(true).build(null);
|
||||
return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
|
||||
}
|
||||
|
||||
private void validateIfValuesAreNotOverridden(Integer loanID, Integer loanProductID) {
|
||||
String loanProductDetails = this.loanTransactionHelper.getLoanProductDetails(this.requestSpec, this.responseSpec, loanProductID);
|
||||
String loanDetails = this.loanTransactionHelper.getLoanDetails(this.requestSpec, this.responseSpec, loanID);
|
||||
|
||||
+31
@@ -32,6 +32,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
|
||||
import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
|
||||
@@ -246,6 +247,36 @@ public class LoanRescheduleOnDecliningBalanceLoanTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateLoanRescheduleRequestFailIfLoanIsChargedOff() {
|
||||
// create all required entities
|
||||
this.createRequiredEntities();
|
||||
this.createLoanRescheduleRequestWhichFailsAsLoanIdChargedOff();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* create new loan reschedule request
|
||||
**/
|
||||
private void createLoanRescheduleRequestWhichFailsAsLoanIdChargedOff() {
|
||||
|
||||
final String requestJSON = new LoanRescheduleRequestTestBuilder().updateGraceOnPrincipal(null).updateGraceOnInterest(null)
|
||||
.updateExtraTerms(null).updateRescheduleFromDate("04 January 2015").updateAdjustedDueDate("04 October 2015")
|
||||
.updateRecalculateInterest(true).build(this.loanId.toString());
|
||||
|
||||
this.loanTransactionHelper.chargeOffLoan((long) this.loanId,
|
||||
new PostLoansLoanIdTransactionsRequest().transactionDate("04 January 2015").locale("en").dateFormat("dd MMMM yyyy"));
|
||||
|
||||
ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(403).build();
|
||||
LoanRescheduleRequestHelper errorLoanRescheduleRequestHelper = new LoanRescheduleRequestHelper(this.requestSpec, responseSpec);
|
||||
HashMap response = errorLoanRescheduleRequestHelper.createLoanRescheduleRequestWithFullResponse(requestJSON);
|
||||
assertEquals("error.msg.loan.is.charged.off", ((Map) ((List) response.get("errors")).get(0)).get("userMessageGlobalisationCode"));
|
||||
|
||||
this.loanTransactionHelper.undoChargeOffLoan((long) this.loanId, new PostLoansLoanIdTransactionsRequest());
|
||||
this.loanTransactionHelper.closeRescheduledLoan((long) this.loanId,
|
||||
new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("04 January 2015").locale("en"));
|
||||
}
|
||||
|
||||
/**
|
||||
* create new loan reschedule request
|
||||
**/
|
||||
|
||||
+46
@@ -50,6 +50,7 @@ import java.util.TimeZone;
|
||||
import org.apache.fineract.client.models.BusinessDateRequest;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
import org.apache.fineract.client.models.PutJobsJobIDRequest;
|
||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
||||
@@ -603,6 +604,51 @@ public class SchedulerJobsTestResults {
|
||||
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyPenaltyForOverdueLoansJobOutcomeIfLoanChargedOff() throws InterruptedException {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
|
||||
this.loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec);
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec);
|
||||
Assertions.assertNotNull(clientID);
|
||||
|
||||
Integer overdueFeeChargeId = ChargesHelper.createCharges(requestSpec, responseSpec, ChargesHelper.getLoanOverdueFeeJSON());
|
||||
Assertions.assertNotNull(overdueFeeChargeId);
|
||||
|
||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||
Assertions.assertNotNull(loanProductID);
|
||||
|
||||
final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2020");
|
||||
Assertions.assertNotNull(loanID);
|
||||
|
||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||
|
||||
loanStatusHashMap = this.loanTransactionHelper.approveLoan("01 March 2020", loanID);
|
||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||
|
||||
String loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
|
||||
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("02 March 2020", loanID,
|
||||
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
|
||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||
|
||||
this.loanTransactionHelper.chargeOffLoan((long) loanID,
|
||||
new PostLoansLoanIdTransactionsRequest().transactionDate("03 March 2020").locale("en").dateFormat("dd MMMM yyyy"));
|
||||
|
||||
String JobName = "Apply penalty to overdue loans";
|
||||
this.schedulerJobHelper.executeAndAwaitJob(JobName);
|
||||
|
||||
ArrayList<HashMap> repaymentScheduleDataAfter = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec,
|
||||
loanID);
|
||||
|
||||
Assertions.assertEquals(0, (Integer) repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
|
||||
"Verifying From Penalty Charges due fot first Repayment after Successful completion of Scheduler Job");
|
||||
|
||||
this.loanTransactionHelper.undoChargeOffLoan((long) loanID, new PostLoansLoanIdTransactionsRequest());
|
||||
this.loanTransactionHelper.closeRescheduledLoan((long) loanID,
|
||||
new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("03 March 2020").locale("en"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanCOBJobOutcome() {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
|
||||
|
||||
+5
@@ -455,6 +455,11 @@ public class ExternalEventConfigurationHelper {
|
||||
loanChargeOffPostBusinessEvent.put("enabled", false);
|
||||
defaults.add(loanChargeOffPostBusinessEvent);
|
||||
|
||||
Map<String, Object> loanUndoChargeOffPostBusinessEvent = new HashMap<>();
|
||||
loanUndoChargeOffPostBusinessEvent.put("type", "LoanUndoChargeOffBusinessEvent");
|
||||
loanUndoChargeOffPostBusinessEvent.put("enabled", false);
|
||||
defaults.add(loanUndoChargeOffPostBusinessEvent);
|
||||
|
||||
return defaults;
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class LoanRescheduleRequestHelper {
|
||||
|
||||
@@ -40,6 +41,11 @@ public class LoanRescheduleRequestHelper {
|
||||
return Utils.performServerPost(this.requestSpec, this.responseSpec, URL, requestJSON, "resourceId");
|
||||
}
|
||||
|
||||
public HashMap createLoanRescheduleRequestWithFullResponse(final String requestJSON) {
|
||||
final String URL = LOAN_RESCHEDULE_REQUEST_URL + "?" + Utils.TENANT_IDENTIFIER;
|
||||
return Utils.performServerPost(this.requestSpec, this.responseSpec, URL, requestJSON, "");
|
||||
}
|
||||
|
||||
public Integer rejectLoanRescheduleRequest(final Integer requestId, final String requestJSON) {
|
||||
final String URL = LOAN_RESCHEDULE_REQUEST_URL + "/" + requestId + "?" + Utils.TENANT_IDENTIFIER + "&command=reject";
|
||||
|
||||
|
||||
+43
@@ -710,6 +710,11 @@ public class LoanTransactionHelper extends IntegrationTest {
|
||||
return ok(fineract().loanTransactions.adjustLoanTransaction1(loanId, transactionExternalId, request, "adjust"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse adjustLoanTransaction(final Long loanId, final Long transactionId,
|
||||
final PostLoansLoanIdTransactionsTransactionIdRequest request) {
|
||||
return ok(fineract().loanTransactions.adjustLoanTransaction(loanId, transactionId, request, "adjust"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse adjustLoanTransaction(final Integer loanId, final Long transactionId, String date,
|
||||
ResponseSpecification responseSpec) {
|
||||
return postLoanTransaction(createLoanTransactionURL(null, loanId, transactionId.intValue()),
|
||||
@@ -757,6 +762,12 @@ public class LoanTransactionHelper extends IntegrationTest {
|
||||
return (Integer) response.get("resourceId");
|
||||
}
|
||||
|
||||
public HashMap addChargesForLoanGetFullResponse(final Integer loanId, final String request) {
|
||||
log.info("--------------------------------- ADD CHARGES FOR LOAN --------------------------------");
|
||||
final String ADD_CHARGES_URL = LOAN_ACCOUNT_URL + "/" + loanId + "/charges?" + Utils.TENANT_IDENTIFIER;
|
||||
return Utils.performServerPost(requestSpec, responseSpec, ADD_CHARGES_URL, request, "");
|
||||
}
|
||||
|
||||
public Integer addChargesForLoan(final Integer loanId, final String request, final ResponseSpecification responseSpecParam) {
|
||||
log.info("--------------------------------- ADD CHARGES FOR LOAN --------------------------------");
|
||||
final String ADD_CHARGES_URL = LOAN_ACCOUNT_URL + "/" + loanId + "/charges?" + Utils.TENANT_IDENTIFIER;
|
||||
@@ -1738,6 +1749,10 @@ public class LoanTransactionHelper extends IntegrationTest {
|
||||
return ok(fineract().loans.stateTransitions1(loanExternalId, request, "disburse"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdResponse disburseLoan(Long loanId, PostLoansLoanIdRequest request) {
|
||||
return ok(fineract().loans.stateTransitions(loanId, request, "disburse"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdResponse disburseToSavingsLoan(String loanExternalId, PostLoansLoanIdRequest request) {
|
||||
return ok(fineract().loans.stateTransitions1(loanExternalId, request, "disburseToSavings"));
|
||||
}
|
||||
@@ -1750,10 +1765,18 @@ public class LoanTransactionHelper extends IntegrationTest {
|
||||
return ok(fineract().loans.stateTransitions1(loanExternalId, request, "undodisbursal"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdResponse undoDisbursalLoan(Long loanId, PostLoansLoanIdRequest request) {
|
||||
return ok(fineract().loans.stateTransitions(loanId, request, "undodisbursal"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdResponse undoLastDisbursalLoan(String loanExternalId, PostLoansLoanIdRequest request) {
|
||||
return ok(fineract().loans.stateTransitions1(loanExternalId, request, "undolastdisbursal"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdResponse undoLastDisbursalLoan(Long loanId, PostLoansLoanIdRequest request) {
|
||||
return ok(fineract().loans.stateTransitions(loanId, request, "undolastdisbursal"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdResponse assignLoanOfficerLoan(String loanExternalId, PostLoansLoanIdRequest request) {
|
||||
return ok(fineract().loans.stateTransitions1(loanExternalId, request, "assignloanofficer"));
|
||||
}
|
||||
@@ -1774,14 +1797,26 @@ public class LoanTransactionHelper extends IntegrationTest {
|
||||
return ok(fineract().loanTransactions.executeLoanTransaction1(loanExternalId, request, "close-rescheduled"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse closeRescheduledLoan(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return ok(fineract().loanTransactions.executeLoanTransaction(loanId, request, "close-rescheduled"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse closeLoan(String loanExternalId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return ok(fineract().loanTransactions.executeLoanTransaction1(loanExternalId, request, "close"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse closeLoan(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return ok(fineract().loanTransactions.executeLoanTransaction(loanId, request, "close"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse forecloseLoan(String loanExternalId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return ok(fineract().loanTransactions.executeLoanTransaction1(loanExternalId, request, "foreclosure"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse forecloseLoan(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return ok(fineract().loanTransactions.executeLoanTransaction(loanId, request, "foreclosure"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse chargeOffLoan(String loanExternalId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return ok(fineract().loanTransactions.executeLoanTransaction1(loanExternalId, request, "charge-off"));
|
||||
}
|
||||
@@ -1789,4 +1824,12 @@ public class LoanTransactionHelper extends IntegrationTest {
|
||||
public PostLoansLoanIdTransactionsResponse chargeOffLoan(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return ok(fineract().loanTransactions.executeLoanTransaction(loanId, request, "charge-off"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse undoChargeOffLoan(String loanExternalId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return ok(fineract().loanTransactions.executeLoanTransaction1(loanExternalId, request, "undo-charge-off"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse undoChargeOffLoan(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return ok(fineract().loanTransactions.executeLoanTransaction(loanId, request, "undo-charge-off"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user