Center Rescheduling
This commit is contained in:
+392
@@ -0,0 +1,392 @@
|
|||||||
|
/**
|
||||||
|
* 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.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.apache.fineract.integrationtests.common.CalendarHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.CenterDomain;
|
||||||
|
import org.apache.fineract.integrationtests.common.CenterHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.GroupHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.OfficeHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
|
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.organisation.StaffHelper;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class LoanReschedulingWithinCenterTest {
|
||||||
|
|
||||||
|
private RequestSpecification requestSpec;
|
||||||
|
private ResponseSpecification responseSpec;
|
||||||
|
private LoanTransactionHelper loanTransactionHelper;
|
||||||
|
private ResponseSpecification generalResponseSpec;
|
||||||
|
private LoanApplicationApprovalTest loanApplicationApprovalTest;
|
||||||
|
|
||||||
|
@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("rawtypes")
|
||||||
|
@Test
|
||||||
|
public void testCenterReschedulingLoansWithInterestRecalculationEnabled() {
|
||||||
|
|
||||||
|
Integer officeId = new OfficeHelper(requestSpec, responseSpec).createOffice("01 July 2007");
|
||||||
|
String name = "TestFullCreation" + new Timestamp(new java.util.Date().getTime());
|
||||||
|
String externalId = Utils.randomStringGenerator("ID_", 7, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||||
|
int staffId = StaffHelper.createStaff(requestSpec, responseSpec);
|
||||||
|
int[] groupMembers = generateGroupMembers(1, officeId);
|
||||||
|
final String centerActivationDate = "01 July 2007";
|
||||||
|
Integer centerId = CenterHelper.createCenter(name, officeId, externalId, staffId, groupMembers, centerActivationDate, requestSpec,
|
||||||
|
responseSpec);
|
||||||
|
CenterDomain center = CenterHelper.retrieveByID(centerId, requestSpec, responseSpec);
|
||||||
|
Integer groupId = groupMembers[0];
|
||||||
|
Assert.assertNotNull(center);
|
||||||
|
Assert.assertTrue(center.getStaffId() == staffId);
|
||||||
|
Assert.assertTrue(center.isActive() == true);
|
||||||
|
|
||||||
|
Integer calendarId = createCalendarMeeting(centerId);
|
||||||
|
|
||||||
|
Integer clientId = createClient(officeId);
|
||||||
|
|
||||||
|
associateClientsToGroup(groupId, clientId);
|
||||||
|
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
|
||||||
|
dateFormat.setTimeZone(Utils.getTimeZoneOfTenant());
|
||||||
|
Calendar today = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||||
|
today.add(Calendar.DAY_OF_MONTH, -14);
|
||||||
|
// CREATE A LOAN PRODUCT
|
||||||
|
final String disbursalDate = dateFormat.format(today.getTime());
|
||||||
|
final String recalculationRestFrequencyDate = "01 January 2012";
|
||||||
|
final boolean isMultiTrancheLoan = false;
|
||||||
|
|
||||||
|
// 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, isMultiTrancheLoan);
|
||||||
|
|
||||||
|
// APPLY FOR TRANCHE LOAN WITH INTEREST RECALCULATION
|
||||||
|
final Integer loanId = applyForLoanApplicationForInterestRecalculation(clientId, groupId, calendarId, loanProductID, disbursalDate,
|
||||||
|
recalculationRestFrequencyDate, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0), null);
|
||||||
|
|
||||||
|
// Test for loan account is created
|
||||||
|
Assert.assertNotNull(loanId);
|
||||||
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanId);
|
||||||
|
|
||||||
|
// Test for loan account is created, can be approved
|
||||||
|
this.loanTransactionHelper.approveLoan(disbursalDate, loanId);
|
||||||
|
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanId);
|
||||||
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
|
||||||
|
// Test for loan account approved can be disbursed
|
||||||
|
this.loanTransactionHelper.disburseLoan(disbursalDate, loanId);
|
||||||
|
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanId);
|
||||||
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
|
||||||
|
System.out.println("---------------------------------CHANGING GROUP MEETING DATE ------------------------------------------");
|
||||||
|
Calendar todaysdate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||||
|
todaysdate.add(Calendar.DAY_OF_MONTH, 14);
|
||||||
|
String oldMeetingDate = dateFormat.format(todaysdate.getTime());
|
||||||
|
todaysdate.add(Calendar.DAY_OF_MONTH, 1);
|
||||||
|
final String centerMeetingNewStartDate = dateFormat.format(todaysdate.getTime());
|
||||||
|
CalendarHelper.updateMeetingCalendarForCenter(this.requestSpec, this.responseSpec, centerId, calendarId.toString(), oldMeetingDate,
|
||||||
|
centerMeetingNewStartDate);
|
||||||
|
|
||||||
|
ArrayList loanRepaymnetSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, generalResponseSpec, loanId);
|
||||||
|
// VERIFY RESCHEDULED DATE
|
||||||
|
ArrayList dueDateLoanSchedule = (ArrayList) ((HashMap) loanRepaymnetSchedule.get(2)).get("dueDate");
|
||||||
|
assertEquals(getDateAsArray(todaysdate, 0), dueDateLoanSchedule);
|
||||||
|
|
||||||
|
// VERIFY THE INTEREST
|
||||||
|
Float interestDue = (Float) ((HashMap) loanRepaymnetSchedule.get(2)).get("interestDue");
|
||||||
|
assertEquals(String.valueOf(interestDue), "90.82");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void associateClientsToGroup(Integer groupId, Integer clientId) {
|
||||||
|
// Associate client to the group
|
||||||
|
GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupId.toString(), clientId.toString());
|
||||||
|
GroupHelper.verifyGroupMembers(this.requestSpec, this.responseSpec, groupId, clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer createClient(Integer officeId) {
|
||||||
|
// CREATE CLIENT
|
||||||
|
final String clientActivationDate = "01 July 2014";
|
||||||
|
Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, clientActivationDate, officeId.toString());
|
||||||
|
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientId);
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer createCalendarMeeting(Integer centerId) {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
|
||||||
|
dateFormat.setTimeZone(Utils.getTimeZoneOfTenant());
|
||||||
|
Calendar today = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||||
|
final String startDate = dateFormat.format(today.getTime());
|
||||||
|
final String frequency = "2"; // 2:Weekly
|
||||||
|
final String interval = "2"; // Every one week
|
||||||
|
final Integer repeatsOnDay = today.get(Calendar.DAY_OF_WEEK) - 1;
|
||||||
|
|
||||||
|
Integer calendarId = CalendarHelper.createMeetingForGroup(this.requestSpec, this.responseSpec, centerId, startDate, frequency,
|
||||||
|
interval, repeatsOnDay.toString());
|
||||||
|
System.out.println("calendarId " + calendarId);
|
||||||
|
return calendarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
@Test
|
||||||
|
public void testCenterReschedulingMultiTrancheLoansWithInterestRecalculationEnabled() {
|
||||||
|
|
||||||
|
Integer officeId = new OfficeHelper(requestSpec, responseSpec).createOffice("01 July 2007");
|
||||||
|
String name = "TestFullCreation" + new Timestamp(new java.util.Date().getTime());
|
||||||
|
String externalId = Utils.randomStringGenerator("ID_", 7, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||||
|
int staffId = StaffHelper.createStaff(requestSpec, responseSpec);
|
||||||
|
int[] groupMembers = generateGroupMembers(1, officeId);
|
||||||
|
final String centerActivationDate = "01 July 2007";
|
||||||
|
Integer centerId = CenterHelper.createCenter(name, officeId, externalId, staffId, groupMembers, centerActivationDate, requestSpec,
|
||||||
|
responseSpec);
|
||||||
|
CenterDomain center = CenterHelper.retrieveByID(centerId, requestSpec, responseSpec);
|
||||||
|
Integer groupId = groupMembers[0];
|
||||||
|
Assert.assertNotNull(center);
|
||||||
|
Assert.assertTrue(center.getStaffId() == staffId);
|
||||||
|
Assert.assertTrue(center.isActive() == true);
|
||||||
|
|
||||||
|
Integer calendarId = createCalendarMeeting(centerId);
|
||||||
|
|
||||||
|
Integer clientId = createClient(officeId);
|
||||||
|
|
||||||
|
associateClientsToGroup(groupId, clientId);
|
||||||
|
|
||||||
|
// CREATE A LOAN PRODUCT
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
|
||||||
|
dateFormat.setTimeZone(Utils.getTimeZoneOfTenant());
|
||||||
|
Calendar today = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||||
|
today.add(Calendar.DAY_OF_MONTH, -14);
|
||||||
|
// CREATE A LOAN PRODUCT
|
||||||
|
final String approveDate = dateFormat.format(today.getTime());
|
||||||
|
final String expectedDisbursementDate = dateFormat.format(today.getTime());
|
||||||
|
final String disbursementDate = dateFormat.format(today.getTime());
|
||||||
|
final String approvalAmount = "10000";
|
||||||
|
final String recalculationRestFrequencyDate = "01 January 2012";
|
||||||
|
final boolean isMultiTrancheLoan = true;
|
||||||
|
|
||||||
|
// 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, isMultiTrancheLoan);
|
||||||
|
|
||||||
|
// CREATE TRANCHES
|
||||||
|
List<HashMap> createTranches = new ArrayList<>();
|
||||||
|
createTranches.add(this.loanApplicationApprovalTest.createTrancheDetail(disbursementDate, "5000"));
|
||||||
|
createTranches.add(this.loanApplicationApprovalTest.createTrancheDetail("25 June 2016", "5000"));
|
||||||
|
|
||||||
|
// APPROVE TRANCHES
|
||||||
|
List<HashMap> approveTranches = new ArrayList<>();
|
||||||
|
approveTranches.add(this.loanApplicationApprovalTest.createTrancheDetail(disbursementDate, "5000"));
|
||||||
|
approveTranches.add(this.loanApplicationApprovalTest.createTrancheDetail("25 June 2016", "5000"));
|
||||||
|
|
||||||
|
// APPLY FOR TRANCHE LOAN WITH INTEREST RECALCULATION
|
||||||
|
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientId, groupId, calendarId, 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.disburseLoan(disbursementDate, loanID);
|
||||||
|
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||||
|
|
||||||
|
System.out.println("---------------------------------CHANGING GROUP MEETING DATE ------------------------------------------");
|
||||||
|
Calendar todaysdate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||||
|
todaysdate.add(Calendar.DAY_OF_MONTH, 14);
|
||||||
|
String oldMeetingDate = dateFormat.format(todaysdate.getTime());
|
||||||
|
todaysdate.add(Calendar.DAY_OF_MONTH, 1);
|
||||||
|
final String centerMeetingNewStartDate = dateFormat.format(todaysdate.getTime());
|
||||||
|
CalendarHelper.updateMeetingCalendarForCenter(this.requestSpec, this.responseSpec, centerId, calendarId.toString(), oldMeetingDate,
|
||||||
|
centerMeetingNewStartDate);
|
||||||
|
|
||||||
|
ArrayList loanRepaymnetSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, generalResponseSpec, loanID);
|
||||||
|
// VERIFY RESCHEDULED DATE
|
||||||
|
ArrayList dueDateLoanSchedule = (ArrayList) ((HashMap) loanRepaymnetSchedule.get(2)).get("dueDate");
|
||||||
|
assertEquals(getDateAsArray(todaysdate, 0), dueDateLoanSchedule);
|
||||||
|
|
||||||
|
// VERIFY THE INTEREST
|
||||||
|
Float interestDue = (Float) ((HashMap) loanRepaymnetSchedule.get(2)).get("interestDue");
|
||||||
|
assertEquals(String.valueOf(interestDue), "41.05");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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 boolean isMultiTrancheLoan) {
|
||||||
|
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, isMultiTrancheLoan);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, final boolean isMultiTrancheLoan) {
|
||||||
|
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
|
||||||
|
LoanProductTestBuilder builder = new LoanProductTestBuilder()
|
||||||
|
.withPrincipal("10000.00")
|
||||||
|
.withNumberOfRepayments("12")
|
||||||
|
.withRepaymentAfterEvery("2")
|
||||||
|
.withRepaymentTypeAsWeek()
|
||||||
|
.withinterestRatePerPeriod("2")
|
||||||
|
.withInterestRateFrequencyTypeAsMonths()
|
||||||
|
.withTranches(isMultiTrancheLoan)
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, Integer groupId, Integer calendarId,
|
||||||
|
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, groupId, calendarId, loanProductID, disbursementDate,
|
||||||
|
restStartDate, compoundingStartDate, repaymentStrategy, charges, graceOnInterestPayment, graceOnPrincipalPayment, tranches);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes", "unused" })
|
||||||
|
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, Integer groupId, Integer calendarId,
|
||||||
|
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").withLoanType("jlg") //
|
||||||
|
.withCalendarID(calendarId.toString()).withAmortizationTypeAsEqualInstallments() //
|
||||||
|
.withFixedEmiAmount("") //
|
||||||
|
.withTranches(tranches).withInterestTypeAsDecliningBalance() //
|
||||||
|
.withInterestCalculationPeriodTypeAsDays() //
|
||||||
|
.withInterestCalculationPeriodTypeAsDays() //
|
||||||
|
.withExpectedDisbursementDate(disbursementDate) //
|
||||||
|
.withSubmittedOnDate(disbursementDate) //
|
||||||
|
.withRestFrequencyDate(restStartDate)//
|
||||||
|
.withwithRepaymentStrategy(repaymentStrategy) //
|
||||||
|
.withCharges(charges)//
|
||||||
|
.build(clientID.toString(), groupId.toString(), loanProductID.toString(), null);
|
||||||
|
return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] generateGroupMembers(int size, int officeId) {
|
||||||
|
int[] groupMembers = new int[size];
|
||||||
|
for (int i = 0; i < groupMembers.length; i++) {
|
||||||
|
final HashMap<String, String> map = new HashMap<>();
|
||||||
|
map.put("officeId", "" + officeId);
|
||||||
|
map.put("name", Utils.randomStringGenerator("Group_Name_", 5));
|
||||||
|
map.put("externalId", Utils.randomStringGenerator("ID_", 7, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
|
||||||
|
map.put("dateFormat", "dd MMMM yyyy");
|
||||||
|
map.put("locale", "en");
|
||||||
|
map.put("active", "true");
|
||||||
|
map.put("activationDate", "04 March 2011");
|
||||||
|
|
||||||
|
groupMembers[i] = Utils.performServerPost(requestSpec, responseSpec, "/fineract-provider/api/v1/groups?"
|
||||||
|
+ Utils.TENANT_IDENTIFIER, new Gson().toJson(map), "groupId");
|
||||||
|
}
|
||||||
|
return groupMembers;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -32,6 +32,8 @@ public class CalendarHelper {
|
|||||||
private static final String BASE_URL = "/fineract-provider/api/v1/";
|
private static final String BASE_URL = "/fineract-provider/api/v1/";
|
||||||
private static final String PARENT_ENTITY_NAME = "groups/";
|
private static final String PARENT_ENTITY_NAME = "groups/";
|
||||||
private static final String ENITY_NAME = "/calendars";
|
private static final String ENITY_NAME = "/calendars";
|
||||||
|
private static final String Center_Entity = "centers/";
|
||||||
|
private static final String Edit_Calendar = "editcalendarbasedonmeetingdates/";
|
||||||
|
|
||||||
public static Integer createMeetingCalendarForGroup(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
public static Integer createMeetingCalendarForGroup(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||||
final Integer groupId, final String startDate, final String frequency, final String interval, final String repeatsOnDay) {
|
final Integer groupId, final String startDate, final String frequency, final String interval, final String repeatsOnDay) {
|
||||||
@@ -86,4 +88,43 @@ public class CalendarHelper {
|
|||||||
final Integer responseCalendarId = from(responseCalendarDetailsinJSON).get("id");
|
final Integer responseCalendarId = from(responseCalendarDetailsinJSON).get("id");
|
||||||
assertEquals("ERROR IN CREATING THE CALENDAR", generatedCalendarId, responseCalendarId);
|
assertEquals("ERROR IN CREATING THE CALENDAR", generatedCalendarId, responseCalendarId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Integer createMeetingForGroup(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||||
|
final Integer groupId, final String startDate, final String frequency, final String interval, final String repeatsOnDay) {
|
||||||
|
|
||||||
|
System.out.println("---------------------------------CREATING A MEETING CALENDAR FOR THE GROUP------------------------------");
|
||||||
|
|
||||||
|
final String CALENDAR_RESOURCE_URL = BASE_URL + Center_Entity + groupId + ENITY_NAME + "?" + Utils.TENANT_IDENTIFIER;
|
||||||
|
|
||||||
|
System.out.println(CALENDAR_RESOURCE_URL);
|
||||||
|
|
||||||
|
return Utils.performServerPost(requestSpec, responseSpec, CALENDAR_RESOURCE_URL,
|
||||||
|
getTestCalendarAsJSON(frequency, interval, repeatsOnDay, startDate), "resourceId");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer updateMeetingCalendarForCenter(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||||
|
Integer centerId, String calendarID, String oldDate, String startDate) {
|
||||||
|
|
||||||
|
System.out.println("---------------------------------UPADATING A MEETING CALENDAR FOR THE CENTER------------------------------");
|
||||||
|
|
||||||
|
final String CALENDAR_RESOURCE_URL = BASE_URL + Center_Entity + centerId + ENITY_NAME + "/" + calendarID + "?"
|
||||||
|
+ Utils.TENANT_IDENTIFIER;
|
||||||
|
|
||||||
|
System.out.println(CALENDAR_RESOURCE_URL);
|
||||||
|
|
||||||
|
return Utils.performServerPut(requestSpec, responseSpec, CALENDAR_RESOURCE_URL, getTestCalendarMeetingAsJSON(oldDate, startDate),
|
||||||
|
"resourceId");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getTestCalendarMeetingAsJSON(String oldDate, String startDate) {
|
||||||
|
final HashMap<String, String> map = new HashMap<>();
|
||||||
|
map.put("dateFormat", "dd MMMM yyyy");
|
||||||
|
map.put("locale", "en");
|
||||||
|
map.put("newMeetingDate", startDate);
|
||||||
|
map.put("presentMeetingDate", oldDate);
|
||||||
|
map.put("reschedulebasedOnMeetingDates", "true");
|
||||||
|
System.out.println("map : " + map);
|
||||||
|
return new Gson().toJson(map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* 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.calendar.data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
|
||||||
|
|
||||||
|
public class CalendarHistoryDataWrapper {
|
||||||
|
|
||||||
|
private final List<CalendarHistory> calendarHistoryList;
|
||||||
|
|
||||||
|
public CalendarHistoryDataWrapper(final Set<CalendarHistory> calendarHistoryList){
|
||||||
|
this.calendarHistoryList = new ArrayList<>();
|
||||||
|
this.calendarHistoryList.addAll(calendarHistoryList);
|
||||||
|
final Comparator<CalendarHistory> orderByDate = new Comparator<CalendarHistory>() {
|
||||||
|
@Override
|
||||||
|
public int compare(CalendarHistory calendarHistory1, CalendarHistory calendarHistory2) {
|
||||||
|
return calendarHistory1.getEndDateLocalDate().compareTo(calendarHistory2.getEndDateLocalDate());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Collections.sort(this.calendarHistoryList, orderByDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CalendarHistory getCalendarHistory(final LocalDate dueRepaymentPeriodDate) {
|
||||||
|
CalendarHistory calendarHistory = null;
|
||||||
|
for (CalendarHistory history : this.calendarHistoryList) {
|
||||||
|
if (history.getEndDateLocalDate().isAfter(dueRepaymentPeriodDate)) {
|
||||||
|
calendarHistory = history;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return calendarHistory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CalendarHistory> getCalendarHistoryList(){
|
||||||
|
return this.calendarHistoryList;
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-1
@@ -95,7 +95,7 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
|
|
||||||
@OneToMany(fetch = FetchType.EAGER)
|
@OneToMany(fetch = FetchType.EAGER)
|
||||||
@JoinColumn(name = "calendar_id")
|
@JoinColumn(name = "calendar_id")
|
||||||
private final Set<CalendarHistory> calendarHistory = new HashSet<>();
|
private Set<CalendarHistory> calendarHistory = new HashSet<>();
|
||||||
|
|
||||||
protected Calendar() {
|
protected Calendar() {
|
||||||
|
|
||||||
@@ -581,4 +581,12 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
this.startDate = startDate.toDate();
|
this.startDate = startDate.toDate();
|
||||||
this.endDate = endDate.toDate();
|
this.endDate = endDate.toDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<CalendarHistory> getCalendarHistory(){
|
||||||
|
return this.calendarHistory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateCalendarHistory(final Set<CalendarHistory> calendarHistory){
|
||||||
|
this.calendarHistory = calendarHistory;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -24,6 +24,7 @@ import java.util.Collection;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
@@ -239,7 +240,6 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
|
|||||||
if (calendarForUpdate == null) { throw new CalendarNotFoundException(calendarId); }
|
if (calendarForUpdate == null) { throw new CalendarNotFoundException(calendarId); }
|
||||||
|
|
||||||
final Date oldStartDate = calendarForUpdate.getStartDate();
|
final Date oldStartDate = calendarForUpdate.getStartDate();
|
||||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
|
||||||
// create calendar history before updating calendar
|
// create calendar history before updating calendar
|
||||||
final CalendarHistory calendarHistory = new CalendarHistory(calendarForUpdate, oldStartDate);
|
final CalendarHistory calendarHistory = new CalendarHistory(calendarForUpdate, oldStartDate);
|
||||||
|
|
||||||
@@ -288,12 +288,12 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
|
|||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
// update calendar history table only if there is a change in
|
// update calendar history table only if there is a change in
|
||||||
// calendar start date.
|
// calendar start date.
|
||||||
if (currentDate.isAfter(new LocalDate(oldStartDate))) {
|
final Date endDate = presentMeetingDate.minusDays(1).toDate();
|
||||||
final Date endDate = calendarForUpdate.getStartDateLocalDate().minusDays(1).toDate();
|
calendarHistory.updateEndDate(endDate);
|
||||||
calendarHistory.updateEndDate(endDate);
|
this.calendarHistoryRepository.save(calendarHistory);
|
||||||
this.calendarHistoryRepository.save(calendarHistory);
|
Set<CalendarHistory> history = calendarForUpdate.getCalendarHistory();
|
||||||
}
|
history.add(calendarHistory);
|
||||||
|
calendarForUpdate.updateCalendarHistory(history);
|
||||||
this.calendarRepository.saveAndFlush(calendarForUpdate);
|
this.calendarRepository.saveAndFlush(calendarForUpdate);
|
||||||
|
|
||||||
if (this.configurationDomainService.isRescheduleFutureRepaymentsEnabled() && calendarForUpdate.isRepeating()) {
|
if (this.configurationDomainService.isRescheduleFutureRepaymentsEnabled() && calendarForUpdate.isRepeating()) {
|
||||||
|
|||||||
+17
-1
@@ -19,6 +19,8 @@
|
|||||||
package org.apache.fineract.portfolio.loanaccount.data;
|
package org.apache.fineract.portfolio.loanaccount.data;
|
||||||
|
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
||||||
|
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||||
|
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
|
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||||
@@ -35,11 +37,14 @@ public class ScheduleGeneratorDTO {
|
|||||||
LocalDate recalculateFrom;
|
LocalDate recalculateFrom;
|
||||||
final Long overdurPenaltyWaitPeriod;
|
final Long overdurPenaltyWaitPeriod;
|
||||||
final FloatingRateDTO floatingRateDTO;
|
final FloatingRateDTO floatingRateDTO;
|
||||||
|
final Calendar calendar;
|
||||||
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper;
|
||||||
|
|
||||||
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
||||||
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
||||||
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance,
|
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance,
|
||||||
final LocalDate recalculateFrom, final Long overdurPenaltyWaitPeriod, final FloatingRateDTO floatingRateDTO) {
|
final LocalDate recalculateFrom, final Long overdurPenaltyWaitPeriod, final FloatingRateDTO floatingRateDTO,
|
||||||
|
final Calendar calendar, final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
|
||||||
|
|
||||||
this.loanScheduleFactory = loanScheduleFactory;
|
this.loanScheduleFactory = loanScheduleFactory;
|
||||||
this.applicationCurrency = applicationCurrency;
|
this.applicationCurrency = applicationCurrency;
|
||||||
@@ -50,6 +55,9 @@ public class ScheduleGeneratorDTO {
|
|||||||
this.overdurPenaltyWaitPeriod = overdurPenaltyWaitPeriod;
|
this.overdurPenaltyWaitPeriod = overdurPenaltyWaitPeriod;
|
||||||
this.holidayDetailDTO = holidayDetailDTO;
|
this.holidayDetailDTO = holidayDetailDTO;
|
||||||
this.floatingRateDTO = floatingRateDTO;
|
this.floatingRateDTO = floatingRateDTO;
|
||||||
|
this.calendar = calendar;
|
||||||
|
this.calendarHistoryDataWrapper = calendarHistoryDataWrapper;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanScheduleGeneratorFactory getLoanScheduleFactory() {
|
public LoanScheduleGeneratorFactory getLoanScheduleFactory() {
|
||||||
@@ -100,4 +108,12 @@ public class ScheduleGeneratorDTO {
|
|||||||
return this.floatingRateDTO;
|
return this.floatingRateDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Calendar getCalendar(){
|
||||||
|
return this.calendar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CalendarHistoryDataWrapper getCalendarHistoryDataWrapper(){
|
||||||
|
return this.calendarHistoryDataWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-2
@@ -71,7 +71,9 @@ import org.apache.fineract.organisation.staff.domain.Staff;
|
|||||||
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
||||||
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
|
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
|
||||||
import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
|
import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
|
||||||
|
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||||
|
import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||||
@@ -5032,6 +5034,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||||
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||||
|
Calendar calendar = null;
|
||||||
|
CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
|
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
|
||||||
compoundingCalendarInstance = scheduleGeneratorDTO.getCompoundingCalendarInstance();
|
compoundingCalendarInstance = scheduleGeneratorDTO.getCompoundingCalendarInstance();
|
||||||
@@ -5039,6 +5043,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
||||||
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
|
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
|
||||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
||||||
|
calendar = scheduleGeneratorDTO.getCalendar();
|
||||||
|
calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
||||||
@@ -5053,7 +5059,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
this.maxOutstandingLoanBalance, getInterestChargedFromDate(), this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
this.maxOutstandingLoanBalance, getInterestChargedFromDate(), this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
||||||
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
||||||
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
||||||
rescheduleStrategyMethod, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations);
|
rescheduleStrategyMethod, calendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations, calendarHistoryDataWrapper);
|
||||||
return loanApplicationTerms;
|
return loanApplicationTerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5270,6 +5276,12 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
final List<DisbursementData> disbursementData = getDisbursmentData();
|
final List<DisbursementData> disbursementData = getDisbursmentData();
|
||||||
|
|
||||||
|
CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||||
|
if (loanCalendar != null) {
|
||||||
|
Set<CalendarHistory> calendarHistory = loanCalendar.getCalendarHistory();
|
||||||
|
calendarHistoryDataWrapper = new CalendarHistoryDataWrapper(calendarHistory);
|
||||||
|
}
|
||||||
|
|
||||||
RecalculationFrequencyType recalculationFrequencyType = null;
|
RecalculationFrequencyType recalculationFrequencyType = null;
|
||||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||||
@@ -5290,7 +5302,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
maxOutstandingBalance, interestChargedFromDate, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
maxOutstandingBalance, interestChargedFromDate, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
||||||
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
||||||
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
||||||
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations);
|
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
||||||
|
calendarHistoryDataWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+22
-3
@@ -18,10 +18,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||||
|
|
||||||
|
|
||||||
import org.apache.fineract.organisation.holiday.service.HolidayUtil;
|
import org.apache.fineract.organisation.holiday.service.HolidayUtil;
|
||||||
import org.apache.fineract.organisation.workingdays.domain.RepaymentRescheduleType;
|
import org.apache.fineract.organisation.workingdays.domain.RepaymentRescheduleType;
|
||||||
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
|
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
|
||||||
|
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||||
|
import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
|
||||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||||
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
|
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
@@ -68,9 +71,25 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
// calendar associated with
|
// calendar associated with
|
||||||
// the loan, and we should use it in order to calculate next
|
// the loan, and we should use it in order to calculate next
|
||||||
// repayment
|
// repayment
|
||||||
LocalDate seedDate = currentCalendar.getStartDateLocalDate();
|
|
||||||
String reccuringString = currentCalendar.getRecurrence();
|
CalendarHistory calendarHistory = null;
|
||||||
dueRepaymentPeriodDate = CalendarUtils.getNewRepaymentMeetingDate(reccuringString, seedDate, dueRepaymentPeriodDate,
|
CalendarHistoryDataWrapper calendarHistoryDataWrapper = loanApplicationTerms.getCalendarHistoryDataWrapper();
|
||||||
|
if(calendarHistoryDataWrapper != null){
|
||||||
|
calendarHistory = loanApplicationTerms.getCalendarHistoryDataWrapper().getCalendarHistory(dueRepaymentPeriodDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the start date from the calendar history
|
||||||
|
LocalDate seedDate = null;
|
||||||
|
String reccuringString = null;
|
||||||
|
if (calendarHistory == null) {
|
||||||
|
seedDate = currentCalendar.getStartDateLocalDate();
|
||||||
|
reccuringString = currentCalendar.getRecurrence();
|
||||||
|
} else {
|
||||||
|
seedDate = calendarHistory.getStartDateLocalDate();
|
||||||
|
reccuringString = calendarHistory.getRecurrence();
|
||||||
|
}
|
||||||
|
|
||||||
|
dueRepaymentPeriodDate = CalendarUtils.getNewRepaymentMeetingDate(reccuringString, seedDate, lastRepaymentDate.plusDays(1),
|
||||||
loanApplicationTerms.getRepaymentEvery(),
|
loanApplicationTerms.getRepaymentEvery(),
|
||||||
CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(loanApplicationTerms.getLoanTermPeriodFrequencyType()),
|
CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(loanApplicationTerms.getLoanTermPeriodFrequencyType()),
|
||||||
holidayDetailDTO.getWorkingDays());
|
holidayDetailDTO.getWorkingDays());
|
||||||
|
|||||||
+22
-10
@@ -27,6 +27,7 @@ import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
|||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||||
|
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||||
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
|
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
|
||||||
@@ -178,6 +179,8 @@ public final class LoanApplicationTerms {
|
|||||||
|
|
||||||
private final LocalDate seedDate;
|
private final LocalDate seedDate;
|
||||||
|
|
||||||
|
private final CalendarHistoryDataWrapper calendarHistoryDataWrapper;
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
||||||
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
||||||
@@ -198,6 +201,7 @@ public final class LoanApplicationTerms {
|
|||||||
|
|
||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||||
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
|
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
|
||||||
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||||
return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery,
|
return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery,
|
||||||
repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod,
|
repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod,
|
||||||
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
||||||
@@ -207,7 +211,7 @@ public final class LoanApplicationTerms {
|
|||||||
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
|
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
|
||||||
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
||||||
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||||
preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
|
preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -224,13 +228,14 @@ public final class LoanApplicationTerms {
|
|||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, BigDecimal approvedAmount, BigDecimal annualNominalInterestRate,
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, BigDecimal approvedAmount, BigDecimal annualNominalInterestRate,
|
||||||
List<LoanTermVariationsData> loanTermVariations) {
|
List<LoanTermVariationsData> loanTermVariations) {
|
||||||
final Calendar loanCalendar = null;
|
final Calendar loanCalendar = null;
|
||||||
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||||
|
|
||||||
return assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDay, dayOfWeek,
|
return assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDay, dayOfWeek,
|
||||||
expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, inArrearsTolerance,
|
expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, inArrearsTolerance,
|
||||||
loanProductRelatedDetail, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, interestChargedFromDate,
|
loanProductRelatedDetail, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, interestChargedFromDate,
|
||||||
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType, restCalendarInstance,
|
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType, restCalendarInstance,
|
||||||
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, loanPreClosureInterestCalculationStrategy,
|
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, loanPreClosureInterestCalculationStrategy,
|
||||||
rescheduleStrategyMethod, loanCalendar, approvedAmount, annualNominalInterestRate, loanTermVariations);
|
rescheduleStrategyMethod, loanCalendar, approvedAmount, annualNominalInterestRate, loanTermVariations, calendarHistoryDataWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -245,7 +250,8 @@ public final class LoanApplicationTerms {
|
|||||||
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar, BigDecimal approvedAmount,
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar, BigDecimal approvedAmount,
|
||||||
BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations) {
|
BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations,
|
||||||
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
|
||||||
|
|
||||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||||
@@ -277,7 +283,7 @@ public final class LoanApplicationTerms {
|
|||||||
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
||||||
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||||
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
|
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -289,8 +295,8 @@ public final class LoanApplicationTerms {
|
|||||||
final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType,
|
final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType,
|
||||||
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||||
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy, BigDecimal approvedAmount,
|
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy, final Calendar loanCalendar,
|
||||||
final BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations) {
|
BigDecimal approvedAmount, final BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations) {
|
||||||
|
|
||||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||||
@@ -319,7 +325,8 @@ public final class LoanApplicationTerms {
|
|||||||
rescheduleStrategyMethod = interestRecalculationDetails.getRescheduleStrategyMethod();
|
rescheduleStrategyMethod = interestRecalculationDetails.getRescheduleStrategyMethod();
|
||||||
interestRecalculationCompoundingMethod = interestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
interestRecalculationCompoundingMethod = interestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
||||||
}
|
}
|
||||||
final Calendar loanCalendar = null;
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||||
|
|
||||||
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
||||||
repaymentEvery, repaymentPeriodFrequencyType, null, null, amortizationMethod, interestMethod, interestRatePerPeriod,
|
repaymentEvery, repaymentPeriodFrequencyType, null, null, amortizationMethod, interestMethod, interestRatePerPeriod,
|
||||||
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
||||||
@@ -329,7 +336,7 @@ public final class LoanApplicationTerms {
|
|||||||
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType,
|
rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType,
|
||||||
compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||||
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
|
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final LoanApplicationTerms applicationTerms,
|
public static LoanApplicationTerms assembleFrom(final LoanApplicationTerms applicationTerms,
|
||||||
@@ -351,7 +358,7 @@ public final class LoanApplicationTerms {
|
|||||||
applicationTerms.compoundingCalendarInstance, applicationTerms.compoundingFrequencyType,
|
applicationTerms.compoundingCalendarInstance, applicationTerms.compoundingFrequencyType,
|
||||||
applicationTerms.principalThresholdForLastInstalment, applicationTerms.installmentAmountInMultiplesOf,
|
applicationTerms.principalThresholdForLastInstalment, applicationTerms.installmentAmountInMultiplesOf,
|
||||||
applicationTerms.preClosureInterestCalculationStrategy, applicationTerms.loanCalendar,
|
applicationTerms.preClosureInterestCalculationStrategy, applicationTerms.loanCalendar,
|
||||||
applicationTerms.approvedPrincipal.getAmount(), loanTermVariations);
|
applicationTerms.approvedPrincipal.getAmount(), loanTermVariations, applicationTerms.calendarHistoryDataWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||||
@@ -372,7 +379,7 @@ public final class LoanApplicationTerms {
|
|||||||
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||||
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar,
|
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar,
|
||||||
BigDecimal approvedAmount, List<LoanTermVariationsData> loanTermVariations) {
|
BigDecimal approvedAmount, List<LoanTermVariationsData> loanTermVariations, final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
|
||||||
this.currency = currency;
|
this.currency = currency;
|
||||||
this.loanTermFrequency = loanTermFrequency;
|
this.loanTermFrequency = loanTermFrequency;
|
||||||
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
|
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
|
||||||
@@ -430,6 +437,7 @@ public final class LoanApplicationTerms {
|
|||||||
} else {
|
} else {
|
||||||
this.seedDate = this.calculatedRepaymentsStartingFromDate;
|
this.seedDate = this.calculatedRepaymentsStartingFromDate;
|
||||||
}
|
}
|
||||||
|
this.calendarHistoryDataWrapper = calendarHistoryDataWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
||||||
@@ -1422,4 +1430,8 @@ public final class LoanApplicationTerms {
|
|||||||
return this.seedDate;
|
return this.seedDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CalendarHistoryDataWrapper getCalendarHistoryDataWrapper(){
|
||||||
|
return this.calendarHistoryDataWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+29
-7
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.service;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||||
@@ -30,8 +31,10 @@ import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepos
|
|||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
||||||
import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||||
|
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
|
import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
|
||||||
|
import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
|
import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||||
@@ -88,8 +91,15 @@ public class LoanUtilService {
|
|||||||
ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||||
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
||||||
CalendarEntityType.LOANS.getValue());
|
CalendarEntityType.LOANS.getValue());
|
||||||
|
Calendar calendar = null;
|
||||||
|
CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||||
|
if (calendarInstance != null) {
|
||||||
|
calendar = calendarInstance.getCalendar();
|
||||||
|
Set<CalendarHistory> calendarHistory = calendar.getCalendarHistory();
|
||||||
|
calendarHistoryDataWrapper = new CalendarHistoryDataWrapper(calendarHistory);
|
||||||
|
}
|
||||||
LocalDate calculatedRepaymentsStartingFromDate = this.getCalculatedRepaymentsStartingFromDate(loan.getDisbursementDate(), loan,
|
LocalDate calculatedRepaymentsStartingFromDate = this.getCalculatedRepaymentsStartingFromDate(loan.getDisbursementDate(), loan,
|
||||||
calendarInstance);
|
calendarInstance, calendarHistoryDataWrapper);
|
||||||
CalendarInstance restCalendarInstance = null;
|
CalendarInstance restCalendarInstance = null;
|
||||||
CalendarInstance compoundingCalendarInstance = null;
|
CalendarInstance compoundingCalendarInstance = null;
|
||||||
Long overdurPenaltyWaitPeriod = null;
|
Long overdurPenaltyWaitPeriod = null;
|
||||||
@@ -103,7 +113,7 @@ public class LoanUtilService {
|
|||||||
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetails, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetails, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod, floatingRateDTO);
|
overdurPenaltyWaitPeriod, floatingRateDTO, calendar, calendarHistoryDataWrapper);
|
||||||
|
|
||||||
return scheduleGeneratorDTO;
|
return scheduleGeneratorDTO;
|
||||||
}
|
}
|
||||||
@@ -111,7 +121,8 @@ public class LoanUtilService {
|
|||||||
public LocalDate getCalculatedRepaymentsStartingFromDate(final Loan loan) {
|
public LocalDate getCalculatedRepaymentsStartingFromDate(final Loan loan) {
|
||||||
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
||||||
CalendarEntityType.LOANS.getValue());
|
CalendarEntityType.LOANS.getValue());
|
||||||
return this.getCalculatedRepaymentsStartingFromDate(loan.getDisbursementDate(), loan, calendarInstance);
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||||
|
return this.getCalculatedRepaymentsStartingFromDate(loan.getDisbursementDate(), loan, calendarInstance, calendarHistoryDataWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HolidayDetailDTO constructHolidayDTO(final Loan loan) {
|
private HolidayDetailDTO constructHolidayDTO(final Loan loan) {
|
||||||
@@ -146,22 +157,33 @@ public class LoanUtilService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private LocalDate getCalculatedRepaymentsStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan,
|
private LocalDate getCalculatedRepaymentsStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan,
|
||||||
final CalendarInstance calendarInstance) {
|
final CalendarInstance calendarInstance, final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
|
||||||
final Calendar calendar = calendarInstance == null ? null : calendarInstance.getCalendar();
|
final Calendar calendar = calendarInstance == null ? null : calendarInstance.getCalendar();
|
||||||
return calculateRepaymentStartingFromDate(actualDisbursementDate, loan, calendar);
|
return calculateRepaymentStartingFromDate(actualDisbursementDate, loan, calendar, calendarHistoryDataWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalDate getCalculatedRepaymentsStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan,
|
public LocalDate getCalculatedRepaymentsStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan,
|
||||||
final Calendar calendar) {
|
final Calendar calendar) {
|
||||||
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||||
if (calendar == null) { return getCalculatedRepaymentsStartingFromDate(loan); }
|
if (calendar == null) { return getCalculatedRepaymentsStartingFromDate(loan); }
|
||||||
return calculateRepaymentStartingFromDate(actualDisbursementDate, loan, calendar);
|
return calculateRepaymentStartingFromDate(actualDisbursementDate, loan, calendar, calendarHistoryDataWrapper);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalDate calculateRepaymentStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan, final Calendar calendar) {
|
private LocalDate calculateRepaymentStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan, final Calendar calendar,
|
||||||
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
|
||||||
LocalDate calculatedRepaymentsStartingFromDate = loan.getExpectedFirstRepaymentOnDate();
|
LocalDate calculatedRepaymentsStartingFromDate = loan.getExpectedFirstRepaymentOnDate();
|
||||||
if (calendar != null) {// sync repayments
|
if (calendar != null) {// sync repayments
|
||||||
|
|
||||||
|
if (calculatedRepaymentsStartingFromDate == null && !calendar.getCalendarHistory().isEmpty() &&
|
||||||
|
calendarHistoryDataWrapper != null) {
|
||||||
|
for (CalendarHistory calendarHistory : calendarHistoryDataWrapper.getCalendarHistoryList()) {
|
||||||
|
calculatedRepaymentsStartingFromDate = calendarHistory.getStartDateLocalDate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return calculatedRepaymentsStartingFromDate;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: AA - user provided first repayment date takes precedence
|
// TODO: AA - user provided first repayment date takes precedence
|
||||||
// over recalculated meeting date
|
// over recalculated meeting date
|
||||||
if (calculatedRepaymentsStartingFromDate == null) {
|
if (calculatedRepaymentsStartingFromDate == null) {
|
||||||
|
|||||||
+20
-8
@@ -83,7 +83,6 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
|||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
|
import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarRepository;
|
import org.apache.fineract.portfolio.calendar.domain.CalendarRepository;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarType;
|
import org.apache.fineract.portfolio.calendar.domain.CalendarType;
|
||||||
import org.apache.fineract.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException;
|
|
||||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
|
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
@@ -130,8 +129,10 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachin
|
|||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTrancheDisbursementCharge;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTrancheDisbursementCharge;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
@@ -219,6 +220,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
private final GuarantorDomainService guarantorDomainService;
|
private final GuarantorDomainService guarantorDomainService;
|
||||||
private final LoanUtilService loanUtilService;
|
private final LoanUtilService loanUtilService;
|
||||||
|
private final LoanSummaryWrapper loanSummaryWrapper;
|
||||||
|
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||||
@@ -245,7 +248,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final AccountAssociationsRepository accountAssociationRepository,
|
final AccountAssociationsRepository accountAssociationRepository,
|
||||||
final AccountTransferDetailRepository accountTransferDetailRepository,
|
final AccountTransferDetailRepository accountTransferDetailRepository,
|
||||||
final BusinessEventNotifierService businessEventNotifierService, final GuarantorDomainService guarantorDomainService,
|
final BusinessEventNotifierService businessEventNotifierService, final GuarantorDomainService guarantorDomainService,
|
||||||
final LoanUtilService loanUtilService) {
|
final LoanUtilService loanUtilService, final LoanSummaryWrapper loanSummaryWrapper,
|
||||||
|
final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
||||||
this.loanAssembler = loanAssembler;
|
this.loanAssembler = loanAssembler;
|
||||||
@@ -280,6 +284,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.businessEventNotifierService = businessEventNotifierService;
|
this.businessEventNotifierService = businessEventNotifierService;
|
||||||
this.guarantorDomainService = guarantorDomainService;
|
this.guarantorDomainService = guarantorDomainService;
|
||||||
this.loanUtilService = loanUtilService;
|
this.loanUtilService = loanUtilService;
|
||||||
|
this.loanSummaryWrapper = loanSummaryWrapper;
|
||||||
|
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||||
@@ -1955,6 +1961,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||||
|
final AppUser currentUser = getAppUserIfPresent();
|
||||||
|
final List<Long> existingTransactionIds = new ArrayList<>();
|
||||||
|
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||||
final Collection<Integer> loanStatuses = new ArrayList<>(Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),
|
final Collection<Integer> loanStatuses = new ArrayList<>(Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),
|
||||||
LoanStatus.APPROVED.getValue(), LoanStatus.ACTIVE.getValue()));
|
LoanStatus.APPROVED.getValue(), LoanStatus.ACTIVE.getValue()));
|
||||||
final Collection<Integer> loanTypes = new ArrayList<>(Arrays.asList(AccountType.GROUP.getValue(), AccountType.JLG.getValue()));
|
final Collection<Integer> loanTypes = new ArrayList<>(Arrays.asList(AccountType.GROUP.getValue(), AccountType.JLG.getValue()));
|
||||||
@@ -1966,16 +1975,19 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
final List<Loan> loans = this.loanRepository.findByIdsAndLoanStatusAndLoanType(loanIds, loanStatuses, loanTypes);
|
final List<Loan> loans = this.loanRepository.findByIdsAndLoanStatusAndLoanType(loanIds, loanStatuses, loanTypes);
|
||||||
List<Holiday> holidays = null;
|
List<Holiday> holidays = null;
|
||||||
|
final LocalDate recalculateFrom = null;
|
||||||
// loop through each loan to reschedule the repayment dates
|
// loop through each loan to reschedule the repayment dates
|
||||||
for (final Loan loan : loans) {
|
for (final Loan loan : loans) {
|
||||||
if (loan != null) {
|
if (loan != null) {
|
||||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
|
||||||
final String defaultUserMessage = "Meeting calendar type update is not supported";
|
|
||||||
throw new CalendarParameterUpdateNotSupportedException("jlg.loan.recalculation", defaultUserMessage);
|
|
||||||
}
|
|
||||||
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
|
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
|
||||||
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
if (reschedulebasedOnMeetingDates != null && reschedulebasedOnMeetingDates) {
|
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
|
||||||
|
loan.setHelpers(null, this.loanSummaryWrapper, this.transactionProcessingStrategy);
|
||||||
|
loan.recalculateScheduleFromLastTransaction(scheduleGeneratorDTO, existingTransactionIds,
|
||||||
|
existingReversedTransactionIds, currentUser);
|
||||||
|
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(
|
||||||
|
loan.fetchRepaymentScheduleInstallments(), loan, null);
|
||||||
|
} else if (reschedulebasedOnMeetingDates != null && reschedulebasedOnMeetingDates) {
|
||||||
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
|
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
|
||||||
holidays, workingDays, reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate);
|
holidays, workingDays, reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user