Merge pull request #1600 from sachinkulkarni12/CC-36-New
Loan Repayment Rescheduling while disbursement
This commit is contained in:
+228
@@ -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)));
|
||||
}
|
||||
}
|
||||
+19
@@ -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);
|
||||
|
||||
+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