FINERACT-2090: restructure loan approvals
This commit is contained in:
committed by
Adam Saghy
parent
9152408c24
commit
fac4832723
+1
-1
@@ -81,7 +81,7 @@ public interface ConfigurationDomainService {
|
|||||||
|
|
||||||
boolean isPrincipalCompoundingDisabledForOverdueLoans();
|
boolean isPrincipalCompoundingDisabledForOverdueLoans();
|
||||||
|
|
||||||
Long retreivePeroidInNumberOfDaysForSkipMeetingDate();
|
Long retreivePeriodInNumberOfDaysForSkipMeetingDate();
|
||||||
|
|
||||||
boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled();
|
boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled();
|
||||||
|
|
||||||
|
|||||||
+2
-127
@@ -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;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor.TransactionCtx;
|
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.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.InvalidLoanStateTransitionException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanTransactionTypeException;
|
import org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanTransactionTypeException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.exception.InvalidRefundDateException;
|
import org.apache.fineract.portfolio.loanaccount.exception.InvalidRefundDateException;
|
||||||
@@ -1740,114 +1739,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return maturityDate;
|
return maturityDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> loanApplicationApproval(final AppUser currentUser, final JsonCommand command,
|
public List<LoanDisbursementDetails> getLoanDisbursementDetails() {
|
||||||
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() {
|
|
||||||
List<LoanDisbursementDetails> currentDisbursementDetails = getDisbursementDetails();
|
List<LoanDisbursementDetails> currentDisbursementDetails = getDisbursementDetails();
|
||||||
if (loanProduct.isDisallowExpectedDisbursements()) {
|
if (loanProduct.isDisallowExpectedDisbursements()) {
|
||||||
if (!currentDisbursementDetails.isEmpty()) {
|
if (!currentDisbursementDetails.isEmpty()) {
|
||||||
@@ -1863,24 +1755,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return currentDisbursementDetails;
|
return currentDisbursementDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void compareApprovedToProposedPrincipal(BigDecimal approvedLoanAmount) {
|
@Deprecated // moved to LoanApplicationValidator
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private BigDecimal getOverAppliedMax() {
|
private BigDecimal getOverAppliedMax() {
|
||||||
if ("percentage".equals(getLoanProduct().getOverAppliedCalculationType())) {
|
if ("percentage".equals(getLoanProduct().getOverAppliedCalculationType())) {
|
||||||
BigDecimal overAppliedNumber = BigDecimal.valueOf(getLoanProduct().getOverAppliedNumber());
|
BigDecimal overAppliedNumber = BigDecimal.valueOf(getLoanProduct().getOverAppliedNumber());
|
||||||
|
|||||||
+1
-1
@@ -284,7 +284,7 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long retreivePeroidInNumberOfDaysForSkipMeetingDate() {
|
public Long retreivePeriodInNumberOfDaysForSkipMeetingDate() {
|
||||||
final String propertyName = "skip-repayment-on-first-day-of-month";
|
final String propertyName = "skip-repayment-on-first-day-of-month";
|
||||||
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
|
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
|
||||||
return property.getValue();
|
return property.getValue();
|
||||||
|
|||||||
+2
-2
@@ -249,7 +249,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
|||||||
Integer numberOfDays = 0;
|
Integer numberOfDays = 0;
|
||||||
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
numberOfDays = this.configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = this.configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
final Collection<LocalDate> recurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, periodStartDate, periodEndDate,
|
final Collection<LocalDate> recurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, periodStartDate, periodEndDate,
|
||||||
@@ -328,7 +328,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
|||||||
Integer numberOfDays = 0;
|
Integer numberOfDays = 0;
|
||||||
boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastMeetingDate != null && !calendarData.isBetweenStartAndEndDate(lastMeetingDate)
|
if (lastMeetingDate != null && !calendarData.isBetweenStartAndEndDate(lastMeetingDate)
|
||||||
|
|||||||
+1
-1
@@ -344,7 +344,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
|
|||||||
Integer numberOfDays = 0;
|
Integer numberOfDays = 0;
|
||||||
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
numberOfDays = this.configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = this.configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
isSkipMeetingOnFirstDay = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(entityId, calendar.getId(),
|
isSkipMeetingOnFirstDay = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(entityId, calendar.getId(),
|
||||||
entityType.getValue().longValue());
|
entityType.getValue().longValue());
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -510,7 +510,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
|
|||||||
Integer numberOfDays = 0;
|
Integer numberOfDays = 0;
|
||||||
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
numberOfDays = this.configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = this.configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
}
|
}
|
||||||
for (CenterData centerData : centerDataArray) {
|
for (CenterData centerData : centerDataArray) {
|
||||||
if (centerData.getCollectionMeetingCalendar().isValidRecurringDate(meetingDate, isSkipRepaymentOnFirstMonthEnabled,
|
if (centerData.getCollectionMeetingCalendar().isValidRecurringDate(meetingDate, isSkipRepaymentOnFirstMonthEnabled,
|
||||||
|
|||||||
+85
-23
@@ -18,6 +18,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.service;
|
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.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
@@ -36,6 +43,7 @@ import java.util.Set;
|
|||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
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.configuration.domain.ConfigurationDomainService;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
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.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
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.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
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.domain.RepaymentStartDateType;
|
||||||
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||||
|
import org.apache.fineract.useradministration.domain.AppUser;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -141,6 +154,8 @@ public class LoanScheduleAssembler {
|
|||||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||||
private final LoanUtilService loanUtilService;
|
private final LoanUtilService loanUtilService;
|
||||||
private final LoanDisbursementDetailsAssembler loanDisbursementDetailsAssembler;
|
private final LoanDisbursementDetailsAssembler loanDisbursementDetailsAssembler;
|
||||||
|
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||||
|
private final LoanLifecycleStateMachine defaultLoanLifecycleStateMachine;
|
||||||
|
|
||||||
public LoanApplicationTerms assembleLoanTerms(final JsonElement element) {
|
public LoanApplicationTerms assembleLoanTerms(final JsonElement element) {
|
||||||
final Long loanProductId = this.fromApiJsonHelper.extractLongNamed("productId", element);
|
final Long loanProductId = this.fromApiJsonHelper.extractLongNamed("productId", element);
|
||||||
@@ -228,7 +243,6 @@ public class LoanScheduleAssembler {
|
|||||||
|
|
||||||
LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
|
LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
|
||||||
|
|
||||||
final Boolean synchDisbursement = this.fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element);
|
|
||||||
final Long calendarId = this.fromApiJsonHelper.extractLongNamed("calendarId", element);
|
final Long calendarId = this.fromApiJsonHelper.extractLongNamed("calendarId", element);
|
||||||
Calendar calendar = null;
|
Calendar calendar = null;
|
||||||
|
|
||||||
@@ -290,19 +304,12 @@ public class LoanScheduleAssembler {
|
|||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
isSkipMeetingOnFirstDay = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(group, calendar);
|
isSkipMeetingOnFirstDay = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(group, calendar);
|
||||||
if (isSkipMeetingOnFirstDay) {
|
if (isSkipMeetingOnFirstDay) {
|
||||||
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((loanType.isJLGAccount() || loanType.isGroupAccount()) && calendar != null) {
|
if ((loanType.isJLGAccount() || loanType.isGroupAccount()) && calendar != null) {
|
||||||
validateRepaymentsStartDateWithMeetingDates(calculatedRepaymentsStartingFromDate, calendar, isSkipMeetingOnFirstDay,
|
validateRepaymentsStartDateWithMeetingDates(calculatedRepaymentsStartingFromDate, calendar, isSkipMeetingOnFirstDay,
|
||||||
numberOfDays);
|
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)) {
|
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,
|
private void validateRepaymentFrequencyIsSameAsMeetingFrequency(final Integer meetingFrequency, final Integer repaymentFrequency,
|
||||||
final Integer meetingInterval, final Integer repaymentInterval) {
|
final Integer meetingInterval, final Integer repaymentInterval) {
|
||||||
// meeting with daily frequency should allow loan products with any
|
// meeting with daily frequency should allow loan products with any frequency.
|
||||||
// frequency.
|
|
||||||
if (!PeriodFrequencyType.DAYS.getValue().equals(meetingFrequency)) {
|
if (!PeriodFrequencyType.DAYS.getValue().equals(meetingFrequency)) {
|
||||||
// repayment frequency must match with meeting frequency
|
// repayment frequency must match with meeting frequency
|
||||||
if (!meetingFrequency.equals(repaymentFrequency)) {
|
if (!meetingFrequency.equals(repaymentFrequency)) {
|
||||||
@@ -886,7 +882,7 @@ public class LoanScheduleAssembler {
|
|||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), loanCalendar);
|
isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), loanCalendar);
|
||||||
if (isSkipRepaymentOnFirstMonth) {
|
if (isSkipRepaymentOnFirstMonth) {
|
||||||
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Integer minGap = installmentConfig.getMinimumGap();
|
final Integer minGap = installmentConfig.getMinimumGap();
|
||||||
@@ -1138,7 +1134,7 @@ public class LoanScheduleAssembler {
|
|||||||
final LocalDate refernceDateForCalculatingFirstRepaymentDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
final LocalDate refernceDateForCalculatingFirstRepaymentDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
||||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar, final LocalDate submittedOnDate) {
|
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar, final LocalDate submittedOnDate) {
|
||||||
boolean isMeetingSkipOnFirstDayOfMonth = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
boolean isMeetingSkipOnFirstDayOfMonth = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
||||||
int numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
int numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||||
final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar,
|
final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar,
|
||||||
refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency, isMeetingSkipOnFirstDayOfMonth, numberOfDays);
|
refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency, isMeetingSkipOnFirstDayOfMonth, numberOfDays);
|
||||||
@@ -1384,4 +1380,70 @@ public class LoanScheduleAssembler {
|
|||||||
loanProductRelatedDetail.setEqualAmortization(newValue);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+213
-4
@@ -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.serialization.FromJsonHelper;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
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.FineractEntityAccessConstants;
|
||||||
import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityAccessType;
|
import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityAccessType;
|
||||||
import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityRelation;
|
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.domain.WorkingDaysRepositoryWrapper;
|
||||||
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
|
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
|
||||||
import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
|
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.calendar.service.CalendarUtils;
|
||||||
import org.apache.fineract.portfolio.client.domain.Client;
|
import org.apache.fineract.portfolio.client.domain.Client;
|
||||||
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
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.api.LoanApiConstants;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
|
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.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
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.LoanTransactionType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
|
||||||
import org.apache.fineract.portfolio.loanaccount.exception.ExceedingTrancheCountException;
|
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.LoanScheduleProcessingType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
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.LoanProductConstants;
|
||||||
import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
|
import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.AdvancedPaymentAllocationsValidator;
|
import org.apache.fineract.portfolio.loanproduct.domain.AdvancedPaymentAllocationsValidator;
|
||||||
@@ -182,6 +193,11 @@ public final class LoanApplicationValidator {
|
|||||||
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||||
private final HolidayRepository holidayRepository;
|
private final HolidayRepository holidayRepository;
|
||||||
private final SavingsAccountRepositoryWrapper savingsAccountRepository;
|
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) {
|
public void validateForCreate(final Loan loan) {
|
||||||
final LocalDate expectedFirstRepaymentOnDate = loan.getExpectedFirstRepaymentOnDate();
|
final LocalDate expectedFirstRepaymentOnDate = loan.getExpectedFirstRepaymentOnDate();
|
||||||
@@ -238,6 +254,7 @@ public final class LoanApplicationValidator {
|
|||||||
final Long groupId = this.fromApiJsonHelper.extractLongNamed(LoanApiConstants.groupIdParameterName, element);
|
final Long groupId = this.fromApiJsonHelper.extractLongNamed(LoanApiConstants.groupIdParameterName, element);
|
||||||
final Client client = clientId != null ? this.clientRepository.findOneWithNotFoundDetection(clientId) : null;
|
final Client client = clientId != null ? this.clientRepository.findOneWithNotFoundDetection(clientId) : null;
|
||||||
final Group group = groupId != null ? this.groupRepository.findOneWithNotFoundDetection(groupId) : null;
|
final Group group = groupId != null ? this.groupRepository.findOneWithNotFoundDetection(groupId) : null;
|
||||||
|
|
||||||
validateClientOrGroup(client, group, productId);
|
validateClientOrGroup(client, group, productId);
|
||||||
|
|
||||||
validateOrThrow("loan", baseDataValidator -> {
|
validateOrThrow("loan", baseDataValidator -> {
|
||||||
@@ -528,7 +545,7 @@ public final class LoanApplicationValidator {
|
|||||||
// charges
|
// charges
|
||||||
loanChargeApiJsonValidator.validateLoanCharges(element, loanProduct, baseDataValidator);
|
loanChargeApiJsonValidator.validateLoanCharges(element, loanProduct, baseDataValidator);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* TODO: Add collaterals for other loan accounts if needed. For now it's only applicable for individual
|
* TODO: Add collaterals for other loan accounts if needed. For now it's only applicable for individual
|
||||||
* accounts. (loanType.isJLG() || loanType.isGLIM())
|
* accounts. (loanType.isJLG() || loanType.isGLIM())
|
||||||
*/
|
*/
|
||||||
@@ -725,7 +742,7 @@ public final class LoanApplicationValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkForProductMixRestrictions(element);
|
checkForProductMixRestrictions(element);
|
||||||
validateSubmittedOnDate(element, null, loanProduct);
|
validateSubmittedOnDate(element, submittedOnDate, loanProduct);
|
||||||
validateDisbursementDetails(loanProduct, element);
|
validateDisbursementDetails(loanProduct, element);
|
||||||
validateCollateral(element);
|
validateCollateral(element);
|
||||||
// validate if disbursement date is a holiday or a non-working day
|
// validate if disbursement date is a holiday or a non-working day
|
||||||
@@ -1381,7 +1398,6 @@ public final class LoanApplicationValidator {
|
|||||||
|
|
||||||
validateDisbursementDetails(loanProduct, element);
|
validateDisbursementDetails(loanProduct, element);
|
||||||
validateSubmittedOnDate(element, loan.getSubmittedOnDate(), loanProduct);
|
validateSubmittedOnDate(element, loan.getSubmittedOnDate(), loanProduct);
|
||||||
|
|
||||||
validateClientOrGroup(client, group, productId);
|
validateClientOrGroup(client, group, productId);
|
||||||
|
|
||||||
// validate if disbursement date is a holiday or a non-working day
|
// validate if disbursement date is a holiday or a non-working day
|
||||||
@@ -1439,7 +1455,7 @@ public final class LoanApplicationValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (disbursementDataSize > loanProduct.maxTrancheCount()) {
|
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,
|
throw new ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName, errorMessage,
|
||||||
loanProduct.maxTrancheCount(), disbursementDataSize);
|
loanProduct.maxTrancheCount(), disbursementDataSize);
|
||||||
}
|
}
|
||||||
@@ -1897,6 +1913,199 @@ public final class LoanApplicationValidator {
|
|||||||
loan.adjustNetDisbursalAmount(netDisbursalAmount);
|
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) {
|
public static void validateOrThrow(String resource, Consumer<DataValidatorBuilder> baseDataValidator) {
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
final DataValidatorBuilder dataValidatorBuilder = new DataValidatorBuilder(dataValidationErrors).resource(resource);
|
final DataValidatorBuilder dataValidatorBuilder = new DataValidatorBuilder(dataValidationErrors).resource(resource);
|
||||||
|
|||||||
+11
-114
@@ -31,23 +31,18 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
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.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.CommandProcessingResult;
|
||||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
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.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.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.EntityTables;
|
||||||
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
|
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
|
||||||
import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
|
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.LoanRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
|
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.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
|
||||||
@@ -109,7 +103,6 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements LoanApplicationWritePlatformService {
|
public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements LoanApplicationWritePlatformService {
|
||||||
|
|
||||||
private final PlatformSecurityContext context;
|
private final PlatformSecurityContext context;
|
||||||
private final FromJsonHelper fromJsonHelper;
|
|
||||||
private final LoanApplicationTransitionValidator loanApplicationTransitionValidator;
|
private final LoanApplicationTransitionValidator loanApplicationTransitionValidator;
|
||||||
private final LoanApplicationValidator loanApplicationValidator;
|
private final LoanApplicationValidator loanApplicationValidator;
|
||||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||||
@@ -121,9 +114,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||||
private final SavingsAccountRepositoryWrapper savingsAccountRepository;
|
private final SavingsAccountRepositoryWrapper savingsAccountRepository;
|
||||||
private final AccountAssociationsRepository accountAssociationsRepository;
|
private final AccountAssociationsRepository accountAssociationsRepository;
|
||||||
private final LoanReadPlatformService loanReadPlatformService;
|
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
private final ConfigurationDomainService configurationDomainService;
|
|
||||||
private final LoanScheduleAssembler loanScheduleAssembler;
|
private final LoanScheduleAssembler loanScheduleAssembler;
|
||||||
private final LoanUtilService loanUtilService;
|
private final LoanUtilService loanUtilService;
|
||||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||||
@@ -510,19 +501,6 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
.build();
|
.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
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult approveGLIMLoanAppication(final Long loanId, final JsonCommand command) {
|
public CommandProcessingResult approveGLIMLoanAppication(final Long loanId, final JsonCommand command) {
|
||||||
@@ -572,100 +550,16 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult approveApplication(final Long loanId, final JsonCommand command) {
|
public CommandProcessingResult approveApplication(final Long loanId, final JsonCommand command) {
|
||||||
|
|
||||||
final AppUser currentUser = getAppUserIfPresent();
|
final AppUser currentUser = getAppUserIfPresent();
|
||||||
LocalDate expectedDisbursementDate = null;
|
loanApplicationValidator.validateApproval(command, loanId);
|
||||||
|
|
||||||
this.loanApplicationTransitionValidator.validateApproval(command.json());
|
Pair<Loan, Map<String, Object>> loanAndChanges = loanScheduleAssembler.assembleLoanApproval(currentUser, command, loanId);
|
||||||
|
final Loan loan = loanAndChanges.getLeft();
|
||||||
Loan loan = retrieveLoanBy(loanId);
|
final Map<String, Object> changes = loanAndChanges.getRight();
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
if (!changes.isEmpty()) {
|
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");
|
final String noteText = command.stringValueOfParameterNamed("note");
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
createNote(noteText, loan).ifPresent(note -> changes.put("note", noteText));
|
||||||
final Note note = Note.loanNote(loan, noteText);
|
|
||||||
changes.put("note", noteText);
|
|
||||||
this.noteRepository.save(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanApprovedBusinessEvent(loan));
|
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)) {
|
if (StringUtils.isNotBlank(submittedOnNote)) {
|
||||||
final Note note = Note.loanNote(newLoanApplication, submittedOnNote);
|
final Note note = Note.loanNote(newLoanApplication, submittedOnNote);
|
||||||
this.noteRepository.save(note);
|
this.noteRepository.save(note);
|
||||||
|
return Optional.of(note);
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -108,7 +108,7 @@ public class LoanUtilService {
|
|||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
|
isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
|
||||||
if (isSkipRepaymentOnFirstMonth) {
|
if (isSkipRepaymentOnFirstMonth) {
|
||||||
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled = this.configurationDomainService
|
final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled = this.configurationDomainService
|
||||||
@@ -251,7 +251,7 @@ public class LoanUtilService {
|
|||||||
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService
|
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService
|
||||||
.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
|
isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
|
||||||
}
|
}
|
||||||
calculatedRepaymentsStartingFromDate = CalendarUtils.getFirstRepaymentMeetingDate(calendar, actualDisbursementDate,
|
calculatedRepaymentsStartingFromDate = CalendarUtils.getFirstRepaymentMeetingDate(calendar, actualDisbursementDate,
|
||||||
@@ -279,7 +279,7 @@ public class LoanUtilService {
|
|||||||
Integer numberOfDays = 0;
|
Integer numberOfDays = 0;
|
||||||
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), historyList.get(0).getCalendar());
|
isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), historyList.get(0).getCalendar());
|
||||||
}
|
}
|
||||||
calculatedRepaymentsStartingFromDate = CalendarUtils.getNextRepaymentMeetingDate(historyList.get(0).getRecurrence(),
|
calculatedRepaymentsStartingFromDate = CalendarUtils.getNextRepaymentMeetingDate(historyList.get(0).getRecurrence(),
|
||||||
|
|||||||
+1
-1
@@ -2326,7 +2326,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
|
isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
|
||||||
if (isSkipRepaymentOnFirstMonth) {
|
if (isSkipRepaymentOnFirstMonth) {
|
||||||
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -216,12 +216,12 @@ public class LoanAccountConfiguration {
|
|||||||
EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, GLIMAccountInfoRepository glimRepository,
|
EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, GLIMAccountInfoRepository glimRepository,
|
||||||
LoanRepository loanRepository, GSIMReadPlatformService gsimReadPlatformService,
|
LoanRepository loanRepository, GSIMReadPlatformService gsimReadPlatformService,
|
||||||
LoanLifecycleStateMachine defaultLoanLifecycleStateMachine) {
|
LoanLifecycleStateMachine defaultLoanLifecycleStateMachine) {
|
||||||
return new LoanApplicationWritePlatformServiceJpaRepositoryImpl(context, fromJsonHelper, loanApplicationTransitionValidator,
|
return new LoanApplicationWritePlatformServiceJpaRepositoryImpl(context, loanApplicationTransitionValidator,
|
||||||
loanApplicationValidator, loanRepositoryWrapper, noteRepository, loanAssembler, loanSummaryWrapper,
|
loanApplicationValidator, loanRepositoryWrapper, noteRepository, loanAssembler, loanSummaryWrapper,
|
||||||
loanRepaymentScheduleTransactionProcessorFactory, calendarRepository, calendarInstanceRepository, savingsAccountRepository,
|
loanRepaymentScheduleTransactionProcessorFactory, calendarRepository, calendarInstanceRepository, savingsAccountRepository,
|
||||||
accountAssociationsRepository, loanReadPlatformService, businessEventNotifierService, configurationDomainService,
|
accountAssociationsRepository, businessEventNotifierService, loanScheduleAssembler, loanUtilService,
|
||||||
loanScheduleAssembler, loanUtilService, calendarReadPlatformService, entityDatatableChecksWritePlatformService,
|
calendarReadPlatformService, entityDatatableChecksWritePlatformService, glimRepository, loanRepository,
|
||||||
glimRepository, loanRepository, gsimReadPlatformService, defaultLoanLifecycleStateMachine);
|
gsimReadPlatformService, defaultLoanLifecycleStateMachine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
+3
-3
@@ -100,7 +100,7 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit
|
|||||||
isSkipRepaymentOnFirstMonth = true;
|
isSkipRepaymentOnFirstMonth = true;
|
||||||
}
|
}
|
||||||
if (isSkipRepaymentOnFirstMonth) {
|
if (isSkipRepaymentOnFirstMonth) {
|
||||||
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Meeting newMeeting = Meeting.createNew(calendarInstance, meetingDate, isTransactionDateOnNonMeetingDate,
|
final Meeting newMeeting = Meeting.createNew(calendarInstance, meetingDate, isTransactionDateOnNonMeetingDate,
|
||||||
@@ -229,7 +229,7 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit
|
|||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
if (calendarInstance != null) {
|
if (calendarInstance != null) {
|
||||||
isSkipRepaymentOnFirstMonth = true;
|
isSkipRepaymentOnFirstMonth = true;
|
||||||
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Meeting meetingForUpdate = this.meetingRepositoryWrapper.findOneWithNotFoundDetection(command.entityId());
|
final Meeting meetingForUpdate = this.meetingRepositoryWrapper.findOneWithNotFoundDetection(command.entityId());
|
||||||
@@ -305,7 +305,7 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit
|
|||||||
if (isSkipRepaymentOnFirstMonthEnabled) {
|
if (isSkipRepaymentOnFirstMonthEnabled) {
|
||||||
isSkipRepaymentOnFirstMonth = true;
|
isSkipRepaymentOnFirstMonth = true;
|
||||||
if (isSkipRepaymentOnFirstMonth) {
|
if (isSkipRepaymentOnFirstMonth) {
|
||||||
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// create new meeting
|
// create new meeting
|
||||||
|
|||||||
+6
-6
@@ -76,9 +76,9 @@ public class AccountTransferTest {
|
|||||||
public static final String TO_LOAN_ACCOUNT_TYPE = "1";
|
public static final String TO_LOAN_ACCOUNT_TYPE = "1";
|
||||||
public static final String TO_SAVINGS_ACCOUNT_TYPE = "2";
|
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 = "10 January 2013";
|
||||||
public static final String LOAN_APPROVAL_DATE_PLUS_ONE = "02 March 2013";
|
public static final String LOAN_APPROVAL_DATE_PLUS_ONE = "11 January 2013";
|
||||||
public static final String LOAN_DISBURSAL_DATE = "01 March 2013";
|
public static final String LOAN_DISBURSAL_DATE = "10 January 2013";
|
||||||
|
|
||||||
private ResponseSpecification responseSpec;
|
private ResponseSpecification responseSpec;
|
||||||
private RequestSpecification requestSpec;
|
private RequestSpecification requestSpec;
|
||||||
@@ -107,12 +107,12 @@ public class AccountTransferTest {
|
|||||||
|
|
||||||
List<HashMap> financialActivities = this.financialActivityAccountHelper.getAllFinancialActivityAccounts(this.responseSpec);
|
List<HashMap> financialActivities = this.financialActivityAccountHelper.getAllFinancialActivityAccounts(this.responseSpec);
|
||||||
if (financialActivities.isEmpty()) {
|
if (financialActivities.isEmpty()) {
|
||||||
/** Setup liability transfer account **/
|
/* Setup liability transfer account **/
|
||||||
/** Create a Liability and an Asset Transfer Account **/
|
/* Create a Liability and an Asset Transfer Account **/
|
||||||
liabilityTransferAccount = accountHelper.createLiabilityAccount();
|
liabilityTransferAccount = accountHelper.createLiabilityAccount();
|
||||||
Assertions.assertNotNull(liabilityTransferAccount);
|
Assertions.assertNotNull(liabilityTransferAccount);
|
||||||
|
|
||||||
/*** Create A Financial Activity to Account Mapping **/
|
/* Create A Financial Activity to Account Mapping **/
|
||||||
financialActivityAccountId = (Integer) financialActivityAccountHelper.createFinancialActivityAccount(
|
financialActivityAccountId = (Integer) financialActivityAccountHelper.createFinancialActivityAccount(
|
||||||
FinancialActivityAccountsTest.LIABILITY_TRANSFER_FINANCIAL_ACTIVITY_ID, liabilityTransferAccount.getAccountID(),
|
FinancialActivityAccountsTest.LIABILITY_TRANSFER_FINANCIAL_ACTIVITY_ID, liabilityTransferAccount.getAccountID(),
|
||||||
responseSpec, CommonConstants.RESPONSE_RESOURCE_ID);
|
responseSpec, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||||
|
|||||||
+8
-8
@@ -573,10 +573,10 @@ public class BatchApiTest {
|
|||||||
|
|
||||||
final BatchRequest applyLoanRequest = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId);
|
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");
|
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");
|
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(8), "disburse");
|
||||||
|
|
||||||
final BatchRequest getLoanRequest = BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId,
|
final BatchRequest getLoanRequest = BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId,
|
||||||
@@ -2348,10 +2348,10 @@ public class BatchApiTest {
|
|||||||
|
|
||||||
final BatchRequest applyLoanRequest = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId);
|
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");
|
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");
|
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(8), "disburse");
|
||||||
|
|
||||||
final BatchRequest updateLoanRequest = BatchHelper.modifyLoanByExternalIdRequest(updateLoanRequestId, approveLoanRequestId);
|
final BatchRequest updateLoanRequest = BatchHelper.modifyLoanByExternalIdRequest(updateLoanRequestId, approveLoanRequestId);
|
||||||
@@ -2414,10 +2414,10 @@ public class BatchApiTest {
|
|||||||
|
|
||||||
final BatchRequest applyLoanRequest = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId);
|
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");
|
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");
|
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(8), "disburse");
|
||||||
|
|
||||||
final BatchRequest getLoanRequest = BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId,
|
final BatchRequest getLoanRequest = BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId,
|
||||||
@@ -2496,10 +2496,10 @@ public class BatchApiTest {
|
|||||||
|
|
||||||
final BatchRequest applyLoanRequest = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId);
|
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");
|
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");
|
LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(8), "disburse");
|
||||||
|
|
||||||
final BatchRequest getLoanRequest = BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId,
|
final BatchRequest getLoanRequest = BatchHelper.getLoanByExternalIdRequest(getLoanRequestId, approveLoanRequestId,
|
||||||
|
|||||||
+2
-2
@@ -445,7 +445,7 @@ public class ClientLoanIntegrationTest {
|
|||||||
|
|
||||||
DateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN, Locale.US);
|
DateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN, Locale.US);
|
||||||
Calendar todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
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-----------------------------------------");
|
LOG.info("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||||
loanStatusHashMap = LOAN_TRANSACTION_HELPER.approveLoan(LOAN_DISBURSEMENT_DATE, loanID);
|
loanStatusHashMap = LOAN_TRANSACTION_HELPER.approveLoan(LOAN_DISBURSEMENT_DATE, loanID);
|
||||||
@@ -1545,7 +1545,7 @@ public class ClientLoanIntegrationTest {
|
|||||||
* amount plus interest
|
* amount plus interest
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void loanWithCahargesOfTypeAmountPlusInterestPercentageAndCashBasedAccountingEnabled() {
|
public void loanWithChargesOfTypeAmountPlusInterestPercentageAndCashBasedAccountingEnabled() {
|
||||||
|
|
||||||
final Integer clientID = ClientHelper.createClient(REQUEST_SPEC, RESPONSE_SPEC);
|
final Integer clientID = ClientHelper.createClient(REQUEST_SPEC, RESPONSE_SPEC);
|
||||||
ClientHelper.verifyClientCreatedOnServer(REQUEST_SPEC, RESPONSE_SPEC, clientID);
|
ClientHelper.verifyClientCreatedOnServer(REQUEST_SPEC, RESPONSE_SPEC, clientID);
|
||||||
|
|||||||
+1
-1
@@ -101,7 +101,7 @@ public class GroupLoanIntegrationTest {
|
|||||||
LOG.info("LoanId : {} ", loanId);
|
LOG.info("LoanId : {} ", loanId);
|
||||||
|
|
||||||
List<Map<String, Object>> approvalFormData = new ArrayList<>();
|
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,
|
HashMap loanStatusHashMap = this.loanTransactionHelper.approveGlimAccount(this.requestSpec, this.responseSpec, approvalFormData,
|
||||||
glimId);
|
glimId);
|
||||||
|
|||||||
+1
-12
@@ -23,9 +23,6 @@ import io.restassured.builder.ResponseSpecBuilder;
|
|||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
import io.restassured.specification.RequestSpecification;
|
import io.restassured.specification.RequestSpecification;
|
||||||
import io.restassured.specification.ResponseSpecification;
|
import io.restassured.specification.ResponseSpecification;
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.fineract.client.models.GetClientsClientIdAccountsResponse;
|
import org.apache.fineract.client.models.GetClientsClientIdAccountsResponse;
|
||||||
@@ -65,15 +62,7 @@ public class LoanAccountsContainsCurrencyFieldTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetClientLoanAccountsUsingExternalIdContainsCurrency() {
|
public void testGetClientLoanAccountsUsingExternalIdContainsCurrency() {
|
||||||
|
String formattedDate = "01 September 2022";
|
||||||
// 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);
|
|
||||||
|
|
||||||
// given
|
// given
|
||||||
GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec,
|
GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec,
|
||||||
|
|||||||
+11
-11
@@ -50,7 +50,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class LoanApplicationApprovalTest {
|
public class LoanApplicationApprovalTest {
|
||||||
|
|
||||||
private static final String DATETIME_PATTERN = "dd MMMM yyyy";
|
|
||||||
private ResponseSpecification responseSpec;
|
private ResponseSpecification responseSpec;
|
||||||
private ResponseSpecification responseSpecForStatusCode403;
|
private ResponseSpecification responseSpecForStatusCode403;
|
||||||
private ResponseSpecification responseSpecForStatusCode400;
|
private ResponseSpecification responseSpecForStatusCode400;
|
||||||
@@ -101,7 +100,7 @@ public class LoanApplicationApprovalTest {
|
|||||||
|
|
||||||
final String proposedAmount = "5000";
|
final String proposedAmount = "5000";
|
||||||
final String approvalAmount = "9000";
|
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 clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||||
final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder().build(null));
|
final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder().build(null));
|
||||||
@@ -131,7 +130,6 @@ public class LoanApplicationApprovalTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loanApplicationApprovalAndValidationForMultiDisburseLoans() {
|
public void loanApplicationApprovalAndValidationForMultiDisburseLoans() {
|
||||||
|
|
||||||
List<HashMap> createTranches = new ArrayList<>();
|
List<HashMap> createTranches = new ArrayList<>();
|
||||||
createTranches.add(createTrancheDetail("01 March 2014", "1000"));
|
createTranches.add(createTrancheDetail("01 March 2014", "1000"));
|
||||||
createTranches.add(createTrancheDetail("23 March 2014", "4000"));
|
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");
|
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014");
|
||||||
log.info("---------------------------------CLIENT CREATED WITH ID--------------------------------------------------- {}", clientID);
|
log.info("---------------------------------CLIENT CREATED WITH ID--------------------------------------------------- {}", clientID);
|
||||||
|
|
||||||
final Integer loanProductID = this.loanTransactionHelper
|
final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder() //
|
||||||
.getLoanProductId(new LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withTranches(true)
|
.withInterestTypeAsDecliningBalance() //
|
||||||
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).build(null));
|
.withTranches(true) //
|
||||||
|
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true) //
|
||||||
|
.build(null));
|
||||||
log.info("----------------------------------LOAN PRODUCT CREATED WITH ID------------------------------------------- {}",
|
log.info("----------------------------------LOAN PRODUCT CREATED WITH ID------------------------------------------- {}",
|
||||||
loanProductID);
|
loanProductID);
|
||||||
|
|
||||||
this.trancheLoansApprovedAmountLesserThanProposedAmount(clientID, loanProductID, createTranches);
|
trancheLoansApprovedAmountLesserThanProposedAmount(clientID, loanProductID, createTranches);
|
||||||
this.trancheLoansApprovalValidation(clientID, loanProductID, createTranches);
|
trancheLoansApprovalValidation(clientID, loanProductID, createTranches);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -266,12 +266,12 @@ public class LoanApplicationApprovalTest {
|
|||||||
error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
|
error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
|
||||||
|
|
||||||
/* If tranches are not specified for a multi-disburse loan */
|
/* If tranches are not specified for a multi-disburse loan */
|
||||||
/**
|
/*
|
||||||
* error = this.loanTransactionHelper.approveLoanForTranches(approveDate, expectedDisbursementDate,
|
* error = this.loanTransactionHelper.approveLoanForTranches(approveDate, expectedDisbursementDate,
|
||||||
* approvalAmount5, loanID, approveTranche5, CommonConstants.RESPONSE_ERROR);
|
* approvalAmount5, loanID, approveTranche5, CommonConstants.RESPONSE_ERROR);
|
||||||
* assertEquals("error.msg.disbursementData.required",
|
* assertEquals("error.msg.disbursementData.required",
|
||||||
* error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
|
* error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
|
||||||
**/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID, final String proposedAmount) {
|
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")
|
final String loanApplication = new LoanApplicationTestBuilder().withPrincipal(proposedAmount).withLoanTermFrequency("5")
|
||||||
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("5").withRepaymentEveryAfter("1")
|
.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")
|
.withCollaterals(collaterals).withSubmittedOnDate("02 April 2012")
|
||||||
.build(clientID.toString(), loanProductID.toString(), null);
|
.build(clientID.toString(), loanProductID.toString(), null);
|
||||||
return this.loanTransactionHelper.getLoanId(loanApplication);
|
return this.loanTransactionHelper.getLoanId(loanApplication);
|
||||||
|
|||||||
+1
-3
@@ -70,7 +70,6 @@ public class LoanApplicationUndoLastTrancheTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loanApplicationUndoLastTranche() {
|
public void loanApplicationUndoLastTranche() {
|
||||||
|
|
||||||
final String proposedAmount = "5000";
|
final String proposedAmount = "5000";
|
||||||
final String approvalAmount = "2000";
|
final String approvalAmount = "2000";
|
||||||
final String approveDate = "01 March 2014";
|
final String approveDate = "01 March 2014";
|
||||||
@@ -139,8 +138,7 @@ public class LoanApplicationUndoLastTrancheTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loanApplicationUndoLastTrancheToClose() {
|
public void loanApplicationUndoLastTrancheToClose() {
|
||||||
final LocalDate todaysDate = Utils.getLocalDateOfTenant();
|
LocalDate transactionDate = LocalDate.of(2014, 3, 1);
|
||||||
LocalDate transactionDate = LocalDate.of(todaysDate.getYear(), 1, 1);
|
|
||||||
String operationDate = Utils.dateFormatter.format(transactionDate);
|
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||||
LOG.info("Operation date {}", transactionDate);
|
LOG.info("Operation date {}", transactionDate);
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -98,7 +98,7 @@ public class LoanAuditingIntegrationTest {
|
|||||||
OffsetDateTime now = Utils.getAuditDateTimeToCompare();
|
OffsetDateTime now = Utils.getAuditDateTimeToCompare();
|
||||||
|
|
||||||
final Integer loanID = applyForLoanApplicationWithPaymentStrategyAndPastMonth(clientID, loanProductID, Collections.emptyList(),
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
@@ -143,7 +143,8 @@ public class LoanAuditingIntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Integer applyForLoanApplicationWithPaymentStrategyAndPastMonth(final Integer clientID, final Integer loanProductID,
|
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--------------------------------");
|
LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
||||||
|
|
||||||
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
|
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
|
||||||
@@ -157,7 +158,7 @@ public class LoanAuditingIntegrationTest {
|
|||||||
.withAmortizationTypeAsEqualInstallments() //
|
.withAmortizationTypeAsEqualInstallments() //
|
||||||
.withInterestTypeAsFlatBalance() //
|
.withInterestTypeAsFlatBalance() //
|
||||||
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
|
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
|
||||||
.withExpectedDisbursementDate(submittedOnDate) //
|
.withExpectedDisbursementDate(disbursementDate) //
|
||||||
.withSubmittedOnDate(submittedOnDate) //
|
.withSubmittedOnDate(submittedOnDate) //
|
||||||
.withRepaymentStrategy(repaymentStrategy) //
|
.withRepaymentStrategy(repaymentStrategy) //
|
||||||
.withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
|
.withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
|
||||||
|
|||||||
+6
-6
@@ -94,7 +94,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -338,7 +338,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -393,7 +393,7 @@ public class LoanCOBAccountLockCatchupInlineCOBTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -97,7 +97,7 @@ public class LoanCatchUpIntegrationTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -119,7 +119,7 @@ public class LoanDueCalculationTest extends BaseLoanIntegrationTest {
|
|||||||
installment(250.0, false, "30 May 2024")) //
|
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"), //
|
verifyRepaymentSchedule(postLoansResponse.getLoanId(), installment(1000.0, null, "30 January 2024"), //
|
||||||
installment(250.0, false, "29 February 2024"), //
|
installment(250.0, false, "29 February 2024"), //
|
||||||
|
|||||||
+4
-3
@@ -96,7 +96,7 @@ public class LoanTransactionAuditingIntegrationTest {
|
|||||||
expenseAccount, overpaymentAccount);
|
expenseAccount, overpaymentAccount);
|
||||||
|
|
||||||
final Integer loanID = applyForLoanApplicationWithPaymentStrategyAndPastMonth(clientID, loanProductID, Collections.emptyList(),
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
@@ -151,7 +151,8 @@ public class LoanTransactionAuditingIntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Integer applyForLoanApplicationWithPaymentStrategyAndPastMonth(final Integer clientID, final Integer loanProductID,
|
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--------------------------------");
|
LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
||||||
|
|
||||||
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
|
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
|
||||||
@@ -165,7 +166,7 @@ public class LoanTransactionAuditingIntegrationTest {
|
|||||||
.withAmortizationTypeAsEqualInstallments() //
|
.withAmortizationTypeAsEqualInstallments() //
|
||||||
.withInterestTypeAsFlatBalance() //
|
.withInterestTypeAsFlatBalance() //
|
||||||
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
|
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
|
||||||
.withExpectedDisbursementDate(submittedOnDate) //
|
.withExpectedDisbursementDate(disbursementDate) //
|
||||||
.withSubmittedOnDate(submittedOnDate) //
|
.withSubmittedOnDate(submittedOnDate) //
|
||||||
.withRepaymentStrategy(repaymentStrategy) //
|
.withRepaymentStrategy(repaymentStrategy) //
|
||||||
.withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
|
.withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
|
||||||
|
|||||||
+27
-25
@@ -103,6 +103,9 @@ public class SchedulerJobsTestResults {
|
|||||||
private static final String TO_ACCOUNT_TYPE_SAVINGS = "2";
|
private static final String TO_ACCOUNT_TYPE_SAVINGS = "2";
|
||||||
private static final String DATE_OF_JOINING = "01 January 2011";
|
private static final String DATE_OF_JOINING = "01 January 2011";
|
||||||
private static final String TRANSACTION_DATE = "01 March 2013";
|
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 ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
|
||||||
private static final String MINIMUM_OPENING_BALANCE = "1000";
|
private static final String MINIMUM_OPENING_BALANCE = "1000";
|
||||||
private static final Float SP_BALANCE = Float.valueOf(MINIMUM_OPENING_BALANCE);
|
private static final Float SP_BALANCE = Float.valueOf(MINIMUM_OPENING_BALANCE);
|
||||||
@@ -263,14 +266,13 @@ public class SchedulerJobsTestResults {
|
|||||||
final Integer loanProductID = createLoanProduct(null);
|
final Integer loanProductID = createLoanProduct(null);
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
|
|
||||||
final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), savingsId.toString(),
|
final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), savingsId.toString(), "1 March 2013");
|
||||||
"10 January 2013");
|
|
||||||
Assertions.assertNotNull(loanID);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
loanStatusHashMap = this.loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE, loanID);
|
loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_APPROVAL_DATE, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
|
||||||
Integer specifiedDueDateChargeId = ChargesHelper.createCharges(requestSpec, responseSpec,
|
Integer specifiedDueDateChargeId = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
@@ -283,7 +285,7 @@ public class SchedulerJobsTestResults {
|
|||||||
Assertions.assertEquals(1, chargesPendingState.size());
|
Assertions.assertEquals(1, chargesPendingState.size());
|
||||||
|
|
||||||
String loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
|
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());
|
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
|
||||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
final HashMap summaryBefore = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
final HashMap summaryBefore = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||||
@@ -315,17 +317,17 @@ public class SchedulerJobsTestResults {
|
|||||||
final Integer loanProductID = createLoanProduct(null);
|
final Integer loanProductID = createLoanProduct(null);
|
||||||
Assertions.assertNotNull(loanProductID);
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
loanStatusHashMap = this.loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE, loanID);
|
loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_APPROVAL_DATE, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
|
||||||
String loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
|
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());
|
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
|
||||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
|
||||||
@@ -656,17 +658,17 @@ public class SchedulerJobsTestResults {
|
|||||||
final Integer loanProductID = createLoanProduct(null);
|
final Integer loanProductID = createLoanProduct(null);
|
||||||
Assertions.assertNotNull(loanProductID);
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
loanStatusHashMap = loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE, loanID);
|
loanStatusHashMap = loanTransactionHelper.approveLoan(LOAN_APPROVAL_DATE, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
|
||||||
String loanDetails = loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
|
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());
|
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
|
||||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
|
||||||
@@ -786,7 +788,7 @@ public class SchedulerJobsTestResults {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
@@ -832,7 +834,7 @@ public class SchedulerJobsTestResults {
|
|||||||
final Integer loanProductID = createLoanProductNoInterest(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProductNoInterest(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
@@ -883,7 +885,7 @@ public class SchedulerJobsTestResults {
|
|||||||
List<Integer> loanIDs = new ArrayList<>();
|
List<Integer> loanIDs = new ArrayList<>();
|
||||||
HashMap loanStatusHashMap;
|
HashMap loanStatusHashMap;
|
||||||
for (int i = 0; i < 3; i++) {
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -946,7 +948,7 @@ public class SchedulerJobsTestResults {
|
|||||||
final Integer loanProductID = createLoanProductWithPeriodicAccrual(null);
|
final Integer loanProductID = createLoanProductWithPeriodicAccrual(null);
|
||||||
Assertions.assertNotNull(loanProductID);
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -1011,7 +1013,7 @@ public class SchedulerJobsTestResults {
|
|||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -1068,7 +1070,7 @@ public class SchedulerJobsTestResults {
|
|||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -1129,7 +1131,7 @@ public class SchedulerJobsTestResults {
|
|||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
HashMap loanStatusHashMap;
|
||||||
// Test penalty where there is 1 day grace period
|
// 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);
|
Assertions.assertNotNull(loanID2);
|
||||||
|
|
||||||
@@ -1186,18 +1188,18 @@ public class SchedulerJobsTestResults {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
loanStatusHashMap = this.loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE, loanID);
|
loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_APPROVAL_DATE, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
|
||||||
String loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
|
String loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
|
||||||
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(AccountTransferTest.LOAN_APPROVAL_DATE_PLUS_ONE,
|
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(LOAN_APPROVAL_DATE_PLUS_ONE, loanID,
|
||||||
loanID, JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
|
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
|
||||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
|
||||||
String JobName = "Apply penalty to overdue loans";
|
String JobName = "Apply penalty to overdue loans";
|
||||||
@@ -1238,18 +1240,18 @@ public class SchedulerJobsTestResults {
|
|||||||
final Integer loanProductID = createLoanProduct(null);
|
final Integer loanProductID = createLoanProduct(null);
|
||||||
Assertions.assertNotNull(loanProductID);
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
loanStatusHashMap = this.loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE, loanID);
|
loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_APPROVAL_DATE, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
|
||||||
String loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
|
String loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
|
||||||
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(AccountTransferTest.LOAN_APPROVAL_DATE_PLUS_ONE,
|
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(LOAN_APPROVAL_DATE_PLUS_ONE, loanID,
|
||||||
loanID, JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
|
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
|
||||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
|
||||||
final Boolean isNPABefore = (Boolean) this.loanTransactionHelper.getLoanDetail(requestSpec, responseSpec, loanID, "isNPA");
|
final Boolean isNPABefore = (Boolean) this.loanTransactionHelper.getLoanDetail(requestSpec, responseSpec, loanID, "isNPA");
|
||||||
|
|||||||
+26
-6
@@ -128,26 +128,35 @@ public class CobPartitioningTest {
|
|||||||
// Let's create 1, 2, ..., N-1, N loans
|
// Let's create 1, 2, ..., N-1, N loans
|
||||||
final CountDownLatch createLatch = new CountDownLatch(N);
|
final CountDownLatch createLatch = new CountDownLatch(N);
|
||||||
Integer loanProductID = createLoanProduct();
|
Integer loanProductID = createLoanProduct();
|
||||||
|
List<Future<?>> futures = new ArrayList<>();
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < N; i++) {
|
||||||
Future<?> unused = executorService.submit(() -> {
|
futures.add(executorService.submit(() -> {
|
||||||
Integer clientID = createClient();
|
Integer clientID = createClient();
|
||||||
Integer loanID = createLoanForClient(clientID, loanProductID);
|
Integer loanID = createLoanForClient(clientID, loanProductID);
|
||||||
loanIds.add(loanID);
|
loanIds.add(loanID);
|
||||||
createLatch.countDown();
|
createLatch.countDown();
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
createLatch.await();
|
waitForFutures(futures, createLatch);
|
||||||
|
futures.clear();
|
||||||
|
|
||||||
// Force close loans 3, 4, ... , N-3, N-2
|
// Force close loans 3, 4, ... , N-3, N-2
|
||||||
Collections.sort(loanIds);
|
Collections.sort(loanIds);
|
||||||
final CountDownLatch closeLatch = new CountDownLatch(N - 4);
|
final CountDownLatch closeLatch = new CountDownLatch(N - 4);
|
||||||
for (int i = 2; i < N - 2; i++) {
|
for (int i = 2; i < N - 2; i++) {
|
||||||
final int idx = i;
|
final int idx = i;
|
||||||
Future<?> unused = executorService.submit(() -> {
|
futures.add(executorService.submit(() -> {
|
||||||
LOAN_TRANSACTION_HELPER.forecloseLoan("02 March 2020", loanIds.get(idx));
|
LOAN_TRANSACTION_HELPER.forecloseLoan("02 March 2020", loanIds.get(idx));
|
||||||
closeLatch.countDown();
|
closeLatch.countDown();
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
futures.forEach(future -> {
|
||||||
|
try {
|
||||||
|
future.get(); // turn any possible async failures into errors
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
closeLatch.await();
|
closeLatch.await();
|
||||||
|
|
||||||
// Let's retrieve the partitions
|
// 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) {
|
private void setInitialBusinessDate(String date) {
|
||||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(REQUEST_SPEC, RESPONSE_SPEC, Boolean.TRUE);
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(REQUEST_SPEC, RESPONSE_SPEC, Boolean.TRUE);
|
||||||
BusinessDateHelper.updateBusinessDate(REQUEST_SPEC, RESPONSE_SPEC, BUSINESS_DATE, LocalDate.parse(date));
|
BusinessDateHelper.updateBusinessDate(REQUEST_SPEC, RESPONSE_SPEC, BUSINESS_DATE, LocalDate.parse(date));
|
||||||
@@ -210,7 +230,7 @@ public class CobPartitioningTest {
|
|||||||
|
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -680,7 +680,7 @@ public final class BatchHelper {
|
|||||||
br.setMethod("POST");
|
br.setMethod("POST");
|
||||||
String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
||||||
br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"approvedOnDate\": \"" + dateString + "\","
|
br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"approvedOnDate\": \"" + dateString + "\","
|
||||||
+ "\"note\": \"Loan approval note\"}");
|
+ "\"note\": \"Loan approval note\", \"expectedDisbursementDate\": \"" + dateString + "\"}");
|
||||||
|
|
||||||
return br;
|
return br;
|
||||||
}
|
}
|
||||||
@@ -756,7 +756,7 @@ public final class BatchHelper {
|
|||||||
* the action to transistion
|
* the action to transistion
|
||||||
* @return BatchRequest the batch request
|
* @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 String command) {
|
||||||
final BatchRequest br = new BatchRequest();
|
final BatchRequest br = new BatchRequest();
|
||||||
|
|
||||||
@@ -769,7 +769,7 @@ public final class BatchHelper {
|
|||||||
br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"actualDisbursementDate\": \"" + dateString + "\"}");
|
br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"actualDisbursementDate\": \"" + dateString + "\"}");
|
||||||
} else if ("approve".equals(command)) {
|
} else if ("approve".equals(command)) {
|
||||||
br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"approvedOnDate\": \"" + dateString + "\","
|
br.setBody("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", \"approvedOnDate\": \"" + dateString + "\","
|
||||||
+ "\"note\": \"Loan approval note\"}");
|
+ "\"note\": \"Loan approval note\", \"expectedDisbursementDate\": \"" + dateString + "\"}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return br;
|
return br;
|
||||||
|
|||||||
+6
-6
@@ -105,7 +105,7 @@ public class InlineLoanCOBTest {
|
|||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -190,7 +190,7 @@ public class InlineLoanCOBTest {
|
|||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ public class InlineLoanCOBTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ public class InlineLoanCOBTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -375,7 +375,7 @@ public class InlineLoanCOBTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
@@ -442,7 +442,7 @@ public class InlineLoanCOBTest {
|
|||||||
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString());
|
||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -307,7 +307,7 @@ public class ExternalAssetOwnerTransferCancelTest {
|
|||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1012,7 +1012,7 @@ public class InitiateExternalAssetOwnerTransferTest {
|
|||||||
Assertions.assertNotNull(loanProductID);
|
Assertions.assertNotNull(loanProductID);
|
||||||
HashMap loanStatusHashMap;
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user