Merge pull request #1600 from sachinkulkarni12/CC-36-New

Loan Repayment Rescheduling while disbursement
This commit is contained in:
pramod
2016-01-18 12:08:33 +05:30
8 changed files with 372 additions and 16 deletions
@@ -0,0 +1,228 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.integrationtests;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mifosplatform.integrationtests.common.ClientHelper;
import org.mifosplatform.integrationtests.common.Utils;
import org.mifosplatform.integrationtests.common.accounting.Account;
import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanStatusChecker;
import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.builder.ResponseSpecBuilder;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
@SuppressWarnings("rawtypes")
public class LoanRepaymentRescheduleAtDisbursementTest {
private ResponseSpecification responseSpec;
private RequestSpecification requestSpec;
private LoanTransactionHelper loanTransactionHelper;
private LoanApplicationApprovalTest loanApplicationApprovalTest;
private ResponseSpecification generalResponseSpec;
@Before
public void setup() {
Utils.initializeRESTAssured();
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
this.loanApplicationApprovalTest = new LoanApplicationApprovalTest();
this.generalResponseSpec = new ResponseSpecBuilder().build();
}
@SuppressWarnings("unchecked")
@Test
public void testLoanRepaymentRescheduleAtDisbursement(){
final String approvalAmount = "10000";
final String approveDate = "01 March 2015";
final String expectedDisbursementDate = "01 March 2015";
final String disbursementDate = "01 March 2015";
final String adjustRepaymentDate = "16 March 2015";
final String recalculationRestFrequencyDate = "01 January 2012";
// CREATE CLIENT
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014");
System.out.println("---------------------------------CLIENT CREATED WITH ID---------------------------------------------------"
+ clientID);
// CREATE LOAN MULTIDISBURSAL PRODUCT WITH INTEREST RECALCULATION
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.RBI_INDIA_STRATEGY,
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0", recalculationRestFrequencyDate,
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
// CREATE TRANCHES
List<HashMap> createTranches = new ArrayList<>();
createTranches.add(this.loanApplicationApprovalTest.createTrancheDetail("01 March 2015", "5000"));
createTranches.add(this.loanApplicationApprovalTest.createTrancheDetail("01 May 2015", "5000"));
// APPROVE TRANCHES
List<HashMap> approveTranches = new ArrayList<>();
approveTranches.add(this.loanApplicationApprovalTest.createTrancheDetail("01 March 2015", "5000"));
approveTranches.add(this.loanApplicationApprovalTest.createTrancheDetail("01 May 2015", "5000"));
// APPLY FOR TRANCHE LOAN WITH INTEREST RECALCULATION
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate,
recalculationRestFrequencyDate, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0), createTranches);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
// VALIDATE THE LOAN STATUS
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------------------------");
loanStatusHashMap = this.loanTransactionHelper.approveLoanWithApproveAmount(approveDate, expectedDisbursementDate, approvalAmount,
loanID, approveTranches);
// VALIDATE THE LOAN IS APPROVED
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
// DISBURSE A FIRST TRANCHE
this.loanTransactionHelper.disburseLoanWithRepaymentReschedule(disbursementDate, loanID, adjustRepaymentDate);
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
ArrayList<HashMap> loanRepaymnetSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, generalResponseSpec, loanID);
HashMap firstInstallement = loanRepaymnetSchedule.get(1);
Map<String, Object> expectedvalues = new HashMap<>(3);
Calendar date = Calendar.getInstance(Utils.getTimeZoneOfTenant());
date.set(2015, Calendar.MARCH, 16);
expectedvalues.put("dueDate", getDateAsArray(date, 0));
expectedvalues.put("principalDue", "834.71");
expectedvalues.put("interestDue", "49.32");
expectedvalues.put("feeChargesDue", "0");
expectedvalues.put("penaltyChargesDue", "0");
expectedvalues.put("totalDueForPeriod", "884.03");
// VALIDATE REPAYMENT SCHEDULE
verifyLoanRepaymentSchedule(firstInstallement, expectedvalues);
}
private void verifyLoanRepaymentSchedule(final HashMap firstInstallement, final Map<String, Object> expectedvalues) {
assertEquals(expectedvalues.get("dueDate"), firstInstallement.get("dueDate"));
assertEquals(String.valueOf(expectedvalues.get("principalDue")), String.valueOf(firstInstallement.get("principalDue")));
assertEquals(String.valueOf(expectedvalues.get("interestDue")), String.valueOf(firstInstallement.get("interestDue")));
assertEquals(String.valueOf(expectedvalues.get("feeChargesDue")), String.valueOf(firstInstallement.get("feeChargesDue")));
assertEquals(String.valueOf(expectedvalues.get("penaltyChargesDue")), String.valueOf(firstInstallement.get("penaltyChargesDue")));
assertEquals(String.valueOf(expectedvalues.get("totalDueForPeriod")), String.valueOf(firstInstallement.get("totalDueForPeriod")));
}
private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts) {
final String recalculationCompoundingFrequencyType = null;
final String recalculationCompoundingFrequencyInterval = null;
final String recalculationCompoundingFrequencyDate = null;
return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false);
}
private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
final String preCloseInterestCalculationStrategy, final Account[] accounts, final String chargeId,
boolean isArrearsBasedOnOriginalSchedule) {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
LoanProductTestBuilder builder = new LoanProductTestBuilder()
.withPrincipal("10000.00")
.withNumberOfRepayments("12")
.withRepaymentAfterEvery("2")
.withRepaymentTypeAsWeek()
.withinterestRatePerPeriod("2")
.withInterestRateFrequencyTypeAsMonths()
.withTranches(true)
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
.withRepaymentStrategy(repaymentStrategy)
.withInterestTypeAsDecliningBalance()
.withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod,
preCloseInterestCalculationStrategy)
.withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval,
recalculationRestFrequencyDate)
.withInterestRecalculationCompoundingFrequencyDetails(recalculationCompoundingFrequencyType,
recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate);
if (accounts != null) {
builder = builder.withAccountingRulePeriodicAccrual(accounts);
}
if (isArrearsBasedOnOriginalSchedule) builder = builder.withArrearsConfiguration();
final String loanProductJSON = builder.build(chargeId);
return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
}
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
final String disbursementDate, final String restStartDate, final String repaymentStrategy, final List<HashMap> charges, List<HashMap> tranches) {
final String graceOnInterestPayment = null;
final String compoundingStartDate = null;
final String graceOnPrincipalPayment = null;
return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, restStartDate,
compoundingStartDate, repaymentStrategy, charges, graceOnInterestPayment, graceOnPrincipalPayment,tranches);
}
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
final String disbursementDate, final String restStartDate, final String compoundingStartDate, final String repaymentStrategy,
final List<HashMap> charges, final String graceOnInterestPayment, final String graceOnPrincipalPayment, List<HashMap> tranches) {
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
.withPrincipal("10000.00") //
.withLoanTermFrequency("24") //
.withLoanTermFrequencyAsWeeks() //
.withNumberOfRepayments("12") //
.withRepaymentEveryAfter("2") //
.withRepaymentFrequencyTypeAsWeeks() //
.withInterestRatePerPeriod("2") //
.withAmortizationTypeAsEqualInstallments() //
.withTranches(tranches)
.withFixedEmiAmount("") //
.withInterestTypeAsDecliningBalance() //
.withInterestCalculationPeriodTypeAsDays() //
.withInterestCalculationPeriodTypeAsDays() //
.withExpectedDisbursementDate(disbursementDate) //
.withSubmittedOnDate(disbursementDate) //
.withRestFrequencyDate(restStartDate)//
.withwithRepaymentStrategy(repaymentStrategy) //
.withCharges(charges)//
.build(clientID.toString(), loanProductID.toString(), null);
return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
}
private List getDateAsArray(Calendar date, int addPeriod) {
return getDateAsArray(date, addPeriod, Calendar.DAY_OF_MONTH);
}
private List getDateAsArray(Calendar date, int addvalue, int type) {
date.add(type, addvalue);
return new ArrayList<>(Arrays.asList(date.get(Calendar.YEAR), date.get(Calendar.MONTH) + 1,
date.get(Calendar.DAY_OF_MONTH)));
}
}
@@ -152,6 +152,11 @@ public class LoanTransactionHelper {
public HashMap disburseLoan(final String date, final Integer loanID) {
return performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_COMMAND, loanID), getDisburseLoanAsJSON(date, null));
}
public HashMap disburseLoanWithRepaymentReschedule(final String date, final Integer loanID, String adjustRepaymentDate) {
return performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_COMMAND, loanID), getDisburseLoanWithRepaymentRescheduleAsJSON(date,
null, adjustRepaymentDate));
}
public HashMap disburseLoan(final String date, final Integer loanID, final String disburseAmt) {
return performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_COMMAND, loanID), getDisburseLoanAsJSON(date, disburseAmt));
@@ -260,6 +265,20 @@ public class LoanTransactionHelper {
System.out.println("Loan Application disburse request : " + map);
return new Gson().toJson(map);
}
private String getDisburseLoanWithRepaymentRescheduleAsJSON(final String actualDisbursementDate, final String transactionAmount, final String adjustRepaymentDate) {
final HashMap<String, String> map = new HashMap<>();
map.put("locale", "en");
map.put("dateFormat", "dd MMMM yyyy");
map.put("actualDisbursementDate", actualDisbursementDate);
map.put("adjustRepaymentDate", adjustRepaymentDate);
map.put("note", "DISBURSE NOTE");
if (transactionAmount != null) {
map.put("transactionAmount", transactionAmount);
}
System.out.println("Loan Application disburse request : " + map);
return new Gson().toJson(map);
}
private String getApproveLoanAsJSON(final String approvalDate) {
return getApproveLoanAsJSON(approvalDate, null, null, null);
@@ -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;
}
@@ -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;
}
}
@@ -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() {
@@ -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));
}
@@ -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());
}
@@ -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) {