FINERACT-1992: Multi delinquency implication on events
This commit is contained in:
committed by
Adam Saghy
parent
f089f01116
commit
48300cd19d
+85
-1
@@ -19,8 +19,12 @@
|
||||
package org.apache.fineract.infrastructure.event.external.service.serialization.serializer.loan;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.avro.generic.GenericContainer;
|
||||
import org.apache.fineract.avro.generator.ByteBufferSerializable;
|
||||
@@ -28,6 +32,8 @@ import org.apache.fineract.avro.loan.v1.DelinquencyRangeDataV1;
|
||||
import org.apache.fineract.avro.loan.v1.LoanAccountDelinquencyRangeDataV1;
|
||||
import org.apache.fineract.avro.loan.v1.LoanAmountDataV1;
|
||||
import org.apache.fineract.avro.loan.v1.LoanChargeDataRangeViewV1;
|
||||
import org.apache.fineract.avro.loan.v1.LoanInstallmentDelinquencyBucketDataV1;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanDelinquencyRangeChangeBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.generic.CurrencyDataMapper;
|
||||
@@ -36,10 +42,12 @@ import org.apache.fineract.infrastructure.event.external.service.serialization.m
|
||||
import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.AvroDateTimeMapper;
|
||||
import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.portfolio.delinquency.data.LoanInstallmentDelinquencyTagData;
|
||||
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
@@ -94,6 +102,10 @@ public class LoanDelinquencyRangeChangeBusinessEventSerializer implements Busine
|
||||
.build();
|
||||
|
||||
DelinquencyRangeDataV1 delinquencyRange = mapper.map(data.getDelinquencyRange());
|
||||
|
||||
List<LoanInstallmentDelinquencyBucketDataV1> installmentsDelinquencyData = calculateInstallmentLevelDelinquencyData(event.get(),
|
||||
data);
|
||||
|
||||
LoanAccountDelinquencyRangeDataV1.Builder builder = LoanAccountDelinquencyRangeDataV1.newBuilder();
|
||||
return builder//
|
||||
.setLoanId(id)//
|
||||
@@ -104,7 +116,79 @@ public class LoanDelinquencyRangeChangeBusinessEventSerializer implements Busine
|
||||
.setAmount(amount)//
|
||||
.setCurrency(currencyMapper.map(data.getCurrency()))//
|
||||
.setDelinquentDate(delinquentDate)//
|
||||
.build();
|
||||
.setInstallmentDelinquencyBuckets(installmentsDelinquencyData).build();
|
||||
}
|
||||
|
||||
private List<LoanInstallmentDelinquencyBucketDataV1> calculateInstallmentLevelDelinquencyData(Loan loan, LoanAccountData data) {
|
||||
List<LoanInstallmentDelinquencyBucketDataV1> loanInstallmentDelinquencyData = new ArrayList<>();
|
||||
if (loan.isEnableInstallmentLevelDelinquency()) {
|
||||
Collection<LoanInstallmentDelinquencyTagData> installmentDelinquencyTags = delinquencyReadPlatformService
|
||||
.retrieveLoanInstallmentsCurrentDelinquencyTag(loan.getId());
|
||||
if (installmentDelinquencyTags != null && installmentDelinquencyTags.size() > 0) {
|
||||
// group installments that are in same range
|
||||
Map<Long, List<LoanInstallmentDelinquencyTagData>> installmentsInSameRange = installmentDelinquencyTags.stream().collect(
|
||||
Collectors.groupingBy(installmentDelnquencyTags -> installmentDelnquencyTags.getDelinquencyRange().getId()));
|
||||
// for installments in each range, get details from loan repayment schedule installment, add amounts,
|
||||
// list charges
|
||||
for (Map.Entry<Long, List<LoanInstallmentDelinquencyTagData>> installmentDelinquencyTagData : installmentsInSameRange
|
||||
.entrySet()) {
|
||||
// get installments details
|
||||
List<LoanRepaymentScheduleInstallment> delinquentInstallmentsInSameRange = loan.getRepaymentScheduleInstallments()
|
||||
.stream().filter(installment -> installmentDelinquencyTagData.getValue().stream()
|
||||
.anyMatch(installmentTag -> installmentTag.getId().equals(installment.getId())))
|
||||
.toList();
|
||||
// add amounts
|
||||
LoanAmountDataV1 amount = LoanAmountDataV1.newBuilder()//
|
||||
.setPrincipalAmount(delinquentInstallmentsInSameRange.stream()
|
||||
.map(instlment -> instlment.getPrincipalOutstanding(loan.getCurrency()).getAmount())
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add))//
|
||||
.setFeeAmount(delinquentInstallmentsInSameRange.stream()
|
||||
.map(instlment -> instlment.getFeeChargesOutstanding(loan.getCurrency()).getAmount())
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add))//
|
||||
.setInterestAmount(delinquentInstallmentsInSameRange.stream()
|
||||
.map(instlment -> instlment.getInterestOutstanding(loan.getCurrency()).getAmount())
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add))//
|
||||
.setPenaltyAmount(delinquentInstallmentsInSameRange.stream()
|
||||
.map(instlment -> instlment.getPenaltyChargesOutstanding(loan.getCurrency()).getAmount())
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add))//
|
||||
.setTotalAmount(delinquentInstallmentsInSameRange.stream()
|
||||
.map(instlment -> instlment.getTotalOutstanding(loan.getCurrency()).getAmount())
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add))//
|
||||
.build();
|
||||
|
||||
// get list of charges for installments in same range
|
||||
List<LoanCharge> chargesForInstallmentsInSameRange = loan.getLoanCharges().stream()
|
||||
.filter(loanCharge -> !loanCharge.isPaid() && delinquentInstallmentsInSameRange.stream().anyMatch(
|
||||
installmentForCharge -> (DateUtils.isAfter(loanCharge.getDueDate(), installmentForCharge.getFromDate())
|
||||
|| DateUtils.isEqual(loanCharge.getDueDate(), installmentForCharge.getFromDate()))
|
||||
&& (DateUtils.isBefore(loanCharge.getDueDate(), installmentForCharge.getDueDate())
|
||||
|| DateUtils.isEqual(loanCharge.getDueDate(), installmentForCharge.getDueDate()))))
|
||||
.toList();
|
||||
|
||||
List<LoanChargeDataRangeViewV1> charges = new ArrayList<>();
|
||||
for (LoanCharge charge : chargesForInstallmentsInSameRange) {
|
||||
LoanChargeDataRangeViewV1 chargeData = LoanChargeDataRangeViewV1.newBuilder().setId(charge.getId())
|
||||
.setName(charge.name()).setAmount(charge.amountOutstanding())
|
||||
.setCurrency(currencyMapper.map(data.getCurrency())).build();
|
||||
charges.add(chargeData);
|
||||
}
|
||||
|
||||
LoanInstallmentDelinquencyTagData.InstallmentDelinquencyRange delinquencyRange = installmentDelinquencyTagData
|
||||
.getValue().get(0).getDelinquencyRange();
|
||||
|
||||
DelinquencyRangeDataV1 delinquencyRangeDataV1 = DelinquencyRangeDataV1.newBuilder().setId(delinquencyRange.getId())
|
||||
.setClassification(delinquencyRange.getClassification()).setMinimumAgeDays(delinquencyRange.getMinimumAgeDays())
|
||||
.setMaximumAgeDays(delinquencyRange.getMaximumAgeDays()).build();
|
||||
|
||||
LoanInstallmentDelinquencyBucketDataV1 installmentDelinquencyBucketDataV1 = LoanInstallmentDelinquencyBucketDataV1
|
||||
.newBuilder().setDelinquencyRange(delinquencyRangeDataV1).setAmount(amount).setCharges(charges)
|
||||
.setCurrency(currencyMapper.map(data.getCurrency())).build();
|
||||
|
||||
loanInstallmentDelinquencyData.add(installmentDelinquencyBucketDataV1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return loanInstallmentDelinquencyData;
|
||||
}
|
||||
|
||||
private BigDecimal calculateDataSummary(Loan loan, BiFunction<Loan, LoanRepaymentScheduleInstallment, BigDecimal> mapper) {
|
||||
|
||||
+2
@@ -22,6 +22,8 @@ import java.math.BigDecimal;
|
||||
|
||||
public interface LoanInstallmentDelinquencyTagData {
|
||||
|
||||
Long getId();
|
||||
|
||||
InstallmentDelinquencyRange getDelinquencyRange();
|
||||
|
||||
BigDecimal getOutstandingAmount();
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ public interface LoanInstallmentDelinquencyTagRepository
|
||||
List<LoanInstallmentDelinquencyTag> findByLoanId(@Param("loanId") Long loanId);
|
||||
|
||||
// Fetching Installment Delinquency range and outstanding amount
|
||||
@Query("select i.delinquencyRange, i.outstandingAmount from LoanInstallmentDelinquencyTag i where i.loan.id = :loanId")
|
||||
@Query("select i.installment.id, i.delinquencyRange, i.outstandingAmount from LoanInstallmentDelinquencyTag i where i.loan.id = :loanId")
|
||||
List<LoanInstallmentDelinquencyTagData> findInstallmentDelinquencyTags(@Param("loanId") Long loanId);
|
||||
|
||||
@Modifying(flushAutomatically = true)
|
||||
|
||||
+7
-6
@@ -175,12 +175,13 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
||||
final CollectionData collectionData = loanDelinquencyData.getLoanCollectionData();
|
||||
// loan installments delinquent data
|
||||
final Map<Long, CollectionData> installmentsCollectionData = loanDelinquencyData.getLoanInstallmentsCollectionData();
|
||||
// delinquency for loan
|
||||
changes = lookUpDelinquencyRange(loan, delinquencyBucket, collectionData.getDelinquentDays());
|
||||
// delinquency for installments
|
||||
if (installmentsCollectionData.size() > 0) {
|
||||
applyDelinquencyDetailsForLoanInstallments(loan, delinquencyBucket, installmentsCollectionData);
|
||||
}
|
||||
// delinquency for loan
|
||||
changes = lookUpDelinquencyRange(loan, delinquencyBucket, collectionData.getDelinquentDays());
|
||||
|
||||
}
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(loan.getId())
|
||||
.withEntityExternalId(loan.getExternalId()).with(changes).build();
|
||||
@@ -196,13 +197,13 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
||||
final CollectionData collectionData = loanDelinquentData.getLoanCollectionData();
|
||||
// loan installments delinquent data
|
||||
final Map<Long, CollectionData> installmentsCollectionData = loanDelinquentData.getLoanInstallmentsCollectionData();
|
||||
log.debug("Delinquency {}", collectionData);
|
||||
// delinquency for loan
|
||||
lookUpDelinquencyRange(loan, delinquencyBucket, collectionData.getDelinquentDays());
|
||||
// delinquency for installments
|
||||
if (installmentsCollectionData.size() > 0) {
|
||||
applyDelinquencyDetailsForLoanInstallments(loan, delinquencyBucket, installmentsCollectionData);
|
||||
}
|
||||
log.debug("Delinquency {}", collectionData);
|
||||
// delinquency for loan
|
||||
lookUpDelinquencyRange(loan, delinquencyBucket, collectionData.getDelinquentDays());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,10 +232,10 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
||||
|
||||
@Override
|
||||
public void removeDelinquencyTagToLoan(final Loan loan) {
|
||||
setLoanDelinquencyTag(loan, null);
|
||||
if (loan.isEnableInstallmentLevelDelinquency()) {
|
||||
cleanLoanInstallmentsDelinquencyTags(loan);
|
||||
}
|
||||
setLoanDelinquencyTag(loan, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user