Merge pull request #1600 from sachinkulkarni12/CC-36-New
Loan Repayment Rescheduling while disbursement
This commit is contained in:
+63
-4
@@ -43,8 +43,9 @@ public class LoanTransactionData {
|
||||
private final BigDecimal outstandingLoanBalance;
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDate submittedOnDate;
|
||||
|
||||
private final boolean manuallyReversed;
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDate possibleNextRepaymentDate;
|
||||
|
||||
// templates
|
||||
final Collection<PaymentTypeData> paymentTypeOptions;
|
||||
@@ -71,7 +72,7 @@ public class LoanTransactionData {
|
||||
feeChargesPortion, penaltyChargesPortion, overpaymentPortion, unrecognizedIncomePortion, null, externalId, transfer,
|
||||
fixedEmiAmount, outstandingLoanBalance,manuallyReversed);
|
||||
}
|
||||
|
||||
|
||||
public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType,
|
||||
final PaymentDetailData paymentDetailData, final CurrencyData currency, final LocalDate date, final BigDecimal amount,
|
||||
final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
|
||||
@@ -121,16 +122,74 @@ public class LoanTransactionData {
|
||||
this.outstandingLoanBalance = outstandingLoanBalance;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.manuallyReversed = manuallyReversed;
|
||||
this.possibleNextRepaymentDate = null;
|
||||
}
|
||||
|
||||
public LoanTransactionData(Long id, LoanTransactionEnumData transactionType, LocalDate date, BigDecimal totalAmount,
|
||||
BigDecimal principalPortion, BigDecimal interestPortion, BigDecimal feeChargesPortion, BigDecimal penaltyChargesPortion,
|
||||
BigDecimal overPaymentPortion, BigDecimal unrecognizedIncomePortion, BigDecimal outstandingLoanBalance,final boolean manuallyReversed) {
|
||||
this(id, null, null, transactionType, null, null, date, totalAmount, principalPortion, interestPortion, feeChargesPortion,
|
||||
penaltyChargesPortion, overPaymentPortion, unrecognizedIncomePortion, null, null, null, null, outstandingLoanBalance, null,manuallyReversed);
|
||||
penaltyChargesPortion, overPaymentPortion, unrecognizedIncomePortion, null, null, null, null, outstandingLoanBalance, null,
|
||||
manuallyReversed);
|
||||
}
|
||||
|
||||
public static LoanTransactionData LoanTransactionDataForDisbursalTemplate(final LoanTransactionEnumData transactionType, final LocalDate expectedDisbursedOnLocalDateForTemplate,
|
||||
final BigDecimal disburseAmountForTemplate, final Collection<PaymentTypeData> paymentOptions,
|
||||
final BigDecimal retriveLastEmiAmount, final LocalDate possibleNextRepaymentDate) {
|
||||
final Long id = null;
|
||||
final Long officeId = null;
|
||||
final String officeName = null;
|
||||
final PaymentDetailData paymentDetailData = null;
|
||||
final CurrencyData currency = null;
|
||||
final BigDecimal unrecognizedIncomePortion = null;
|
||||
final BigDecimal principalPortion = null;;
|
||||
final BigDecimal interestPortion = null;
|
||||
final BigDecimal feeChargesPortion = null;
|
||||
final BigDecimal penaltyChargesPortion = null;
|
||||
final BigDecimal overpaymentPortion = null;
|
||||
final String externalId = null;
|
||||
final BigDecimal outstandingLoanBalance = null;
|
||||
final AccountTransferData transfer = null;
|
||||
final LocalDate submittedOnDate = null;
|
||||
final boolean manuallyReversed = false;
|
||||
return new LoanTransactionData(id, officeId, officeName, transactionType, paymentDetailData, currency, expectedDisbursedOnLocalDateForTemplate,
|
||||
disburseAmountForTemplate, principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion, overpaymentPortion, unrecognizedIncomePortion,
|
||||
paymentOptions, transfer, externalId, retriveLastEmiAmount, outstandingLoanBalance, submittedOnDate, manuallyReversed, possibleNextRepaymentDate);
|
||||
|
||||
}
|
||||
|
||||
public LocalDate dateOf() {
|
||||
private LoanTransactionData(Long id , final Long officeId, final String officeName, LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData,
|
||||
final CurrencyData currency, final LocalDate date, BigDecimal amount, final BigDecimal principalPortion, final BigDecimal interestPortion,
|
||||
final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion, BigDecimal unrecognizedIncomePortion, Collection<PaymentTypeData> paymentOptions,
|
||||
final AccountTransferData transfer, final String externalId, final BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance,
|
||||
final LocalDate submittedOnDate, final boolean manuallyReversed, final LocalDate possibleNextRepaymentDate) {
|
||||
this.id = id;
|
||||
this.officeId = officeId;
|
||||
this.officeName = officeName;
|
||||
this.type = transactionType;
|
||||
this.paymentDetailData = paymentDetailData;
|
||||
this.currency = currency;
|
||||
this.date = date;
|
||||
this.amount = amount;
|
||||
this.principalPortion = principalPortion;
|
||||
this.interestPortion = interestPortion;
|
||||
this.feeChargesPortion = feeChargesPortion;
|
||||
this.penaltyChargesPortion = penaltyChargesPortion;
|
||||
this.unrecognizedIncomePortion = unrecognizedIncomePortion;
|
||||
this.paymentTypeOptions = paymentOptions;
|
||||
this.externalId = externalId;
|
||||
this.transfer = transfer;
|
||||
this.overpaymentPortion = overpaymentPortion;
|
||||
this.fixedEmiAmount = fixedEmiAmount;
|
||||
this.outstandingLoanBalance = outstandingLoanBalance;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.manuallyReversed = manuallyReversed;
|
||||
this.possibleNextRepaymentDate = possibleNextRepaymentDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public LocalDate dateOf() {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
|
||||
+36
-2
@@ -2324,7 +2324,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public void regenerateScheduleOnDisbursement(final ScheduleGeneratorDTO scheduleGeneratorDTO, final boolean recalculateSchedule,
|
||||
final LocalDate actualDisbursementDate, BigDecimal emiAmount, final AppUser currentUser) {
|
||||
final LocalDate actualDisbursementDate, BigDecimal emiAmount, final AppUser currentUser, LocalDate nextPossibleRepaymentDate, Date rescheduledRepaymentDate) {
|
||||
boolean isEmiAmountChanged = false;
|
||||
if ((this.loanProduct.isMultiDisburseLoan() || this.loanProduct.canDefineInstallmentAmount()) && emiAmount != null
|
||||
&& emiAmount.compareTo(retriveLastEmiAmount()) != 0) {
|
||||
@@ -2332,13 +2332,19 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final Date dateValue = null;
|
||||
final boolean isSpecificToInstallment = false;
|
||||
LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(),
|
||||
actualDisbursementDate.toDate(), emiAmount, dateValue, isSpecificToInstallment, this);
|
||||
actualDisbursementDate.toDate(), emiAmount, dateValue, isSpecificToInstallment, this, LoanStatus.ACTIVE.getValue());
|
||||
this.loanTermVariations.add(loanVariationTerms);
|
||||
} else {
|
||||
this.fixedEmiAmount = emiAmount;
|
||||
}
|
||||
isEmiAmountChanged = true;
|
||||
}
|
||||
if(rescheduledRepaymentDate != null && this.loanProduct.isMultiDisburseLoan()){
|
||||
final boolean isSpecificToInstallment = false;
|
||||
LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.DUE_DATE.getValue(),
|
||||
nextPossibleRepaymentDate.toDate(), emiAmount, rescheduledRepaymentDate, isSpecificToInstallment, this, LoanStatus.ACTIVE.getValue());
|
||||
this.loanTermVariations.add(loanVariationTerms);
|
||||
}
|
||||
|
||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged) {
|
||||
regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
|
||||
@@ -5533,6 +5539,12 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
actualDisbursementDate = lastTransactionDate;
|
||||
updateLoanToLastDisbursalState(actualDisbursementDate);
|
||||
for (Iterator<LoanTermVariations> iterator = this.loanTermVariations.iterator(); iterator.hasNext();) {
|
||||
LoanTermVariations loanTermVariations = iterator.next();
|
||||
if (loanTermVariations.fetchDateValue().isAfter(actualDisbursementDate)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
reverseExistingTransactionsTillLastDisbursal(actualDisbursementDate);
|
||||
loan.recalculateScheduleFromLastTransaction(scheduleGeneratorDTO, existingTransactionIds, existingReversedTransactionIds,
|
||||
currentUser);
|
||||
@@ -5621,5 +5633,27 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
public void setExpectedFirstRepaymentOnDate(Date expectedFirstRepaymentOnDate) {
|
||||
this.expectedFirstRepaymentOnDate = expectedFirstRepaymentOnDate;
|
||||
}
|
||||
|
||||
/*
|
||||
* get the next repayment date for rescheduling at the time of disbursement
|
||||
*/
|
||||
public LocalDate getNextPossibleRepaymentDateForRescheduling(){
|
||||
Set<LoanDisbursementDetails> loanDisbursementDetails = this.disbursementDetails;
|
||||
LocalDate nextRepaymentDate = new LocalDate();
|
||||
for(LoanDisbursementDetails loanDisbursementDetail : loanDisbursementDetails){
|
||||
if(loanDisbursementDetail.actualDisbursementDate() == null){
|
||||
for (final LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) {
|
||||
if (installment.getDueDate().isEqual(loanDisbursementDetail.expectedDisbursementDateAsLocalDate()) ||
|
||||
installment.getDueDate().isAfter(loanDisbursementDetail.expectedDisbursementDateAsLocalDate())
|
||||
&& installment.isNotFullyPaidOff()) {
|
||||
nextRepaymentDate = installment.getDueDate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nextRepaymentDate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
@@ -60,6 +60,17 @@ public class LoanTermVariations extends AbstractPersistable<Long> {
|
||||
this.isSpecificToInstallment = isSpecificToInstallment;
|
||||
this.onLoanStatus = loan.status().getValue();
|
||||
}
|
||||
|
||||
public LoanTermVariations(final Integer termType, final Date termApplicableFrom, final BigDecimal decimalValue, final Date dateValue,
|
||||
final boolean isSpecificToInstallment, final Loan loan, final Integer loanStatus) {
|
||||
this.loan = loan;
|
||||
this.termApplicableFrom = termApplicableFrom;
|
||||
this.termType = termType;
|
||||
this.decimalValue = decimalValue;
|
||||
this.dateValue = dateValue;
|
||||
this.isSpecificToInstallment = isSpecificToInstallment;
|
||||
this.onLoanStatus = loanStatus;
|
||||
}
|
||||
|
||||
protected LoanTermVariations() {
|
||||
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ public final class LoanEventApiJsonValidator {
|
||||
"dateFormat", LoanApiConstants.principalDisbursedParameterName, LoanApiConstants.emiAmountParameterName));
|
||||
} else {
|
||||
disbursementParameters = new HashSet<>(Arrays.asList("actualDisbursementDate", "externalId", "note", "locale",
|
||||
"dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber",
|
||||
"dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber", "adjustRepaymentDate",
|
||||
LoanApiConstants.principalDisbursedParameterName, LoanApiConstants.emiAmountParameterName));
|
||||
}
|
||||
|
||||
|
||||
+2
-5
@@ -480,11 +480,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
if (paymentDetailsRequired) {
|
||||
paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||
}
|
||||
final BigDecimal outstandingLoanBalance = null;
|
||||
final BigDecimal unrecognizedIncomePortion = null;
|
||||
return new LoanTransactionData(null, null, null, transactionType, null, null, loan.getExpectedDisbursedOnLocalDateForTemplate(),
|
||||
loan.getDisburseAmountForTemplate(), null, null, null, null, null, unrecognizedIncomePortion, paymentOptions, null, null,
|
||||
loan.retriveLastEmiAmount(), outstandingLoanBalance, false);
|
||||
return LoanTransactionData.LoanTransactionDataForDisbursalTemplate(transactionType, loan.getExpectedDisbursedOnLocalDateForTemplate(), loan.getDisburseAmountForTemplate(),
|
||||
paymentOptions, loan.retriveLastEmiAmount(), loan.getNextPossibleRepaymentDateForRescheduling());
|
||||
|
||||
}
|
||||
|
||||
|
||||
+12
-4
@@ -9,6 +9,7 @@ import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -283,6 +284,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
checkClientOrGroupActive(loan);
|
||||
|
||||
final LocalDate nextPossibleRepaymentDate = loan.getNextPossibleRepaymentDateForRescheduling();
|
||||
final Date rescheduledRepaymentDate = command.DateValueOfParameterNamed("adjustRepaymentDate");
|
||||
|
||||
// check for product mix validations
|
||||
checkForProductMixRestrictions(loan);
|
||||
@@ -333,7 +337,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
LocalDate recalculateFrom = null;
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
|
||||
|
||||
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO);
|
||||
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate, rescheduledRepaymentDate);
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(loan.fetchRepaymentScheduleInstallments(),
|
||||
loan, null);
|
||||
@@ -518,6 +522,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final SingleDisbursalCommand[] disbursalCommand = bulkDisbursalCommand.getDisburseTransactions();
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
if (disbursalCommand == null) { return changes; }
|
||||
|
||||
final LocalDate nextPossibleRepaymentDate = null;
|
||||
final Date rescheduledRepaymentDate = null;
|
||||
|
||||
for (int i = 0; i < disbursalCommand.length; i++) {
|
||||
final SingleDisbursalCommand singleLoanDisbursalCommand = disbursalCommand[i];
|
||||
@@ -563,7 +570,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
LocalDate recalculateFrom = null;
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
|
||||
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO);
|
||||
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate, rescheduledRepaymentDate);
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(
|
||||
loan.fetchRepaymentScheduleInstallments(), loan, null);
|
||||
@@ -2669,11 +2676,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
|
||||
private void regenerateScheduleOnDisbursement(final JsonCommand command, final Loan loan, final boolean recalculateSchedule,
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO, final LocalDate nextPossibleRepaymentDate, final Date rescheduledRepaymentDate) {
|
||||
AppUser currentUser = getAppUserIfPresent();
|
||||
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
|
||||
BigDecimal emiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName);
|
||||
loan.regenerateScheduleOnDisbursement(scheduleGeneratorDTO, recalculateSchedule, actualDisbursementDate, emiAmount, currentUser);
|
||||
loan.regenerateScheduleOnDisbursement(scheduleGeneratorDTO, recalculateSchedule, actualDisbursementDate, emiAmount, currentUser,
|
||||
nextPossibleRepaymentDate, rescheduledRepaymentDate);
|
||||
}
|
||||
|
||||
private List<LoanRepaymentScheduleInstallment> retrieveRepaymentScheduleFromModel(LoanScheduleModel model) {
|
||||
|
||||
Reference in New Issue
Block a user