This is an automated email from the ASF dual-hosted git repository.
adamsaghy 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 fac483272 FINERACT-2090: restructure loan approvals
fac483272 is described below
commit fac4832723746f347a2e192166f542d47ed04835
Author: Kristof Jozsa <[email protected]>
AuthorDate: Wed Jun 19 14:46:37 2024 +0200
FINERACT-2090: restructure loan approvals
---
.../domain/ConfigurationDomainService.java | 2 +-
.../portfolio/loanaccount/domain/Loan.java | 129 +-----------
.../domain/ConfigurationDomainServiceJpa.java | 2 +-
.../service/CalendarReadPlatformServiceImpl.java | 4 +-
.../CollectionSheetReadPlatformServiceImpl.java | 2 +-
.../service/CenterReadPlatformServiceImpl.java | 2 +-
.../service/LoanScheduleAssembler.java | 108 +++++++---
.../serialization/LoanApplicationValidator.java | 217 ++++++++++++++++++++-
...ationWritePlatformServiceJpaRepositoryImpl.java | 125 ++----------
.../loanaccount/service/LoanUtilService.java | 6 +-
.../LoanWritePlatformServiceJpaRepositoryImpl.java | 2 +-
.../starter/LoanAccountConfiguration.java | 8 +-
...etingWritePlatformServiceJpaRepositoryImpl.java | 6 +-
.../integrationtests/AccountTransferTest.java | 12 +-
.../fineract/integrationtests/BatchApiTest.java | 16 +-
.../ClientLoanIntegrationTest.java | 4 +-
.../integrationtests/GroupLoanIntegrationTest.java | 2 +-
.../LoanAccountsContainsCurrencyFieldTest.java | 13 +-
.../LoanApplicationApprovalTest.java | 22 +--
.../LoanApplicationUndoLastTrancheTest.java | 4 +-
.../LoanAuditingIntegrationTest.java | 7 +-
.../LoanCOBAccountLockCatchupInlineCOBTest.java | 12 +-
.../LoanCatchUpIntegrationTest.java | 2 +-
.../integrationtests/LoanDueCalculationTest.java | 2 +-
.../LoanTransactionAuditingIntegrationTest.java | 7 +-
.../integrationtests/SchedulerJobsTestResults.java | 52 ++---
.../integrationtests/cob/CobPartitioningTest.java | 32 ++-
.../integrationtests/common/BatchHelper.java | 6 +-
.../inlinecob/InlineLoanCOBTest.java | 12 +-
.../ExternalAssetOwnerTransferCancelTest.java | 2 +-
.../InitiateExternalAssetOwnerTransferTest.java | 2 +-
31 files changed, 438 insertions(+), 384 deletions(-)
diff --git
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
index 579b5e232..164986e87 100644
---
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
+++
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
@@ -81,7 +81,7 @@ public interface ConfigurationDomainService {
boolean isPrincipalCompoundingDisabledForOverdueLoans();
- Long retreivePeroidInNumberOfDaysForSkipMeetingDate();
+ Long retreivePeriodInNumberOfDaysForSkipMeetingDate();
boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled();
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index a39fd9ebc..cfb680585 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -113,7 +113,6 @@ import
org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor.TransactionCtx;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
-import
org.apache.fineract.portfolio.loanaccount.exception.ExceedingTrancheCountException;
import
org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanStateTransitionException;
import
org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanTransactionTypeException;
import
org.apache.fineract.portfolio.loanaccount.exception.InvalidRefundDateException;
@@ -1740,114 +1739,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
return maturityDate;
}
- public Map<String, Object> loanApplicationApproval(final AppUser
currentUser, final JsonCommand command,
- final JsonArray disbursementDataArray, final
LoanLifecycleStateMachine loanLifecycleStateMachine) {
- validateAccountStatus(LoanEvent.LOAN_APPROVED);
-
- final Map<String, Object> actualChanges = new LinkedHashMap<>();
-
- /*
- * statusEnum is holding the possible new status derived from
loanLifecycleStateMachine.transition.
- */
-
- final LoanStatus newStatusEnum =
loanLifecycleStateMachine.dryTransition(LoanEvent.LOAN_APPROVED, this);
-
- /*
- * FIXME: There is no need to check below condition, if
loanLifecycleStateMachine.transition is doing it's
- * responsibility properly. Better implementation approach is, if code
passes invalid combination of states
- * (fromState and toState), state machine should return invalidate
state and below if condition should check for
- * not equal to invalidateState, instead of check new value is same as
present value.
- */
-
- if (!newStatusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
- loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVED,
this);
- actualChanges.put(PARAM_STATUS,
LoanEnumerations.status(this.loanStatus));
-
- // only do below if status has changed in the 'approval' case
- LocalDate approvedOn =
command.localDateValueOfParameterNamed(APPROVED_ON_DATE);
- String approvedOnDateChange =
command.stringValueOfParameterNamed(APPROVED_ON_DATE);
- if (approvedOn == null) {
- approvedOn =
command.localDateValueOfParameterNamed(EVENT_DATE);
- approvedOnDateChange =
command.stringValueOfParameterNamed(EVENT_DATE);
- }
-
- LocalDate expectedDisbursementDate =
command.localDateValueOfParameterNamed(EXPECTED_DISBURSEMENT_DATE);
-
- BigDecimal approvedLoanAmount =
command.bigDecimalValueOfParameterNamed(LoanApiConstants.approvedLoanAmountParameterName);
- if (approvedLoanAmount != null) {
- compareApprovedToProposedPrincipal(approvedLoanAmount);
-
- /*
- * All the calculations are done based on the principal
amount, so it is necessary to set principal
- * amount to approved amount
- */
- this.approvedPrincipal = approvedLoanAmount;
-
-
this.loanRepaymentScheduleDetail.setPrincipal(approvedLoanAmount);
-
actualChanges.put(LoanApiConstants.approvedLoanAmountParameterName,
approvedLoanAmount);
-
actualChanges.put(LoanApiConstants.disbursementPrincipalParameterName,
approvedLoanAmount);
-
actualChanges.put(LoanApiConstants.disbursementNetDisbursalAmountParameterName,
netDisbursalAmount);
-
- if (disbursementDataArray != null) {
- updateDisbursementDetails(command, actualChanges);
- }
- }
-
- recalculateAllCharges();
-
- if (loanProduct.isMultiDisburseLoan()) {
- List<LoanDisbursementDetails> currentDisbursementDetails =
getLoanDisbursementDetails();
-
- if (currentDisbursementDetails.size() >
loanProduct.maxTrancheCount()) {
- final String errorMessage = "Number of tranche shouldn't
be greater than " + loanProduct.maxTrancheCount();
- throw new
ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName,
errorMessage,
- loanProduct.maxTrancheCount(),
currentDisbursementDetails.size());
- }
- }
- this.approvedOnDate = approvedOn;
- this.approvedBy = currentUser;
- actualChanges.put(LOCALE, command.locale());
- actualChanges.put(DATE_FORMAT, command.dateFormat());
- actualChanges.put(APPROVED_ON_DATE, approvedOnDateChange);
-
- final LocalDate submittalDate = this.submittedOnDate;
- if (DateUtils.isBefore(approvedOn, submittalDate)) {
- final String errorMessage = "The date on which a loan is
approved cannot be before its submittal date: " + submittalDate;
- throw new InvalidLoanStateTransitionException("approval",
"cannot.be.before.submittal.date", errorMessage,
- getApprovedOnDate(), submittalDate);
- }
-
- if (expectedDisbursementDate != null) {
- this.expectedDisbursementDate = expectedDisbursementDate;
- actualChanges.put(EXPECTED_DISBURSEMENT_DATE,
this.expectedDisbursementDate);
-
- if (DateUtils.isBefore(expectedDisbursementDate, approvedOn)) {
- final String errorMessage = "The expected disbursement
date should be either on or after the approval date: "
- + approvedOn;
- throw new
InvalidLoanStateTransitionException("expecteddisbursal",
"should.be.on.or.after.approval.date", errorMessage,
- getApprovedOnDate(), expectedDisbursementDate);
- }
- }
-
-
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_APPROVED,
approvedOn);
-
- if (DateUtils.isDateInTheFuture(approvedOn)) {
- final String errorMessage = "The date on which a loan is
approved cannot be in the future.";
- throw new InvalidLoanStateTransitionException("approval",
"cannot.be.a.future.date", errorMessage, getApprovedOnDate());
- }
-
- if (this.loanOfficer != null) {
- final LoanOfficerAssignmentHistory
loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this,
- this.loanOfficer, approvedOn);
- this.loanOfficerHistory.add(loanOfficerAssignmentHistory);
- }
- this.adjustNetDisbursalAmount(this.approvedPrincipal);
- }
-
- return actualChanges;
- }
-
- private List<LoanDisbursementDetails> getLoanDisbursementDetails() {
+ public List<LoanDisbursementDetails> getLoanDisbursementDetails() {
List<LoanDisbursementDetails> currentDisbursementDetails =
getDisbursementDetails();
if (loanProduct.isDisallowExpectedDisbursements()) {
if (!currentDisbursementDetails.isEmpty()) {
@@ -1863,24 +1755,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
return currentDisbursementDetails;
}
- private void compareApprovedToProposedPrincipal(BigDecimal
approvedLoanAmount) {
- if (this.loanProduct().isDisallowExpectedDisbursements() &&
this.loanProduct().isAllowApprovedDisbursedAmountsOverApplied()) {
- BigDecimal maxApprovedLoanAmount = getOverAppliedMax();
- if (approvedLoanAmount.compareTo(maxApprovedLoanAmount) > 0) {
- final String errorMessage = "Loan approved amount can't be
greater than maximum applied loan amount calculation.";
- throw new InvalidLoanStateTransitionException("approval",
-
"amount.can't.be.greater.than.maximum.applied.loan.amount.calculation",
errorMessage, approvedLoanAmount,
- maxApprovedLoanAmount);
- }
- } else {
- if (approvedLoanAmount.compareTo(this.proposedPrincipal) > 0) {
- final String errorMessage = "Loan approved amount can't be
greater than loan amount demanded.";
- throw new InvalidLoanStateTransitionException("approval",
"amount.can't.be.greater.than.loan.amount.demanded", errorMessage,
- this.proposedPrincipal, approvedLoanAmount);
- }
- }
- }
-
+ @Deprecated // moved to LoanApplicationValidator
private BigDecimal getOverAppliedMax() {
if
("percentage".equals(getLoanProduct().getOverAppliedCalculationType())) {
BigDecimal overAppliedNumber =
BigDecimal.valueOf(getLoanProduct().getOverAppliedNumber());
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
index 58b0bf3dc..7c2bf1740 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
@@ -284,7 +284,7 @@ public class ConfigurationDomainServiceJpa implements
ConfigurationDomainService
}
@Override
- public Long retreivePeroidInNumberOfDaysForSkipMeetingDate() {
+ public Long retreivePeriodInNumberOfDaysForSkipMeetingDate() {
final String propertyName = "skip-repayment-on-first-day-of-month";
final GlobalConfigurationPropertyData property =
getGlobalConfigurationPropertyData(propertyName);
return property.getValue();
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java
index 22bee0c55..5c4cb8a26 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java
@@ -249,7 +249,7 @@ public class CalendarReadPlatformServiceImpl implements
CalendarReadPlatformServ
Integer numberOfDays = 0;
boolean isSkipRepaymentOnFirstMonthEnabled =
this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
if (isSkipRepaymentOnFirstMonthEnabled) {
- numberOfDays =
this.configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
this.configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
final Collection<LocalDate> recurringDates =
CalendarUtils.getRecurringDates(rrule, seedDate, periodStartDate, periodEndDate,
@@ -328,7 +328,7 @@ public class CalendarReadPlatformServiceImpl implements
CalendarReadPlatformServ
Integer numberOfDays = 0;
boolean isSkipRepaymentOnFirstMonthEnabled =
configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
if (isSkipRepaymentOnFirstMonthEnabled) {
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
if (lastMeetingDate != null &&
!calendarData.isBetweenStartAndEndDate(lastMeetingDate)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java
index 97d7a1489..1c721ac4d 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java
@@ -344,7 +344,7 @@ public class CollectionSheetReadPlatformServiceImpl
implements CollectionSheetRe
Integer numberOfDays = 0;
boolean isSkipRepaymentOnFirstMonthEnabled =
this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
if (isSkipRepaymentOnFirstMonthEnabled) {
- numberOfDays =
this.configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
this.configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
isSkipMeetingOnFirstDay =
this.calendarReadPlatformService.isCalendarAssociatedWithEntity(entityId,
calendar.getId(),
entityType.getValue().longValue());
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
index d6fe072d5..9175ef444 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
@@ -510,7 +510,7 @@ public class CenterReadPlatformServiceImpl implements
CenterReadPlatformService
Integer numberOfDays = 0;
boolean isSkipRepaymentOnFirstMonthEnabled =
this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
if (isSkipRepaymentOnFirstMonthEnabled) {
- numberOfDays =
this.configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
this.configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
for (CenterData centerData : centerDataArray) {
if
(centerData.getCollectionMeetingCalendar().isValidRecurringDate(meetingDate,
isSkipRepaymentOnFirstMonthEnabled,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
index f4a7003fd..716015764 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
@@ -18,6 +18,13 @@
*/
package org.apache.fineract.portfolio.loanaccount.loanschedule.service;
+import static
org.apache.fineract.portfolio.loanaccount.domain.Loan.APPROVED_ON_DATE;
+import static
org.apache.fineract.portfolio.loanaccount.domain.Loan.DATE_FORMAT;
+import static org.apache.fineract.portfolio.loanaccount.domain.Loan.EVENT_DATE;
+import static
org.apache.fineract.portfolio.loanaccount.domain.Loan.EXPECTED_DISBURSEMENT_DATE;
+import static org.apache.fineract.portfolio.loanaccount.domain.Loan.LOCALE;
+import static
org.apache.fineract.portfolio.loanaccount.domain.Loan.PARAM_STATUS;
+
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -36,6 +43,7 @@ import java.util.Set;
import java.util.TreeSet;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
import
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
@@ -87,7 +95,11 @@ import
org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
+import
org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
+import
org.apache.fineract.portfolio.loanaccount.domain.LoanOfficerAssignmentHistory;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
@@ -118,6 +130,7 @@ import
org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyTy
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
import
org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
+import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.stereotype.Service;
@Service
@@ -141,6 +154,8 @@ public class LoanScheduleAssembler {
private final CalendarInstanceRepository calendarInstanceRepository;
private final LoanUtilService loanUtilService;
private final LoanDisbursementDetailsAssembler
loanDisbursementDetailsAssembler;
+ private final LoanRepositoryWrapper loanRepositoryWrapper;
+ private final LoanLifecycleStateMachine defaultLoanLifecycleStateMachine;
public LoanApplicationTerms assembleLoanTerms(final JsonElement element) {
final Long loanProductId =
this.fromApiJsonHelper.extractLongNamed("productId", element);
@@ -228,7 +243,6 @@ public class LoanScheduleAssembler {
LocalDate calculatedRepaymentsStartingFromDate =
repaymentsStartingFromDate;
- final Boolean synchDisbursement =
this.fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting",
element);
final Long calendarId =
this.fromApiJsonHelper.extractLongNamed("calendarId", element);
Calendar calendar = null;
@@ -290,19 +304,12 @@ public class LoanScheduleAssembler {
if (isSkipRepaymentOnFirstMonthEnabled) {
isSkipMeetingOnFirstDay =
this.loanUtilService.isLoanRepaymentsSyncWithMeeting(group, calendar);
if (isSkipMeetingOnFirstDay) {
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
}
if ((loanType.isJLGAccount() || loanType.isGroupAccount()) && calendar
!= null) {
validateRepaymentsStartDateWithMeetingDates(calculatedRepaymentsStartingFromDate,
calendar, isSkipMeetingOnFirstDay,
numberOfDays);
-
- /*
- * If disbursement is synced on meeting, make sure disbursement
date is on a meeting date
- */
- if (synchDisbursement != null && synchDisbursement.booleanValue())
{
-
validateDisbursementDateWithMeetingDates(expectedDisbursementDate, calendar,
isSkipMeetingOnFirstDay, numberOfDays);
- }
}
if
(RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)) {
@@ -601,20 +608,9 @@ public class LoanScheduleAssembler {
}
}
- public void validateDisbursementDateWithMeetingDates(final LocalDate
expectedDisbursementDate, final Calendar calendar,
- Boolean isSkipRepaymentOnFirstMonth, Integer numberOfDays) {
- // disbursement date should fall on a meeting date
- if (calendar != null &&
!calendar.isValidRecurringDate(expectedDisbursementDate,
isSkipRepaymentOnFirstMonth, numberOfDays)) {
- final String errorMessage = "Expected disbursement date '" +
expectedDisbursementDate + "' do not fall on a meeting date";
- throw new
LoanApplicationDateException("disbursement.date.do.not.match.meeting.date",
errorMessage, expectedDisbursementDate);
- }
-
- }
-
private void validateRepaymentFrequencyIsSameAsMeetingFrequency(final
Integer meetingFrequency, final Integer repaymentFrequency,
final Integer meetingInterval, final Integer repaymentInterval) {
- // meeting with daily frequency should allow loan products with any
- // frequency.
+ // meeting with daily frequency should allow loan products with any
frequency.
if (!PeriodFrequencyType.DAYS.getValue().equals(meetingFrequency)) {
// repayment frequency must match with meeting frequency
if (!meetingFrequency.equals(repaymentFrequency)) {
@@ -886,7 +882,7 @@ public class LoanScheduleAssembler {
if (isSkipRepaymentOnFirstMonthEnabled) {
isSkipRepaymentOnFirstMonth =
this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(),
loanCalendar);
if (isSkipRepaymentOnFirstMonth) {
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
}
final Integer minGap = installmentConfig.getMinimumGap();
@@ -1138,7 +1134,7 @@ public class LoanScheduleAssembler {
final LocalDate refernceDateForCalculatingFirstRepaymentDate,
final PeriodFrequencyType repaymentPeriodFrequencyType,
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final
Calendar calendar, final LocalDate submittedOnDate) {
boolean isMeetingSkipOnFirstDayOfMonth =
configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
- int numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ int numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
final String frequency =
CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
final LocalDate derivedFirstRepayment =
CalendarUtils.getFirstRepaymentMeetingDate(calendar,
refernceDateForCalculatingFirstRepaymentDate, repaymentEvery,
frequency, isMeetingSkipOnFirstDayOfMonth, numberOfDays);
@@ -1384,4 +1380,70 @@ public class LoanScheduleAssembler {
loanProductRelatedDetail.setEqualAmortization(newValue);
}
}
+
+ public Pair<Loan, Map<String, Object>> assembleLoanApproval(AppUser
currentUser, JsonCommand command, Long loanId) {
+ final JsonArray disbursementDataArray =
command.arrayOfParameterNamed(LoanApiConstants.disbursementDataParameterName);
+ final Loan loan =
this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId, true);
+
+ final Map<String, Object> actualChanges = new HashMap<>();
+ defaultLoanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVED,
loan);
+ actualChanges.put(PARAM_STATUS,
LoanEnumerations.status(loan.getStatus()));
+
+ LocalDate approvedOn =
command.localDateValueOfParameterNamed(APPROVED_ON_DATE);
+ String approvedOnDateChange =
command.stringValueOfParameterNamed(APPROVED_ON_DATE);
+ if (approvedOn == null) {
+ approvedOn = command.localDateValueOfParameterNamed(EVENT_DATE);
+ approvedOnDateChange =
command.stringValueOfParameterNamed(EVENT_DATE);
+ }
+
+ LocalDate expectedDisbursementDate =
command.localDateValueOfParameterNamed(EXPECTED_DISBURSEMENT_DATE);
+
+ BigDecimal approvedLoanAmount =
command.bigDecimalValueOfParameterNamed(LoanApiConstants.approvedLoanAmountParameterName);
+ if (approvedLoanAmount != null) {
+ /*
+ * All the calculations are done based on the principal amount, so
it is necessary to set principal amount
+ * to approved amount
+ */
+ loan.setApprovedPrincipal(approvedLoanAmount);
+
loan.getLoanRepaymentScheduleDetail().setPrincipal(approvedLoanAmount);
+
actualChanges.put(LoanApiConstants.approvedLoanAmountParameterName,
approvedLoanAmount);
+
actualChanges.put(LoanApiConstants.disbursementPrincipalParameterName,
approvedLoanAmount);
+
actualChanges.put(LoanApiConstants.disbursementNetDisbursalAmountParameterName,
loan.getNetDisbursalAmount());
+
+ if (disbursementDataArray != null) {
+ loan.updateDisbursementDetails(command, actualChanges);
+ }
+ }
+
+ loan.recalculateAllCharges();
+
+ loan.setApprovedOnDate(approvedOn);
+ loan.setApprovedBy(currentUser);
+
+ actualChanges.put(LOCALE, command.locale());
+ actualChanges.put(DATE_FORMAT, command.dateFormat());
+ actualChanges.put(APPROVED_ON_DATE, approvedOnDateChange);
+
+ if (expectedDisbursementDate != null) {
+ loan.setExpectedDisbursementDate(expectedDisbursementDate);
+ actualChanges.put(EXPECTED_DISBURSEMENT_DATE,
expectedDisbursementDate);
+ }
+
+ if (loan.getLoanOfficer() != null) {
+ final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory =
LoanOfficerAssignmentHistory.createNew(loan,
+ loan.getLoanOfficer(), approvedOn);
+ loan.getLoanOfficerHistory().add(loanOfficerAssignmentHistory);
+ }
+
+ loan.adjustNetDisbursalAmount(loan.getApprovedPrincipal());
+
+ if (!actualChanges.isEmpty()) {
+ if
(actualChanges.containsKey(LoanApiConstants.approvedLoanAmountParameterName)
+ || actualChanges.containsKey("recalculateLoanSchedule") ||
actualChanges.containsKey("expectedDisbursementDate")) {
+
loan.regenerateRepaymentSchedule(loanUtilService.buildScheduleGeneratorDTO(loan,
null));
+ }
+ }
+
+ return Pair.of(loan, actualChanges);
+ }
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationValidator.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationValidator.java
index d8d78ed21..0d21be1cc 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationValidator.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationValidator.java
@@ -52,6 +52,9 @@ import
org.apache.fineract.infrastructure.core.exception.UnsupportedParameterExc
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import
org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
import
org.apache.fineract.infrastructure.entityaccess.FineractEntityAccessConstants;
import
org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityAccessType;
import
org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityRelation;
@@ -68,6 +71,10 @@ import
org.apache.fineract.organisation.workingdays.domain.WorkingDays;
import
org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
+import org.apache.fineract.portfolio.calendar.domain.Calendar;
+import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
+import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
+import
org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
@@ -83,9 +90,12 @@ import
org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
+import
org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
import
org.apache.fineract.portfolio.loanaccount.exception.ExceedingTrancheCountException;
@@ -99,6 +109,7 @@ import
org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementData
import
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
import
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
import
org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
+import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
import
org.apache.fineract.portfolio.loanproduct.domain.AdvancedPaymentAllocationsValidator;
@@ -182,6 +193,11 @@ public final class LoanApplicationValidator {
private final WorkingDaysRepositoryWrapper workingDaysRepository;
private final HolidayRepository holidayRepository;
private final SavingsAccountRepositoryWrapper savingsAccountRepository;
+ private final LoanLifecycleStateMachine defaultLoanLifecycleStateMachine;
+ private final LoanSummaryWrapper loanSummaryWrapper;
+ private final CalendarInstanceRepository calendarInstanceRepository;
+ private final LoanUtilService loanUtilService;
+ private final EntityDatatableChecksWritePlatformService
entityDatatableChecksWritePlatformService;
public void validateForCreate(final Loan loan) {
final LocalDate expectedFirstRepaymentOnDate =
loan.getExpectedFirstRepaymentOnDate();
@@ -238,6 +254,7 @@ public final class LoanApplicationValidator {
final Long groupId =
this.fromApiJsonHelper.extractLongNamed(LoanApiConstants.groupIdParameterName,
element);
final Client client = clientId != null ?
this.clientRepository.findOneWithNotFoundDetection(clientId) : null;
final Group group = groupId != null ?
this.groupRepository.findOneWithNotFoundDetection(groupId) : null;
+
validateClientOrGroup(client, group, productId);
validateOrThrow("loan", baseDataValidator -> {
@@ -528,7 +545,7 @@ public final class LoanApplicationValidator {
// charges
loanChargeApiJsonValidator.validateLoanCharges(element,
loanProduct, baseDataValidator);
- /**
+ /*
* TODO: Add collaterals for other loan accounts if needed. For
now it's only applicable for individual
* accounts. (loanType.isJLG() || loanType.isGLIM())
*/
@@ -725,7 +742,7 @@ public final class LoanApplicationValidator {
}
checkForProductMixRestrictions(element);
- validateSubmittedOnDate(element, null, loanProduct);
+ validateSubmittedOnDate(element, submittedOnDate, loanProduct);
validateDisbursementDetails(loanProduct, element);
validateCollateral(element);
// validate if disbursement date is a holiday or a non-working day
@@ -1381,7 +1398,6 @@ public final class LoanApplicationValidator {
validateDisbursementDetails(loanProduct, element);
validateSubmittedOnDate(element, loan.getSubmittedOnDate(),
loanProduct);
-
validateClientOrGroup(client, group, productId);
// validate if disbursement date is a holiday or a non-working day
@@ -1439,7 +1455,7 @@ public final class LoanApplicationValidator {
}
}
if (disbursementDataSize > loanProduct.maxTrancheCount()) {
- final String errorMessage = "Number of tranche shouldn't be
greter than " + loanProduct.maxTrancheCount();
+ final String errorMessage = "Number of tranche shouldn't be
greater than " + loanProduct.maxTrancheCount();
throw new
ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName,
errorMessage,
loanProduct.maxTrancheCount(), disbursementDataSize);
}
@@ -1897,6 +1913,199 @@ public final class LoanApplicationValidator {
loan.adjustNetDisbursalAmount(netDisbursalAmount);
}
+ public void validateApproval(JsonCommand command, Long loanId) {
+ String json = command.json();
+ if (StringUtils.isBlank(json)) {
+ throw new InvalidJsonException();
+ }
+
+ final Set<String> disbursementParameters = new HashSet<>(
+ Arrays.asList(LoanApiConstants.loanIdTobeApproved,
LoanApiConstants.approvedLoanAmountParameterName,
+ LoanApiConstants.approvedOnDateParameterName,
LoanApiConstants.disbursementNetDisbursalAmountParameterName,
+ LoanApiConstants.noteParameterName,
LoanApiConstants.localeParameterName, LoanApiConstants.dateFormatParameterName,
+ LoanApiConstants.disbursementDataParameterName,
LoanApiConstants.expectedDisbursementDateParameterName));
+
+ final Type typeOfMap = new TypeToken<Map<String, Object>>()
{}.getType();
+ this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
disbursementParameters);
+
+ validateOrThrow("loanapplication", baseDataValidator -> {
+ final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+ final BigDecimal principal = this.fromApiJsonHelper
+
.extractBigDecimalWithLocaleNamed(LoanApiConstants.approvedLoanAmountParameterName,
element);
+
baseDataValidator.reset().parameter(LoanApiConstants.approvedLoanAmountParameterName).value(principal).ignoreIfNull()
+ .positiveAmount();
+
+ final BigDecimal netDisbursalAmount = this.fromApiJsonHelper
+
.extractBigDecimalWithLocaleNamed(LoanApiConstants.disbursementNetDisbursalAmountParameterName,
element);
+
baseDataValidator.reset().parameter(LoanApiConstants.disbursementNetDisbursalAmountParameterName).value(netDisbursalAmount)
+ .ignoreIfNull().positiveAmount();
+
+ final LocalDate approvedOnDate =
this.fromApiJsonHelper.extractLocalDateNamed(LoanApiConstants.approvedOnDateParameterName,
+ element);
+
baseDataValidator.reset().parameter(LoanApiConstants.approvedOnDateParameterName).value(approvedOnDate).notNull();
+
+ LocalDate expectedDisbursementDate = this.fromApiJsonHelper
+
.extractLocalDateNamed(LoanApiConstants.expectedDisbursementDateParameterName,
element);
+
baseDataValidator.reset().parameter(LoanApiConstants.expectedDisbursementDateParameterName).value(expectedDisbursementDate)
+ .ignoreIfNull();
+
+ final String note =
this.fromApiJsonHelper.extractStringNamed(LoanApiConstants.noteParameterName,
element);
+
baseDataValidator.reset().parameter(LoanApiConstants.noteParameterName).value(note).notExceedingLengthOf(1000);
+
+ final Loan loan =
this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId, true);
+ loan.setHelpers(defaultLoanLifecycleStateMachine,
this.loanSummaryWrapper,
+ this.loanRepaymentScheduleTransactionProcessorFactory);
+
+ final Client client = loan.client();
+ if (client != null && client.isNotActive()) {
+ throw new ClientNotActiveException(client.getId());
+ }
+ final Group group = loan.group();
+ if (group != null && group.isNotActive()) {
+ throw new GroupNotActiveException(group.getId());
+ }
+
+ if (expectedDisbursementDate == null) {
+ expectedDisbursementDate =
loan.getExpectedDisbursedOnLocalDate();
+ }
+
+ if (DateUtils.isBefore(approvedOnDate, loan.getSubmittedOnDate()))
{
+ final String errorMessage = "Loan approval date " +
approvedOnDate + " can not be before its submittal date: "
+ + loan.getSubmittedOnDate();
+ throw new InvalidLoanStateTransitionException("approval",
"cannot.be.before.submittal.date", errorMessage, approvedOnDate,
+ loan.getSubmittedOnDate());
+ }
+
+ LoanProduct loanProduct = loan.loanProduct();
+ if (loanProduct.isMultiDisburseLoan()) {
+ validateLoanMultiDisbursementDate(element,
expectedDisbursementDate, principal);
+
+ final JsonArray disbursementDataArray = this.fromApiJsonHelper
+
.extractJsonArrayNamed(LoanApiConstants.disbursementDataParameterName, element);
+ int disbursementDataSize = disbursementDataArray != null ?
disbursementDataArray.size() : 0;
+ if (disbursementDataSize > loanProduct.maxTrancheCount()) {
+ final String errorMessage = "Number of tranche shouldn't
be greater than " + loanProduct.maxTrancheCount();
+ throw new
ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName,
errorMessage,
+ loanProduct.maxTrancheCount(),
disbursementDataSize);
+ }
+ }
+
+ boolean isSkipRepaymentOnFirstMonth;
+ int numberOfDays = 0;
+ if (loan.isSyncDisbursementWithMeeting() && (loan.isGroupLoan() ||
loan.isJLGLoan())) {
+ Calendar calendar = getCalendarInstance(loan);
+ isSkipRepaymentOnFirstMonth =
isLoanRepaymentsSyncWithMeeting(loan, calendar);
+ if (isSkipRepaymentOnFirstMonth) {
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
+ }
+
+
validateDisbursementDateWithMeetingDates(expectedDisbursementDate, calendar,
isSkipRepaymentOnFirstMonth, numberOfDays);
+ }
+
+
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId,
EntityTables.LOAN.getName(),
+ StatusEnum.APPROVE.getCode().longValue(),
EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
+
+ if (loan.isTopup() && loan.getClientId() != null) {
+ validateTopupLoan(loan, expectedDisbursementDate);
+ }
+
+ if (!loan.getStatus().isSubmittedAndPendingApproval()) {
+ final String defaultUserMessage = "Loan Account Approval is
not allowed. Loan Account is not in submitted and pending approval state.";
+ final ApiParameterError error = ApiParameterError
+
.generalError("error.msg.loan.approve.account.is.not.submitted.and.pending.state",
defaultUserMessage);
+ baseDataValidator.getDataValidationErrors().add(error);
+ }
+
+ BigDecimal approvedLoanAmount =
command.bigDecimalValueOfParameterNamed(LoanApiConstants.approvedLoanAmountParameterName);
+ if (approvedLoanAmount != null) {
+ compareApprovedToProposedPrincipal(loan, approvedLoanAmount);
+ }
+
+ if (expectedDisbursementDate != null) {
+ if (DateUtils.isBefore(expectedDisbursementDate,
approvedOnDate)) {
+ final String errorMessage = "The expected disbursement
date " + expectedDisbursementDate
+ + " should be either on or after the approval
date: " + approvedOnDate;
+ throw new
InvalidLoanStateTransitionException("expecteddisbursal",
"should.be.on.or.after.approval.date", errorMessage,
+ approvedOnDate, expectedDisbursementDate);
+ }
+ }
+
+ if (client != null && client.getOfficeJoiningDate() != null) {
+ final LocalDate clientOfficeJoiningDate =
client.getOfficeJoiningDate();
+ if (DateUtils.isBefore(approvedOnDate,
clientOfficeJoiningDate)) {
+ throw new InvalidLoanStateTransitionException("approval",
"cannot.be.before.client.transfer.date",
+ "The date on which a loan is approved cannot be
earlier than client's transfer date to this office",
+ clientOfficeJoiningDate);
+ }
+ }
+
+ if (DateUtils.isDateInTheFuture(approvedOnDate)) {
+ final String errorMessage = "The date on which a loan is
approved cannot be in the future.";
+ throw new InvalidLoanStateTransitionException("approval",
"cannot.be.a.future.date", errorMessage, approvedOnDate);
+ }
+
+ final LoanStatus newStatus =
defaultLoanLifecycleStateMachine.dryTransition(LoanEvent.LOAN_APPROVED, loan);
+ if (newStatus.hasStateOf(loan.getStatus())) {
+ final String defaultUserMessage = "Loan is already approved.";
+ final ApiParameterError error = ApiParameterError
+
.generalError("error.msg.loan.approve.account.is.not.submitted.and.pending.state",
defaultUserMessage);
+ baseDataValidator.getDataValidationErrors().add(error);
+ }
+ }); // end validation
+ }
+
+ private void compareApprovedToProposedPrincipal(Loan loan, BigDecimal
approvedLoanAmount) {
+ if (loan.loanProduct().isDisallowExpectedDisbursements() &&
loan.loanProduct().isAllowApprovedDisbursedAmountsOverApplied()) {
+ BigDecimal maxApprovedLoanAmount = getOverAppliedMax(loan);
+ if (approvedLoanAmount.compareTo(maxApprovedLoanAmount) > 0) {
+ final String errorMessage = "Loan approved amount can't be
greater than maximum applied loan amount calculation.";
+ throw new InvalidLoanStateTransitionException("approval",
+
"amount.can't.be.greater.than.maximum.applied.loan.amount.calculation",
errorMessage, approvedLoanAmount,
+ maxApprovedLoanAmount);
+ }
+ } else {
+ if (approvedLoanAmount.compareTo(loan.getProposedPrincipal()) > 0)
{
+ final String errorMessage = "Loan approved amount can't be
greater than loan amount demanded.";
+ throw new InvalidLoanStateTransitionException("approval",
"amount.can't.be.greater.than.loan.amount.demanded", errorMessage,
+ loan.getProposedPrincipal(), approvedLoanAmount);
+ }
+ }
+ }
+
+ private BigDecimal getOverAppliedMax(Loan loan) {
+ LoanProduct loanProduct = loan.getLoanProduct();
+ if ("percentage".equals(loanProduct.getOverAppliedCalculationType())) {
+ BigDecimal overAppliedNumber =
BigDecimal.valueOf(loanProduct.getOverAppliedNumber());
+ BigDecimal totalPercentage =
BigDecimal.valueOf(1).add(overAppliedNumber.divide(BigDecimal.valueOf(100)));
+ return loan.getProposedPrincipal().multiply(totalPercentage);
+ } else {
+ return
loan.getProposedPrincipal().add(BigDecimal.valueOf(loanProduct.getOverAppliedNumber()));
+ }
+ }
+
+ /**
+ * validate disbursement date should fall on a meeting date
+ */
+ public void validateDisbursementDateWithMeetingDates(final LocalDate
expectedDisbursementDate, final Calendar calendar,
+ Boolean isSkipRepaymentOnFirstMonth, Integer numberOfDays) {
+ if (calendar != null &&
!calendar.isValidRecurringDate(expectedDisbursementDate,
isSkipRepaymentOnFirstMonth, numberOfDays)) {
+ final String errorMessage = "Expected disbursement date '" +
expectedDisbursementDate + "' do not fall on a meeting date";
+ throw new
LoanApplicationDateException("disbursement.date.do.not.match.meeting.date",
errorMessage, expectedDisbursementDate);
+ }
+ }
+
+ private Calendar getCalendarInstance(Loan loan) {
+ CalendarInstance calendarInstance =
calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
+ CalendarEntityType.LOANS.getValue());
+ return calendarInstance != null ? calendarInstance.getCalendar() :
null;
+ }
+
+ private boolean isLoanRepaymentsSyncWithMeeting(Loan loan, Calendar
calendar) {
+ return
configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled()
+ &&
loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
+ }
+
public static void validateOrThrow(String resource,
Consumer<DataValidatorBuilder> baseDataValidator) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder dataValidatorBuilder = new
DataValidatorBuilder(dataValidationErrors).resource(resource);
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
index 94aad8ec9..b61f03576 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
@@ -31,23 +31,18 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
-import
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import
org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
-import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
-import
org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
-import
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
-import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
-import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
import
org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
@@ -85,7 +80,6 @@ import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import
org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
import
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
import
org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
@@ -109,7 +103,6 @@ import
org.springframework.transaction.annotation.Transactional;
public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements
LoanApplicationWritePlatformService {
private final PlatformSecurityContext context;
- private final FromJsonHelper fromJsonHelper;
private final LoanApplicationTransitionValidator
loanApplicationTransitionValidator;
private final LoanApplicationValidator loanApplicationValidator;
private final LoanRepositoryWrapper loanRepositoryWrapper;
@@ -121,9 +114,7 @@ public class
LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
private final CalendarInstanceRepository calendarInstanceRepository;
private final SavingsAccountRepositoryWrapper savingsAccountRepository;
private final AccountAssociationsRepository accountAssociationsRepository;
- private final LoanReadPlatformService loanReadPlatformService;
private final BusinessEventNotifierService businessEventNotifierService;
- private final ConfigurationDomainService configurationDomainService;
private final LoanScheduleAssembler loanScheduleAssembler;
private final LoanUtilService loanUtilService;
private final CalendarReadPlatformService calendarReadPlatformService;
@@ -510,19 +501,6 @@ public class
LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
.build();
}
- public void validateMultiDisbursementData(final JsonCommand command,
LocalDate expectedDisbursementDate) {
- final String json = command.json();
- final JsonElement element = this.fromJsonHelper.parse(json);
-
- final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
- final DataValidatorBuilder baseDataValidator = new
DataValidatorBuilder(dataValidationErrors).resource("loan");
- final BigDecimal principal =
this.fromJsonHelper.extractBigDecimalWithLocaleNamed("approvedLoanAmount",
element);
- loanApplicationValidator.validateLoanMultiDisbursementDate(element,
baseDataValidator, expectedDisbursementDate, principal);
- if (!dataValidationErrors.isEmpty()) {
- throw new PlatformApiDataValidationException(dataValidationErrors);
- }
- }
-
@Transactional
@Override
public CommandProcessingResult approveGLIMLoanAppication(final Long
loanId, final JsonCommand command) {
@@ -572,100 +550,16 @@ public class
LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
@Transactional
@Override
public CommandProcessingResult approveApplication(final Long loanId, final
JsonCommand command) {
-
final AppUser currentUser = getAppUserIfPresent();
- LocalDate expectedDisbursementDate = null;
-
-
this.loanApplicationTransitionValidator.validateApproval(command.json());
-
- Loan loan = retrieveLoanBy(loanId);
-
- final JsonArray disbursementDataArray =
command.arrayOfParameterNamed(LoanApiConstants.disbursementDataParameterName);
-
- expectedDisbursementDate =
command.localDateValueOfParameterNamed(LoanApiConstants.expectedDisbursementDateParameterName);
- if (expectedDisbursementDate == null) {
- expectedDisbursementDate = loan.getExpectedDisbursedOnLocalDate();
- }
- if (loan.loanProduct().isMultiDisburseLoan()) {
- this.validateMultiDisbursementData(command,
expectedDisbursementDate);
- }
-
- loanApplicationTransitionValidator.checkClientOrGroupActive(loan);
- Boolean isSkipRepaymentOnFirstMonth = false;
- Integer numberOfDays = 0;
- // validate expected disbursement date against meeting date
- if (loan.isSyncDisbursementWithMeeting() && (loan.isGroupLoan() ||
loan.isJLGLoan())) {
- final CalendarInstance calendarInstance =
this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
- CalendarEntityType.LOANS.getValue());
- Calendar calendar = null;
- if (calendarInstance != null) {
- calendar = calendarInstance.getCalendar();
- }
- // final Calendar calendar = calendarInstance.getCalendar();
- boolean isSkipRepaymentOnFirstMonthEnabled =
this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
- if (isSkipRepaymentOnFirstMonthEnabled) {
- isSkipRepaymentOnFirstMonth =
this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
- if (isSkipRepaymentOnFirstMonth) {
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
- }
- }
-
this.loanScheduleAssembler.validateDisbursementDateWithMeetingDates(expectedDisbursementDate,
calendar,
- isSkipRepaymentOnFirstMonth, numberOfDays);
-
- }
+ loanApplicationValidator.validateApproval(command, loanId);
- final Map<String, Object> changes =
loan.loanApplicationApproval(currentUser, command, disbursementDataArray,
- defaultLoanLifecycleStateMachine);
-
-
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId,
EntityTables.LOAN.getName(),
- StatusEnum.APPROVE.getCode().longValue(),
EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
+ Pair<Loan, Map<String, Object>> loanAndChanges =
loanScheduleAssembler.assembleLoanApproval(currentUser, command, loanId);
+ final Loan loan = loanAndChanges.getLeft();
+ final Map<String, Object> changes = loanAndChanges.getRight();
if (!changes.isEmpty()) {
-
- // If loan approved amount less than loan demanded amount, then
need
- // to recompute the schedule
- if
(changes.containsKey(LoanApiConstants.approvedLoanAmountParameterName) ||
changes.containsKey("recalculateLoanSchedule")
- || changes.containsKey("expectedDisbursementDate")) {
- LocalDate recalculateFrom = null;
- ScheduleGeneratorDTO scheduleGeneratorDTO =
this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
- loan.regenerateRepaymentSchedule(scheduleGeneratorDTO);
- }
-
- if (loan.isTopup() && loan.getClientId() != null) {
- final Long loanIdToClose =
loan.getTopupLoanDetails().getLoanIdToClose();
- final Loan loanToClose =
this.loanRepositoryWrapper.findNonClosedLoanThatBelongsToClient(loanIdToClose,
loan.getClientId());
- if (loanToClose == null) {
- throw new
GeneralPlatformDomainRuleException("error.msg.loan.to.be.closed.with.topup.is.not.active",
- "Loan to be closed with this topup is not
active.");
- }
-
- final LocalDate lastUserTransactionOnLoanToClose =
loanToClose.getLastUserTransactionDate();
- if (DateUtils.isBefore(loan.getDisbursementDate(),
lastUserTransactionOnLoanToClose)) {
- throw new GeneralPlatformDomainRuleException(
-
"error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
- "Disbursal date of this loan application " +
loan.getDisbursementDate()
- + " should be after last transaction date
of loan to be closed " + lastUserTransactionOnLoanToClose);
- }
- BigDecimal loanOutstanding = this.loanReadPlatformService
-
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose,
expectedDisbursementDate).getAmount();
- final BigDecimal firstDisbursalAmount =
loan.getFirstDisbursalAmount();
- if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
- throw new
GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
- "Topup loan amount should be greater than
outstanding amount of loan to be closed.");
- }
- BigDecimal netDisbursalAmount =
loan.getApprovedPrincipal().subtract(loanOutstanding);
- loan.adjustNetDisbursalAmount(netDisbursalAmount);
- }
-
- loan = loanRepository.saveAndFlush(loan);
-
final String noteText =
command.stringValueOfParameterNamed("note");
- if (StringUtils.isNotBlank(noteText)) {
- final Note note = Note.loanNote(loan, noteText);
- changes.put("note", noteText);
- this.noteRepository.save(note);
- }
-
+ createNote(noteText, loan).ifPresent(note -> changes.put("note",
noteText));
businessEventNotifierService.notifyPostBusinessEvent(new
LoanApprovedBusinessEvent(loan));
}
@@ -944,10 +838,13 @@ public class
LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
}
}
- private void createNote(String submittedOnNote, Loan newLoanApplication) {
+ private Optional<Note> createNote(String submittedOnNote, Loan
newLoanApplication) {
if (StringUtils.isNotBlank(submittedOnNote)) {
final Note note = Note.loanNote(newLoanApplication,
submittedOnNote);
this.noteRepository.save(note);
+ return Optional.of(note);
+ } else {
+ return Optional.empty();
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
index 824178d49..b0b451f1d 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
@@ -108,7 +108,7 @@ public class LoanUtilService {
if (isSkipRepaymentOnFirstMonthEnabled) {
isSkipRepaymentOnFirstMonth =
isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
if (isSkipRepaymentOnFirstMonth) {
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
}
final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled
= this.configurationDomainService
@@ -251,7 +251,7 @@ public class LoanUtilService {
boolean isSkipRepaymentOnFirstMonthEnabled =
this.configurationDomainService
.isSkippingMeetingOnFirstDayOfMonthEnabled();
if (isSkipRepaymentOnFirstMonthEnabled) {
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
isSkipRepaymentOnFirstMonth =
isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
}
calculatedRepaymentsStartingFromDate =
CalendarUtils.getFirstRepaymentMeetingDate(calendar, actualDisbursementDate,
@@ -279,7 +279,7 @@ public class LoanUtilService {
Integer numberOfDays = 0;
boolean isSkipRepaymentOnFirstMonthEnabled =
this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
if (isSkipRepaymentOnFirstMonthEnabled) {
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
isSkipRepaymentOnFirstMonth =
isLoanRepaymentsSyncWithMeeting(loan.group(), historyList.get(0).getCalendar());
}
calculatedRepaymentsStartingFromDate =
CalendarUtils.getNextRepaymentMeetingDate(historyList.get(0).getRecurrence(),
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index b5e91f434..0040243bf 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -2326,7 +2326,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
if (isSkipRepaymentOnFirstMonthEnabled) {
isSkipRepaymentOnFirstMonth =
this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
if (isSkipRepaymentOnFirstMonth) {
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
index 89ba8a678..c89b911da 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
@@ -216,12 +216,12 @@ public class LoanAccountConfiguration {
EntityDatatableChecksWritePlatformService
entityDatatableChecksWritePlatformService, GLIMAccountInfoRepository
glimRepository,
LoanRepository loanRepository, GSIMReadPlatformService
gsimReadPlatformService,
LoanLifecycleStateMachine defaultLoanLifecycleStateMachine) {
- return new
LoanApplicationWritePlatformServiceJpaRepositoryImpl(context, fromJsonHelper,
loanApplicationTransitionValidator,
+ return new
LoanApplicationWritePlatformServiceJpaRepositoryImpl(context,
loanApplicationTransitionValidator,
loanApplicationValidator, loanRepositoryWrapper,
noteRepository, loanAssembler, loanSummaryWrapper,
loanRepaymentScheduleTransactionProcessorFactory,
calendarRepository, calendarInstanceRepository, savingsAccountRepository,
- accountAssociationsRepository, loanReadPlatformService,
businessEventNotifierService, configurationDomainService,
- loanScheduleAssembler, loanUtilService,
calendarReadPlatformService, entityDatatableChecksWritePlatformService,
- glimRepository, loanRepository, gsimReadPlatformService,
defaultLoanLifecycleStateMachine);
+ accountAssociationsRepository, businessEventNotifierService,
loanScheduleAssembler, loanUtilService,
+ calendarReadPlatformService,
entityDatatableChecksWritePlatformService, glimRepository, loanRepository,
+ gsimReadPlatformService, defaultLoanLifecycleStateMachine);
}
@Bean
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java
index bd6cf4396..1ce2185ad 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java
@@ -100,7 +100,7 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl
implements MeetingWrit
isSkipRepaymentOnFirstMonth = true;
}
if (isSkipRepaymentOnFirstMonth) {
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
}
final Meeting newMeeting = Meeting.createNew(calendarInstance,
meetingDate, isTransactionDateOnNonMeetingDate,
@@ -229,7 +229,7 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl
implements MeetingWrit
if (isSkipRepaymentOnFirstMonthEnabled) {
if (calendarInstance != null) {
isSkipRepaymentOnFirstMonth = true;
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
}
final Meeting meetingForUpdate =
this.meetingRepositoryWrapper.findOneWithNotFoundDetection(command.entityId());
@@ -305,7 +305,7 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl
implements MeetingWrit
if (isSkipRepaymentOnFirstMonthEnabled) {
isSkipRepaymentOnFirstMonth = true;
if (isSkipRepaymentOnFirstMonth) {
- numberOfDays =
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ numberOfDays =
configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
}
// create new meeting
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountTransferTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountTransferTest.java
index f12404848..8d61a0b85 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountTransferTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountTransferTest.java
@@ -76,9 +76,9 @@ public class AccountTransferTest {
public static final String TO_LOAN_ACCOUNT_TYPE = "1";
public static final String TO_SAVINGS_ACCOUNT_TYPE = "2";
- public static final String LOAN_APPROVAL_DATE = "01 March 2013";
- public static final String LOAN_APPROVAL_DATE_PLUS_ONE = "02 March 2013";
- public static final String LOAN_DISBURSAL_DATE = "01 March 2013";
+ public static final String LOAN_APPROVAL_DATE = "10 January 2013";
+ public static final String LOAN_APPROVAL_DATE_PLUS_ONE = "11 January 2013";
+ public static final String LOAN_DISBURSAL_DATE = "10 January 2013";
private ResponseSpecification responseSpec;
private RequestSpecification requestSpec;
@@ -107,12 +107,12 @@ public class AccountTransferTest {
List<HashMap> financialActivities =
this.financialActivityAccountHelper.getAllFinancialActivityAccounts(this.responseSpec);
if (financialActivities.isEmpty()) {
- /** Setup liability transfer account **/
- /** Create a Liability and an Asset Transfer Account **/
+ /* Setup liability transfer account **/
+ /* Create a Liability and an Asset Transfer Account **/
liabilityTransferAccount = accountHelper.createLiabilityAccount();
Assertions.assertNotNull(liabilityTransferAccount);
- /*** Create A Financial Activity to Account Mapping **/
+ /* Create A Financial Activity to Account Mapping **/
financialActivityAccountId = (Integer)
financialActivityAccountHelper.createFinancialActivityAccount(
FinancialActivityAccountsTest.LIABILITY_TRANSFER_FINANCIAL_ACTIVITY_ID,
liabilityTransferAccount.getAccountID(),
responseSpec, CommonConstants.RESPONSE_RESOURCE_ID);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java
index fd2398012..0b274ff7f 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java
@@ -573,10 +573,10 @@ public class BatchApiTest {
final BatchRequest applyLoanRequest =
BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId,
productId);
- final BatchRequest approveLoanRequest =
BatchHelper.transistionLoanStateByExternalId(approveLoanRequestId,
applyLoanRequestId,
+ final BatchRequest approveLoanRequest =
BatchHelper.transitionLoanStateByExternalId(approveLoanRequestId,
applyLoanRequestId,
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(10),
"approve");
- final BatchRequest disburseLoanRequest =
BatchHelper.transistionLoanStateByExternalId(disburseLoanRequestId,
approveLoanRequestId,
+ final BatchRequest disburseLoanRequest =
BatchHelper.transitionLoanStateByExternalId(disburseLoanRequestId,
approveLoanRequestId,
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(8),
"disburse");
final BatchRequest getLoanRequest =
BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId,
@@ -2348,10 +2348,10 @@ public class BatchApiTest {
final BatchRequest applyLoanRequest =
BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId,
productId);
- final BatchRequest approveLoanRequest =
BatchHelper.transistionLoanStateByExternalId(approveLoanRequestId,
applyLoanRequestId,
+ final BatchRequest approveLoanRequest =
BatchHelper.transitionLoanStateByExternalId(approveLoanRequestId,
applyLoanRequestId,
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(10),
"approve");
- final BatchRequest disburseLoanRequest =
BatchHelper.transistionLoanStateByExternalId(disburseLoanRequestId,
approveLoanRequestId,
+ final BatchRequest disburseLoanRequest =
BatchHelper.transitionLoanStateByExternalId(disburseLoanRequestId,
approveLoanRequestId,
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(8),
"disburse");
final BatchRequest updateLoanRequest =
BatchHelper.modifyLoanByExternalIdRequest(updateLoanRequestId,
approveLoanRequestId);
@@ -2414,10 +2414,10 @@ public class BatchApiTest {
final BatchRequest applyLoanRequest =
BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId,
productId);
- final BatchRequest approveLoanRequest =
BatchHelper.transistionLoanStateByExternalId(approveLoanRequestId,
applyLoanRequestId,
+ final BatchRequest approveLoanRequest =
BatchHelper.transitionLoanStateByExternalId(approveLoanRequestId,
applyLoanRequestId,
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(10),
"approve");
- final BatchRequest disburseLoanRequest =
BatchHelper.transistionLoanStateByExternalId(disburseLoanRequestId,
approveLoanRequestId,
+ final BatchRequest disburseLoanRequest =
BatchHelper.transitionLoanStateByExternalId(disburseLoanRequestId,
approveLoanRequestId,
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(8),
"disburse");
final BatchRequest getLoanRequest =
BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId,
@@ -2496,10 +2496,10 @@ public class BatchApiTest {
final BatchRequest applyLoanRequest =
BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId,
productId);
- final BatchRequest approveLoanRequest =
BatchHelper.transistionLoanStateByExternalId(approveLoanRequestId,
applyLoanRequestId,
+ final BatchRequest approveLoanRequest =
BatchHelper.transitionLoanStateByExternalId(approveLoanRequestId,
applyLoanRequestId,
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(10),
"approve");
- final BatchRequest disburseLoanRequest =
BatchHelper.transistionLoanStateByExternalId(disburseLoanRequestId,
approveLoanRequestId,
+ final BatchRequest disburseLoanRequest =
BatchHelper.transitionLoanStateByExternalId(disburseLoanRequestId,
approveLoanRequestId,
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(8),
"disburse");
final BatchRequest getLoanRequest =
BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId,
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
index c7150d369..348b8b9be 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
@@ -445,7 +445,7 @@ public class ClientLoanIntegrationTest {
DateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN,
Locale.US);
Calendar todaysDate =
Calendar.getInstance(Utils.getTimeZoneOfTenant());
- final String LOAN_DISBURSEMENT_DATE =
dateFormat.format(todaysDate.getTime());
+ final String LOAN_DISBURSEMENT_DATE = "2 June 2014";
LOG.info("-----------------------------------APPROVE
LOAN-----------------------------------------");
loanStatusHashMap =
LOAN_TRANSACTION_HELPER.approveLoan(LOAN_DISBURSEMENT_DATE, loanID);
@@ -1545,7 +1545,7 @@ public class ClientLoanIntegrationTest {
* amount plus interest
*/
@Test
- public void
loanWithCahargesOfTypeAmountPlusInterestPercentageAndCashBasedAccountingEnabled()
{
+ public void
loanWithChargesOfTypeAmountPlusInterestPercentageAndCashBasedAccountingEnabled()
{
final Integer clientID = ClientHelper.createClient(REQUEST_SPEC,
RESPONSE_SPEC);
ClientHelper.verifyClientCreatedOnServer(REQUEST_SPEC, RESPONSE_SPEC,
clientID);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupLoanIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupLoanIntegrationTest.java
index 4ca54a512..0bfe3501c 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupLoanIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupLoanIntegrationTest.java
@@ -101,7 +101,7 @@ public class GroupLoanIntegrationTest {
LOG.info("LoanId : {} ", loanId);
List<Map<String, Object>> approvalFormData = new ArrayList<>();
- approvalFormData.add(approvalFormData(loanId, "22 September 2011"));
+ approvalFormData.add(approvalFormData(loanId, "20 September 2011"));
HashMap loanStatusHashMap =
this.loanTransactionHelper.approveGlimAccount(this.requestSpec,
this.responseSpec, approvalFormData,
glimId);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java
index 4ee2cc95e..caa85a2bf 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java
@@ -23,9 +23,6 @@ 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.ZoneId;
-import java.time.format.DateTimeFormatter;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.client.models.GetClientsClientIdAccountsResponse;
@@ -65,15 +62,7 @@ public class LoanAccountsContainsCurrencyFieldTest {
@Test
public void testGetClientLoanAccountsUsingExternalIdContainsCurrency() {
-
- // Get today's date
- LocalDate today = LocalDate.now(ZoneId.systemDefault());
-
- // Define a custom date formatter
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM
yyyy");
-
- // Format today's date using the custom formatter
- String formattedDate = today.format(formatter);
+ String formattedDate = "01 September 2022";
// given
GlobalConfigurationHelper.manageConfigurations(requestSpec,
responseSpec,
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationApprovalTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationApprovalTest.java
index 6b37a3043..0f24bdf64 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationApprovalTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationApprovalTest.java
@@ -50,7 +50,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
@Slf4j
public class LoanApplicationApprovalTest {
- private static final String DATETIME_PATTERN = "dd MMMM yyyy";
private ResponseSpecification responseSpec;
private ResponseSpecification responseSpecForStatusCode403;
private ResponseSpecification responseSpecForStatusCode400;
@@ -101,7 +100,7 @@ public class LoanApplicationApprovalTest {
final String proposedAmount = "5000";
final String approvalAmount = "9000";
- final String approveDate = "20 September 2011";
+ final String approveDate = "2 April 2012";
final Integer clientID = ClientHelper.createClient(this.requestSpec,
this.responseSpec, "01 January 2012");
final Integer loanProductID =
this.loanTransactionHelper.getLoanProductId(new
LoanProductTestBuilder().build(null));
@@ -131,7 +130,6 @@ public class LoanApplicationApprovalTest {
@Test
public void loanApplicationApprovalAndValidationForMultiDisburseLoans() {
-
List<HashMap> createTranches = new ArrayList<>();
createTranches.add(createTrancheDetail("01 March 2014", "1000"));
createTranches.add(createTrancheDetail("23 March 2014", "4000"));
@@ -139,14 +137,16 @@ public class LoanApplicationApprovalTest {
final Integer clientID = ClientHelper.createClient(this.requestSpec,
this.responseSpec, "01 January 2014");
log.info("---------------------------------CLIENT CREATED WITH
ID--------------------------------------------------- {}", clientID);
- final Integer loanProductID = this.loanTransactionHelper
- .getLoanProductId(new
LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withTranches(true)
-
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).build(null));
+ final Integer loanProductID =
this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder() //
+ .withInterestTypeAsDecliningBalance() //
+ .withTranches(true) //
+ .withInterestCalculationPeriodTypeAsRepaymentPeriod(true) //
+ .build(null));
log.info("----------------------------------LOAN PRODUCT CREATED WITH
ID------------------------------------------- {}",
loanProductID);
- this.trancheLoansApprovedAmountLesserThanProposedAmount(clientID,
loanProductID, createTranches);
- this.trancheLoansApprovalValidation(clientID, loanProductID,
createTranches);
+ trancheLoansApprovedAmountLesserThanProposedAmount(clientID,
loanProductID, createTranches);
+ trancheLoansApprovalValidation(clientID, loanProductID,
createTranches);
}
@Test
@@ -266,12 +266,12 @@ public class LoanApplicationApprovalTest {
error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
/* If tranches are not specified for a multi-disburse loan */
- /**
+ /*
* error =
this.loanTransactionHelper.approveLoanForTranches(approveDate,
expectedDisbursementDate,
* approvalAmount5, loanID, approveTranche5,
CommonConstants.RESPONSE_ERROR);
* assertEquals("error.msg.disbursementData.required",
* error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
- **/
+ */
}
private Integer applyForLoanApplication(final Integer clientID, final
Integer loanProductID, final String proposedAmount) {
@@ -285,7 +285,7 @@ public class LoanApplicationApprovalTest {
final String loanApplication = new
LoanApplicationTestBuilder().withPrincipal(proposedAmount).withLoanTermFrequency("5")
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("5").withRepaymentEveryAfter("1")
-
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2").withExpectedDisbursementDate("04
April 2012")
+
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2").withExpectedDisbursementDate("20
September 2012")
.withCollaterals(collaterals).withSubmittedOnDate("02 April
2012")
.build(clientID.toString(), loanProductID.toString(), null);
return this.loanTransactionHelper.getLoanId(loanApplication);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationUndoLastTrancheTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationUndoLastTrancheTest.java
index 39e9271d0..23d04cfb0 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationUndoLastTrancheTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationUndoLastTrancheTest.java
@@ -70,7 +70,6 @@ public class LoanApplicationUndoLastTrancheTest {
@Test
public void loanApplicationUndoLastTranche() {
-
final String proposedAmount = "5000";
final String approvalAmount = "2000";
final String approveDate = "01 March 2014";
@@ -139,8 +138,7 @@ public class LoanApplicationUndoLastTrancheTest {
@Test
public void loanApplicationUndoLastTrancheToClose() {
- final LocalDate todaysDate = Utils.getLocalDateOfTenant();
- LocalDate transactionDate = LocalDate.of(todaysDate.getYear(), 1, 1);
+ LocalDate transactionDate = LocalDate.of(2014, 3, 1);
String operationDate = Utils.dateFormatter.format(transactionDate);
LOG.info("Operation date {}", transactionDate);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java
index f36d51827..1ff92e392 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java
@@ -98,7 +98,7 @@ public class LoanAuditingIntegrationTest {
OffsetDateTime now = Utils.getAuditDateTimeToCompare();
final Integer loanID =
applyForLoanApplicationWithPaymentStrategyAndPastMonth(clientID, loanProductID,
Collections.emptyList(),
- null, "10000", LoanApplicationTestBuilder.DEFAULT_STRATEGY,
"10 July 2022");
+ null, "10000", LoanApplicationTestBuilder.DEFAULT_STRATEGY,
"10 July 2022", "11 July 2022");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
@@ -143,7 +143,8 @@ public class LoanAuditingIntegrationTest {
}
private Integer
applyForLoanApplicationWithPaymentStrategyAndPastMonth(final Integer clientID,
final Integer loanProductID,
- List<HashMap> charges, final String savingsId, String principal,
final String repaymentStrategy, final String submittedOnDate) {
+ List<HashMap> charges, final String savingsId, String principal,
final String repaymentStrategy, final String submittedOnDate,
+ final String disbursementDate) {
LOG.info("--------------------------------APPLYING FOR LOAN
APPLICATION--------------------------------");
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
@@ -157,7 +158,7 @@ public class LoanAuditingIntegrationTest {
.withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsFlatBalance() //
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
- .withExpectedDisbursementDate(submittedOnDate) //
+ .withExpectedDisbursementDate(disbursementDate) //
.withSubmittedOnDate(submittedOnDate) //
.withRepaymentStrategy(repaymentStrategy) //
.withCharges(charges).build(clientID.toString(),
loanProductID.toString(), savingsId);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCOBAccountLockCatchupInlineCOBTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCOBAccountLockCatchupInlineCOBTest.java
index d4fdbde03..f68accb80 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCOBAccountLockCatchupInlineCOBTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCOBAccountLockCatchupInlineCOBTest.java
@@ -94,7 +94,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -150,7 +150,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -207,7 +207,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -279,7 +279,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -338,7 +338,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -393,7 +393,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCatchUpIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCatchUpIntegrationTest.java
index 5aa7e3736..62f5d962b 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCatchUpIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCatchUpIntegrationTest.java
@@ -97,7 +97,7 @@ public class LoanCatchUpIntegrationTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDueCalculationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDueCalculationTest.java
index 6700364f7..bb1b9284a 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDueCalculationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDueCalculationTest.java
@@ -119,7 +119,7 @@ public class LoanDueCalculationTest extends
BaseLoanIntegrationTest {
installment(250.0, false, "30 May 2024")) //
;
-
loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(),
approveLoanRequest(1000.0, "31 January 2024"));
+
loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(),
approveLoanRequest(1000.0, "30 January 2024"));
verifyRepaymentSchedule(postLoansResponse.getLoanId(),
installment(1000.0, null, "30 January 2024"), //
installment(250.0, false, "29 February 2024"), //
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java
index c1a4e5f47..161947b8b 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java
@@ -96,7 +96,7 @@ public class LoanTransactionAuditingIntegrationTest {
expenseAccount, overpaymentAccount);
final Integer loanID =
applyForLoanApplicationWithPaymentStrategyAndPastMonth(clientID, loanProductID,
Collections.emptyList(),
- null, "10000", LoanApplicationTestBuilder.DEFAULT_STRATEGY,
"10 July 2022");
+ null, "10000", LoanApplicationTestBuilder.DEFAULT_STRATEGY,
"10 July 2022", "12 July 2022");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
@@ -151,7 +151,8 @@ public class LoanTransactionAuditingIntegrationTest {
}
private Integer
applyForLoanApplicationWithPaymentStrategyAndPastMonth(final Integer clientID,
final Integer loanProductID,
- List<HashMap> charges, final String savingsId, String principal,
final String repaymentStrategy, final String submittedOnDate) {
+ List<HashMap> charges, final String savingsId, String principal,
final String repaymentStrategy, final String submittedOnDate,
+ final String disbursementDate) {
LOG.info("--------------------------------APPLYING FOR LOAN
APPLICATION--------------------------------");
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
@@ -165,7 +166,7 @@ public class LoanTransactionAuditingIntegrationTest {
.withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsFlatBalance() //
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
- .withExpectedDisbursementDate(submittedOnDate) //
+ .withExpectedDisbursementDate(disbursementDate) //
.withSubmittedOnDate(submittedOnDate) //
.withRepaymentStrategy(repaymentStrategy) //
.withCharges(charges).build(clientID.toString(),
loanProductID.toString(), savingsId);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
index f16e3cf19..797baefe0 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
@@ -103,6 +103,9 @@ public class SchedulerJobsTestResults {
private static final String TO_ACCOUNT_TYPE_SAVINGS = "2";
private static final String DATE_OF_JOINING = "01 January 2011";
private static final String TRANSACTION_DATE = "01 March 2013";
+ public static final String LOAN_APPROVAL_DATE = "01 March 2013";
+ public static final String LOAN_APPROVAL_DATE_PLUS_ONE = "02 March 2013";
+ public static final String LOAN_DISBURSAL_DATE = "01 March 2013";
private static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
private static final String MINIMUM_OPENING_BALANCE = "1000";
private static final Float SP_BALANCE =
Float.valueOf(MINIMUM_OPENING_BALANCE);
@@ -263,14 +266,13 @@ public class SchedulerJobsTestResults {
final Integer loanProductID = createLoanProduct(null);
Assertions.assertNotNull(loanProductID);
- final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), savingsId.toString(),
- "10 January 2013");
+ final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), savingsId.toString(), "1 March 2013");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
- loanStatusHashMap =
this.loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE,
loanID);
+ loanStatusHashMap =
this.loanTransactionHelper.approveLoan(LOAN_APPROVAL_DATE, loanID);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
Integer specifiedDueDateChargeId =
ChargesHelper.createCharges(requestSpec, responseSpec,
@@ -283,7 +285,7 @@ public class SchedulerJobsTestResults {
Assertions.assertEquals(1, chargesPendingState.size());
String loanDetails =
this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
- loanStatusHashMap =
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(AccountTransferTest.LOAN_DISBURSAL_DATE,
loanID,
+ loanStatusHashMap =
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(LOAN_DISBURSAL_DATE,
loanID,
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
final HashMap summaryBefore =
this.savingsAccountHelper.getSavingsSummary(savingsId);
@@ -315,17 +317,17 @@ public class SchedulerJobsTestResults {
final Integer loanProductID = createLoanProduct(null);
Assertions.assertNotNull(loanProductID);
- final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "01 January 2013");
+ final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "01 March 2013");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
- loanStatusHashMap =
this.loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE,
loanID);
+ loanStatusHashMap =
this.loanTransactionHelper.approveLoan(LOAN_APPROVAL_DATE, loanID);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
String loanDetails =
this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
- loanStatusHashMap =
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(AccountTransferTest.LOAN_DISBURSAL_DATE,
loanID,
+ loanStatusHashMap =
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(LOAN_DISBURSAL_DATE,
loanID,
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
@@ -656,17 +658,17 @@ public class SchedulerJobsTestResults {
final Integer loanProductID = createLoanProduct(null);
Assertions.assertNotNull(loanProductID);
- final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "10 January 2013");
+ final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "1 March 2013");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
- loanStatusHashMap =
loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE,
loanID);
+ loanStatusHashMap =
loanTransactionHelper.approveLoan(LOAN_APPROVAL_DATE, loanID);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
String loanDetails = loanTransactionHelper.getLoanDetails(requestSpec,
responseSpec, loanID);
- loanStatusHashMap =
loanTransactionHelper.disburseLoanWithNetDisbursalAmount(AccountTransferTest.LOAN_DISBURSAL_DATE,
loanID,
+ loanStatusHashMap =
loanTransactionHelper.disburseLoanWithNetDisbursalAmount(LOAN_DISBURSAL_DATE,
loanID,
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
@@ -786,7 +788,7 @@ public class SchedulerJobsTestResults {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
- final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "10 January 2020");
+ final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "1 March 2020");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
@@ -832,7 +834,7 @@ public class SchedulerJobsTestResults {
final Integer loanProductID =
createLoanProductNoInterest(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
- final Integer loanID =
applyForLoanApplicationNoInterest(clientID.toString(),
loanProductID.toString(), null, "10 January 2020");
+ final Integer loanID =
applyForLoanApplicationNoInterest(clientID.toString(),
loanProductID.toString(), null, "01 March 2020");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
@@ -883,7 +885,7 @@ public class SchedulerJobsTestResults {
List<Integer> loanIDs = new ArrayList<>();
HashMap loanStatusHashMap;
for (int i = 0; i < 3; i++) {
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -946,7 +948,7 @@ public class SchedulerJobsTestResults {
final Integer loanProductID =
createLoanProductWithPeriodicAccrual(null);
Assertions.assertNotNull(loanProductID);
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
June 2020");
Assertions.assertNotNull(loanID);
@@ -1011,7 +1013,7 @@ public class SchedulerJobsTestResults {
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
July 2020");
Assertions.assertNotNull(loanID);
@@ -1068,7 +1070,7 @@ public class SchedulerJobsTestResults {
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2019");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2019");
Assertions.assertNotNull(loanID);
@@ -1129,7 +1131,7 @@ public class SchedulerJobsTestResults {
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
// Test penalty where there is 1 day grace period
- final Integer loanID2 =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID2 =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
April 2020");
Assertions.assertNotNull(loanID2);
@@ -1186,18 +1188,18 @@ public class SchedulerJobsTestResults {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
- final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "10 January 2013");
+ final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "1 March 2013");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
- loanStatusHashMap =
this.loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE,
loanID);
+ loanStatusHashMap =
this.loanTransactionHelper.approveLoan(LOAN_APPROVAL_DATE, loanID);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
String loanDetails =
this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
- loanStatusHashMap =
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(AccountTransferTest.LOAN_APPROVAL_DATE_PLUS_ONE,
- loanID,
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
+ loanStatusHashMap =
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(LOAN_APPROVAL_DATE_PLUS_ONE,
loanID,
+
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
String JobName = "Apply penalty to overdue loans";
@@ -1238,18 +1240,18 @@ public class SchedulerJobsTestResults {
final Integer loanProductID = createLoanProduct(null);
Assertions.assertNotNull(loanProductID);
- final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "10 January 2013");
+ final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "1 March 2013");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
- loanStatusHashMap =
this.loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE,
loanID);
+ loanStatusHashMap =
this.loanTransactionHelper.approveLoan(LOAN_APPROVAL_DATE, loanID);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
String loanDetails =
this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
- loanStatusHashMap =
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(AccountTransferTest.LOAN_APPROVAL_DATE_PLUS_ONE,
- loanID,
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
+ loanStatusHashMap =
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(LOAN_APPROVAL_DATE_PLUS_ONE,
loanID,
+
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
final Boolean isNPABefore = (Boolean)
this.loanTransactionHelper.getLoanDetail(requestSpec, responseSpec, loanID,
"isNPA");
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/cob/CobPartitioningTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/cob/CobPartitioningTest.java
index 79089f6e8..084c9e4b3 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/cob/CobPartitioningTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/cob/CobPartitioningTest.java
@@ -128,26 +128,35 @@ public class CobPartitioningTest {
// Let's create 1, 2, ..., N-1, N loans
final CountDownLatch createLatch = new CountDownLatch(N);
Integer loanProductID = createLoanProduct();
+ List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < N; i++) {
- Future<?> unused = executorService.submit(() -> {
+ futures.add(executorService.submit(() -> {
Integer clientID = createClient();
Integer loanID = createLoanForClient(clientID,
loanProductID);
loanIds.add(loanID);
createLatch.countDown();
- });
+ }));
}
- createLatch.await();
+ waitForFutures(futures, createLatch);
+ futures.clear();
// Force close loans 3, 4, ... , N-3, N-2
Collections.sort(loanIds);
final CountDownLatch closeLatch = new CountDownLatch(N - 4);
for (int i = 2; i < N - 2; i++) {
final int idx = i;
- Future<?> unused = executorService.submit(() -> {
+ futures.add(executorService.submit(() -> {
LOAN_TRANSACTION_HELPER.forecloseLoan("02 March 2020",
loanIds.get(idx));
closeLatch.countDown();
- });
+ }));
}
+ futures.forEach(future -> {
+ try {
+ future.get(); // turn any possible async failures into
errors
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
closeLatch.await();
// Let's retrieve the partitions
@@ -171,6 +180,17 @@ public class CobPartitioningTest {
}
}
+ private static void waitForFutures(List<Future<?>> futures, CountDownLatch
createLatch) throws InterruptedException {
+ futures.forEach(future -> {
+ try {
+ future.get(); // turn any possible async failures into errors
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+ createLatch.await();
+ }
+
private void setInitialBusinessDate(String date) {
GlobalConfigurationHelper.updateIsBusinessDateEnabled(REQUEST_SPEC,
RESPONSE_SPEC, Boolean.TRUE);
BusinessDateHelper.updateBusinessDate(REQUEST_SPEC, RESPONSE_SPEC,
BUSINESS_DATE, LocalDate.parse(date));
@@ -210,7 +230,7 @@ public class CobPartitioningTest {
HashMap loanStatusHashMap;
- Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), "10 January 2020");
+ Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), "1 March 2020");
Assertions.assertNotNull(loanID);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
index 80b50eaec..6be2a4871 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
@@ -680,7 +680,7 @@ public final class BatchHelper {
br.setMethod("POST");
String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM
yyyy"));
br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\",
\"approvedOnDate\": \"" + dateString + "\","
- + "\"note\": \"Loan approval note\"}");
+ + "\"note\": \"Loan approval note\",
\"expectedDisbursementDate\": \"" + dateString + "\"}");
return br;
}
@@ -756,7 +756,7 @@ public final class BatchHelper {
* the action to transistion
* @return BatchRequest the batch request
*/
- public static BatchRequest transistionLoanStateByExternalId(final Long
requestId, final Long reference, final LocalDate date,
+ public static BatchRequest transitionLoanStateByExternalId(final Long
requestId, final Long reference, final LocalDate date,
final String command) {
final BatchRequest br = new BatchRequest();
@@ -769,7 +769,7 @@ public final class BatchHelper {
br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\",
\"actualDisbursementDate\": \"" + dateString + "\"}");
} else if ("approve".equals(command)) {
br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\",
\"approvedOnDate\": \"" + dateString + "\","
- + "\"note\": \"Loan approval note\"}");
+ + "\"note\": \"Loan approval note\",
\"expectedDisbursementDate\": \"" + dateString + "\"}");
}
return br;
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java
index 888bbd78e..91e820f8e 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java
@@ -105,7 +105,7 @@ public class InlineLoanCOBTest {
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -190,7 +190,7 @@ public class InlineLoanCOBTest {
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -260,7 +260,7 @@ public class InlineLoanCOBTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -318,7 +318,7 @@ public class InlineLoanCOBTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -375,7 +375,7 @@ public class InlineLoanCOBTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
@@ -442,7 +442,7 @@ public class InlineLoanCOBTest {
final Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null,
"10 January 2020");
+ final Integer loanID =
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "1
March 2020");
Assertions.assertNotNull(loanID);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferCancelTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferCancelTest.java
index 7617989ca..de22d71bb 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferCancelTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferCancelTest.java
@@ -307,7 +307,7 @@ public class ExternalAssetOwnerTransferCancelTest {
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), "10 January 2020");
+ Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), "1 March 2020");
Assertions.assertNotNull(loanID);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java
index 752217f4b..dcab08598 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java
@@ -1012,7 +1012,7 @@ public class InitiateExternalAssetOwnerTransferTest {
Assertions.assertNotNull(loanProductID);
HashMap loanStatusHashMap;
- Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), "10 January 2020");
+ Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), "1 March 2020");
Assertions.assertNotNull(loanID);