Real time Loan Delinquency Classification
This commit is contained in:
committed by
Arnold Gálovics
parent
17b36a0919
commit
3f1743a3d4
+1
-2
@@ -143,8 +143,7 @@ public final class DelinquencyApiResourceSwagger {
|
||||
public Integer id;
|
||||
@Schema(example = "10")
|
||||
public Long loanId;
|
||||
@Schema(example = "Delinquent 1")
|
||||
public String delinquencyRange;
|
||||
public GetDelinquencyRangesResponse delinquencyRange;
|
||||
@Schema(example = "2013,1,2")
|
||||
public LocalDate addedOnDate;
|
||||
@Schema(example = "2013,2,20")
|
||||
|
||||
+2
@@ -38,4 +38,6 @@ public interface LoanDelinquencyTagHistoryRepository
|
||||
|
||||
Long countByDelinquencyRange(DelinquencyRange delinquencyRange);
|
||||
|
||||
List<LoanDelinquencyTagHistory> findByLoan(Loan loan);
|
||||
|
||||
}
|
||||
|
||||
+7
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.delinquency.service;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
public interface DelinquencyWritePlatformService {
|
||||
|
||||
@@ -41,4 +42,10 @@ public interface DelinquencyWritePlatformService {
|
||||
|
||||
void applyDelinquencyTagToLoan(Long loanId, Long ageDays);
|
||||
|
||||
void applyDelinquencyTagToLoan(Loan loan, Long ageDays);
|
||||
|
||||
void removeDelinquencyTagToLoan(Loan loan);
|
||||
|
||||
void cleanLoanDelinquencyTags(Loan loan);
|
||||
|
||||
}
|
||||
|
||||
+20
-3
@@ -167,9 +167,26 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
||||
@Override
|
||||
public void applyDelinquencyTagToLoan(Long loanId, Long ageDays) {
|
||||
final Loan loan = this.loanRepository.findOneWithNotFoundDetection(loanId);
|
||||
final DelinquencyBucket delinquencyBucket = loan.getLoanProduct().getDelinquencyBucket();
|
||||
if (delinquencyBucket != null) {
|
||||
lookUpDelinquencyRange(loan, delinquencyBucket, ageDays);
|
||||
applyDelinquencyTagToLoan(loan, ageDays);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDelinquencyTagToLoan(final Loan loan, Long ageDays) {
|
||||
if (loan.hasDelinquencyBucket()) {
|
||||
lookUpDelinquencyRange(loan, loan.getLoanProduct().getDelinquencyBucket(), ageDays);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDelinquencyTagToLoan(final Loan loan) {
|
||||
setLoanDelinquencyTag(loan, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanLoanDelinquencyTags(Loan loan) {
|
||||
List<LoanDelinquencyTagHistory> loanDelinquencyTags = this.loanDelinquencyTagRepository.findByLoan(loan);
|
||||
if (loanDelinquencyTags != null && loanDelinquencyTags.size() > 0) {
|
||||
this.loanDelinquencyTagRepository.deleteAll(loanDelinquencyTags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-4
@@ -143,8 +143,6 @@ import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.rate.domain.Rate;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Entity
|
||||
@@ -153,8 +151,6 @@ import org.springframework.stereotype.Component;
|
||||
@UniqueConstraint(columnNames = { "external_id" }, name = "loan_externalid_UNIQUE") })
|
||||
public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Loan.class);
|
||||
|
||||
/** Disable optimistic locking till batch jobs failures can be fixed **/
|
||||
@Version
|
||||
int version;
|
||||
@@ -6864,4 +6860,21 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
// Return empty set instead of null to avoid NPE
|
||||
return Optional.ofNullable(this.charges).orElse(new HashSet<>());
|
||||
}
|
||||
|
||||
public boolean hasDelinquencyBucket() {
|
||||
return (getLoanProduct().getDelinquencyBucket() != null);
|
||||
}
|
||||
|
||||
public Long getAgeOfOverdueDays(LocalDate baseDate) {
|
||||
Long ageOfOverdueDays = 0L;
|
||||
|
||||
List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments();
|
||||
for (final LoanRepaymentScheduleInstallment installment : installments) {
|
||||
if (!installment.isObligationsMet()) {
|
||||
ageOfOverdueDays = DateUtils.getDifferenceInDays(installment.getDueDate(), baseDate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ageOfOverdueDays;
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -62,6 +62,15 @@ public interface LoanAccountDomainService {
|
||||
*/
|
||||
void recalculateAccruals(Loan loan);
|
||||
|
||||
/**
|
||||
* This method is to set a Delinquency Tag If the loan is overdue, If the loan after the repayment transaction is
|
||||
* not overdue and It has a Delinquency Tag, It is removed
|
||||
*
|
||||
* @param loan
|
||||
* @param transactionDate
|
||||
*/
|
||||
void setLoanDelinquencyTag(Loan loan, LocalDate transactionDate);
|
||||
|
||||
LoanTransaction makeRepayment(LoanTransactionType repaymentTransactionType, Loan loan, CommandProcessingResultBuilder builderResult,
|
||||
LocalDate transactionDate, BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId,
|
||||
boolean isRecoveryRepayment, String chargeRefundChargeType, boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto,
|
||||
|
||||
+18
-15
@@ -20,7 +20,6 @@ package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -29,6 +28,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
@@ -60,7 +60,6 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.transaction
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionRecoveryPaymentPostBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionRecoveryPaymentPreBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||
import org.apache.fineract.organisation.holiday.domain.HolidayRepository;
|
||||
import org.apache.fineract.organisation.holiday.domain.HolidayStatusType;
|
||||
@@ -80,6 +79,7 @@ import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
@@ -94,12 +94,12 @@ import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.data.PostDatedChecksStatus;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecksRepository;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
@@ -116,12 +116,12 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
private final AccountTransferRepository accountTransferRepository;
|
||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
|
||||
private final LoanAccrualPlatformService loanAccrualPlatformService;
|
||||
private final PlatformSecurityContext context;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final LoanUtilService loanUtilService;
|
||||
private final StandingInstructionRepository standingInstructionRepository;
|
||||
private final PostDatedChecksRepository postDatedChecksRepository;
|
||||
private final LoanCollateralManagementRepository loanCollateralManagementRepository;
|
||||
private final DelinquencyWritePlatformService delinquencyWritePlatformService;
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@@ -157,7 +157,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
final PaymentDetail paymentDetail, final String noteText, final String txnExternalId, final boolean isRecoveryRepayment,
|
||||
final String chargeRefundChargeType, boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto,
|
||||
Boolean isHolidayValidationDone, final boolean isLoanToLoanTransfer) {
|
||||
AppUser currentUser = getAppUserIfPresent();
|
||||
checkClientOrGroupActive(loan);
|
||||
|
||||
LoanBusinessEvent repaymentEvent = getLoanRepaymentTypeBusinessEvent(repaymentTransactionType, isRecoveryRepayment, loan);
|
||||
@@ -224,6 +223,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
|
||||
recalculateAccruals(loan);
|
||||
|
||||
setLoanDelinquencyTag(loan, transactionDate);
|
||||
|
||||
if (!repaymentTransactionType.isChargeRefund()) {
|
||||
LoanTransactionBusinessEvent transactionRepaymentEvent = getTransactionRepaymentTypeBusinessEvent(repaymentTransactionType,
|
||||
isRecoveryRepayment, newRepaymentTransaction);
|
||||
@@ -536,6 +537,18 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
recalculateAccruals(loan, loan.repaymentScheduleDetail().isInterestRecalculationEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoanDelinquencyTag(final Loan loan, final LocalDate transactionDate) {
|
||||
// Revalidate the Delinquency Classification
|
||||
final Long ageOfOverdueDays = loan.getAgeOfOverdueDays(transactionDate);
|
||||
log.debug("Loan {} with {} days and current classification {}", loan.getId(), ageOfOverdueDays);
|
||||
if (ageOfOverdueDays > 0L) { // If loan is overdue
|
||||
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loan, ageOfOverdueDays);
|
||||
} else {
|
||||
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loan);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculateAccruals(Loan loan, boolean isInterestCalculationHappened) {
|
||||
LocalDate accruedTill = loan.getAccruedTill();
|
||||
@@ -629,14 +642,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
}
|
||||
}
|
||||
|
||||
private AppUser getAppUserIfPresent() {
|
||||
AppUser user = null;
|
||||
if (this.context != null) {
|
||||
user = this.context.getAuthenticatedUserIfPresent();
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResultBuilder creditBalanceRefund(Long loanId, LocalDate transactionDate, BigDecimal transactionAmount,
|
||||
String noteText, String externalId) {
|
||||
@@ -720,7 +725,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
existingTransactionIds.addAll(loan.findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = null;
|
||||
AppUser appUser = getAppUserIfPresent();
|
||||
final LoanRepaymentScheduleInstallment foreCloseDetail = loan.fetchLoanForeclosureDetail(foreClosureDate);
|
||||
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()
|
||||
&& (loan.getAccruedTill() == null || !foreClosureDate.isEqual(loan.getAccruedTill()))) {
|
||||
@@ -763,7 +767,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
if (payPrincipal.plus(interestPayable).plus(feePayable).plus(penaltyPayable).isGreaterThanZero()) {
|
||||
final PaymentDetail paymentDetail = null;
|
||||
String externalId = null;
|
||||
final LocalDateTime currentDateTime = DateUtils.getLocalDateTimeOfTenant();
|
||||
payment = LoanTransaction.repayment(loan.getOffice(), payPrincipal.plus(interestPayable).plus(feePayable).plus(penaltyPayable),
|
||||
paymentDetail, foreClosureDate, externalId);
|
||||
payment.updateLoan(loan);
|
||||
|
||||
+15
@@ -522,6 +522,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
updateRecurringCalendarDatesForInterestRecalculation(loan);
|
||||
this.loanAccountDomainService.recalculateAccruals(loan);
|
||||
this.loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
|
||||
// Post Dated Checks
|
||||
if (command.parameterExists("postDatedChecks")) {
|
||||
@@ -784,6 +785,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
updateRecurringCalendarDatesForInterestRecalculation(loan);
|
||||
loanAccountDomainService.recalculateAccruals(loan);
|
||||
loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanDisbursalBusinessEvent(loan));
|
||||
}
|
||||
|
||||
@@ -1148,6 +1150,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.loanAccountDomainService.recalculateAccruals(loan);
|
||||
|
||||
this.loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
|
||||
LoanAdjustTransactionBusinessEvent.Data eventData = new LoanAdjustTransactionBusinessEvent.Data(transactionToAdjust);
|
||||
if (newTransactionDetail.isRepaymentType() && newTransactionDetail.isGreaterThanZero(loan.getPrincipal().getCurrency())) {
|
||||
eventData.setNewTransactionDetail(newTransactionDetail);
|
||||
@@ -1227,6 +1232,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
loanAccountDomainService.recalculateAccruals(loan);
|
||||
loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanWaiveInterestBusinessEvent(waiveInterestTransaction));
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(waiveInterestTransaction.getId())
|
||||
.withOfficeId(loan.getOfficeId()).withClientId(loan.getClientId()).withGroupId(loan.getGroupId()).withLoanId(loanId)
|
||||
@@ -1244,6 +1251,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
|
||||
changes.put("locale", command.locale());
|
||||
changes.put("dateFormat", command.dateFormat());
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
if (command.hasParameter("writeoffReasonId")) {
|
||||
Long writeoffReasonId = command.longValueOfParameterNamed("writeoffReasonId");
|
||||
@@ -1290,6 +1298,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
loanAccountDomainService.recalculateAccruals(loan);
|
||||
loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanWrittenOffPostBusinessEvent(writeOff));
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(writeOff.getId())
|
||||
.withOfficeId(loan.getOfficeId()).withClientId(loan.getClientId()).withGroupId(loan.getGroupId()).withLoanId(loanId)
|
||||
@@ -1310,6 +1319,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
|
||||
changes.put("locale", command.locale());
|
||||
changes.put("dateFormat", command.dateFormat());
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||
@@ -1346,6 +1356,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
loanAccountDomainService.recalculateAccruals(loan);
|
||||
|
||||
loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanCloseBusinessEvent(loan));
|
||||
|
||||
// Update loan transaction on repayment.
|
||||
@@ -2731,6 +2743,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
&& loan.isFeeCompoundingEnabledForInterestRecalculation()) {
|
||||
this.loanAccountDomainService.recalculateAccruals(loan);
|
||||
}
|
||||
this.loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanApplyOverdueChargeBusinessEvent(loan));
|
||||
}
|
||||
}
|
||||
@@ -2860,6 +2873,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
if (writeOffTransaction != null) {
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoWrittenOffBusinessEvent(writeOffTransaction));
|
||||
}
|
||||
this.loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withOfficeId(loan.getOfficeId()) //
|
||||
.withClientId(loan.getClientId()) //
|
||||
@@ -3004,6 +3018,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
this.loanAccountDomainService.recalculateAccruals(loan);
|
||||
this.loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withOfficeId(loan.getOfficeId()) //
|
||||
.withClientId(loan.getClientId()) //
|
||||
|
||||
+337
-18
@@ -36,12 +36,14 @@ import org.apache.fineract.client.models.DeleteDelinquencyBucketResponse;
|
||||
import org.apache.fineract.client.models.DeleteDelinquencyRangeResponse;
|
||||
import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
|
||||
import org.apache.fineract.client.models.GetDelinquencyRangesResponse;
|
||||
import org.apache.fineract.client.models.GetDelinquencyTagHistoryResponse;
|
||||
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentSchedule;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PostDelinquencyBucketResponse;
|
||||
import org.apache.fineract.client.models.PostDelinquencyRangeResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.client.models.PutDelinquencyBucketResponse;
|
||||
import org.apache.fineract.client.models.PutDelinquencyRangeResponse;
|
||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
@@ -63,6 +65,7 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
|
||||
private ResponseSpecification responseSpec;
|
||||
private RequestSpecification requestSpec;
|
||||
private static final String principalAmount = "10000";
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
@@ -259,27 +262,22 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||
delinquencyBucketResponse.getResourceId());
|
||||
|
||||
// Client and Loan account creation
|
||||
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||
final HashMap<String, Object> loanProductMap = new LoanProductTestBuilder().build(null, delinquencyBucket.getId());
|
||||
final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
|
||||
|
||||
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId);
|
||||
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper,
|
||||
delinquencyBucket.getId());
|
||||
assertNotNull(getLoanProductsProductResponse);
|
||||
log.info("Loan Product Bucket Name: {}", getLoanProductsProductResponse.getDelinquencyBucket().getName());
|
||||
assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName());
|
||||
|
||||
final String operationDate = Utils.dateFormatter.format(businessDate);
|
||||
final String principalAmount = "10000";
|
||||
final LocalDate todaysDate = Utils.getLocalDateOfTenant();
|
||||
// Older date to have more than one overdue installment
|
||||
final LocalDate transactionDate = todaysDate.minusDays(65);
|
||||
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
|
||||
String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal(principalAmount).withLoanTermFrequency("12")
|
||||
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("12").withRepaymentEveryAfter("1")
|
||||
.withRepaymentFrequencyTypeAsMonths() //
|
||||
.withInterestRatePerPeriod("2") //
|
||||
.withExpectedDisbursementDate(operationDate) //
|
||||
.withInterestTypeAsDecliningBalance() //
|
||||
.withSubmittedOnDate(operationDate) //
|
||||
.build(clientId.toString(), loanProductId.toString(), null);
|
||||
final Integer loanId = loanTransactionHelper.getLoanId(loanApplicationJSON);
|
||||
loanTransactionHelper.approveLoan(operationDate, principalAmount, loanId, null);
|
||||
loanTransactionHelper.disburseLoanWithNetDisbursalAmount(operationDate, loanId, principalAmount);
|
||||
// Create Loan Account
|
||||
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||
getLoanProductsProductResponse.getId().toString(), operationDate);
|
||||
|
||||
// When
|
||||
// Run first time the Job
|
||||
@@ -294,7 +292,8 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
if (getLoanRepaymentSchedule != null) {
|
||||
log.info("Loan with {} periods", getLoanRepaymentSchedule.getPeriods().size());
|
||||
for (GetLoansLoanIdRepaymentPeriod period : getLoanRepaymentSchedule.getPeriods()) {
|
||||
log.info("Period number {} for due date {}", period.getPeriod(), period.getDueDate());
|
||||
log.info("Period number {} for due date {} and outstanding {}", period.getPeriod(), period.getDueDate(),
|
||||
period.getTotalOutstandingForPeriod());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,4 +320,324 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanClassificationRealtime() {
|
||||
// Given
|
||||
final LoanTransactionHelper loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
ArrayList<Integer> rangeIds = new ArrayList<>();
|
||||
// First Range
|
||||
String jsonRange = DelinquencyRangesHelper.getAsJSON(1, 3);
|
||||
PostDelinquencyRangeResponse delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec,
|
||||
jsonRange);
|
||||
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||
jsonRange = DelinquencyRangesHelper.getAsJSON(4, 60);
|
||||
|
||||
GetDelinquencyRangesResponse range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec,
|
||||
delinquencyRangeResponse.getResourceId());
|
||||
|
||||
// Second Range
|
||||
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||
|
||||
range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec, delinquencyRangeResponse.getResourceId());
|
||||
final String classificationExpected = range.getClassification();
|
||||
log.info("Expected Delinquency Range classification after Disbursement {}", classificationExpected);
|
||||
|
||||
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||
PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
|
||||
responseSpec, jsonBucket);
|
||||
assertNotNull(delinquencyBucketResponse);
|
||||
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||
delinquencyBucketResponse.getResourceId());
|
||||
|
||||
// Client and Loan account creation
|
||||
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper,
|
||||
delinquencyBucket.getId());
|
||||
assertNotNull(getLoanProductsProductResponse);
|
||||
log.info("Loan Product Bucket Name: {}", getLoanProductsProductResponse.getDelinquencyBucket().getName());
|
||||
assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName());
|
||||
|
||||
final LocalDate todaysDate = Utils.getLocalDateOfTenant();
|
||||
// Older date to have more than one overdue installment
|
||||
final LocalDate transactionDate = todaysDate.minusDays(45);
|
||||
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
|
||||
// Create Loan Account
|
||||
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||
getLoanProductsProductResponse.getId().toString(), operationDate);
|
||||
|
||||
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
log.info("Loan Delinquency Range after Disbursement {}", getLoansLoanIdResponse.getDelinquencyRange().getClassification());
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
// First Loan Delinquency Classification after Disbursement command
|
||||
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected);
|
||||
|
||||
printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
// Apply a partial repayment
|
||||
operationDate = Utils.dateFormatter.format(todaysDate);
|
||||
loanTransactionHelper.makeLoanRepayment(operationDate, 100.0f, loanId);
|
||||
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
log.info("Loan Delinquency Range after Repayment {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
assertNotNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
// First Loan Delinquency Classification remains after Repayment because the installment is not fully paid
|
||||
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected);
|
||||
|
||||
// Apply a repayment to get a full paid installment
|
||||
loanTransactionHelper.makeLoanRepayment(operationDate, 1000.0f, loanId);
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
log.info("Loan Delinquency Range after Repayment {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
// The Loan Delinquency Classification after Repayment command must be null
|
||||
assertNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
// Get the Delinquency Tags
|
||||
ArrayList<GetDelinquencyTagHistoryResponse> getDelinquencyTagsHistory = loanTransactionHelper.getLoanDelinquencyTags(requestSpec,
|
||||
responseSpec, loanId);
|
||||
assertNotNull(getDelinquencyTagsHistory);
|
||||
log.info("Delinquency Tag History items {}", getDelinquencyTagsHistory.size());
|
||||
assertEquals(1, getDelinquencyTagsHistory.size());
|
||||
assertNotNull(getDelinquencyTagsHistory.get(0).getLiftedOnDate());
|
||||
assertEquals(getDelinquencyTagsHistory.get(0).getAddedOnDate(), Utils.getLocalDateOfTenant());
|
||||
assertEquals(getDelinquencyTagsHistory.get(0).getLiftedOnDate(), Utils.getLocalDateOfTenant());
|
||||
assertEquals(getDelinquencyTagsHistory.get(0).getDelinquencyRange().getClassification(), classificationExpected);
|
||||
log.info("Delinquency Tag Item with Lifted On {}", getDelinquencyTagsHistory.get(0).getLiftedOnDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanClassificationRealtimeOlderLoan() {
|
||||
// Given
|
||||
final LoanTransactionHelper loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
ArrayList<Integer> rangeIds = new ArrayList<>();
|
||||
// First Range
|
||||
String jsonRange = DelinquencyRangesHelper.getAsJSON(4, 30);
|
||||
PostDelinquencyRangeResponse delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec,
|
||||
jsonRange);
|
||||
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||
GetDelinquencyRangesResponse range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec,
|
||||
delinquencyRangeResponse.getResourceId());
|
||||
final String classificationExpected02 = range.getClassification();
|
||||
log.info("Expected Delinquency Range classification after first repayment {}", classificationExpected02);
|
||||
|
||||
// Second Range
|
||||
jsonRange = DelinquencyRangesHelper.getAsJSON(31, 60);
|
||||
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||
|
||||
range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec, delinquencyRangeResponse.getResourceId());
|
||||
final String classificationExpected01 = range.getClassification();
|
||||
log.info("Expected Delinquency Range classification after Disbursement {}", classificationExpected01);
|
||||
|
||||
// Third Range
|
||||
jsonRange = DelinquencyRangesHelper.getAsJSON(61, 90);
|
||||
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||
|
||||
range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec, delinquencyRangeResponse.getResourceId());
|
||||
|
||||
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||
PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
|
||||
responseSpec, jsonBucket);
|
||||
assertNotNull(delinquencyBucketResponse);
|
||||
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||
delinquencyBucketResponse.getResourceId());
|
||||
|
||||
// Client and Loan account creation
|
||||
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper,
|
||||
delinquencyBucket.getId());
|
||||
assertNotNull(getLoanProductsProductResponse);
|
||||
log.info("Loan Product Bucket Name: {}", getLoanProductsProductResponse.getDelinquencyBucket().getName());
|
||||
assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName());
|
||||
|
||||
final LocalDate todaysDate = Utils.getLocalDateOfTenant();
|
||||
// Older date to have more than one overdue installment
|
||||
final LocalDate transactionDate = todaysDate.minusDays(85);
|
||||
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
|
||||
// Create Loan Account
|
||||
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||
getLoanProductsProductResponse.getId().toString(), operationDate);
|
||||
|
||||
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
log.info("Loan Delinquency Range after Disbursement in null? {}", (getLoansLoanIdResponse.getDelinquencyRange() == null));
|
||||
assertNotNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
log.info("Loan Delinquency Range after Disbursement {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
// First Loan Delinquency Classification after Disbursement command
|
||||
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected01);
|
||||
|
||||
printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
// Apply a repayment to get a first full paid installment
|
||||
operationDate = Utils.dateFormatter.format(todaysDate);
|
||||
PostLoansLoanIdTransactionsResponse loansLoanIdTransactions = loanTransactionHelper.makeLoanRepayment(operationDate, 1050.0f,
|
||||
loanId);
|
||||
assertNotNull(loansLoanIdTransactions);
|
||||
log.info("Loan repayment transaction id {}", loansLoanIdTransactions.getResourceId());
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
log.info("Loan Delinquency Range after first Repayment {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
assertNotNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
// First Loan Delinquency Classification remains after Repayment because the installment is not fully paid
|
||||
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected02);
|
||||
|
||||
ArrayList<GetDelinquencyTagHistoryResponse> getDelinquencyTagsHistory = loanTransactionHelper.getLoanDelinquencyTags(requestSpec,
|
||||
responseSpec, loanId);
|
||||
assertNotNull(getDelinquencyTagsHistory);
|
||||
log.info("Delinquency Tag History items {}", getDelinquencyTagsHistory.size());
|
||||
log.info("Delinquency Tag Item with Lifted On {}", getDelinquencyTagsHistory.get(0).getLiftedOnDate());
|
||||
assertEquals(getDelinquencyTagsHistory.get(0).getAddedOnDate(), Utils.getLocalDateOfTenant());
|
||||
assertEquals(getDelinquencyTagsHistory.get(0).getLiftedOnDate(), Utils.getLocalDateOfTenant());
|
||||
assertEquals(getDelinquencyTagsHistory.get(0).getDelinquencyRange().getClassification(), classificationExpected01);
|
||||
log.info("Loan Id {} with Loan status {}", getLoansLoanIdResponse.getId(), getLoansLoanIdResponse.getStatus().getCode());
|
||||
|
||||
// Apply a repayment to get a second full paid installment
|
||||
loansLoanIdTransactions = loanTransactionHelper.makeLoanRepayment(operationDate, 1020.0f, loanId);
|
||||
assertNotNull(loansLoanIdTransactions);
|
||||
log.info("Loan repayment transaction id {}", loansLoanIdTransactions.getResourceId());
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
log.info("Loan Delinquency Range after second Repayment {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
// The Loan Delinquency Classification after Repayment command must be null
|
||||
assertNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
|
||||
getDelinquencyTagsHistory = loanTransactionHelper.getLoanDelinquencyTags(requestSpec, responseSpec, loanId);
|
||||
assertNotNull(getDelinquencyTagsHistory);
|
||||
log.info("Delinquency Tag History items {}", getDelinquencyTagsHistory.size());
|
||||
log.info("Delinquency Tag Item with Lifted On {}", getDelinquencyTagsHistory.get(1).getLiftedOnDate());
|
||||
assertEquals(getDelinquencyTagsHistory.get(1).getAddedOnDate(), Utils.getLocalDateOfTenant());
|
||||
assertEquals(getDelinquencyTagsHistory.get(1).getLiftedOnDate(), Utils.getLocalDateOfTenant());
|
||||
assertEquals(getDelinquencyTagsHistory.get(1).getDelinquencyRange().getClassification(), classificationExpected02);
|
||||
log.info("Loan Id {} with final Loan status {}", getLoansLoanIdResponse.getId(), getLoansLoanIdResponse.getStatus().getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanClassificationRealtimeWithReversedRepayment() {
|
||||
// Given
|
||||
final LoanTransactionHelper loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
ArrayList<Integer> rangeIds = new ArrayList<>();
|
||||
// First Range
|
||||
String jsonRange = DelinquencyRangesHelper.getAsJSON(4, 30);
|
||||
PostDelinquencyRangeResponse delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec,
|
||||
jsonRange);
|
||||
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||
GetDelinquencyRangesResponse range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec,
|
||||
delinquencyRangeResponse.getResourceId());
|
||||
final String classificationExpected = range.getClassification();
|
||||
log.info("Expected Delinquency Range classification after first repayment {}", classificationExpected);
|
||||
|
||||
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||
PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
|
||||
responseSpec, jsonBucket);
|
||||
assertNotNull(delinquencyBucketResponse);
|
||||
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||
delinquencyBucketResponse.getResourceId());
|
||||
|
||||
// Client and Loan account creation
|
||||
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper,
|
||||
delinquencyBucket.getId());
|
||||
assertNotNull(getLoanProductsProductResponse);
|
||||
log.info("Loan Product Bucket Name: {}", getLoanProductsProductResponse.getDelinquencyBucket().getName());
|
||||
assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName());
|
||||
|
||||
final LocalDate todaysDate = Utils.getLocalDateOfTenant();
|
||||
// Older date to have more than one overdue installment
|
||||
final LocalDate transactionDate = todaysDate.minusDays(45);
|
||||
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
|
||||
// Create Loan Account
|
||||
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||
getLoanProductsProductResponse.getId().toString(), operationDate);
|
||||
|
||||
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
log.info("Loan Delinquency Range after Disbursement in null? {}", (getLoansLoanIdResponse.getDelinquencyRange() == null));
|
||||
assertNotNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
log.info("Loan Delinquency Range after Disbursement {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
// First Loan Delinquency Classification after Disbursement command
|
||||
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected);
|
||||
|
||||
printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
// Apply a repayment to get a full paid installment
|
||||
operationDate = Utils.dateFormatter.format(todaysDate);
|
||||
PostLoansLoanIdTransactionsResponse loansLoanIdTransactions = loanTransactionHelper.makeLoanRepayment(operationDate, 1050.0f,
|
||||
loanId);
|
||||
assertNotNull(loansLoanIdTransactions);
|
||||
log.info("Loan repayment transaction id {}", loansLoanIdTransactions.getResourceId());
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
log.info("Loan Delinquency Range after Repayment {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
// Loan Delinquency Classification removed after Repayment because the installment is fully paid
|
||||
assertNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
|
||||
ArrayList<GetDelinquencyTagHistoryResponse> getDelinquencyTagsHistory = loanTransactionHelper.getLoanDelinquencyTags(requestSpec,
|
||||
responseSpec, loanId);
|
||||
assertNotNull(getDelinquencyTagsHistory);
|
||||
log.info("Delinquency Tag History items {}", getDelinquencyTagsHistory.size());
|
||||
log.info("Delinquency Tag Item with Lifted On {}", getDelinquencyTagsHistory.get(0).getLiftedOnDate());
|
||||
assertEquals(getDelinquencyTagsHistory.get(0).getAddedOnDate(), Utils.getLocalDateOfTenant());
|
||||
assertEquals(getDelinquencyTagsHistory.get(0).getLiftedOnDate(), Utils.getLocalDateOfTenant());
|
||||
assertEquals(getDelinquencyTagsHistory.get(0).getDelinquencyRange().getClassification(), classificationExpected);
|
||||
log.info("Loan Id {} with Loan status {}", getLoansLoanIdResponse.getId(), getLoansLoanIdResponse.getStatus().getCode());
|
||||
|
||||
// Reverse the Previous Loan Repayment
|
||||
PostLoansLoanIdTransactionsResponse loansLoanIdReverseTransactions = loanTransactionHelper.reverseLoanRepayment(loanId,
|
||||
loansLoanIdTransactions.getResourceId(), operationDate);
|
||||
assertNotNull(loansLoanIdReverseTransactions);
|
||||
log.info("Loan repayment reverse transaction id {}", loansLoanIdReverseTransactions.getResourceId());
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
log.info("Loan Delinquency Range after Reverse Repayment {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
// Loan Delinquency Classification goes back after Repayment because the installment is not paid
|
||||
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected);
|
||||
|
||||
getDelinquencyTagsHistory = loanTransactionHelper.getLoanDelinquencyTags(requestSpec, responseSpec, loanId);
|
||||
assertNotNull(getDelinquencyTagsHistory);
|
||||
log.info("Delinquency Tag History items {}", getDelinquencyTagsHistory.size());
|
||||
log.info("Delinquency Tag Item with Lifted On {}", getDelinquencyTagsHistory.get(1).getLiftedOnDate());
|
||||
assertEquals(getDelinquencyTagsHistory.get(1).getAddedOnDate(), Utils.getLocalDateOfTenant());
|
||||
// Second record is open with liftedOn in null
|
||||
assertNull(getDelinquencyTagsHistory.get(1).getLiftedOnDate());
|
||||
assertEquals(getDelinquencyTagsHistory.get(1).getDelinquencyRange().getClassification(), classificationExpected);
|
||||
log.info("Loan Id {} with final Loan status {}", getLoansLoanIdResponse.getId(), getLoansLoanIdResponse.getStatus().getCode());
|
||||
}
|
||||
|
||||
private GetLoanProductsProductIdResponse createLoanProduct(final LoanTransactionHelper loanTransactionHelper,
|
||||
final Integer delinquencyBucketId) {
|
||||
final HashMap<String, Object> loanProductMap = new LoanProductTestBuilder().build(null, delinquencyBucketId);
|
||||
final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
|
||||
return loanTransactionHelper.getLoanProduct(loanProductId);
|
||||
}
|
||||
|
||||
private Integer createLoanAccount(final LoanTransactionHelper loanTransactionHelper, final String clientId, final String loanProductId,
|
||||
final String operationDate) {
|
||||
final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal(principalAmount).withLoanTermFrequency("12")
|
||||
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("12").withRepaymentEveryAfter("1")
|
||||
.withRepaymentFrequencyTypeAsMonths() //
|
||||
.withInterestRatePerPeriod("2") //
|
||||
.withExpectedDisbursementDate(operationDate) //
|
||||
.withInterestTypeAsDecliningBalance() //
|
||||
.withSubmittedOnDate(operationDate) //
|
||||
.build(clientId, loanProductId, null);
|
||||
final Integer loanId = loanTransactionHelper.getLoanId(loanApplicationJSON);
|
||||
loanTransactionHelper.approveLoan(operationDate, principalAmount, loanId, null);
|
||||
loanTransactionHelper.disburseLoanWithNetDisbursalAmount(operationDate, loanId, principalAmount);
|
||||
return loanId;
|
||||
}
|
||||
|
||||
private void printRepaymentSchedule(GetLoansLoanIdResponse getLoansLoanIdResponse) {
|
||||
GetLoansLoanIdRepaymentSchedule getLoanRepaymentSchedule = getLoansLoanIdResponse.getRepaymentSchedule();
|
||||
if (getLoanRepaymentSchedule != null) {
|
||||
log.info("Loan with {} periods", getLoanRepaymentSchedule.getPeriods().size());
|
||||
for (GetLoansLoanIdRepaymentPeriod period : getLoanRepaymentSchedule.getPeriods()) {
|
||||
log.info("Period number {} for due date {} and outstanding {}", period.getPeriod(), period.getDueDate(),
|
||||
period.getTotalOutstandingForPeriod());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+25
-1
@@ -22,12 +22,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.linecorp.armeria.internal.shaded.guava.reflect.TypeToken;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
@@ -38,8 +40,10 @@ import java.util.Map;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.GetDelinquencyTagHistoryResponse;
|
||||
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.client.util.JSON;
|
||||
import org.apache.fineract.integrationtests.common.CommonConstants;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
@@ -188,6 +192,14 @@ public class LoanTransactionHelper {
|
||||
return Utils.performServerGet(requestSpec, responseSpec, URL, null);
|
||||
}
|
||||
|
||||
public ArrayList<GetDelinquencyTagHistoryResponse> getLoanDelinquencyTags(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec, final Integer loanID) {
|
||||
final String URL = "/fineract-provider/api/v1/loans/" + loanID + "/delinquencytags?" + Utils.TENANT_IDENTIFIER;
|
||||
final String response = Utils.performServerGet(requestSpec, responseSpec, URL);
|
||||
Type delinquencyTagsListType = new TypeToken<ArrayList<GetDelinquencyTagHistoryResponse>>() {}.getType();
|
||||
return GSON.fromJson(response, delinquencyTagsListType);
|
||||
}
|
||||
|
||||
public Object getLoanProductDetail(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||
final Integer loanProductId, final String jsonAttributeToGetBack) {
|
||||
final String URL = "/fineract-provider/api/v1/loanproducts/" + loanProductId + "?associations=all&" + Utils.TENANT_IDENTIFIER;
|
||||
@@ -397,6 +409,14 @@ public class LoanTransactionHelper {
|
||||
return (HashMap) performLoanTransaction(createLoanTransactionURL(UNDO, loanId, transactionId), getUndoJsonBody(date), "");
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse makeLoanRepayment(final String date, final Float amountToBePaid, final Integer loanID) {
|
||||
return postLoanTransaction(createLoanTransactionURL(MAKE_REPAYMENT_COMMAND, loanID), getRepaymentBodyAsJSON(date, amountToBePaid));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse reverseLoanRepayment(final Integer loanId, final Integer transactionId, String date) {
|
||||
return postLoanTransaction(createLoanTransactionURL(UNDO, loanId, transactionId), getUndoJsonBody(date));
|
||||
}
|
||||
|
||||
public HashMap makeRepaymentWithPDC(final String date, final Float amountToBePaid, final Integer loanID, final Integer paymentType) {
|
||||
return (HashMap) performLoanTransaction(createLoanTransactionURL(MAKE_REPAYMENT_COMMAND, loanID),
|
||||
getRepaymentWithPDCBodyAsJSON(date, amountToBePaid, paymentType), "");
|
||||
@@ -785,7 +805,6 @@ public class LoanTransactionHelper {
|
||||
}
|
||||
|
||||
private HashMap performLoanTransaction(final String postURLForLoanTransaction, final String jsonToBeSent) {
|
||||
|
||||
final HashMap response = Utils.performServerPost(this.requestSpec, this.responseSpec, postURLForLoanTransaction, jsonToBeSent,
|
||||
"changes");
|
||||
return (HashMap) response.get("status");
|
||||
@@ -803,6 +822,11 @@ public class LoanTransactionHelper {
|
||||
return Utils.performServerPost(this.requestSpec, this.responseSpec, postURLForLoanTransaction, jsonToBeSent, responseAttribute);
|
||||
}
|
||||
|
||||
private PostLoansLoanIdTransactionsResponse postLoanTransaction(final String postURLForLoanTransaction, final String jsonToBeSent) {
|
||||
final String response = Utils.performServerPost(this.requestSpec, this.responseSpec, postURLForLoanTransaction, jsonToBeSent);
|
||||
return GSON.fromJson(response, PostLoansLoanIdTransactionsResponse.class);
|
||||
}
|
||||
|
||||
private Object performLoanTransaction(final String postURLForLoanTransaction, final String jsonToBeSent,
|
||||
ResponseSpecification responseValidationError) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user