Delinquency classification including Chargeback transactions
This commit is contained in:
committed by
Arnold Gálovics
parent
cce7902054
commit
90f1eccd4b
+2
-5
@@ -478,7 +478,7 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
|
||||
|
||||
.append(" l.closedon_date as closedOnDate,")
|
||||
.append(" cbu.username as closedByUsername, cbu.firstname as closedByFirstname, cbu.lastname as closedByLastname,")
|
||||
.append(" la.overdue_since_date_derived as overdueSinceDate,")
|
||||
.append(" la.overdue_since_date_derived as overdueSinceDate, ")
|
||||
.append(" l.writtenoffon_date as writtenOffOnDate, l.expected_maturedon_date as expectedMaturityDate")
|
||||
|
||||
.append(" from m_loan l ").append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id")
|
||||
@@ -550,10 +550,7 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
|
||||
final LocalDate expectedMaturityDate = JdbcSupport.getLocalDate(rs, "expectedMaturityDate");
|
||||
|
||||
final LocalDate overdueSinceDate = JdbcSupport.getLocalDate(rs, "overdueSinceDate");
|
||||
Boolean inArrears = true;
|
||||
if (overdueSinceDate == null) {
|
||||
inArrears = false;
|
||||
}
|
||||
Boolean inArrears = (overdueSinceDate != null);
|
||||
|
||||
final LoanApplicationTimelineData timeline = new LoanApplicationTimelineData(submittedOnDate, submittedByUsername,
|
||||
submittedByFirstname, submittedByLastname, rejectedOnDate, rejectedByUsername, rejectedByFirstname, rejectedByLastname,
|
||||
|
||||
+3
@@ -22,6 +22,7 @@ import java.util.Collection;
|
||||
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||
import org.apache.fineract.portfolio.delinquency.data.LoanDelinquencyTagHistoryData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||
|
||||
public interface DelinquencyReadPlatformService {
|
||||
|
||||
@@ -37,4 +38,6 @@ public interface DelinquencyReadPlatformService {
|
||||
|
||||
Collection<LoanDelinquencyTagHistoryData> retrieveDelinquencyRangeHistory(Long loanId);
|
||||
|
||||
CollectionData calculateLoanCollectionData(Long loanId);
|
||||
|
||||
}
|
||||
|
||||
+100
@@ -18,10 +18,15 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.delinquency.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||
import org.apache.fineract.portfolio.delinquency.data.LoanDelinquencyTagHistoryData;
|
||||
@@ -34,8 +39,13 @@ import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistor
|
||||
import org.apache.fineract.portfolio.delinquency.mapper.DelinquencyBucketMapper;
|
||||
import org.apache.fineract.portfolio.delinquency.mapper.DelinquencyRangeMapper;
|
||||
import org.apache.fineract.portfolio.delinquency.mapper.LoanDelinquencyTagMapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -97,4 +107,94 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
|
||||
return mapperLoanDelinquencyTagHistory.map(loanDelinquencyTagData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionData calculateLoanCollectionData(final Long loanId) {
|
||||
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||
final Optional<Loan> optLoan = this.loanRepository.findById(loanId);
|
||||
|
||||
CollectionData collectionData = CollectionData.template();
|
||||
if (optLoan.isPresent()) {
|
||||
final Loan loan = optLoan.get();
|
||||
|
||||
collectionData.setAvailableDisbursementAmount(loan.getApprovedPrincipal().subtract(loan.getDisbursedAmount()));
|
||||
collectionData.setNextPaymentDueDate(loan.possibleNextRepaymentDate());
|
||||
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
BigDecimal delinquentAmount = BigDecimal.ZERO;
|
||||
// Overdue Days calculation
|
||||
Long overdueDays = 0L;
|
||||
LocalDate overdueSinceDate = null;
|
||||
final List<LoanTransaction> chargebackTransactions = loan.retrieveListOfTransactionsByType(LoanTransactionType.CHARGEBACK);
|
||||
for (LoanTransaction loanTransaction : chargebackTransactions) {
|
||||
Set<LoanTransactionToRepaymentScheduleMapping> loanTransactionToRepaymentScheduleMappings = loanTransaction
|
||||
.getLoanTransactionToRepaymentScheduleMappings();
|
||||
LoanTransactionToRepaymentScheduleMapping loanTransactionToRepaymentScheduleMapping = loanTransactionToRepaymentScheduleMappings
|
||||
.iterator().next();
|
||||
if (!loanTransactionToRepaymentScheduleMapping.getLoanRepaymentScheduleInstallment().isPrincipalCompleted(currency)) {
|
||||
overdueSinceDate = loanTransaction.getTransactionDate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
|
||||
if (overdueSinceDate == null) {
|
||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||
if (installment.isNotFullyPaidOff()) {
|
||||
overdueSinceDate = installment.getDueDate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Integer graceDays = 0;
|
||||
if (overdueSinceDate != null) {
|
||||
if (loan.loanProduct().getLoanProductConfigurableAttributes().getGraceOnArrearsAgingBoolean()) {
|
||||
graceDays = loan.loanProduct().getLoanProductRelatedDetail().getGraceOnArrearsAgeing();
|
||||
if (graceDays == null) {
|
||||
graceDays = 0;
|
||||
}
|
||||
overdueSinceDate = overdueSinceDate.plusDays(graceDays);
|
||||
}
|
||||
overdueDays = DateUtils.getDifferenceInDays(overdueSinceDate, businessDate);
|
||||
if (overdueDays < 0) {
|
||||
overdueDays = 0L;
|
||||
}
|
||||
collectionData.setDelinquentDate(overdueSinceDate);
|
||||
}
|
||||
|
||||
collectionData.setPastDueDays(overdueDays);
|
||||
if (overdueDays > 0) {
|
||||
collectionData.setDelinquentDays(overdueDays - graceDays);
|
||||
}
|
||||
|
||||
final LoanTransaction lastRepaymenTransaction = loan.getLastRepaymentTransaction();
|
||||
if (lastRepaymenTransaction != null) {
|
||||
collectionData.setLastPaymentDate(lastRepaymenTransaction.getTransactionDate());
|
||||
collectionData.setLastPaymentAmount(lastRepaymenTransaction.getAmount());
|
||||
}
|
||||
|
||||
// Calculate Delinquency Amount
|
||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||
if (installment.getDueDate().isBefore(businessDate)) {
|
||||
delinquentAmount = delinquentAmount.add(installment.getTotalOutstanding(currency).getAmount());
|
||||
}
|
||||
}
|
||||
for (LoanTransaction loanTransaction : chargebackTransactions) {
|
||||
Set<LoanTransactionToRepaymentScheduleMapping> loanTransactionToRepaymentScheduleMappings = loanTransaction
|
||||
.getLoanTransactionToRepaymentScheduleMappings();
|
||||
for (LoanTransactionToRepaymentScheduleMapping loanTransactionToRepaymentScheduleMapping : loanTransactionToRepaymentScheduleMappings) {
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loanTransactionToRepaymentScheduleMapping
|
||||
.getLoanRepaymentScheduleInstallment();
|
||||
if (!loanRepaymentScheduleInstallment.isPrincipalCompleted(currency)) {
|
||||
delinquentAmount = delinquentAmount.add(loanTransaction.getAmount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collectionData.setDelinquentAmount(delinquentAmount);
|
||||
}
|
||||
|
||||
return collectionData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-4
@@ -18,8 +18,10 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.delinquency.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
public interface DelinquencyWritePlatformService {
|
||||
@@ -38,12 +40,14 @@ public interface DelinquencyWritePlatformService {
|
||||
|
||||
CommandProcessingResult applyDelinquencyTagToLoan(Long loanId, JsonCommand command);
|
||||
|
||||
void applyDelinquencyTagToLoan(Long loanId, Long ageDays);
|
||||
|
||||
void applyDelinquencyTagToLoan(Loan loan, Long ageDays);
|
||||
|
||||
void removeDelinquencyTagToLoan(Loan loan);
|
||||
|
||||
void cleanLoanDelinquencyTags(Loan loan);
|
||||
|
||||
LoanScheduleDelinquencyData calculateDelinquencyData(LoanScheduleDelinquencyData loanScheduleDelinquencyData);
|
||||
|
||||
void applyDelinquencyTagToLoan(LoanScheduleDelinquencyData loanDelinquencyData);
|
||||
|
||||
LocalDate getOverdueSinceDate(Loan loan, LocalDate businessDate, Integer graceOnArrearAgeing);
|
||||
|
||||
}
|
||||
|
||||
+98
-27
@@ -33,6 +33,7 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.portfolio.delinquency.api.DelinquencyApiConstants;
|
||||
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||
@@ -48,10 +49,13 @@ import org.apache.fineract.portfolio.delinquency.exception.DelinquencyBucketAges
|
||||
import org.apache.fineract.portfolio.delinquency.exception.DelinquencyRangeInvalidAgesException;
|
||||
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyBucketParseAndValidator;
|
||||
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyRangeParseAndValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -69,7 +73,6 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
||||
private final LoanDelinquencyTagHistoryRepository loanDelinquencyTagRepository;
|
||||
private final LoanRepositoryWrapper loanRepository;
|
||||
private final LoanProductRepository loanProductRepository;
|
||||
private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult createDelinquencyRange(JsonCommand command) {
|
||||
@@ -100,8 +103,9 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
||||
"Data integrity issue with resource: " + delinquencyRange.getId());
|
||||
}
|
||||
repositoryRange.delete(delinquencyRange);
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyRange.getId()).build();
|
||||
}
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyRange.getId()).build();
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyRangeId).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -135,7 +139,71 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
||||
}
|
||||
repositoryBucket.delete(delinquencyBucket);
|
||||
}
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyBucket.getId()).build();
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyBucketId).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanScheduleDelinquencyData calculateDelinquencyData(LoanScheduleDelinquencyData loanScheduleDelinquencyData) {
|
||||
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||
Loan loan = loanScheduleDelinquencyData.getLoan();
|
||||
if (loan == null) {
|
||||
loan = this.loanRepository.findOneWithNotFoundDetection(loanScheduleDelinquencyData.getLoanId());
|
||||
}
|
||||
|
||||
final Integer graceOnArrearAgeing = loan.getLoanProduct().getLoanProductRelatedDetail().getGraceOnArrearsAgeing();
|
||||
final LocalDate overdueSinceDate = getOverdueSinceDate(loan, businessDate, graceOnArrearAgeing);
|
||||
final Long overdueDays = calculateOverdueDays(businessDate, overdueSinceDate);
|
||||
return new LoanScheduleDelinquencyData(loan.getId(), overdueSinceDate, overdueDays, loan);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate getOverdueSinceDate(final Loan loan, final LocalDate businessDate, final Integer graceOnArrearAgeing) {
|
||||
LoanRepaymentScheduleInstallment loanRepaymentSchedule = null;
|
||||
for (LoanRepaymentScheduleInstallment installment : loan.getRepaymentScheduleInstallments()) {
|
||||
if (installment.getDueDate().isBefore(businessDate) && installment.isNotFullyPaidOff()) {
|
||||
loanRepaymentSchedule = installment;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LocalDate overdueSinceDate = null;
|
||||
final MonetaryCurrency loanCurrency = loan.getCurrency();
|
||||
final List<LoanTransaction> loanTransactions = loan.retrieveListOfTransactionsByType(LoanTransactionType.CHARGEBACK);
|
||||
if (loanRepaymentSchedule != null) {
|
||||
// Default Due date
|
||||
overdueSinceDate = loanRepaymentSchedule.getDueDate();
|
||||
}
|
||||
|
||||
// If there is some Loan Transaction Chargeback
|
||||
for (LoanTransaction loanTransaction : loanTransactions) {
|
||||
if (loanTransaction.getLoanTransactionToRepaymentScheduleMappings().iterator().hasNext()) {
|
||||
final LoanTransactionToRepaymentScheduleMapping transactionMapping = loanTransaction
|
||||
.getLoanTransactionToRepaymentScheduleMappings().iterator().next();
|
||||
|
||||
if (transactionMapping != null
|
||||
&& !transactionMapping.getLoanRepaymentScheduleInstallment().isPrincipalCompleted(loanCurrency)) {
|
||||
overdueSinceDate = loanTransaction.getTransactionDate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Include grace days If It's defined
|
||||
if (overdueSinceDate != null && graceOnArrearAgeing != null) {
|
||||
overdueSinceDate = overdueSinceDate.plusDays(graceOnArrearAgeing.longValue());
|
||||
}
|
||||
return overdueSinceDate;
|
||||
}
|
||||
|
||||
private Long calculateOverdueDays(final LocalDate businessDate, LocalDate overdueSinceDate) {
|
||||
Long overdueDays = 0L;
|
||||
if (overdueSinceDate != null) {
|
||||
overdueDays = DateUtils.getDifferenceInDays(overdueSinceDate, businessDate);
|
||||
if (overdueDays < 0) {
|
||||
overdueDays = 0L;
|
||||
}
|
||||
}
|
||||
return overdueDays;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,28 +214,31 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
||||
final DelinquencyBucket delinquencyBucket = loan.getLoanProduct().getDelinquencyBucket();
|
||||
if (delinquencyBucket != null) {
|
||||
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||
LoanRepaymentScheduleInstallment loanRepaymentSchedule = this.loanRepaymentScheduleInstallmentRepository
|
||||
.findFirstByLoanAndDueDateLessThanEqualAndObligationsMetOnDateOrderByDueDate(loan, businessDate, null);
|
||||
|
||||
Long overdueDays = 0L;
|
||||
if (loanRepaymentSchedule != null) {
|
||||
overdueDays = DateUtils.getDifferenceInDays(loanRepaymentSchedule.getDueDate(), businessDate);
|
||||
}
|
||||
final Integer graceOnArrearAgeing = loan.getLoanProduct().getLoanProductRelatedDetail().getGraceOnArrearsAgeing();
|
||||
final LocalDate overdueSinceDate = getOverdueSinceDate(loan, businessDate, graceOnArrearAgeing);
|
||||
|
||||
final Long overdueDays = calculateOverdueDays(businessDate, overdueSinceDate);
|
||||
changes = lookUpDelinquencyRange(loan, delinquencyBucket, overdueDays);
|
||||
}
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(loan.getId()).with(changes).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDelinquencyTagToLoan(Long loanId, Long ageDays) {
|
||||
final Loan loan = this.loanRepository.findOneWithNotFoundDetection(loanId);
|
||||
applyDelinquencyTagToLoan(loan, ageDays);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDelinquencyTagToLoan(final Loan loan, Long ageDays) {
|
||||
public void applyDelinquencyTagToLoan(LoanScheduleDelinquencyData loanDelinquencyData) {
|
||||
final Loan loan = loanDelinquencyData.getLoan();
|
||||
if (loan.hasDelinquencyBucket()) {
|
||||
lookUpDelinquencyRange(loan, loan.getLoanProduct().getDelinquencyBucket(), ageDays);
|
||||
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||
final DelinquencyBucket delinquencyBucket = loan.getLoanProduct().getDelinquencyBucket();
|
||||
final Integer graceOnArrearAgeing = loan.getLoanProduct().getLoanProductRelatedDetail().getGraceOnArrearsAgeing();
|
||||
|
||||
LocalDate overdueSinceDate = loanDelinquencyData.getOverdueSinceDate();
|
||||
if (overdueSinceDate == null) {
|
||||
getOverdueSinceDate(loan, businessDate, graceOnArrearAgeing);
|
||||
}
|
||||
|
||||
final Long overdueDays = calculateOverdueDays(businessDate, overdueSinceDate);
|
||||
lookUpDelinquencyRange(loan, delinquencyBucket, overdueDays);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,11 +360,11 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> lookUpDelinquencyRange(final Loan loan, final DelinquencyBucket delinquencyBucket, long ageDays) {
|
||||
private Map<String, Object> lookUpDelinquencyRange(final Loan loan, final DelinquencyBucket delinquencyBucket, long overdueDays) {
|
||||
Map<String, Object> changes = new HashMap<>();
|
||||
|
||||
if (ageDays <= 0) { // No Delinquency
|
||||
log.debug("Loan {} without delinquency range with {} days", loan.getId(), ageDays);
|
||||
if (overdueDays <= 0) { // No Delinquency
|
||||
log.debug("Loan {} without delinquency range with {} days", loan.getId(), overdueDays);
|
||||
changes = setLoanDelinquencyTag(loan, null);
|
||||
|
||||
} else {
|
||||
@@ -302,27 +373,27 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
||||
|
||||
for (final DelinquencyRange delinquencyRange : ranges) {
|
||||
if (delinquencyRange.getMaximumAgeDays() == null) { // Last Range in the Bucket
|
||||
if (delinquencyRange.getMinimumAgeDays() <= ageDays) {
|
||||
if (delinquencyRange.getMinimumAgeDays() <= overdueDays) {
|
||||
log.debug("Loan {} with delinquency range {} with {} days", loan.getId(), delinquencyRange.getClassification(),
|
||||
ageDays);
|
||||
overdueDays);
|
||||
changes = setLoanDelinquencyTag(loan, delinquencyRange.getId());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (delinquencyRange.getMinimumAgeDays() <= ageDays && delinquencyRange.getMaximumAgeDays() >= ageDays) {
|
||||
if (delinquencyRange.getMinimumAgeDays() <= overdueDays && delinquencyRange.getMaximumAgeDays() >= overdueDays) {
|
||||
log.debug("Loan {} with delinquency range {} with {} days", loan.getId(), delinquencyRange.getClassification(),
|
||||
ageDays);
|
||||
overdueDays);
|
||||
changes = setLoanDelinquencyTag(loan, delinquencyRange.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
changes.put("ageDays", ageDays);
|
||||
changes.put("overdueDays", overdueDays);
|
||||
return changes;
|
||||
}
|
||||
|
||||
public Map<String, Object> setLoanDelinquencyTag(Loan loan, Long delinquencyRangeId) {
|
||||
private Map<String, Object> setLoanDelinquencyTag(Loan loan, Long delinquencyRangeId) {
|
||||
Map<String, Object> changes = new HashMap<>();
|
||||
List<LoanDelinquencyTagHistory> loanDelinquencyTagHistory = new ArrayList<>();
|
||||
final LocalDate transactionDate = DateUtils.getBusinessLocalDate();
|
||||
|
||||
+2
-2
@@ -610,8 +610,8 @@ public class LoansApiResource {
|
||||
|
||||
if (associationParameters.contains(DataTableApiConstant.collectionAssociateParamName)) {
|
||||
mandatoryResponseParameters.add(DataTableApiConstant.collectionAssociateParamName);
|
||||
if (LoanStatus.fromInt(loanBasicDetails.getStatus().getId().intValue()).isActive()) {
|
||||
collectionData = this.loanReadPlatformService.retrieveLoanCollectionData(loanId);
|
||||
if (loanBasicDetails.isActive()) {
|
||||
collectionData = this.delinquencyReadPlatformService.calculateLoanCollectionData(loanId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-28
@@ -20,45 +20,27 @@ package org.apache.fineract.portfolio.loanaccount.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public final class CollectionData {
|
||||
|
||||
private BigDecimal availableDisbursementAmount;
|
||||
private int pastDueDays;
|
||||
private Long pastDueDays;
|
||||
private LocalDate nextPaymentDueDate;
|
||||
private int delinquentDays;
|
||||
private Long delinquentDays;
|
||||
private LocalDate delinquentDate;
|
||||
private BigDecimal delinquentAmount;
|
||||
private LocalDate lastPaymentDate;
|
||||
private BigDecimal lastPaymentAmount;
|
||||
|
||||
private CollectionData(BigDecimal availableDisbursementAmount, int pastDueDays, LocalDate nextPaymentDueDate, int delinquentDays,
|
||||
LocalDate delinquentDate, BigDecimal delinquentAmount, LocalDate lastPaymentDate, BigDecimal lastPaymentAmount) {
|
||||
this.availableDisbursementAmount = availableDisbursementAmount;
|
||||
this.pastDueDays = pastDueDays;
|
||||
this.nextPaymentDueDate = nextPaymentDueDate;
|
||||
this.delinquentDays = delinquentDays;
|
||||
this.delinquentDate = delinquentDate;
|
||||
this.delinquentAmount = delinquentAmount;
|
||||
this.lastPaymentDate = lastPaymentDate;
|
||||
this.lastPaymentAmount = lastPaymentAmount;
|
||||
}
|
||||
|
||||
public static CollectionData instance(BigDecimal availableDisbursementAmount, int pastDueDays, LocalDate nextPaymentDueDate,
|
||||
int delinquentDays, LocalDate delinquentDate, BigDecimal delinquentAmount, LocalDate lastPaymentDate,
|
||||
BigDecimal lastPaymentAmount) {
|
||||
return new CollectionData(availableDisbursementAmount, pastDueDays, nextPaymentDueDate, delinquentDays, delinquentDate,
|
||||
delinquentAmount, lastPaymentDate, lastPaymentAmount);
|
||||
}
|
||||
|
||||
public static CollectionData template() {
|
||||
final BigDecimal zero = BigDecimal.ZERO;
|
||||
return new CollectionData(zero, 0, null, 0, null, zero, null, zero);
|
||||
return new CollectionData(zero, 0L, null, 0L, null, zero, null, zero);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -44,6 +44,7 @@ import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||
import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||
import org.apache.fineract.portfolio.fund.data.FundData;
|
||||
import org.apache.fineract.portfolio.group.data.GroupGeneralData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.apache.fineract.portfolio.loanaccount.guarantor.data.GuarantorData;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||
import org.apache.fineract.portfolio.loanproduct.data.LoanProductBorrowerCycleVariationData;
|
||||
@@ -56,6 +57,7 @@ import org.apache.fineract.portfolio.rate.data.RateData;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@SuppressWarnings("ObjectToString")
|
||||
public class LoanAccountData {
|
||||
|
||||
// basic loan details
|
||||
@@ -1167,4 +1169,8 @@ public class LoanAccountData {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return LoanStatus.fromInt(getStatus().getId().intValue()).isActive();
|
||||
}
|
||||
}
|
||||
|
||||
+9
-4
@@ -22,14 +22,19 @@ import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class LoanScheduleDelinquencyData implements Serializable {
|
||||
|
||||
private final Long loanId;
|
||||
private final Long productId;
|
||||
private final LocalDate dueDate;
|
||||
private final Long ageDays;
|
||||
private Long loanId;
|
||||
private LocalDate overdueSinceDate;
|
||||
private Long overdueDays;
|
||||
private Loan loan;
|
||||
|
||||
}
|
||||
|
||||
+48
-27
@@ -672,7 +672,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
ChangedTransactionDetail changedTransactionDetail = null;
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
@@ -832,7 +832,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
* Consider removing this block of code or logically completing it for the future by getting the list of
|
||||
* affected Transactions
|
||||
***/
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
||||
getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||
}
|
||||
@@ -900,7 +900,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
* Consider removing this block of code or logically completing it for the future by getting the list of
|
||||
* affected Transactions
|
||||
***/
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
||||
getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||
} else {
|
||||
@@ -1087,7 +1087,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
* Consider removing this block of code or logically completing it for the future by getting the list of
|
||||
* affected Transactions
|
||||
***/
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
||||
getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||
} else {
|
||||
@@ -1284,7 +1284,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
* method updates accrual derived fields on installments and reverse the unprocessed transactions
|
||||
*/
|
||||
private void applyAccurals() {
|
||||
Collection<LoanTransaction> accruals = retreiveListOfAccrualTransactions();
|
||||
Collection<LoanTransaction> accruals = retrieveListOfAccrualTransactions();
|
||||
if (!accruals.isEmpty()) {
|
||||
if (isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
||||
applyPeriodicAccruals(accruals);
|
||||
@@ -2634,7 +2634,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
private ChangedTransactionDetail reprocessTransactionForDisbursement() {
|
||||
ChangedTransactionDetail changedTransactionDetail = null;
|
||||
if (this.loanProduct.isMultiDisburseLoan()) {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
if (!allNonContraTransactionsPostDisbursement.isEmpty()) {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||
@@ -3250,7 +3250,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
|
||||
}
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
@@ -3300,7 +3300,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
return installment;
|
||||
}
|
||||
|
||||
private List<LoanTransaction> retreiveListOfIncomePostingTransactions() {
|
||||
private List<LoanTransaction> retrieveListOfIncomePostingTransactions() {
|
||||
final List<LoanTransaction> incomePostTransactions = new ArrayList<>();
|
||||
List<LoanTransaction> trans = getLoanTransactions();
|
||||
for (final LoanTransaction transaction : trans) {
|
||||
@@ -3313,7 +3313,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
return incomePostTransactions;
|
||||
}
|
||||
|
||||
private List<LoanTransaction> retreiveListOfTransactionsPostDisbursement() {
|
||||
private List<LoanTransaction> retrieveListOfTransactionsPostDisbursement() {
|
||||
final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
|
||||
List<LoanTransaction> trans = getLoanTransactions();
|
||||
for (final LoanTransaction transaction : trans) {
|
||||
@@ -3326,7 +3326,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
return repaymentsOrWaivers;
|
||||
}
|
||||
|
||||
public List<LoanTransaction> retreiveListOfTransactionsPostDisbursementExcludeAccruals() {
|
||||
public List<LoanTransaction> retrieveListOfTransactionsPostDisbursementExcludeAccruals() {
|
||||
final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
if (transaction.isNotReversed()
|
||||
@@ -3340,7 +3340,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
return repaymentsOrWaivers;
|
||||
}
|
||||
|
||||
private List<LoanTransaction> retreiveListOfTransactionsExcludeAccruals() {
|
||||
private List<LoanTransaction> retrieveListOfTransactionsExcludeAccruals() {
|
||||
final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
if (transaction.isNotReversed() && !(transaction.isAccrual() || transaction.isNonMonetaryTransaction())) {
|
||||
@@ -3352,7 +3352,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
return repaymentsOrWaivers;
|
||||
}
|
||||
|
||||
private List<LoanTransaction> retreiveListOfAccrualTransactions() {
|
||||
private List<LoanTransaction> retrieveListOfAccrualTransactions() {
|
||||
final List<LoanTransaction> transactions = new ArrayList<>();
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
if (transaction.isNotReversed() && transaction.isAccrual()) {
|
||||
@@ -3364,6 +3364,18 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
public List<LoanTransaction> retrieveListOfTransactionsByType(LoanTransactionType transactionType) {
|
||||
final List<LoanTransaction> transactions = new ArrayList<>();
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
if (transaction.isNotReversed() && transaction.getTypeOf().equals(transactionType)) {
|
||||
transactions.add(transaction);
|
||||
}
|
||||
}
|
||||
final LoanTransactionComparator transactionComparator = new LoanTransactionComparator();
|
||||
Collections.sort(transactions, transactionComparator);
|
||||
return transactions;
|
||||
}
|
||||
|
||||
private boolean doPostLoanTransactionChecks(final LocalDate transactionDate,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
boolean statusChanged = false;
|
||||
@@ -3403,12 +3415,12 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
if (this.loanInterestRecalculationDetails != null && this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()
|
||||
&& this.getStatus().isClosedObligationsMet()) {
|
||||
LocalDate closedDate = this.getClosedOnDate();
|
||||
reverseTransactionsOnOrAfter(retreiveListOfIncomePostingTransactions(), closedDate);
|
||||
reverseTransactionsOnOrAfter(retreiveListOfAccrualTransactions(), closedDate);
|
||||
reverseTransactionsOnOrAfter(retrieveListOfIncomePostingTransactions(), closedDate);
|
||||
reverseTransactionsOnOrAfter(retrieveListOfAccrualTransactions(), closedDate);
|
||||
HashMap<String, BigDecimal> cumulativeIncomeFromInstallments = new HashMap<>();
|
||||
determineCumulativeIncomeFromInstallments(cumulativeIncomeFromInstallments);
|
||||
HashMap<String, BigDecimal> cumulativeIncomeFromIncomePosting = new HashMap<>();
|
||||
determineCumulativeIncomeDetails(retreiveListOfIncomePostingTransactions(), cumulativeIncomeFromIncomePosting);
|
||||
determineCumulativeIncomeDetails(retrieveListOfIncomePostingTransactions(), cumulativeIncomeFromIncomePosting);
|
||||
BigDecimal interestToPost = cumulativeIncomeFromInstallments.get(INTEREST)
|
||||
.subtract(cumulativeIncomeFromIncomePosting.get(INTEREST));
|
||||
BigDecimal feeToPost = cumulativeIncomeFromInstallments.get(FEE).subtract(cumulativeIncomeFromIncomePosting.get(FEE));
|
||||
@@ -3419,7 +3431,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
interestToPost, feeToPost, penaltyToPost);
|
||||
addLoanTransaction(finalIncomeTransaction);
|
||||
if (isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
||||
List<LoanTransaction> updatedAccrualTransactions = retreiveListOfAccrualTransactions();
|
||||
List<LoanTransaction> updatedAccrualTransactions = retrieveListOfAccrualTransactions();
|
||||
LocalDate lastAccruedDate = this.getDisbursementDate();
|
||||
if (!updatedAccrualTransactions.isEmpty()) {
|
||||
lastAccruedDate = updatedAccrualTransactions.get(updatedAccrualTransactions.size() - 1).getTransactionDate();
|
||||
@@ -3646,7 +3658,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING_UNDO, this);
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
|
||||
}
|
||||
@@ -3789,7 +3801,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
|
||||
}
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
@@ -4856,6 +4868,15 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
return currentTransactionDate;
|
||||
}
|
||||
|
||||
public LoanTransaction getLastRepaymentTransaction() {
|
||||
for (final LoanTransaction loanTransaction : this.loanTransactions) {
|
||||
if (!loanTransaction.isReversed() && loanTransaction.isRepaymentType()) {
|
||||
return loanTransaction;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public LocalDate getLastUserTransactionForChargeCalc() {
|
||||
LocalDate lastTransaction = getDisbursementDate();
|
||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
@@ -5130,7 +5151,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
|
||||
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(),
|
||||
getActiveCharges());
|
||||
@@ -5243,7 +5264,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
/*
|
||||
* LocalDate recalculateFrom = null; List<LoanTransaction> loanTransactions =
|
||||
* this.retreiveListOfTransactionsPostDisbursementExcludeAccruals(); for (LoanTransaction loanTransaction :
|
||||
* this.retrieveListOfTransactionsPostDisbursementExcludeAccruals(); for (LoanTransaction loanTransaction :
|
||||
* loanTransactions) { if (recalculateFrom == null ||
|
||||
* loanTransaction.getTransactionDate().isAfter(recalculateFrom)) { recalculateFrom =
|
||||
* loanTransaction.getTransactionDate(); } } generatorDTO.setRecalculateFrom(recalculateFrom);
|
||||
@@ -5266,7 +5287,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
public ChangedTransactionDetail processTransactions() {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
|
||||
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(),
|
||||
getActiveCharges());
|
||||
@@ -5344,8 +5365,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
if (this.loanInterestRecalculationDetails != null && this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()) {
|
||||
LocalDate lastCompoundingDate = this.getDisbursementDate();
|
||||
List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = extractInterestRecalculationAdditionalDetails();
|
||||
List<LoanTransaction> incomeTransactions = retreiveListOfIncomePostingTransactions();
|
||||
List<LoanTransaction> accrualTransactions = retreiveListOfAccrualTransactions();
|
||||
List<LoanTransaction> incomeTransactions = retrieveListOfIncomePostingTransactions();
|
||||
List<LoanTransaction> accrualTransactions = retrieveListOfAccrualTransactions();
|
||||
for (LoanInterestRecalcualtionAdditionalDetails compoundingDetail : compoundingDetails) {
|
||||
if (!compoundingDetail.getEffectiveDate().isBefore(DateUtils.getBusinessLocalDate())) {
|
||||
break;
|
||||
@@ -5495,7 +5516,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
public void processPostDisbursementTransactions() {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> copyTransactions = new ArrayList<>();
|
||||
if (!allNonContraTransactionsPostDisbursement.isEmpty()) {
|
||||
for (LoanTransaction loanTransaction : allNonContraTransactionsPostDisbursement) {
|
||||
@@ -5653,7 +5674,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
private void updateLoanOutstandingBalances() {
|
||||
Money outstanding = Money.zero(getCurrency());
|
||||
List<LoanTransaction> loanTransactions = retreiveListOfTransactionsExcludeAccruals();
|
||||
List<LoanTransaction> loanTransactions = retrieveListOfTransactionsExcludeAccruals();
|
||||
for (LoanTransaction loanTransaction : loanTransactions) {
|
||||
if (loanTransaction.isDisbursement() || loanTransaction.isIncomePosting()) {
|
||||
outstanding = outstanding.plus(loanTransaction.getAmount(getCurrency()));
|
||||
@@ -6099,7 +6120,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
loanRepaymentScheduleTransactionProcessor.handleRefund(loanTransaction, getCurrency(), getRepaymentScheduleInstallments(),
|
||||
getActiveCharges());
|
||||
} else {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
@@ -6191,7 +6212,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_DISBURSAL_UNDO_LAST, getDisbursementDate());
|
||||
LocalDate actualDisbursementDate = null;
|
||||
LocalDate lastTransactionDate = getDisbursementDate();
|
||||
List<LoanTransaction> loanTransactions = retreiveListOfTransactionsExcludeAccruals();
|
||||
List<LoanTransaction> loanTransactions = retrieveListOfTransactionsExcludeAccruals();
|
||||
Collections.reverse(loanTransactions);
|
||||
for (final LoanTransaction previousTransaction : loanTransactions) {
|
||||
if (lastTransactionDate.isBefore(previousTransaction.getTransactionDate())
|
||||
|
||||
+9
-6
@@ -84,6 +84,7 @@ import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
||||
@@ -541,13 +542,15 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
|
||||
@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);
|
||||
LoanScheduleDelinquencyData loanDelinquencyData = new LoanScheduleDelinquencyData(loan.getId(), transactionDate, null, loan);
|
||||
loanDelinquencyData = this.delinquencyWritePlatformService.calculateDelinquencyData(loanDelinquencyData);
|
||||
log.debug("Processing Loan {} with {} overdue days since date {}", loanDelinquencyData.getLoanId(),
|
||||
loanDelinquencyData.getOverdueDays(), loanDelinquencyData.getOverdueSinceDate());
|
||||
// Set or Unset the Delinquency Classification Tag
|
||||
if (loanDelinquencyData.getOverdueDays() > 0) {
|
||||
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData);
|
||||
} else {
|
||||
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loan);
|
||||
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loanDelinquencyData.getLoan());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -637,7 +637,10 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
||||
private void checkIfRepaymentPeriodObligationsAreMet(final LocalDate transactionDate, final MonetaryCurrency currency) {
|
||||
this.obligationsMet = getTotalOutstanding(currency).isZero();
|
||||
if (this.obligationsMet) {
|
||||
this.obligationsMetOnDate = transactionDate;
|
||||
this.obligationsMet = getCredits(currency).isZero();
|
||||
if (this.obligationsMet) {
|
||||
this.obligationsMetOnDate = transactionDate;
|
||||
}
|
||||
} else {
|
||||
this.obligationsMetOnDate = null;
|
||||
}
|
||||
@@ -704,7 +707,6 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
||||
this.principal = this.principal.add(transactionAmount.getAmount());
|
||||
}
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, transactionAmount.getCurrency());
|
||||
|
||||
}
|
||||
|
||||
public void addToCredits(final BigDecimal amount) {
|
||||
|
||||
+35
-4
@@ -19,16 +19,47 @@
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
public interface LoanRepaymentScheduleInstallmentRepository
|
||||
extends JpaRepository<LoanRepaymentScheduleInstallment, Long>, JpaSpecificationExecutor<LoanRepaymentScheduleInstallment> {
|
||||
|
||||
LoanRepaymentScheduleInstallment findFirstByLoanAndDueDateLessThanEqualAndObligationsMetOnDateOrderByDueDate(Loan loan,
|
||||
LocalDate businnessDate, LocalDate obligationsMetOnDate);
|
||||
@Query("""
|
||||
SELECT new org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData(
|
||||
lrs.loan.id,
|
||||
min(lrs.dueDate),
|
||||
0L,
|
||||
lrs.loan
|
||||
) FROM LoanRepaymentScheduleInstallment lrs
|
||||
WHERE lrs.loan.loanStatus = :loanStatus AND
|
||||
lrs.dueDate <= :businessDate AND
|
||||
lrs.obligationsMet = :obligationsMet AND
|
||||
lrs.loan.loanProduct.delinquencyBucket IS NOT NULL
|
||||
GROUP BY lrs.loan
|
||||
""")
|
||||
Collection<LoanScheduleDelinquencyData> fetchLoanScheduleDataByDueDateAndObligationsMet(Integer loanStatus, LocalDate businessDate,
|
||||
boolean obligationsMet);
|
||||
|
||||
@Query("""
|
||||
SELECT new org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData(
|
||||
lrs.loan.id,
|
||||
min(lrs.dueDate),
|
||||
0L,
|
||||
lrs.loan
|
||||
) FROM LoanRepaymentScheduleInstallment lrs
|
||||
WHERE lrs.loan.loanStatus = :loanStatus AND
|
||||
lrs.dueDate <= :businessDate AND
|
||||
lrs.obligationsMet = :obligationsMet AND
|
||||
lrs.loan.loanProduct.delinquencyBucket IS NOT NULL AND
|
||||
lrs.loan.id NOT IN :loanIds
|
||||
GROUP BY lrs.loan
|
||||
""")
|
||||
Collection<LoanScheduleDelinquencyData> fetchLoanScheduleDataByDueDateAndObligationsMet(Integer loanStatus, LocalDate businessDate,
|
||||
boolean obligationsMet, List<Long> loanIds);
|
||||
|
||||
List<LoanRepaymentScheduleInstallment> findByLoanAndDueDateLessThanEqualAndObligationsMetOnDateOrderByDueDate(Loan loan,
|
||||
LocalDate businnessDate, LocalDate obligationsMetOnDate);
|
||||
}
|
||||
|
||||
+19
@@ -18,11 +18,30 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
public interface LoanTransactionRepository extends JpaRepository<LoanTransaction, Long>, JpaSpecificationExecutor<LoanTransaction> {
|
||||
|
||||
Optional<LoanTransaction> findByIdAndLoanId(Long transactionId, Long loanId);
|
||||
|
||||
@Query("""
|
||||
SELECT new org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData(
|
||||
lt.loan.id,
|
||||
min(lt.dateOf),
|
||||
0L,
|
||||
lt.loan
|
||||
) FROM LoanTransaction lt
|
||||
WHERE lt.typeOf = :transactionType and
|
||||
lt.dateOf <= :businessDate and
|
||||
lt.loan.loanProduct.delinquencyBucket is not null
|
||||
GROUP BY lt.loan
|
||||
""")
|
||||
Collection<LoanScheduleDelinquencyData> fetchLoanTransactionsByTypeAndLessOrEqualDate(Integer transactionType, LocalDate businessDate);
|
||||
|
||||
}
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface LoanTransactionToRepaymentScheduleMappingRepository extends JpaRepository<LoanTransactionToRepaymentScheduleMapping, Long>,
|
||||
JpaSpecificationExecutor<LoanTransactionToRepaymentScheduleMapping> {
|
||||
|
||||
LoanTransactionToRepaymentScheduleMapping findByLoanTransaction(LoanTransaction loanTransaction);
|
||||
|
||||
}
|
||||
+1
-1
@@ -540,8 +540,8 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||
pastDueDate = currentInstallment.getDueDate();
|
||||
if (!currentInstallment.isAdditional() && currentInstallment.getDueDate().isAfter(transactionDate)) {
|
||||
currentInstallment.addToPrincipal(transactionDate, transactionAmountUnprocessed);
|
||||
currentInstallment.addToCredits(transactionAmountUnprocessed.getAmount());
|
||||
currentInstallment.addToPrincipal(transactionDate, transactionAmountUnprocessed);
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
|
||||
transactionAmountUnprocessed, zeroMoney, zeroMoney, zeroMoney));
|
||||
|
||||
|
||||
+6
-3
@@ -21,7 +21,8 @@ package org.apache.fineract.portfolio.loanaccount.jobs.setloandelinquencytags;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
|
||||
@@ -38,7 +39,8 @@ public class SetLoanDelinquencyTagsConfig {
|
||||
private StepBuilderFactory steps;
|
||||
|
||||
private DelinquencyWritePlatformService delinquencyWritePlatformService;
|
||||
private LoanReadPlatformService loanReadPlatformService;
|
||||
private LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
||||
private LoanTransactionRepository loanTransactionRepository;
|
||||
|
||||
@Bean
|
||||
public Step setLoanDelinquencyTagsStep() {
|
||||
@@ -53,7 +55,8 @@ public class SetLoanDelinquencyTagsConfig {
|
||||
|
||||
@Bean
|
||||
public SetLoanDelinquencyTagsTasklet setLoanDelinquencyTagsTasklet() {
|
||||
return new SetLoanDelinquencyTagsTasklet(delinquencyWritePlatformService, loanReadPlatformService);
|
||||
return new SetLoanDelinquencyTagsTasklet(delinquencyWritePlatformService, loanRepaymentScheduleInstallmentRepository,
|
||||
loanTransactionRepository);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+49
-13
@@ -18,14 +18,20 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.jobs.setloandelinquencytags;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
@@ -36,24 +42,54 @@ import org.springframework.batch.repeat.RepeatStatus;
|
||||
public class SetLoanDelinquencyTagsTasklet implements Tasklet {
|
||||
|
||||
private final DelinquencyWritePlatformService delinquencyWritePlatformService;
|
||||
private final LoanReadPlatformService loanReadPlatformService;
|
||||
private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
||||
private final LoanTransactionRepository loanTransactionRepository;
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
log.debug("Run job for date {}", DateUtils.getBusinessLocalDate());
|
||||
Collection<LoanScheduleDelinquencyData> loanScheduleDelinquencyData = this.loanReadPlatformService
|
||||
.retrieveScheduleDelinquencyData(DateUtils.getBusinessLocalDate());
|
||||
log.debug("Were found {} items", loanScheduleDelinquencyData.size());
|
||||
for (LoanScheduleDelinquencyData loanDelinquencyData : loanScheduleDelinquencyData) {
|
||||
log.debug("Processing Loan {} with due date {} and {} overdue days", loanDelinquencyData.getLoanId(),
|
||||
loanDelinquencyData.getDueDate(), loanDelinquencyData.getAgeDays());
|
||||
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData.getLoanId(),
|
||||
loanDelinquencyData.getAgeDays());
|
||||
}
|
||||
|
||||
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||
log.debug("Run job for date {}", businessDate);
|
||||
|
||||
// Read Loan Ids with Loan Transaction Charge back
|
||||
Collection<LoanScheduleDelinquencyData> loanScheduleDelinquencyData = this.loanTransactionRepository
|
||||
.fetchLoanTransactionsByTypeAndLessOrEqualDate(LoanTransactionType.CHARGEBACK.getValue(), businessDate);
|
||||
List<Long> processedLoans = applyDelinquencyTagToLoans(loanScheduleDelinquencyData);
|
||||
log.debug("{}: Records affected by setLoanDelinquencyTags: {}", ThreadLocalContextUtil.getTenant().getName(),
|
||||
loanScheduleDelinquencyData.size());
|
||||
processedLoans.size());
|
||||
|
||||
// Read Loan Ids with overdue installments
|
||||
if (processedLoans.isEmpty()) {
|
||||
loanScheduleDelinquencyData = this.loanRepaymentScheduleInstallmentRepository
|
||||
.fetchLoanScheduleDataByDueDateAndObligationsMet(LoanStatus.ACTIVE.getValue(), businessDate, false);
|
||||
} else {
|
||||
loanScheduleDelinquencyData = this.loanRepaymentScheduleInstallmentRepository
|
||||
.fetchLoanScheduleDataByDueDateAndObligationsMet(LoanStatus.ACTIVE.getValue(), businessDate, false, processedLoans);
|
||||
}
|
||||
processedLoans = applyDelinquencyTagToLoans(loanScheduleDelinquencyData);
|
||||
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
private List<Long> applyDelinquencyTagToLoans(Collection<LoanScheduleDelinquencyData> loanScheduleDelinquencyData) {
|
||||
List<Long> processedLoans = new ArrayList<>();
|
||||
|
||||
log.debug("Were found {} items", loanScheduleDelinquencyData.size());
|
||||
for (LoanScheduleDelinquencyData loanDelinquencyData : loanScheduleDelinquencyData) {
|
||||
// Set the data used by Delinquency Classification method
|
||||
loanDelinquencyData = this.delinquencyWritePlatformService.calculateDelinquencyData(loanDelinquencyData);
|
||||
log.debug("Processing Loan {} with {} overdue days since date {}", loanDelinquencyData.getLoanId(),
|
||||
loanDelinquencyData.getOverdueDays(), loanDelinquencyData.getOverdueSinceDate());
|
||||
// Set or Unset the Delinquency Classification Tag
|
||||
if (loanDelinquencyData.getOverdueDays() > 0) {
|
||||
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData);
|
||||
} else {
|
||||
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loanDelinquencyData.getLoan());
|
||||
}
|
||||
|
||||
processedLoans.add(loanDelinquencyData.getLoanId());
|
||||
}
|
||||
return processedLoans;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -2671,7 +2671,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
LoanScheduleDTO loanScheduleDTO = rescheduleNextInstallments(mc, loanApplicationTerms, loan, holidayDetailDTO,
|
||||
loanRepaymentScheduleTransactionProcessor, onDate, calculateTill);
|
||||
List<LoanTransaction> loanTransactions = loan.retreiveListOfTransactionsPostDisbursementExcludeAccruals();
|
||||
List<LoanTransaction> loanTransactions = loan.retrieveListOfTransactionsPostDisbursementExcludeAccruals();
|
||||
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanApplicationTerms.getExpectedDisbursementDate(), loanTransactions,
|
||||
currency, loanScheduleDTO.getInstallments(), loan.getActiveCharges());
|
||||
|
||||
-6
@@ -27,13 +27,11 @@ import org.apache.fineract.infrastructure.core.service.SearchParameters;
|
||||
import org.apache.fineract.organisation.staff.data.StaffData;
|
||||
import org.apache.fineract.portfolio.calendar.data.CalendarData;
|
||||
import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanApprovalData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionRelationData;
|
||||
@@ -109,8 +107,6 @@ public interface LoanReadPlatformService {
|
||||
|
||||
Collection<LoanScheduleAccrualData> retriveScheduleAccrualData();
|
||||
|
||||
Collection<LoanScheduleDelinquencyData> retrieveScheduleDelinquencyData(LocalDate businessLocalDate);
|
||||
|
||||
LoanTransactionData retrieveRecoveryPaymentTemplate(Long loanId);
|
||||
|
||||
LoanTransactionData retrieveLoanWriteoffTemplate(Long loanId);
|
||||
@@ -157,8 +153,6 @@ public interface LoanReadPlatformService {
|
||||
|
||||
List<LoanRepaymentScheduleInstallmentData> getRepaymentDataResponse(Long loanId);
|
||||
|
||||
CollectionData retrieveLoanCollectionData(Long loanId);
|
||||
|
||||
List<LoanTransactionRelationData> retrieveLoanTransactionRelationsByLoanTransactionId(Long loanTransactionId);
|
||||
|
||||
}
|
||||
|
||||
+8
-115
@@ -84,7 +84,6 @@ import org.apache.fineract.portfolio.group.data.GroupGeneralData;
|
||||
import org.apache.fineract.portfolio.group.data.GroupRoleData;
|
||||
import org.apache.fineract.portfolio.group.service.GroupReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanApplicationTimelineData;
|
||||
@@ -92,7 +91,6 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanApprovalData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanInterestRecalculationData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanStatusEnumData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
@@ -240,7 +238,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final LoanScheduleResultSetExtractor fullResultsetExtractor = new LoanScheduleResultSetExtractor(
|
||||
repaymentScheduleRelatedLoanData, disbursementData, isInterestRecalculationEnabled, totalPaidFeeCharges);
|
||||
repaymentScheduleRelatedLoanData, disbursementData, isInterestRecalculationEnabled);
|
||||
final String sql = "select " + fullResultsetExtractor.schema() + " where ls.loan_id = ? order by ls.loan_id, ls.installment";
|
||||
|
||||
return this.jdbcTemplate.query(sql, fullResultsetExtractor, loanId); // NOSONAR
|
||||
@@ -639,7 +637,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " l.loan_sub_status_id as loanSubStatusId, la.principal_overdue_derived as principalOverdue, l.is_fraud as isFraud, "
|
||||
+ " la.interest_overdue_derived as interestOverdue, la.fee_charges_overdue_derived as feeChargesOverdue,"
|
||||
+ " la.penalty_charges_overdue_derived as penaltyChargesOverdue, la.total_overdue_derived as totalOverdue,"
|
||||
+ " la.overdue_since_date_derived as overdueSinceDate,"
|
||||
+ " la.overdue_since_date_derived as overdueSinceDate, "
|
||||
+ " l.sync_disbursement_with_meeting as syncDisbursementWithMeeting,"
|
||||
+ " l.loan_counter as loanCounter, l.loan_product_counter as loanProductCounter,"
|
||||
+ " l.is_npa as isNPA, l.days_in_month_enum as daysInMonth, l.days_in_year_enum as daysInYear, "
|
||||
@@ -678,7 +676,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " left join m_code_value codev on codev.id = l.writeoff_reason_cv_id"
|
||||
+ " left join m_product_loan_variable_installment_config lpvi on lpvi.loan_product_id = l.product_id"
|
||||
+ " left join m_loan_topup as topup on l.id = topup.loan_id"
|
||||
+ " left join m_loan as topuploan on topuploan.id = topup.closure_loan_id";
|
||||
+ " left join m_loan as topuploan on topuploan.id = topup.closure_loan_id ";
|
||||
|
||||
}
|
||||
|
||||
@@ -888,9 +886,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final BigDecimal totalRecovered = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalRecovered");
|
||||
|
||||
final LocalDate overdueSinceDate = JdbcSupport.getLocalDate(rs, "overdueSinceDate");
|
||||
if (overdueSinceDate != null) {
|
||||
inArrears = true;
|
||||
}
|
||||
inArrears = (overdueSinceDate != null);
|
||||
|
||||
loanSummary = new LoanSummaryData(currencyData, principalDisbursed, principalAdjustments, principalPaid,
|
||||
principalWrittenOff, principalOutstanding, principalOverdue, interestCharged, interestPaid, interestWaived,
|
||||
@@ -1062,10 +1058,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
private LocalDate lastDueDate;
|
||||
private BigDecimal outstandingLoanPrincipalBalance;
|
||||
private boolean excludePastUndisbursed;
|
||||
private final BigDecimal totalPaidFeeCharges;
|
||||
|
||||
LoanScheduleResultSetExtractor(final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
|
||||
Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled, BigDecimal totalPaidFeeCharges) {
|
||||
Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled) {
|
||||
this.currency = repaymentScheduleRelatedLoanData.getCurrency();
|
||||
this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
|
||||
this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
|
||||
@@ -1073,7 +1068,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
this.outstandingLoanPrincipalBalance = this.disbursement.getPrincipal();
|
||||
this.disbursementData = disbursementData;
|
||||
this.excludePastUndisbursed = isInterestRecalculationEnabled;
|
||||
this.totalPaidFeeCharges = totalPaidFeeCharges;
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
@@ -1699,25 +1693,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoanScheduleDelinquencyData> retrieveScheduleDelinquencyData(LocalDate businessLocalDate) {
|
||||
LoanScheduleDelinquencyMapper mapper = new LoanScheduleDelinquencyMapper(DateUtils.getBusinessLocalDate());
|
||||
final StringBuilder sqlBuilder = new StringBuilder(400);
|
||||
sqlBuilder.append("select ").append(mapper.schema())
|
||||
// Just get the overdued installments
|
||||
.append(" where loan.loan_status_id=:active and ls.duedate <= :businessLocalDate and ")
|
||||
// Just get the unpaid installments using the completed_derived flag
|
||||
.append(" ls.completed_derived = false and ")
|
||||
// Just the Loan Product linked to delinquency bucket
|
||||
.append(" mpl.delinquency_bucket_id is not null ");
|
||||
sqlBuilder.append(" group by ls.loan_id, loan.product_id ");
|
||||
Map<String, Object> paramMap = new HashMap<>(3);
|
||||
paramMap.put("active", LoanStatus.ACTIVE.getValue());
|
||||
paramMap.put("businessLocalDate", businessLocalDate);
|
||||
|
||||
return this.namedParameterJdbcTemplate.query(sqlBuilder.toString(), paramMap, mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoanScheduleAccrualData> retriveScheduleAccrualData() {
|
||||
|
||||
@@ -1887,33 +1862,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LoanScheduleDelinquencyMapper implements RowMapper<LoanScheduleDelinquencyData> {
|
||||
|
||||
private LocalDate businessDate;
|
||||
|
||||
LoanScheduleDelinquencyMapper(LocalDate businessDate) {
|
||||
this.businessDate = businessDate;
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
final StringBuilder sqlBuilder = new StringBuilder(400);
|
||||
sqlBuilder.append(" ls.loan_id as loanId, loan.product_id as productId, min(ls.duedate) as duedate ")
|
||||
.append(" from m_loan_repayment_schedule ls left join m_loan loan on loan.id=ls.loan_id ")
|
||||
.append(" left join m_product_loan mpl on mpl.id = loan.product_id ");
|
||||
return sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanScheduleDelinquencyData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
|
||||
|
||||
final Long loanId = rs.getLong("loanId");
|
||||
final Long productId = rs.getLong("productId");
|
||||
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "duedate");
|
||||
final long ageDays = DateUtils.getDifferenceInDays(dueDate, businessDate);
|
||||
return new LoanScheduleDelinquencyData(loanId, productId, dueDate, ageDays);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanTransactionData retrieveRecoveryPaymentTemplate(Long loanId) {
|
||||
final Loan loan = this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId, true);
|
||||
@@ -2283,7 +2231,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
@Override
|
||||
public Collection<Long> retrieveLoanIdsWithPendingIncomePostingTransactions() {
|
||||
LocalDate currentdate = DateUtils.getBusinessLocalDate();
|
||||
StringBuilder sqlBuilder = new StringBuilder().append(" select distinct loan.id ").append(" from m_loan as loan ").append(
|
||||
StringBuilder sqlBuilder = new StringBuilder().append(" select distinct loan.id from m_loan as loan ").append(
|
||||
" inner join m_loan_recalculation_details as recdet on (recdet.loan_id = loan.id and recdet.is_compounding_to_be_posted_as_transaction is not null and recdet.is_compounding_to_be_posted_as_transaction = true) ")
|
||||
.append(" inner join m_loan_repayment_schedule as repsch on repsch.loan_id = loan.id ")
|
||||
.append(" inner join m_loan_interest_recalculation_additional_details as adddet on adddet.loan_repayment_schedule_id = repsch.id ")
|
||||
@@ -2292,7 +2240,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
.append(" and adddet.effective_date is not null ").append(" and trans.transaction_date is null ")
|
||||
.append(" and adddet.effective_date < ? ");
|
||||
try {
|
||||
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), new Object[] { currentdate }, Long.class);
|
||||
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class, new Object[] { currentdate });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
@@ -2438,62 +2386,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
return this.jdbcTemplate.queryForObject(sql, Integer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionData retrieveLoanCollectionData(Long loanId) {
|
||||
final CollectionDataMapper mapper = new CollectionDataMapper(sqlGenerator);
|
||||
String sql = "select " + mapper.schema();
|
||||
CollectionData collectionData = this.jdbcTemplate.queryForObject(sql, mapper, loanId, loanId); // NOSONAR
|
||||
return collectionData;
|
||||
}
|
||||
|
||||
private static final class CollectionDataMapper implements RowMapper<CollectionData> {
|
||||
|
||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||
|
||||
CollectionDataMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
|
||||
this.sqlGenerator = sqlGenerator;
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
StringBuilder sqlBuilder = new StringBuilder();
|
||||
|
||||
sqlBuilder.append(
|
||||
"l.id as loanId, coalesce((l.approved_principal - l.principal_disbursed_derived), 0) as availableDisbursementAmount, ");
|
||||
sqlBuilder.append(
|
||||
sqlGenerator.dateDiff(sqlGenerator.currentBusinessDate(), "laa.overdue_since_date_derived") + " as pastDueDays, ");
|
||||
sqlBuilder.append(
|
||||
"(select coalesce(min(lrs.duedate), null) as duedate from m_loan_repayment_schedule lrs where lrs.loan_id=l.id and lrs.completed_derived is false and lrs.duedate >= "
|
||||
+ sqlGenerator.currentBusinessDate() + ") as nextPaymentDueDate, ");
|
||||
sqlBuilder.append(
|
||||
sqlGenerator.dateDiff(sqlGenerator.currentBusinessDate(), "laa.overdue_since_date_derived") + " as delinquentDays, ");
|
||||
sqlBuilder.append(sqlGenerator.currentBusinessDate()
|
||||
+ " as delinquentDate, coalesce(laa.total_overdue_derived, 0) as delinquentAmount, ");
|
||||
sqlBuilder.append("lre.transactionDate as lastPaymentDate, coalesce(lre.amount, 0) as lastPaymentAmount ");
|
||||
sqlBuilder.append("from m_loan l left join m_loan_arrears_aging laa on laa.loan_id = l.id ");
|
||||
sqlBuilder.append(
|
||||
"left join (select lt.loan_id, lt.transaction_date as transactionDate, lt.amount as amount from m_loan_transaction lt ");
|
||||
sqlBuilder.append(
|
||||
"where lt.loan_id =? and lt.is_reversed = false and lt.transaction_type_enum=2 order by lt.transaction_date desc, lt.id desc limit 1) lre on lre.loan_id = l.id ");
|
||||
sqlBuilder.append("where l.id=? ");
|
||||
return sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionData mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
final LocalDate nextPaymentDueDate = JdbcSupport.getLocalDate(rs, "nextPaymentDueDate");
|
||||
final LocalDate delinquentDate = JdbcSupport.getLocalDate(rs, "delinquentDate");
|
||||
final LocalDate lastPaymentDate = JdbcSupport.getLocalDate(rs, "lastPaymentDate");
|
||||
final BigDecimal availableDisbursementAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "availableDisbursementAmount");
|
||||
final BigDecimal delinquentAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "delinquentAmount");
|
||||
final BigDecimal lastPaymentAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "lastPaymentAmount");
|
||||
final int pastDueDays = rs.getInt("pastDueDays");
|
||||
final int delinquentDays = rs.getInt("delinquentDays");
|
||||
|
||||
return CollectionData.instance(availableDisbursementAmount, pastDueDays, nextPaymentDueDate, delinquentDays, delinquentDate,
|
||||
delinquentAmount, lastPaymentDate, lastPaymentAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LoanTransactionRelationData> retrieveLoanTransactionRelationsByLoanTransactionId(Long loanTransactionId) {
|
||||
final LoanTransaction loanTransaction = this.loanTransactionRepository.getReferenceById(loanTransactionId);
|
||||
@@ -2501,4 +2393,5 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
.findByFromTransactionAndRelationType(loanTransaction, LoanTransactionRelationTypeEnum.CHARGEBACK);
|
||||
return loanTransactionRelationMapper.map(loanTransactionRelations);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -1289,7 +1289,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
this.loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
this.loanAccountDomainService.setLoanDelinquencyTag(loan, transactionDate);
|
||||
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanChargebackTransactionBusinessEvent(loanTransaction));
|
||||
|
||||
|
||||
+2
-2
@@ -388,7 +388,7 @@ public class FixedDepositAccount extends SavingsAccount {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions = retreiveListOfTransactions();
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions = retrieveListOfTransactions();
|
||||
if (savingsAccountTransactions.size() > 0) {
|
||||
final SavingsAccountTransaction accountTransaction = savingsAccountTransactions.get(savingsAccountTransactions.size() - 1);
|
||||
if (accountTransaction.isAfter(closedDate)) {
|
||||
@@ -473,7 +473,7 @@ public class FixedDepositAccount extends SavingsAccount {
|
||||
}
|
||||
}
|
||||
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions = retreiveListOfTransactions();
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions = retrieveListOfTransactions();
|
||||
if (savingsAccountTransactions.size() > 0) {
|
||||
final SavingsAccountTransaction accountTransaction = savingsAccountTransactions.get(savingsAccountTransactions.size() - 1);
|
||||
if (accountTransaction.isAfter(closedDate)) {
|
||||
|
||||
+3
-3
@@ -492,7 +492,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
}
|
||||
}
|
||||
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions = retreiveListOfTransactions();
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions = retrieveListOfTransactions();
|
||||
if (savingsAccountTransactions.size() > 0) {
|
||||
final SavingsAccountTransaction accountTransaction = savingsAccountTransactions.get(savingsAccountTransactions.size() - 1);
|
||||
if (accountTransaction.isAfter(closedDate)) {
|
||||
@@ -593,7 +593,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions = retreiveListOfTransactions();
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions = retrieveListOfTransactions();
|
||||
if (savingsAccountTransactions.size() > 0) {
|
||||
final SavingsAccountTransaction accountTransaction = savingsAccountTransactions.get(savingsAccountTransactions.size() - 1);
|
||||
if (accountTransaction.isAfter(closedDate)) {
|
||||
@@ -934,7 +934,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
}
|
||||
|
||||
private List<SavingsAccountTransaction> retreiveOrderedDepositTransactions() {
|
||||
final List<SavingsAccountTransaction> listOfTransactionsSorted = retreiveListOfTransactions();
|
||||
final List<SavingsAccountTransaction> listOfTransactionsSorted = retrieveListOfTransactions();
|
||||
|
||||
final List<SavingsAccountTransaction> orderedDepositTransactions = new ArrayList<>();
|
||||
|
||||
|
||||
+10
-10
@@ -928,7 +928,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
protected List<SavingsAccountTransaction> retreiveOrderedNonInterestPostingTransactions() {
|
||||
final List<SavingsAccountTransaction> listOfTransactionsSorted = retreiveListOfTransactions();
|
||||
final List<SavingsAccountTransaction> listOfTransactionsSorted = retrieveListOfTransactions();
|
||||
|
||||
final List<SavingsAccountTransaction> orderedNonInterestPostingTransactions = new ArrayList<>();
|
||||
|
||||
@@ -965,7 +965,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
return listOfTransactionsSorted;
|
||||
}
|
||||
|
||||
protected List<SavingsAccountTransaction> retreiveListOfTransactions() {
|
||||
protected List<SavingsAccountTransaction> retrieveListOfTransactions() {
|
||||
final List<SavingsAccountTransaction> listOfTransactionsSorted = new ArrayList<>();
|
||||
listOfTransactionsSorted.addAll(this.transactions);
|
||||
|
||||
@@ -983,7 +983,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
accountTransactionsSorted = retrieveSortedTransactions();
|
||||
} else {
|
||||
accountTransactionsSorted = retreiveListOfTransactions();
|
||||
accountTransactionsSorted = retrieveListOfTransactions();
|
||||
}
|
||||
|
||||
boolean isTransactionsModified = false;
|
||||
@@ -1058,7 +1058,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
accountTransactionsSorted = retrieveSortedTransactions();
|
||||
} else {
|
||||
accountTransactionsSorted = retreiveListOfTransactions();
|
||||
accountTransactionsSorted = retrieveListOfTransactions();
|
||||
}
|
||||
}
|
||||
resetAccountTransactionsEndOfDayBalances(accountTransactionsSorted, interestPostingUpToDate);
|
||||
@@ -1415,7 +1415,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
boolean transactionBeforeLastInterestPosting = false;
|
||||
|
||||
if (!backdatedTxnsAllowedTill) {
|
||||
for (final SavingsAccountTransaction transaction : retreiveListOfTransactions()) {
|
||||
for (final SavingsAccountTransaction transaction : retrieveListOfTransactions()) {
|
||||
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
|
||||
&& transaction.isAfter(transactionDate) && !transaction.isReversalTransaction()) {
|
||||
transactionBeforeLastInterestPosting = true;
|
||||
@@ -1441,7 +1441,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
transactionsSortedByDate = retrieveSortedTransactions();
|
||||
} else {
|
||||
transactionsSortedByDate = retreiveListOfTransactions();
|
||||
transactionsSortedByDate = retrieveListOfTransactions();
|
||||
}
|
||||
|
||||
Money runningBalance = Money.zero(this.currency);
|
||||
@@ -1524,7 +1524,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
transactionsSortedByDate = retrieveSortedTransactions();
|
||||
} else {
|
||||
transactionsSortedByDate = retreiveListOfTransactions();
|
||||
transactionsSortedByDate = retrieveListOfTransactions();
|
||||
}
|
||||
Money runningBalance = Money.zero(this.currency);
|
||||
|
||||
@@ -2507,7 +2507,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
public void validateAccountBalanceDoesNotBecomeNegativeMinimal(final BigDecimal transactionAmount, final boolean isException) {
|
||||
// final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
||||
// final List<SavingsAccountTransaction> transactionsSortedByDate = retrieveListOfTransactions();
|
||||
Money runningBalance = this.summary.getAccountBalance(getCurrency());
|
||||
Money minRequiredBalance = minRequiredBalanceDerived(getCurrency());
|
||||
org.joda.time.LocalDate lastSavingsDate = null;
|
||||
@@ -2846,7 +2846,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions = retreiveListOfTransactions();
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions = retrieveListOfTransactions();
|
||||
if (savingsAccountTransactions.size() > 0) {
|
||||
final SavingsAccountTransaction accountTransaction = savingsAccountTransactions.get(savingsAccountTransactions.size() - 1);
|
||||
if (accountTransaction.isAfter(closedDate)) {
|
||||
@@ -3806,7 +3806,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
public LocalDate retrieveLastTransactionDate() {
|
||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retrieveListOfTransactions();
|
||||
SavingsAccountTransaction lastTransaction = null;
|
||||
if (transactionsSortedByDate.size() > 0) {
|
||||
lastTransaction = transactionsSortedByDate.get(transactionsSortedByDate.size() - 1);
|
||||
|
||||
+4
-4
@@ -305,7 +305,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
|
||||
}
|
||||
|
||||
private List<SavingsAccountTransactionData> retreiveOrderedNonInterestPostingTransactions(final SavingsAccountData savingsAccountData) {
|
||||
final List<SavingsAccountTransactionData> listOfTransactionsSorted = retreiveListOfTransactions(savingsAccountData);
|
||||
final List<SavingsAccountTransactionData> listOfTransactionsSorted = retrieveListOfTransactions(savingsAccountData);
|
||||
|
||||
final List<SavingsAccountTransactionData> orderedNonInterestPostingTransactions = new ArrayList<>();
|
||||
|
||||
@@ -319,7 +319,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
|
||||
return orderedNonInterestPostingTransactions;
|
||||
}
|
||||
|
||||
private List<SavingsAccountTransactionData> retreiveListOfTransactions(final SavingsAccountData savingsAccountData) {
|
||||
private List<SavingsAccountTransactionData> retrieveListOfTransactions(final SavingsAccountData savingsAccountData) {
|
||||
final List<SavingsAccountTransactionData> listOfTransactionsSorted = new ArrayList<>();
|
||||
listOfTransactionsSorted.addAll(savingsAccountData.getSavingsAccountTransactionData());
|
||||
|
||||
@@ -407,7 +407,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
|
||||
|
||||
Money runningBalance = openingAccountBalance.copy();
|
||||
|
||||
List<SavingsAccountTransactionData> accountTransactionsSorted = retreiveListOfTransactions(savingsAccountData);
|
||||
List<SavingsAccountTransactionData> accountTransactionsSorted = retrieveListOfTransactions(savingsAccountData);
|
||||
boolean isTransactionsModified = false;
|
||||
|
||||
for (final SavingsAccountTransactionData transaction : accountTransactionsSorted) {
|
||||
@@ -466,7 +466,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
|
||||
}
|
||||
|
||||
if (isTransactionsModified) {
|
||||
accountTransactionsSorted = retreiveListOfTransactions(savingsAccountData);
|
||||
accountTransactionsSorted = retrieveListOfTransactions(savingsAccountData);
|
||||
}
|
||||
resetAccountTransactionsEndOfDayBalances(accountTransactionsSorted, interestPostingUpToDate, savingsAccountData);
|
||||
}
|
||||
|
||||
@@ -85,4 +85,5 @@
|
||||
<include file="parts/0063_add_permissions_for_external_event_configuration.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0064_refactor_loan_transaction_strategy.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0065_add_bypass_loan_write_transaction_permission.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0066_delinquency_classification_chargeback.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
<changeSet id="1" author="fineract">
|
||||
<createIndex indexName="ind_m_loan_delinquency_tag_history_loan_id" tableName="m_loan_delinquency_tag_history">
|
||||
<column name="loan_id"/>
|
||||
</createIndex>
|
||||
<createIndex indexName="ind_m_loan_delinquency_tag_history_liftedon_date" tableName="m_loan_delinquency_tag_history">
|
||||
<column name="liftedon_date"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
import io.restassured.http.ContentType;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
|
||||
import org.apache.fineract.client.models.GetDelinquencyRangesResponse;
|
||||
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.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
|
||||
import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||
import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Slf4j
|
||||
public class DelinquencyAndChargebackIntegrationTest {
|
||||
|
||||
private ResponseSpecification responseSpec;
|
||||
private RequestSpecification requestSpec;
|
||||
private LoanTransactionHelper loanTransactionHelper;
|
||||
private static final String principalAmount = "1200.00";
|
||||
private static final Double doubleZERO = Double.valueOf("0.00");
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
Utils.initializeRESTAssured();
|
||||
|
||||
requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||
requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
|
||||
responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||
|
||||
loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanClassificationStepAsPartOfCOB() {
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||
|
||||
final LocalDate todaysDate = Utils.getLocalDateOfTenant();
|
||||
LocalDate businessDate = todaysDate.minusDays(57);
|
||||
log.info("Current Business date {}", businessDate);
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
|
||||
|
||||
final SchedulerJobHelper schedulerJobHelper = new SchedulerJobHelper(requestSpec);
|
||||
// Delinquency Bucket
|
||||
final Integer delinquencyBucketId = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
|
||||
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||
delinquencyBucketId);
|
||||
|
||||
// Client and Loan account creation
|
||||
final Integer clientId = ClientHelper.createClient(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());
|
||||
|
||||
// Older date to have more than one overdue installment
|
||||
LocalDate transactionDate = businessDate;
|
||||
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
log.info("Operation date {}", transactionDate);
|
||||
|
||||
// Create Loan Account
|
||||
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||
getLoanProductsProductResponse.getId().toString(), operationDate);
|
||||
|
||||
// Run first time the Loan COB Job
|
||||
final String jobName = "Loan COB";
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
|
||||
// Get loan details expecting to have not a delinquency classification
|
||||
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
validateLoanAccount(getLoansLoanIdResponse, "0.00", principalAmount, 0, doubleZERO);
|
||||
|
||||
// Move the Business date to get older the loan and to have an overdue loan
|
||||
businessDate = businessDate.plusDays(43);
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
|
||||
log.info("Current Business date {}", businessDate);
|
||||
|
||||
String amountVal = "100.00";
|
||||
Float transactionAmount = Float.valueOf(amountVal);
|
||||
PostLoansLoanIdTransactionsResponse loanIdTransactionsResponse = loanTransactionHelper.makeLoanRepayment(operationDate,
|
||||
transactionAmount, loanId);
|
||||
assertNotNull(loanIdTransactionsResponse);
|
||||
final Integer transactionId = loanIdTransactionsResponse.getResourceId();
|
||||
loanTransactionHelper.reviewLoanTransactionRelations(loanId, transactionId, 0);
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
validateLoanAccount(getLoansLoanIdResponse, "0.00", "1100.00", 0, doubleZERO);
|
||||
|
||||
final Integer chargebackTransactionId = loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, amountVal, 0,
|
||||
responseSpec);
|
||||
loanTransactionHelper.reviewLoanTransactionRelations(loanId, transactionId, 1);
|
||||
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
// Past Due Days in Zero because the Charge back transaction exists and It was done with the current date
|
||||
validateLoanAccount(getLoansLoanIdResponse, amountVal, principalAmount, 0, Double.valueOf("100.00"));
|
||||
|
||||
// Move the Business date to get older the loan and to have an overdue loan
|
||||
businessDate = businessDate.plusDays(9);
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
|
||||
log.info("Current Business date {}", businessDate);
|
||||
// Run Second time the Job
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
|
||||
// Get loan details expecting to have a delinquency classification
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
|
||||
// The value is lower due the 3 grace days
|
||||
validateLoanAccount(getLoansLoanIdResponse, "100.00", principalAmount, 9, Double.valueOf("100.00"));
|
||||
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||
}
|
||||
|
||||
private GetLoanProductsProductIdResponse createLoanProduct(final LoanTransactionHelper loanTransactionHelper,
|
||||
final Integer delinquencyBucketId) {
|
||||
final HashMap<String, Object> loanProductMap = new LoanProductTestBuilder().build(null, delinquencyBucketId);
|
||||
final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
|
||||
return loanTransactionHelper.getLoanProduct(loanProductId);
|
||||
}
|
||||
|
||||
private Integer createLoanAccount(final 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("0") //
|
||||
.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 GetDelinquencyRangesResponse validateLoanAccount(GetLoansLoanIdResponse getLoansLoanIdResponse, final String adjustments,
|
||||
final String outstanding, Integer pastDueDays, Double delinquentAmount) {
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
final GetDelinquencyRangesResponse delinquencyRange = getLoansLoanIdResponse.getDelinquencyRange();
|
||||
|
||||
log.info("Loan Delinquency Range is null {}", (delinquencyRange == null));
|
||||
if (delinquencyRange != null) {
|
||||
log.info("Loan Delinquency Range is {}", delinquencyRange.getClassification());
|
||||
}
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
loanTransactionHelper.evaluateLoanSummaryAdjustments(getLoansLoanIdResponse, Double.valueOf(adjustments));
|
||||
DelinquencyBucketsHelper.evaluateLoanCollectionData(getLoansLoanIdResponse, pastDueDays, delinquentAmount);
|
||||
|
||||
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, Double.valueOf(outstanding));
|
||||
|
||||
return delinquencyRange;
|
||||
}
|
||||
|
||||
}
|
||||
+394
-397
@@ -234,12 +234,394 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, response403Spec, jsonBucket);
|
||||
}
|
||||
|
||||
@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(50);
|
||||
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);
|
||||
|
||||
loanTransactionHelper.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 testLoanClassificationRealtimeWithCharges() {
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||
|
||||
// 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
|
||||
LocalDate transactionDate = todaysDate.minusMonths(2).minusDays(5);
|
||||
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);
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
// Apply a repayment to get a full paid installment
|
||||
operationDate = Utils.dateFormatter.format(todaysDate);
|
||||
loanTransactionHelper.makeLoanRepayment(operationDate, 2049.99f, loanId);
|
||||
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
// The Loan Delinquency Classification after Repayment command must be null
|
||||
log.info("Loan Delinquency Range after Repayment {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
assertNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
transactionDate = todaysDate.minusDays(18);
|
||||
operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
|
||||
// Create and apply Charge for Specific Due Date
|
||||
final Integer chargeId = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||
ChargesHelper.getLoanSpecifiedDueDateJSON(1, "30", false));
|
||||
assertNotNull(chargeId);
|
||||
final Integer loanChargeId = loanTransactionHelper.addChargesForLoan(loanId, getChargeApplyJSON(chargeId, operationDate),
|
||||
responseSpec);
|
||||
assertNotNull(loanChargeId);
|
||||
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
log.info("Loan Delinquency Range after add Loan Charge {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
assertNotNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
// Evaluate a Delinquency Tag set after add charge to the Loan
|
||||
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanClassificationRealtimeOlderLoan() {
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||
|
||||
// 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
|
||||
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);
|
||||
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
// Apply a repayment to get a first full paid installment
|
||||
transactionDate = todaysDate.minusDays(1);
|
||||
operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
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();
|
||||
log.info("Local date of Tenant: {}", todaysDate);
|
||||
|
||||
// Older date to have more than one overdue installment
|
||||
final LocalDate transactionDate = todaysDate.minusDays(50);
|
||||
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);
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||
|
||||
log.info("Loan Delinquency Range after Disbursement in null? {}", (getLoansLoanIdResponse.getDelinquencyRange() == null));
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
assertNotNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
log.info("Loan Delinquency Range after Disbursement {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
// First Loan Delinquency Classification after Disbursement command
|
||||
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected);
|
||||
|
||||
loanTransactionHelper.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.reverseLoanTransaction(loanId,
|
||||
loansLoanIdTransactions.getResourceId(), operationDate, responseSpec);
|
||||
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());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanClassificationJob() {
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||
|
||||
LocalDate businessDate = Utils.getLocalDateOfTenant();
|
||||
businessDate = businessDate.minusDays(57);
|
||||
businessDate = businessDate.minusDays(37);
|
||||
log.info("Current date {}", businessDate);
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
|
||||
|
||||
@@ -277,7 +659,7 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
|
||||
final LocalDate todaysDate = Utils.getLocalDateOfTenant();
|
||||
// Older date to have more than one overdue installment
|
||||
final LocalDate transactionDate = todaysDate.minusDays(65);
|
||||
final LocalDate transactionDate = todaysDate.minusDays(57);
|
||||
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
|
||||
// Create Loan Account
|
||||
@@ -290,19 +672,13 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
|
||||
// Get loan details expecting to have not a delinquency classification
|
||||
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||
final GetDelinquencyRangesResponse firstTestCase = getLoansLoanIdResponse.getDelinquencyRange();
|
||||
log.info("Loan Delinquency Range is null {}", (firstTestCase == null));
|
||||
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());
|
||||
}
|
||||
}
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
// Move the Business date to get older the loan and to have an overdue loan
|
||||
businessDate = businessDate.plusDays(40);
|
||||
businessDate = businessDate.plusMonths(1);
|
||||
log.info("Current date {}", businessDate);
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
|
||||
// Run Second time the Job
|
||||
@@ -310,7 +686,11 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
|
||||
// Get loan details expecting to have a delinquency classification
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||
|
||||
final GetDelinquencyRangesResponse secondTestCase = getLoansLoanIdResponse.getDelinquencyRange();
|
||||
assertNotNull(secondTestCase);
|
||||
log.info("Loan Delinquency Range is {}", secondTestCase.getClassification());
|
||||
|
||||
// Then
|
||||
@@ -318,7 +698,6 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
assertNotNull(getLoanProductsProductResponse);
|
||||
assertNull(firstTestCase);
|
||||
assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName());
|
||||
assertNotNull(secondTestCase);
|
||||
assertEquals(secondTestCase.getClassification(), classificationExpected);
|
||||
|
||||
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||
@@ -402,7 +781,7 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
}
|
||||
|
||||
// Move the Business date to get older the loan and to have an overdue loan
|
||||
businessDate = businessDate.plusDays(40);
|
||||
businessDate = businessDate.plusDays(50);
|
||||
log.info("Current date {}", businessDate);
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
|
||||
// Run Second time the Job
|
||||
@@ -410,7 +789,9 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
|
||||
// Get loan details expecting to have a delinquency classification
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
final GetDelinquencyRangesResponse secondTestCase = getLoansLoanIdResponse.getDelinquencyRange();
|
||||
assertNotNull(secondTestCase);
|
||||
log.info("Loan Delinquency Range is {}", secondTestCase.getClassification());
|
||||
|
||||
// Then
|
||||
@@ -418,384 +799,11 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
assertNotNull(getLoanProductsProductResponse);
|
||||
assertNull(firstTestCase);
|
||||
assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName());
|
||||
assertNotNull(secondTestCase);
|
||||
assertEquals(secondTestCase.getClassification(), classificationExpected);
|
||||
|
||||
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);
|
||||
|
||||
loanTransactionHelper.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 testLoanClassificationRealtimeWithCharges() {
|
||||
// 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
|
||||
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 repayment to get a full paid installment
|
||||
operationDate = Utils.dateFormatter.format(todaysDate);
|
||||
loanTransactionHelper.makeLoanRepayment(operationDate, 1033.33f, 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());
|
||||
printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
transactionDate = todaysDate.minusDays(18);
|
||||
operationDate = Utils.dateFormatter.format(transactionDate);
|
||||
|
||||
// Create and apply Charge for Specific Due Date
|
||||
final Integer chargeId = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||
ChargesHelper.getLoanSpecifiedDueDateJSON(1, "30", false));
|
||||
assertNotNull(chargeId);
|
||||
final Integer loanChargeId = loanTransactionHelper.addChargesForLoan(loanId, getChargeApplyJSON(chargeId, operationDate),
|
||||
responseSpec);
|
||||
assertNotNull(loanChargeId);
|
||||
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
log.info("Loan Delinquency Range after add Loan Charge {}", getLoansLoanIdResponse.getDelinquencyRange());
|
||||
assertNotNull(getLoansLoanIdResponse.getDelinquencyRange());
|
||||
// Evaluate a Delinquency Tag set after add charge to the Loan
|
||||
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected);
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
loanTransactionHelper.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);
|
||||
|
||||
loanTransactionHelper.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.reverseLoanTransaction(loanId,
|
||||
loansLoanIdTransactions.getResourceId(), operationDate, responseSpec);
|
||||
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);
|
||||
@@ -819,17 +827,6 @@ public class DelinquencyBucketsIntegrationTest {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getChargeApplyJSON(final Integer chargeId, final String dueDate) {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("chargeId", chargeId);
|
||||
|
||||
+68
-62
@@ -20,9 +20,8 @@ package org.apache.fineract.integrationtests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
import io.restassured.http.ContentType;
|
||||
@@ -30,26 +29,23 @@ import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
|
||||
import org.apache.fineract.client.models.GetDelinquencyRangesResponse;
|
||||
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.GetLoansLoanIdSummary;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse;
|
||||
import org.apache.fineract.client.models.GetPaymentTypesResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdResponse;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.CommonConstants;
|
||||
import org.apache.fineract.integrationtests.common.PaymentTypeHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||
import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -99,7 +95,8 @@ public class LoanTransactionChargebackTest {
|
||||
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 0, Double.valueOf("0.00"));
|
||||
|
||||
final Integer chargebackTransactionId = applyChargebackTransaction(loanId, transactionId, "1000.00", 0, responseSpec);
|
||||
final Integer chargebackTransactionId = loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "1000.00", 0,
|
||||
responseSpec);
|
||||
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 1, Double.valueOf("0.00"));
|
||||
reviewLoanTransactionRelations(loanId, chargebackTransactionId, 0, Double.valueOf("1000.00"));
|
||||
@@ -141,7 +138,8 @@ public class LoanTransactionChargebackTest {
|
||||
final Integer transactionId = loanIdTransactionsResponse.getResourceId();
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 0, Double.valueOf("666.67"));
|
||||
|
||||
final Integer chargebackTransactionId = applyChargebackTransaction(loanId, transactionId, amount.toString(), 0, responseSpec);
|
||||
final Integer chargebackTransactionId = loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, amount.toString(),
|
||||
0, responseSpec);
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 1, Double.valueOf("666.67"));
|
||||
reviewLoanTransactionRelations(loanId, chargebackTransactionId, 0, Double.valueOf("1000.00"));
|
||||
|
||||
@@ -160,7 +158,8 @@ public class LoanTransactionChargebackTest {
|
||||
}
|
||||
}
|
||||
|
||||
evaluateLoanSummaryAdjustments(getLoansLoanIdResponse, Double.valueOf(baseAmount));
|
||||
loanTransactionHelper.evaluateLoanSummaryAdjustments(getLoansLoanIdResponse, Double.valueOf(baseAmount));
|
||||
DelinquencyBucketsHelper.evaluateLoanCollectionData(getLoansLoanIdResponse, 0, Double.valueOf("333.33"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -179,7 +178,7 @@ public class LoanTransactionChargebackTest {
|
||||
log.info("Try to apply the Charge back over transaction Id {} with type {}", loanTransaction.getId(),
|
||||
loanTransaction.getType().getCode());
|
||||
|
||||
applyChargebackTransaction(loanId, loanTransaction.getId().intValue(), amountVal, 0, responseSpecError);
|
||||
loanTransactionHelper.applyChargebackTransaction(loanId, loanTransaction.getId().intValue(), amountVal, 0, responseSpecError);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -191,6 +190,11 @@ public class LoanTransactionChargebackTest {
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
GetDelinquencyRangesResponse delinquencyRange = getLoansLoanIdResponse.getDelinquencyRange();
|
||||
assertNotNull(delinquencyRange);
|
||||
log.info("Loan Delinquency Range is {}", delinquencyRange.getClassification());
|
||||
|
||||
GetLoansLoanIdRepaymentSchedule getLoanRepaymentSchedule = getLoansLoanIdResponse.getRepaymentSchedule();
|
||||
log.info("Loan with {} periods", getLoanRepaymentSchedule.getPeriods().size());
|
||||
assertEquals(2, getLoanRepaymentSchedule.getPeriods().size());
|
||||
@@ -207,7 +211,8 @@ public class LoanTransactionChargebackTest {
|
||||
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 0, Double.valueOf("0.00"));
|
||||
|
||||
Integer chargebackTransactionId = applyChargebackTransaction(loanId, transactionId, "500.00", 0, responseSpec);
|
||||
Integer chargebackTransactionId = loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "500.00", 0,
|
||||
responseSpec);
|
||||
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 1, Double.valueOf("0.00"));
|
||||
reviewLoanTransactionRelations(loanId, chargebackTransactionId, 0, Double.valueOf("500.00"));
|
||||
@@ -232,7 +237,7 @@ public class LoanTransactionChargebackTest {
|
||||
}
|
||||
}
|
||||
|
||||
chargebackTransactionId = applyChargebackTransaction(loanId, transactionId, "300.00", 0, responseSpec);
|
||||
chargebackTransactionId = loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "300.00", 0, responseSpec);
|
||||
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 2, Double.valueOf("0.00"));
|
||||
reviewLoanTransactionRelations(loanId, chargebackTransactionId, 0, Double.valueOf("800.00"));
|
||||
@@ -241,6 +246,10 @@ public class LoanTransactionChargebackTest {
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
loanTransactionHelper.validateLoanStatus(getLoansLoanIdResponse, "loanStatusType.active");
|
||||
|
||||
delinquencyRange = getLoansLoanIdResponse.getDelinquencyRange();
|
||||
assertNull(delinquencyRange);
|
||||
log.info("Loan Delinquency Range is null {}", (delinquencyRange == null));
|
||||
|
||||
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, Double.valueOf("800.00"));
|
||||
|
||||
// N+1 Scenario -- Remains the same periods number
|
||||
@@ -280,7 +289,8 @@ public class LoanTransactionChargebackTest {
|
||||
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 0, Double.valueOf("0.00"));
|
||||
|
||||
final Integer chargebackTransactionId = applyChargebackTransaction(loanId, transactionId, "200.00", 0, responseSpec);
|
||||
final Integer chargebackTransactionId = loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "200.00", 0,
|
||||
responseSpec);
|
||||
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 1, Double.valueOf("0.00"));
|
||||
reviewLoanTransactionRelations(loanId, chargebackTransactionId, 0, Double.valueOf("100.00"));
|
||||
@@ -290,6 +300,10 @@ public class LoanTransactionChargebackTest {
|
||||
loanTransactionHelper.validateLoanStatus(getLoansLoanIdResponse, "loanStatusType.active");
|
||||
|
||||
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, Double.valueOf("100.00"));
|
||||
|
||||
final GetDelinquencyRangesResponse delinquencyRange = getLoansLoanIdResponse.getDelinquencyRange();
|
||||
assertNull(delinquencyRange);
|
||||
log.info("Loan Delinquency Range is null {}", (delinquencyRange == null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -314,7 +328,8 @@ public class LoanTransactionChargebackTest {
|
||||
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 0, Double.valueOf("0.00"));
|
||||
|
||||
final Integer chargebackTransactionId = applyChargebackTransaction(loanId, transactionId, "100.00", 0, responseSpec);
|
||||
final Integer chargebackTransactionId = loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "100.00", 0,
|
||||
responseSpec);
|
||||
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 1, Double.valueOf("0.00"));
|
||||
reviewLoanTransactionRelations(loanId, chargebackTransactionId, 0, Double.valueOf("0.00"));
|
||||
@@ -348,8 +363,11 @@ public class LoanTransactionChargebackTest {
|
||||
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 0, Double.valueOf("0.00"));
|
||||
|
||||
final Integer chargebackTransactionId = applyChargebackTransaction(loanId, transactionId, "50.00", 0, responseSpec);
|
||||
|
||||
GetDelinquencyRangesResponse delinquencyRange = getLoansLoanIdResponse.getDelinquencyRange();
|
||||
assertNull(delinquencyRange);
|
||||
log.info("Loan Delinquency Range is null {}", (delinquencyRange == null));
|
||||
final Integer chargebackTransactionId = loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "50.00", 0,
|
||||
responseSpec);
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 1, Double.valueOf("0.00"));
|
||||
reviewLoanTransactionRelations(loanId, chargebackTransactionId, 0, Double.valueOf("0.00"));
|
||||
|
||||
@@ -357,6 +375,10 @@ public class LoanTransactionChargebackTest {
|
||||
assertNotNull(getLoansLoanIdResponse);
|
||||
loanTransactionHelper.validateLoanStatus(getLoansLoanIdResponse, "loanStatusType.overpaid");
|
||||
|
||||
delinquencyRange = getLoansLoanIdResponse.getDelinquencyRange();
|
||||
assertNull(delinquencyRange);
|
||||
log.info("Loan Delinquency Range is null {}", (delinquencyRange == null));
|
||||
|
||||
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, Double.valueOf("0.00"));
|
||||
}
|
||||
|
||||
@@ -383,38 +405,56 @@ public class LoanTransactionChargebackTest {
|
||||
// First round, empty array
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 0, Double.valueOf("0.00"));
|
||||
|
||||
applyChargebackTransaction(loanId, transactionId, "200.00", 0, responseSpec);
|
||||
loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "200.00", 0, responseSpec);
|
||||
|
||||
Double expectedAmount = Double.valueOf("200.00");
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, Double.valueOf("200.00"));
|
||||
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, expectedAmount);
|
||||
|
||||
evaluateLoanSummaryAdjustments(getLoansLoanIdResponse, Double.valueOf("200.00"));
|
||||
loanTransactionHelper.evaluateLoanSummaryAdjustments(getLoansLoanIdResponse, expectedAmount);
|
||||
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||
DelinquencyBucketsHelper.evaluateLoanCollectionData(getLoansLoanIdResponse, 0, expectedAmount);
|
||||
|
||||
// Second round, array size equal to 1
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 1, Double.valueOf("0.00"));
|
||||
|
||||
applyChargebackTransaction(loanId, transactionId, "300.00", 1, responseSpec);
|
||||
loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "300.00", 1, responseSpec);
|
||||
|
||||
expectedAmount = Double.valueOf("500.00");
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, Double.valueOf("500.00"));
|
||||
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, expectedAmount);
|
||||
|
||||
evaluateLoanSummaryAdjustments(getLoansLoanIdResponse, Double.valueOf("500.00"));
|
||||
loanTransactionHelper.evaluateLoanSummaryAdjustments(getLoansLoanIdResponse, expectedAmount);
|
||||
DelinquencyBucketsHelper.evaluateLoanCollectionData(getLoansLoanIdResponse, 0, expectedAmount);
|
||||
|
||||
// Third round, array size equal to 2
|
||||
reviewLoanTransactionRelations(loanId, transactionId, 2, Double.valueOf("0.00"));
|
||||
|
||||
applyChargebackTransaction(loanId, transactionId, "500.00", 0, responseSpec);
|
||||
loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "500.00", 0, responseSpec);
|
||||
|
||||
expectedAmount = Double.valueOf("1000.00");
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, Double.valueOf("1000.00"));
|
||||
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, expectedAmount);
|
||||
|
||||
evaluateLoanSummaryAdjustments(getLoansLoanIdResponse, Double.valueOf("1000.00"));
|
||||
loanTransactionHelper.evaluateLoanSummaryAdjustments(getLoansLoanIdResponse, expectedAmount);
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
DelinquencyBucketsHelper.evaluateLoanCollectionData(getLoansLoanIdResponse, 0, expectedAmount);
|
||||
}
|
||||
|
||||
private Integer createAccounts(final Integer daysToSubtract, final Integer numberOfRepayments) {
|
||||
// Delinquency Bucket
|
||||
final Integer delinquencyBucketId = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
|
||||
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||
delinquencyBucketId);
|
||||
|
||||
// Client and Loan account creation
|
||||
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper, null);
|
||||
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper,
|
||||
delinquencyBucketId);
|
||||
assertNotNull(getLoanProductsProductResponse);
|
||||
log.info("Loan Product Bucket Name: {}", getLoanProductsProductResponse.getDelinquencyBucket().getName());
|
||||
assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName());
|
||||
|
||||
// Older date to have more than one overdue installment
|
||||
final LocalDate transactionDate = this.todaysDate.minusDays(daysToSubtract + (30 * (numberOfRepayments - 1)));
|
||||
@@ -424,16 +464,6 @@ public class LoanTransactionChargebackTest {
|
||||
operationDate, amountVal, numberOfRepayments.toString());
|
||||
}
|
||||
|
||||
private String createChargebackPayload(final String transactionAmount, final Integer paymentTypeId) {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("transactionAmount", transactionAmount);
|
||||
map.put("paymentTypeId", paymentTypeId);
|
||||
map.put("locale", CommonConstants.LOCALE);
|
||||
final String chargebackPayload = new Gson().toJson(map);
|
||||
log.info("{}", chargebackPayload);
|
||||
return chargebackPayload;
|
||||
}
|
||||
|
||||
private GetLoanProductsProductIdResponse createLoanProduct(final LoanTransactionHelper loanTransactionHelper,
|
||||
final Integer delinquencyBucketId) {
|
||||
final HashMap<String, Object> loanProductMap = new LoanProductTestBuilder().build(null, delinquencyBucketId);
|
||||
@@ -457,21 +487,6 @@ public class LoanTransactionChargebackTest {
|
||||
return loanId;
|
||||
}
|
||||
|
||||
private Integer applyChargebackTransaction(final Integer loanId, final Integer transactionId, final String amount,
|
||||
final Integer paymentTypeIdx, ResponseSpecification responseSpec) {
|
||||
List<GetPaymentTypesResponse> paymentTypeList = PaymentTypeHelper.getSystemPaymentType(this.requestSpec, this.responseSpec);
|
||||
assertTrue(!paymentTypeList.isEmpty());
|
||||
|
||||
final String payload = createChargebackPayload(amount, paymentTypeList.get(paymentTypeIdx).getId());
|
||||
log.info("Loan Chargeback: {}", payload);
|
||||
PostLoansLoanIdTransactionsTransactionIdResponse postLoansTransactionCommandResponse = loanTransactionHelper
|
||||
.applyLoanTransactionCommand(loanId, transactionId, "chargeback", payload, responseSpec);
|
||||
assertNotNull(postLoansTransactionCommandResponse);
|
||||
|
||||
log.info("Loan Chargeback Id: {}", postLoansTransactionCommandResponse.getResourceId());
|
||||
return postLoansTransactionCommandResponse.getResourceId();
|
||||
}
|
||||
|
||||
private void reviewLoanTransactionRelations(final Integer loanId, final Integer transactionId, final Integer expectedSize,
|
||||
final Double outstandingBalance) {
|
||||
log.info("Loan Transaction Id: {} {}", loanId, transactionId);
|
||||
@@ -487,13 +502,4 @@ public class LoanTransactionChargebackTest {
|
||||
assertEquals(outstandingBalance, getLoansTransactionResponse.getOutstandingLoanBalance());
|
||||
}
|
||||
|
||||
private void evaluateLoanSummaryAdjustments(GetLoansLoanIdResponse getLoansLoanIdResponse, Double amountExpected) {
|
||||
// Evaluate The Loan Summary Principal Adjustments
|
||||
GetLoansLoanIdSummary getLoansLoanIdSummary = getLoansLoanIdResponse.getSummary();
|
||||
if (getLoansLoanIdSummary != null) {
|
||||
log.info("Loan with Principal Adjustments {} expected {}", getLoansLoanIdSummary.getPrincipalAdjustments(), amountExpected);
|
||||
assertEquals(amountExpected, getLoansLoanIdSummary.getPrincipalAdjustments());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+55
-2
@@ -20,6 +20,7 @@ package org.apache.fineract.integrationtests.common.loans;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
@@ -43,11 +44,13 @@ 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.GetLoansLoanIdCollectionData;
|
||||
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.GetLoansLoanIdSummary;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse;
|
||||
import org.apache.fineract.client.models.GetPaymentTypesResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
@@ -55,6 +58,7 @@ import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionI
|
||||
import org.apache.fineract.client.models.PutLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.util.JSON;
|
||||
import org.apache.fineract.integrationtests.common.CommonConstants;
|
||||
import org.apache.fineract.integrationtests.common.PaymentTypeHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
@@ -1155,12 +1159,19 @@ public class LoanTransactionHelper {
|
||||
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());
|
||||
log.info("Period number {} for due date {} and outstanding {} {}", period.getPeriod(), period.getDueDate(),
|
||||
period.getTotalOutstandingForPeriod(), period.getComplete());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void printDelinquencyData(GetLoansLoanIdResponse getLoansLoanIdResponse) {
|
||||
GetLoansLoanIdCollectionData getLoansLoanIdCollectionData = getLoansLoanIdResponse.getDelinquent();
|
||||
if (getLoansLoanIdCollectionData != null) {
|
||||
log.info("Loan Delinquency {}", getLoansLoanIdCollectionData.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void validateLoanStatus(GetLoansLoanIdResponse getLoansLoanIdResponse, final String statusCodeExpected) {
|
||||
final String statusCode = getLoansLoanIdResponse.getStatus().getCode();
|
||||
log.info("Loan with Id {} is with Status {}", getLoansLoanIdResponse.getId(), statusCode);
|
||||
@@ -1192,4 +1203,46 @@ public class LoanTransactionHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public Integer applyChargebackTransaction(final Integer loanId, final Integer transactionId, final String amount,
|
||||
final Integer paymentTypeIdx, ResponseSpecification responseSpec) {
|
||||
List<GetPaymentTypesResponse> paymentTypeList = PaymentTypeHelper.getSystemPaymentType(this.requestSpec, this.responseSpec);
|
||||
assertTrue(!paymentTypeList.isEmpty());
|
||||
|
||||
final String payload = createChargebackPayload(amount, paymentTypeList.get(paymentTypeIdx).getId());
|
||||
log.info("Loan Chargeback: {}", payload);
|
||||
PostLoansLoanIdTransactionsTransactionIdResponse postLoansTransactionCommandResponse = applyLoanTransactionCommand(loanId,
|
||||
transactionId, "chargeback", payload, responseSpec);
|
||||
assertNotNull(postLoansTransactionCommandResponse);
|
||||
|
||||
log.info("Loan Chargeback Id: {}", postLoansTransactionCommandResponse.getResourceId());
|
||||
return postLoansTransactionCommandResponse.getResourceId();
|
||||
}
|
||||
|
||||
public void reviewLoanTransactionRelations(final Integer loanId, final Integer transactionId, final Integer expectedSize) {
|
||||
GetLoansLoanIdTransactionsTransactionIdResponse getLoansTransactionResponse = getLoanTransaction(loanId, transactionId);
|
||||
assertNotNull(getLoansTransactionResponse);
|
||||
assertNotNull(getLoansTransactionResponse.getTransactionRelations());
|
||||
assertEquals(expectedSize, getLoansTransactionResponse.getTransactionRelations().size());
|
||||
log.info("Loan with {} Chargeback Transactions", getLoansTransactionResponse.getTransactionRelations().size());
|
||||
}
|
||||
|
||||
public void evaluateLoanSummaryAdjustments(GetLoansLoanIdResponse getLoansLoanIdResponse, Double amountExpected) {
|
||||
// Evaluate The Loan Summary Principal Adjustments
|
||||
GetLoansLoanIdSummary getLoansLoanIdSummary = getLoansLoanIdResponse.getSummary();
|
||||
if (getLoansLoanIdSummary != null) {
|
||||
log.info("Loan with Principal Adjustments {} expected {}", getLoansLoanIdSummary.getPrincipalAdjustments(), amountExpected);
|
||||
assertEquals(amountExpected, getLoansLoanIdSummary.getPrincipalAdjustments());
|
||||
}
|
||||
}
|
||||
|
||||
private String createChargebackPayload(final String transactionAmount, final Integer paymentTypeId) {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("transactionAmount", transactionAmount);
|
||||
map.put("paymentTypeId", paymentTypeId);
|
||||
map.put("locale", CommonConstants.LOCALE);
|
||||
final String chargebackPayload = new Gson().toJson(map);
|
||||
log.info("{}", chargebackPayload);
|
||||
return chargebackPayload;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+60
-6
@@ -18,6 +18,10 @@
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.common.products;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
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;
|
||||
@@ -25,22 +29,24 @@ import io.restassured.specification.ResponseSpecification;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.DeleteDelinquencyBucketResponse;
|
||||
import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
|
||||
import org.apache.fineract.client.models.GetDelinquencyRangesResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdCollectionData;
|
||||
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.PutDelinquencyBucketResponse;
|
||||
import org.apache.fineract.client.util.JSON;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Slf4j
|
||||
public class DelinquencyBucketsHelper {
|
||||
|
||||
private static final String DELINQUENCY_BUCKETS_URL = "/fineract-provider/api/v1/delinquency/buckets";
|
||||
private static final Gson GSON = new JSON().getGson();
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DelinquencyBucketsHelper.class);
|
||||
|
||||
protected DelinquencyBucketsHelper() {}
|
||||
|
||||
public static ArrayList<GetDelinquencyBucketsResponse> getDelinquencyBuckets(final RequestSpecification requestSpec,
|
||||
@@ -60,7 +66,7 @@ public class DelinquencyBucketsHelper {
|
||||
|
||||
public static PostDelinquencyBucketResponse createDelinquencyBucket(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec, final String json) {
|
||||
LOG.info("JSON: {}", json);
|
||||
log.info("JSON: {}", json);
|
||||
final String response = Utils.performServerPost(requestSpec, responseSpec, DELINQUENCY_BUCKETS_URL + "?" + Utils.TENANT_IDENTIFIER,
|
||||
json, null);
|
||||
return GSON.fromJson(response, PostDelinquencyBucketResponse.class);
|
||||
@@ -68,7 +74,7 @@ public class DelinquencyBucketsHelper {
|
||||
|
||||
public static PutDelinquencyBucketResponse updateDelinquencyBucket(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec, final Integer resourceId, final String json) {
|
||||
LOG.info("JSON: {}", json);
|
||||
log.info("JSON: {}", json);
|
||||
final String response = Utils.performServerPut(requestSpec, responseSpec,
|
||||
DELINQUENCY_BUCKETS_URL + "/" + resourceId + "?" + Utils.TENANT_IDENTIFIER, json, null);
|
||||
return GSON.fromJson(response, PutDelinquencyBucketResponse.class);
|
||||
@@ -88,4 +94,52 @@ public class DelinquencyBucketsHelper {
|
||||
return new Gson().toJson(map);
|
||||
}
|
||||
|
||||
public static Integer createDelinquencyBucket(final RequestSpecification requestSpec, final ResponseSpecification 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());
|
||||
|
||||
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||
PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
|
||||
responseSpec, jsonBucket);
|
||||
assertNotNull(delinquencyBucketResponse);
|
||||
|
||||
return delinquencyBucketResponse.getResourceId();
|
||||
}
|
||||
|
||||
public static void evaluateLoanCollectionData(GetLoansLoanIdResponse getLoansLoanIdResponse, Integer pastDueDays,
|
||||
Double amountExpected) {
|
||||
GetLoansLoanIdCollectionData getCollectionData = getLoansLoanIdResponse.getDelinquent();
|
||||
if (getCollectionData != null) {
|
||||
log.info("Loan Delinquency Data in Days {} and Amount {}", getCollectionData.getPastDueDays(),
|
||||
getCollectionData.getDelinquentAmount());
|
||||
assertEquals(pastDueDays, getCollectionData.getPastDueDays());
|
||||
assertEquals(amountExpected, getCollectionData.getDelinquentAmount());
|
||||
} else {
|
||||
log.info("Loan Delinquency Data is null");
|
||||
}
|
||||
|
||||
GetDelinquencyRangesResponse delinquencyRange = getLoansLoanIdResponse.getDelinquencyRange();
|
||||
if (delinquencyRange != null) {
|
||||
log.info("Loan Delinquency Classification is {} : ({} - {}) {}", delinquencyRange.getClassification(),
|
||||
delinquencyRange.getMinimumAgeDays(), delinquencyRange.getMaximumAgeDays(), pastDueDays);
|
||||
assertTrue(delinquencyRange.getMinimumAgeDays() <= pastDueDays);
|
||||
assertTrue(delinquencyRange.getMaximumAgeDays() >= pastDueDays);
|
||||
} else {
|
||||
log.info("Loan Delinquency Classification is null");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ public class DelinquencyRangesHelper {
|
||||
|
||||
public static String getAsJSON(int minimumAgeDays, int maximumAgeDays) {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("classification", Utils.randomNameGenerator("Delinquency_", 4));
|
||||
map.put("classification", Utils.randomNameGenerator("Delinquency__" + minimumAgeDays + "_" + maximumAgeDays + "__", 4));
|
||||
map.put("minimumAgeDays", minimumAgeDays);
|
||||
map.put("maximumAgeDays", maximumAgeDays);
|
||||
map.put("locale", "en");
|
||||
|
||||
Reference in New Issue
Block a user