This is an automated email from the ASF dual-hosted git repository.
arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 8457b31c0 FINERACT-1829-Store-Overpaid-Date-for-Loan
8457b31c0 is described below
commit 8457b31c0f7594f742c3a25fe9534a79f0c3ae51
Author: Ruchi Dhamankar <[email protected]>
AuthorDate: Mon Dec 12 13:55:02 2022 +0530
FINERACT-1829-Store-Overpaid-Date-for-Loan
---
.../loanaccount/api/LoansApiResourceSwagger.java | 2 +
.../loanaccount/data/LoanAccountData.java | 24 +--
.../portfolio/loanaccount/domain/Loan.java | 16 +-
.../service/LoanReadPlatformServiceImpl.java | 5 +-
.../db/changelog/tenant/changelog-tenant.xml | 1 +
.../parts/0077_add_overpaid_date_for_loan.xml | 32 ++++
.../LoanAccountOverpaidDateStatusTest.java | 189 +++++++++++++++++++++
7 files changed, 255 insertions(+), 14 deletions(-)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
index fa32ec58a..0e25608b9 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
@@ -1005,6 +1005,8 @@ final class LoansApiResourceSwagger {
@Schema(example = "250.000000")
public Double totalOverpaid;
public LocalDate lastClosedBusinessDate;
+ @Schema(example = "[2013, 11, 1]")
+ public LocalDate overpaidOnDate;
}
@Schema(description = "GetLoansResponse")
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
index caf3dc0f8..4ddca73c0 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
@@ -247,6 +247,7 @@ public class LoanAccountData {
private String linkAccountId;
private Long groupId;
private LocalDate expectedDisbursementDate;
+ private LocalDate overpaidOnDate;
private CollectionData delinquent;
private DelinquencyRangeData delinquencyRange;
@@ -379,7 +380,7 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
- .setFraud(acc.fraud);
+ .setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate);
}
/**
@@ -450,7 +451,7 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
- .setFraud(acc.fraud);
+ .setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate);
}
public static LoanAccountData loanProductWithTemplateDefaults(final
LoanProductData product,
@@ -617,7 +618,8 @@ public class LoanAccountData {
.setClosureLoanId(acc.closureLoanId).setClosureLoanAccountNo(acc.closureLoanAccountNo).setTopupAmount(acc.topupAmount)
.setIsEqualAmortization(product.isEqualAmortization()).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(product.getFixedPrincipalPercentagePerInstallment()).setDelinquent(delinquent)
-
.setDisallowExpectedDisbursements(product.getDisallowExpectedDisbursements()).setFraud(acc.fraud);
+
.setDisallowExpectedDisbursements(product.getDisallowExpectedDisbursements()).setFraud(acc.fraud)
+ .setOverpaidOnDate(acc.overpaidOnDate);
}
/*
@@ -650,7 +652,7 @@ public class LoanAccountData {
final boolean canUseForTopup, final boolean isTopup, final Long
closureLoanId, final String closureLoanAccountNo,
final BigDecimal topupAmount, final boolean isEqualAmortization,
final BigDecimal fixedPrincipalPercentagePerInstallment,
final DelinquencyRangeData delinquencyRange, final boolean
disallowExpectedDisbursements, final boolean fraud,
- LocalDate lastClosedBusinessDate) {
+ LocalDate lastClosedBusinessDate, LocalDate overpaidOnDate) {
final CollectionData delinquent = CollectionData.template();
@@ -690,7 +692,7 @@ public class LoanAccountData {
.setClosureLoanAccountNo(closureLoanAccountNo).setTopupAmount(topupAmount).setIsEqualAmortization(isEqualAmortization)
.setFixedPrincipalPercentagePerInstallment(fixedPrincipalPercentagePerInstallment).setDelinquent(delinquent)
.setDelinquencyRange(delinquencyRange).setDisallowExpectedDisbursements(disallowExpectedDisbursements).setFraud(fraud)
- .setLastClosedBusinessDate(lastClosedBusinessDate);
+
.setLastClosedBusinessDate(lastClosedBusinessDate).setOverpaidOnDate(overpaidOnDate);
}
/*
@@ -774,7 +776,7 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
-
.setFraud(acc.fraud).setLastClosedBusinessDate(acc.getLastClosedBusinessDate());
+
.setFraud(acc.fraud).setLastClosedBusinessDate(acc.getLastClosedBusinessDate()).setOverpaidOnDate(acc.overpaidOnDate);
}
public static LoanAccountData associationsAndTemplate(final
LoanAccountData acc, final Collection<LoanProductData> productOptions,
@@ -849,7 +851,7 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
- .setFraud(acc.fraud);
+ .setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate);
}
public static LoanAccountData associateMemberVariations(final
LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
@@ -946,7 +948,7 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
- .setFraud(acc.fraud);
+ .setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate);
}
public static LoanAccountData withInterestRecalculationCalendarData(final
LoanAccountData acc, final CalendarData calendarData,
@@ -1011,7 +1013,7 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
- .setFraud(acc.fraud);
+ .setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate);
}
public static LoanAccountData withLoanCalendarData(final LoanAccountData
acc, final CalendarData calendarData) {
@@ -1069,7 +1071,7 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
- .setFraud(acc.fraud);
+ .setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate);
}
public static LoanAccountData withOriginalSchedule(final LoanAccountData
acc, final LoanScheduleData originalSchedule) {
@@ -1130,7 +1132,7 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
- .setFraud(acc.fraud);
+ .setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate);
}
public static final Comparator<LoanAccountData> ClientNameComparator =
(loan1, loan2) -> {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index ac4b0a997..e6b3f10ad 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -314,6 +314,9 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
@Column(name = "total_overpaid_derived", scale = 6, precision = 19)
private BigDecimal totalOverpaid;
+ @Column(name = "overpaidon_date")
+ private LocalDate overpaidOnDate;
+
@Column(name = "loan_counter")
private Integer loanCounter;
@@ -3410,6 +3413,9 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
handleLoanRepaymentInFull(transactionDate,
loanLifecycleStateMachine);
statusChanged = true;
}
+ if (this.totalOverpaid == null ||
BigDecimal.ZERO.compareTo(this.totalOverpaid) == 0) {
+ this.overpaidOnDate = null;
+ }
return statusChanged;
}
@@ -3429,6 +3435,9 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
this.closedOnDate = transactionDate;
this.actualMaturityDate = transactionDate;
} else if (LoanStatus.fromInt(this.loanStatus).isOverpaid()) {
+ if (this.totalOverpaid == null ||
BigDecimal.ZERO.compareTo(this.totalOverpaid) == 0) {
+ this.overpaidOnDate = null;
+ }
loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, this);
}
processIncomeAccrualTransactionOnLoanClosure();
@@ -3512,7 +3521,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
private void handleLoanOverpayment(final LoanLifecycleStateMachine
loanLifecycleStateMachine) {
loanLifecycleStateMachine.transition(LoanEvent.LOAN_OVERPAYMENT, this);
-
+ this.overpaidOnDate = DateUtils.getBusinessLocalDate();
this.closedOnDate = null;
this.actualMaturityDate = null;
}
@@ -5280,6 +5289,10 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
return this.totalOverpaid;
}
+ public LocalDate getOverpaidOnDate() {
+ return this.overpaidOnDate;
+ }
+
public void updateIsInterestRecalculationEnabled() {
this.loanRepaymentScheduleDetail.updateIsInterestRecalculationEnabled(isInterestRecalculationEnabledForProduct());
}
@@ -6086,6 +6099,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
updateLoanSummaryDerivedFields();
if (this.totalOverpaid == null ||
BigDecimal.ZERO.compareTo(this.totalOverpaid) == 0) {
+ this.overpaidOnDate = null;
defaultLoanLifecycleStateMachine.transition(LoanEvent.LOAN_CREDIT_BALANCE_REFUND,
this);
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index 16ecd7028..530274e5c 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -661,7 +661,7 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService {
+ " lpvi.minimum_gap as minimuminstallmentgap,
lpvi.maximum_gap as maximuminstallmentgap, "
+ " lp.can_use_for_topup as canUseForTopup, l.is_topup as
isTopup, topup.closure_loan_id as closureLoanId, "
+ " l.total_recovered_derived as totalRecovered,
topuploan.account_no as closureLoanAccountNo, "
- + " topup.topup_amount as topupAmount,
l.last_closed_business_date as lastClosedBusinessDate from m_loan l" //
+ + " topup.topup_amount as topupAmount,
l.last_closed_business_date as lastClosedBusinessDate,l.overpaidon_date as
overpaidOnDate from m_loan l" //
+ " join m_product_loan lp on lp.id = l.product_id" //
+ " left join m_loan_recalculation_details lir on
lir.loan_id = l.id join m_currency rc on rc."
+ sqlGenerator.escape("code") + " = l.currency_code" //
@@ -988,6 +988,7 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService {
final boolean isFraud = rs.getBoolean("isFraud");
final LocalDate lastClosedBusinessDate =
JdbcSupport.getLocalDate(rs, "lastClosedBusinessDate");
+ final LocalDate overpaidOnDate = JdbcSupport.getLocalDate(rs,
"overpaidOnDate");
return LoanAccountData.basicLoanDetails(id, accountNo, status,
externalId, clientId, clientAccountNo, clientName,
clientOfficeId, clientExternalId, groupData, loanType,
loanProductId, loanProductName, loanProductDescription,
@@ -1004,7 +1005,7 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService {
createStandingInstructionAtDisbursement,
isvariableInstallmentsAllowed, minimumGap, maximumGap, loanSubStatus,
canUseForTopup, isTopup, closureLoanId,
closureLoanAccountNo, topupAmount, isEqualAmortization,
fixedPrincipalPercentagePerInstallment, delinquencyRange,
disallowExpectedDisbursements, isFraud,
- lastClosedBusinessDate);
+ lastClosedBusinessDate, overpaidOnDate);
}
}
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index 19b969f99..fd5e528f8 100644
---
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -96,4 +96,5 @@
<include file="parts/0074_add_last_cob_business_date_column_to_loan.xml"
relativeToChangelogFile="true"/>
<include file="parts/0075_add_processed_commands_purge_job.xml"
relativeToChangelogFile="true" />
<include file="parts/0076_add_loan_transaction_enum_values.xml"
relativeToChangelogFile="true" />
+ <include file="parts/0077_add_overpaid_date_for_loan.xml"
relativeToChangelogFile="true" />
</databaseChangeLog>
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0077_add_overpaid_date_for_loan.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0077_add_overpaid_date_for_loan.xml
new file mode 100644
index 000000000..b40a2b43c
--- /dev/null
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0077_add_overpaid_date_for_loan.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
+ <changeSet author="fineract" id="1">
+ <addColumn tableName="m_loan">
+ <column name="overpaidon_date" type="date">
+ <constraints nullable="true"/>
+ </column>
+ </addColumn>
+ </changeSet>
+</databaseChangeLog>
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountOverpaidDateStatusTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountOverpaidDateStatusTest.java
new file mode 100644
index 000000000..544388edd
--- /dev/null
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountOverpaidDateStatusTest.java
@@ -0,0 +1,189 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.integrationtests;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import io.restassured.builder.RequestSpecBuilder;
+import io.restassured.builder.ResponseSpecBuilder;
+import io.restassured.http.ContentType;
+import io.restassured.specification.RequestSpecification;
+import io.restassured.specification.ResponseSpecification;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.util.HashMap;
+import java.util.UUID;
+import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
+import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
+import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
+import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.integrationtests.common.BusinessDateHelper;
+import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
+import org.apache.fineract.integrationtests.common.Utils;
+import
org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
+import
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
+import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
+import
org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class LoanAccountOverpaidDateStatusTest {
+
+ private ResponseSpecification responseSpec;
+ private ResponseSpecification responseSpecErr400;
+ private ResponseSpecification responseSpecErr503;
+ private RequestSpecification requestSpec;
+ private ClientHelper clientHelper;
+ private LoanTransactionHelper loanTransactionHelper;
+ private DateTimeFormatter dateFormatter = new
DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter();
+
+ @BeforeEach
+ public void setup() {
+ Utils.initializeRESTAssured();
+ this.requestSpec = new
RequestSpecBuilder().setContentType(ContentType.JSON).build();
+ this.requestSpec.header("Authorization", "Basic " +
Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
+ this.responseSpec = new
ResponseSpecBuilder().expectStatusCode(200).build();
+ this.responseSpecErr400 = new
ResponseSpecBuilder().expectStatusCode(400).build();
+ this.responseSpecErr503 = new
ResponseSpecBuilder().expectStatusCode(503).build();
+ this.loanTransactionHelper = new
LoanTransactionHelper(this.requestSpec, this.responseSpec);
+ this.clientHelper = new ClientHelper(this.requestSpec,
this.responseSpec);
+ }
+
+ @Test
+ public void loanOverpaidDateStatusTest() {
+ // Set business date
+ final LocalDate todaysDate = Utils.getLocalDateOfTenant();
+ GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec,
responseSpec, Boolean.TRUE);
+ BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec,
BusinessDateType.BUSINESS_DATE, todaysDate);
+
+ // Loan ExternalId
+ String loanExternalIdStr = UUID.randomUUID().toString();
+
+ // Delinquency Bucket
+ final Integer delinquencyBucketId =
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
+ final GetDelinquencyBucketsResponse delinquencyBucket =
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
+ delinquencyBucketId);
+
+ // Client and Loan account creation
+
+ final Integer clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
+ final GetLoanProductsProductIdResponse getLoanProductsProductResponse
= createLoanProduct(loanTransactionHelper,
+ delinquencyBucketId);
+ assertNotNull(getLoanProductsProductResponse);
+
+ final Integer loanId = createLoanAccount(clientId,
getLoanProductsProductResponse.getId(), loanExternalIdStr);
+
+ // make Repayments
+ final PostLoansLoanIdTransactionsResponse repaymentTransaction_1 =
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+ new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM
yyyy").transactionDate("5 September 2022").locale("en")
+ .transactionAmount(200.0));
+
+ final PostLoansLoanIdTransactionsResponse repaymentTransaction_2 =
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+ new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM
yyyy").transactionDate("6 September 2022").locale("en")
+ .transactionAmount(200.0));
+
+ final PostLoansLoanIdTransactionsResponse repaymentTransaction_3 =
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+ new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM
yyyy").transactionDate("7 September 2022").locale("en")
+ .transactionAmount(500.0));
+
+ // make repayment to make loan overpaid
+ final PostLoansLoanIdTransactionsResponse repaymentTransaction_4 =
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+ new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM
yyyy").transactionDate("9 September 2022").locale("en")
+ .transactionAmount(200.0));
+
+ // check loan overpaid date is not null and is set as Business date
and loan status
+ GetLoansLoanIdResponse loanDetailsOverpaid =
loanTransactionHelper.getLoanDetails((long) loanId);
+ assertTrue(loanDetailsOverpaid.getStatus().getOverpaid());
+ assertNotNull(loanDetailsOverpaid.getOverpaidOnDate());
+ assertEquals(loanDetailsOverpaid.getOverpaidOnDate(), todaysDate);
+
+ // reverse repayment to make loan not overpaid and overpaid date is
reset
+ loanTransactionHelper.reverseRepayment(loanId,
repaymentTransaction_4.getResourceId().intValue(), "10 September 2022");
+ GetLoansLoanIdResponse loanDetailsNotOverpaidAfterReversal =
loanTransactionHelper.getLoanDetails((long) loanId);
+
assertFalse(loanDetailsNotOverpaidAfterReversal.getStatus().getOverpaid());
+ assertNull(loanDetailsNotOverpaidAfterReversal.getOverpaidOnDate());
+
+ // make repayment to make loan overpaid again
+ final PostLoansLoanIdTransactionsResponse repaymentTransaction_5 =
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+ new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM
yyyy").transactionDate("11 September 2022").locale("en")
+ .transactionAmount(200.0));
+
+ // check loan overpaid date is not null and is set as Business date
and loan status
+ GetLoansLoanIdResponse loanDetailsOverpaid_1 =
loanTransactionHelper.getLoanDetails((long) loanId);
+ assertTrue(loanDetailsOverpaid_1.getStatus().getOverpaid());
+ assertNotNull(loanDetailsOverpaid_1.getOverpaidOnDate());
+ assertEquals(loanDetailsOverpaid_1.getOverpaidOnDate(), todaysDate);
+
+ // Credit balance refund to reset overpaid status
+ loanTransactionHelper.creditBalanceRefund("12 September 2022",
Float.valueOf(100), null, loanId, "");
+ GetLoansLoanIdResponse loanDetailsNotOverpaidAfterCBR =
loanTransactionHelper.getLoanDetails((long) loanId);
+ assertFalse(loanDetailsNotOverpaidAfterCBR.getStatus().getOverpaid());
+ assertNull(loanDetailsNotOverpaidAfterCBR.getOverpaidOnDate());
+
+ // reverse repayment to make loan active again
+ loanTransactionHelper.reverseRepayment(loanId,
repaymentTransaction_2.getResourceId().intValue(), "13 September 2022");
+ GetLoansLoanIdResponse loanDetailsNotOverpaidAfterReversal_1 =
loanTransactionHelper.getLoanDetails((long) loanId);
+
assertFalse(loanDetailsNotOverpaidAfterReversal_1.getStatus().getOverpaid());
+ assertNull(loanDetailsNotOverpaidAfterReversal_1.getOverpaidOnDate());
+
+ // make repayment to make loan overpaid again
+ final PostLoansLoanIdTransactionsResponse repaymentTransaction_6 =
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+ new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM
yyyy").transactionDate("14 September 2022").locale("en")
+ .transactionAmount(300.0));
+
+ // check loan overpaid date is not null and is set as Business date
and loan status
+ GetLoansLoanIdResponse loanDetailsOverpaid_3 =
loanTransactionHelper.getLoanDetails((long) loanId);
+ assertTrue(loanDetailsOverpaid_3.getStatus().getOverpaid());
+ assertNotNull(loanDetailsOverpaid_3.getOverpaidOnDate());
+ assertEquals(loanDetailsOverpaid_3.getOverpaidOnDate(), todaysDate);
+
+ GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec,
responseSpec, Boolean.FALSE);
+
+ }
+
+ private GetLoanProductsProductIdResponse createLoanProduct(final
LoanTransactionHelper loanTransactionHelper,
+ final Integer delinquencyBucketId) {
+ final HashMap<String, Object> loanProductMap = new
LoanProductTestBuilder().build(null, delinquencyBucketId);
+ final Integer loanProductId =
loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
+ return loanTransactionHelper.getLoanProduct(loanProductId);
+ }
+
+ private Integer createLoanAccount(final Integer clientID, final Long
loanProductID, final String externalId) {
+
+ String loanApplicationJSON = new
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1")
+
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1")
+
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance()
+
.withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod()
+ .withExpectedDisbursementDate("03 September
2022").withSubmittedOnDate("01 September 2022").withLoanType("individual")
+ .withExternalId(externalId).build(clientID.toString(),
loanProductID.toString(), null);
+
+ final Integer loanId =
loanTransactionHelper.getLoanId(loanApplicationJSON);
+ loanTransactionHelper.approveLoan("02 September 2022", "1000", loanId,
null);
+ loanTransactionHelper.disburseLoanWithNetDisbursalAmount("03 September
2022", loanId, "1000");
+ return loanId;
+ }
+}