This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 50eefd2ee FINERACT-2031: Fix reschedule to next repayment date.
Schedule should shift all the remaining installments to next repayment date as
per the loan frequency.
50eefd2ee is described below
commit 50eefd2ee54463d085a8bc4b0cac4979f0bba2a2
Author: 2vinodhkumar <[email protected]>
AuthorDate: Wed Dec 27 17:01:37 2023 +0530
FINERACT-2031: Fix reschedule to next repayment date. Schedule should shift
all the remaining installments to next repayment date as per the loan frequency.
FINERACT-2031: Fix reschedule to next repayment date. Schedule should shift
all the remaining installments to next repayment date as per the loan frequency.
FINERACT-2031: Fix reschedule to next repayment date. Schedule should shift
all the remaining installments to next repayment date as per the loan frequency.
FINERACT-2031: Fix reschedule to next repayment date. Schedule should shift
all the remaining installments to next repayment date as per the loan frequency.
FINERACT-2031: Fix reschedule to next repayment date. Schedule should shift
all the remaining installments to next repayment date as per the loan frequency.
---
.../ApplyHolidaysToLoansTasklet.java | 39 +++++-
.../integrationtests/SchedulerJobsTestResults.java | 136 +++++++++++++++++++++
.../integrationtests/common/HolidayHelper.java | 23 ++++
3 files changed, 197 insertions(+), 1 deletion(-)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/applyholidaystoloans/ApplyHolidaysToLoansTasklet.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/applyholidaystoloans/ApplyHolidaysToLoansTasklet.java
index 3c3d2bd5c..690004ada 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/applyholidaystoloans/ApplyHolidaysToLoansTasklet.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/applyholidaystoloans/ApplyHolidaysToLoansTasklet.java
@@ -96,6 +96,7 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
public void applyHolidayToRepaymentScheduleDates(Loan loan, Holiday
holiday) {
LocalDate adjustedRescheduleToDate = null;
+ boolean isResheduleToNextRepaymentDate =
holiday.getReScheduleType().isResheduleToNextRepaymentDate();
if (holiday.getReScheduleType().isResheduleToNextRepaymentDate()) {
adjustedRescheduleToDate = getNextRepaymentDate(loan, holiday);
} else {
@@ -103,7 +104,11 @@ public class ApplyHolidaysToLoansTasklet implements
Tasklet {
}
if (isRepaymentScheduleAdjustmentNeeded(adjustedRescheduleToDate)) {
- adjustRepaymentSchedules(loan, holiday, adjustedRescheduleToDate);
+ if (isResheduleToNextRepaymentDate) {
+ adjustAllRepaymentSchedules(loan, holiday,
adjustedRescheduleToDate);
+ } else {
+ adjustRepaymentSchedules(loan, holiday,
adjustedRescheduleToDate);
+ }
businessEventNotifierService.notifyPostBusinessEvent(new
LoanRescheduledDueHolidayBusinessEvent(loan));
}
}
@@ -144,6 +149,38 @@ public class ApplyHolidaysToLoansTasklet implements
Tasklet {
}
}
+ private void adjustAllRepaymentSchedules(Loan loan, Holiday holiday,
LocalDate adjustedRescheduleToDate) {
+ final DefaultScheduledDateGenerator scheduledDateGenerator = new
DefaultScheduledDateGenerator();
+ ScheduleGeneratorDTO scheduleGeneratorDTO =
loanUtilService.buildScheduleGeneratorDTO(loan, holiday.getFromDate());
+ final LoanApplicationTerms loanApplicationTerms =
loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
+
+ // first repayment's from date is same as disbursement date.
+ LocalDate tmpFromDate = loan.getDisbursementDate();
+
+ // Loop through all loanRepayments
+ List<LoanRepaymentScheduleInstallment> installments =
loan.getRepaymentScheduleInstallments();
+ for (final LoanRepaymentScheduleInstallment
loanRepaymentScheduleInstallment : installments) {
+ final LocalDate oldDueDate =
loanRepaymentScheduleInstallment.getDueDate();
+
+ // update from date if it's not same as previous installment's due
+ // date.
+ if (!DateUtils.isEqual(tmpFromDate,
loanRepaymentScheduleInstallment.getFromDate())) {
+ loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
+ }
+
+ if (!DateUtils.isBefore(oldDueDate, holiday.getFromDate())) {
+ // FIXME: AA do we need to apply non-working days.
+ // Assuming holiday's repayment reschedule to date cannot be
+ // created on a non-working day.
+
+ adjustedRescheduleToDate =
scheduledDateGenerator.generateNextRepaymentDate(adjustedRescheduleToDate,
loanApplicationTerms,
+ false);
+
loanRepaymentScheduleInstallment.updateDueDate(adjustedRescheduleToDate);
+ }
+ tmpFromDate = loanRepaymentScheduleInstallment.getDueDate();
+ }
+ }
+
private LocalDate getNextRepaymentDate(Loan loan, Holiday holiday) {
LocalDate adjustedRescheduleToDate = null;
final LocalDate rescheduleToDate = holiday.getToDate();
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
index f8ec562bd..166019e81 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
@@ -402,6 +402,142 @@ public class SchedulerJobsTestResults {
Assertions.assertEquals(fromDateDayBefore, fromDateDayAfter, message);
}
+ @Test
+ public void testApplyType1HolidaysToLoansJobOutcome() throws
InterruptedException {
+ this.loanTransactionHelper = new LoanTransactionHelper(requestSpec,
responseSpec);
+
+ final Integer clientID = ClientHelper.createClient(requestSpec,
responseSpec);
+ Assertions.assertNotNull(clientID);
+
+ Integer holidayId = HolidayHelper.createTyoe1Holidays(requestSpec,
responseSpec);
+ Assertions.assertNotNull(holidayId);
+
+ final Integer loanProductID = createLoanProduct(null);
+ Assertions.assertNotNull(loanProductID);
+
+ final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "04 January 2024");
+ Assertions.assertNotNull(loanID);
+
+ HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
+ LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
+
+ loanStatusHashMap = this.loanTransactionHelper.approveLoan("04 January
2024", loanID);
+ LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
+
+ String loanDetails =
this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
+ loanStatusHashMap =
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("04 January
2024", loanID,
+
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
+ LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
+
+ // Retrieving All Global Configuration details
+ final ArrayList<HashMap> globalConfig =
GlobalConfigurationHelper.getAllGlobalConfigurations(requestSpec, responseSpec);
+ Assertions.assertNotNull(globalConfig);
+
+ // Updating Value for reschedule-repayments-on-holidays Global
+ // Configuration
+ Integer configId = (Integer) globalConfig.get(3).get("id");
+ Assertions.assertNotNull(configId);
+
+ HashMap configData =
GlobalConfigurationHelper.getGlobalConfigurationById(requestSpec, responseSpec,
configId.toString());
+ Assertions.assertNotNull(configData);
+
+ Boolean enabled = (Boolean) globalConfig.get(3).get("enabled");
+
+ if (!enabled) {
+ enabled = true;
+
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec,
responseSpec, configId, enabled);
+ }
+
+ holidayId = HolidayHelper.activateHolidays(requestSpec, responseSpec,
holidayId.toString());
+ Assertions.assertNotNull(holidayId);
+
+ HashMap holidayData = HolidayHelper.getHolidayById(requestSpec,
responseSpec, holidayId.toString());
+
+ LinkedHashMap repaymentScheduleHashMap =
JsonPath.from(loanDetails).get("repaymentSchedule");
+ ArrayList<LinkedHashMap> periods = (ArrayList<LinkedHashMap>)
repaymentScheduleHashMap.get("periods");
+ String JobName = "Apply Holidays To Loans";
+
+ this.schedulerJobHelper.executeAndAwaitJob(JobName);
+
+ // Loan Repayment Schedule After Apply Holidays To Loans
+ loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec,
responseSpec, loanID);
+ repaymentScheduleHashMap =
JsonPath.from(loanDetails).get("repaymentSchedule");
+ ArrayList<LinkedHashMap> periodsAfterRescheduleApplied =
(ArrayList<LinkedHashMap>) repaymentScheduleHashMap.get("periods");
+
+ ArrayList<Integer> fromDateValues = (ArrayList<Integer>)
periods.get(1).get("fromDate");
+ LocalDate fromDate = LocalDate.of(fromDateValues.get(0),
fromDateValues.get(1), fromDateValues.get(2));
+ ArrayList<Integer> dueDateValues = (ArrayList<Integer>)
periods.get(1).get("dueDate");
+ LocalDate dueDate = LocalDate.of(dueDateValues.get(0),
dueDateValues.get(1), dueDateValues.get(2));
+ Assertions.assertEquals(LocalDate.of(2024, 1, 4), fromDate,
+ "Verifying Repayment Rescheduled Date before Running Apply
Holidays to Loans Scheduler Job");
+ Assertions.assertEquals(LocalDate.of(2024, 2, 4), dueDate,
+ "Verifying Repayment Rescheduled Date before Running Apply
Holidays to Loans Scheduler Job");
+
+ fromDateValues = (ArrayList<Integer>) periods.get(2).get("fromDate");
+ fromDate = LocalDate.of(fromDateValues.get(0), fromDateValues.get(1),
fromDateValues.get(2));
+ dueDateValues = (ArrayList<Integer>) periods.get(2).get("dueDate");
+ dueDate = LocalDate.of(dueDateValues.get(0), dueDateValues.get(1),
dueDateValues.get(2));
+ Assertions.assertEquals(LocalDate.of(2024, 2, 4), fromDate,
+ "Verifying Repayment Rescheduled Date before Running Apply
Holidays to Loans Scheduler Job");
+ Assertions.assertEquals(LocalDate.of(2024, 3, 4), dueDate,
+ "Verifying Repayment Rescheduled Date before Running Apply
Holidays to Loans Scheduler Job");
+
+ fromDateValues = (ArrayList<Integer>) periods.get(3).get("fromDate");
+ fromDate = LocalDate.of(fromDateValues.get(0), fromDateValues.get(1),
fromDateValues.get(2));
+ dueDateValues = (ArrayList<Integer>) periods.get(3).get("dueDate");
+ dueDate = LocalDate.of(dueDateValues.get(0), dueDateValues.get(1),
dueDateValues.get(2));
+ Assertions.assertEquals(LocalDate.of(2024, 3, 4), fromDate,
+ "Verifying Repayment Rescheduled Date before Running Apply
Holidays to Loans Scheduler Job");
+ Assertions.assertEquals(LocalDate.of(2024, 4, 4), dueDate,
+ "Verifying Repayment Rescheduled Date before Running Apply
Holidays to Loans Scheduler Job");
+
+ fromDateValues = (ArrayList<Integer>) periods.get(4).get("fromDate");
+ fromDate = LocalDate.of(fromDateValues.get(0), fromDateValues.get(1),
fromDateValues.get(2));
+ dueDateValues = (ArrayList<Integer>) periods.get(4).get("dueDate");
+ dueDate = LocalDate.of(dueDateValues.get(0), dueDateValues.get(1),
dueDateValues.get(2));
+ Assertions.assertEquals(LocalDate.of(2024, 4, 4), fromDate,
+ "Verifying Repayment Rescheduled Date before Running Apply
Holidays to Loans Scheduler Job");
+ Assertions.assertEquals(LocalDate.of(2024, 5, 4), dueDate,
+ "Verifying Repayment Rescheduled Date before Running Apply
Holidays to Loans Scheduler Job");
+
+ fromDateValues = (ArrayList<Integer>)
periodsAfterRescheduleApplied.get(1).get("fromDate");
+ fromDate = LocalDate.of(fromDateValues.get(0), fromDateValues.get(1),
fromDateValues.get(2));
+ dueDateValues = (ArrayList<Integer>)
periodsAfterRescheduleApplied.get(1).get("dueDate");
+ dueDate = LocalDate.of(dueDateValues.get(0), dueDateValues.get(1),
dueDateValues.get(2));
+ Assertions.assertEquals(LocalDate.of(2024, 1, 4), fromDate,
+ "Verifying Repayment Rescheduled Date after Running Apply
Holidays to Loans Scheduler Job");
+ Assertions.assertEquals(LocalDate.of(2024, 2, 4), dueDate,
+ "Verifying Repayment Rescheduled Date after Running Apply
Holidays to Loans Scheduler Job");
+
+ fromDateValues = (ArrayList<Integer>)
periodsAfterRescheduleApplied.get(2).get("fromDate");
+ fromDate = LocalDate.of(fromDateValues.get(0), fromDateValues.get(1),
fromDateValues.get(2));
+ dueDateValues = (ArrayList<Integer>)
periodsAfterRescheduleApplied.get(2).get("dueDate");
+ dueDate = LocalDate.of(dueDateValues.get(0), dueDateValues.get(1),
dueDateValues.get(2));
+ Assertions.assertEquals(LocalDate.of(2024, 2, 4), fromDate,
+ "Verifying Repayment Rescheduled Date after Running Apply
Holidays to Loans Scheduler Job");
+ Assertions.assertEquals(LocalDate.of(2024, 3, 4), dueDate,
+ "Verifying Repayment Rescheduled Date after Running Apply
Holidays to Loans Scheduler Job");
+
+ fromDateValues = (ArrayList<Integer>)
periodsAfterRescheduleApplied.get(3).get("fromDate");
+ fromDate = LocalDate.of(fromDateValues.get(0), fromDateValues.get(1),
fromDateValues.get(2));
+ dueDateValues = (ArrayList<Integer>)
periodsAfterRescheduleApplied.get(3).get("dueDate");
+ dueDate = LocalDate.of(dueDateValues.get(0), dueDateValues.get(1),
dueDateValues.get(2));
+ Assertions.assertEquals(LocalDate.of(2024, 3, 4), fromDate,
+ "Verifying Repayment Rescheduled Date after Running Apply
Holidays to Loans Scheduler Job");
+ Assertions.assertEquals(LocalDate.of(2024, 5, 4), dueDate,
+ "Verifying Repayment Rescheduled Date after Running Apply
Holidays to Loans Scheduler Job");
+
+ fromDateValues = (ArrayList<Integer>)
periodsAfterRescheduleApplied.get(4).get("fromDate");
+ fromDate = LocalDate.of(fromDateValues.get(0), fromDateValues.get(1),
fromDateValues.get(2));
+ dueDateValues = (ArrayList<Integer>)
periodsAfterRescheduleApplied.get(4).get("dueDate");
+ dueDate = LocalDate.of(dueDateValues.get(0), dueDateValues.get(1),
dueDateValues.get(2));
+ Assertions.assertEquals(LocalDate.of(2024, 5, 4), fromDate,
+ "Verifying Repayment Rescheduled Date after Running Apply
Holidays to Loans Scheduler Job");
+ Assertions.assertEquals(LocalDate.of(2024, 6, 4), dueDate,
+ "Verifying Repayment Rescheduled Date after Running Apply
Holidays to Loans Scheduler Job");
+
+ }
+
@Test
public void testApplyDueFeeChargesForSavingsJobOutcome() throws
InterruptedException {
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec,
responseSpec);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/HolidayHelper.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/HolidayHelper.java
index 32f9a08e4..163057505 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/HolidayHelper.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/HolidayHelper.java
@@ -64,6 +64,25 @@ public class HolidayHelper {
return HolidayCreateJson;
}
+ public static String getCreateType1HolidayDataAsJSON() {
+ final HashMap<String, Object> map = new HashMap<>();
+ List<HashMap<String, String>> offices = new ArrayList<HashMap<String,
String>>();
+ HashMap<String, String> officeMap = new HashMap<>();
+ officeMap.put("officeId", OFFICE_ID);
+ offices.add(officeMap);
+
+ map.put("offices", offices);
+ map.put("locale", "en");
+ map.put("dateFormat", "dd MMMM yyyy");
+ map.put("name", Utils.uniqueRandomStringGenerator("HOLIDAY_", 5));
+ map.put("fromDate", "04 April 2024");
+ map.put("toDate", "04 April 2024");
+ map.put("reschedulingType", 1);
+ String HolidayCreateJson = new Gson().toJson(map);
+ LOG.info("{}", HolidayCreateJson);
+ return HolidayCreateJson;
+ }
+
public static String getActivateHolidayDataAsJSON() {
final HashMap<String, String> map = new HashMap<>();
String activateHoliday = new Gson().toJson(map);
@@ -75,6 +94,10 @@ public class HolidayHelper {
return Utils.performServerPost(requestSpec, responseSpec,
CREATE_HOLIDAY_URL, getCreateHolidayDataAsJSON(), "resourceId");
}
+ public static Integer createTyoe1Holidays(final RequestSpecification
requestSpec, final ResponseSpecification responseSpec) {
+ return Utils.performServerPost(requestSpec, responseSpec,
CREATE_HOLIDAY_URL, getCreateType1HolidayDataAsJSON(), "resourceId");
+ }
+
public static Integer activateHolidays(final RequestSpecification
requestSpec, final ResponseSpecification responseSpec,
final String holidayID) {
final String ACTIVATE_HOLIDAY_URL = HOLIDAYS_URL + "/" + holidayID +
"?command=activate&" + Utils.TENANT_IDENTIFIER;