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 8d6528408 FINERACT-2017: Fix apply holidays to loans job
8d6528408 is described below
commit 8d6528408df6ca9431295c87c5320a754ff48279
Author: mariiaKraievska <[email protected]>
AuthorDate: Tue Dec 19 00:07:00 2023 +0200
FINERACT-2017: Fix apply holidays to loans job
---
.../infrastructure/core/service/DateUtils.java | 18 ++++++++++
.../ApplyHolidaysToLoansTasklet.java | 8 +++--
.../domain/DefaultScheduledDateGenerator.java | 38 ++++++++++++++++++++
.../integrationtests/SchedulerJobsTestResults.java | 42 ++++++++++++++++++----
4 files changed, 97 insertions(+), 9 deletions(-)
diff --git
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java
index d706e8fd5..c8a9ccb6f 100644
---
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java
+++
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java
@@ -352,6 +352,24 @@ public final class DateUtils {
return dateTime == null ? null :
dateTime.format(getDateTimeFormatter(format, locale));
}
+ /**
+ * Checks if a specific date falls within a given range (inclusive).
+ *
+ * @param targetDate
+ * the date to be checked
+ * @param startDate
+ * the start date of the range
+ * @param endDate
+ * the end date of the range
+ * @return true if targetDate is within range or equal to start/end dates,
otherwise false
+ */
+ public static boolean isDateWithinRange(LocalDate targetDate, LocalDate
startDate, LocalDate endDate) {
+ if (targetDate == null || startDate == null || endDate == null) {
+ throw new IllegalArgumentException("Dates must not be null");
+ }
+ return !targetDate.isBefore(startDate) && !targetDate.isAfter(endDate);
+ }
+
@NotNull
private static DateTimeFormatter getDateFormatter(String format, Locale
locale) {
DateTimeFormatter formatter = DEFAULT_DATE_FORMATTER;
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 cf77e23c6..67bbeeac6 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
@@ -18,6 +18,8 @@
*/
package org.apache.fineract.portfolio.loanaccount.jobs.applyholidaystoloans;
+import static
org.apache.fineract.infrastructure.core.service.DateUtils.isDateWithinRange;
+
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
@@ -129,13 +131,13 @@ public class ApplyHolidaysToLoansTasklet implements
Tasklet {
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
}
- if (!DateUtils.isBefore(oldDueDate, holiday.getFromDate())) {
+ if (isDateWithinRange(oldDueDate, holiday.getFromDate(),
holiday.getToDate())) {
// 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);
+ adjustedRescheduleToDate =
scheduledDateGenerator.generateNextRepaymentDateWhenHolidayApply(adjustedRescheduleToDate,
+ loanApplicationTerms);
loanRepaymentScheduleInstallment.updateDueDate(adjustedRescheduleToDate);
}
tmpFromDate = loanRepaymentScheduleInstallment.getDueDate();
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
index 72e529af0..5108bff37 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
@@ -358,4 +358,42 @@ public class DefaultScheduledDateGenerator implements
ScheduledDateGenerator {
}
return adjustedDate;
}
+
+ public LocalDate generateNextRepaymentDateWhenHolidayApply(final LocalDate
lastRepaymentDate,
+ final LoanApplicationTerms loanApplicationTerms) {
+ LocalDate seedDate;
+ String reccuringString;
+ Calendar currentCalendar = loanApplicationTerms.getLoanCalendar();
+ LocalDate dueRepaymentPeriodDate = lastRepaymentDate;
+ dueRepaymentPeriodDate = (LocalDate)
CalendarUtils.adjustDate(dueRepaymentPeriodDate,
loanApplicationTerms.getSeedDate(),
+ loanApplicationTerms.getRepaymentPeriodFrequencyType());
+ if (currentCalendar != null) {
+ // If we have currentCalendar object, this means there is a
+ // calendar associated with
+ // the loan, and we should use it in order to calculate next
+ // repayment
+
+ CalendarHistory calendarHistory = null;
+ CalendarHistoryDataWrapper calendarHistoryDataWrapper =
loanApplicationTerms.getCalendarHistoryDataWrapper();
+ if (calendarHistoryDataWrapper != null) {
+ calendarHistory =
loanApplicationTerms.getCalendarHistoryDataWrapper().getCalendarHistory(dueRepaymentPeriodDate);
+ }
+
+ // get the start date from the calendar history
+ if (calendarHistory == null) {
+ seedDate = currentCalendar.getStartDateLocalDate();
+ reccuringString = currentCalendar.getRecurrence();
+ } else {
+ seedDate = calendarHistory.getStartDate();
+ reccuringString = calendarHistory.getRecurrence();
+ }
+
+ dueRepaymentPeriodDate =
CalendarUtils.getNextRepaymentMeetingDate(reccuringString, seedDate,
lastRepaymentDate,
+ loanApplicationTerms.getRepaymentEvery(),
+
CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(loanApplicationTerms.getLoanTermPeriodFrequencyType()),
+ loanApplicationTerms.isSkipRepaymentOnFirstDayofMonth(),
loanApplicationTerms.getNumberOfdays());
+ }
+
+ return dueRepaymentPeriodDate;
+ }
}
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 bb8d478b7..eb410a05d 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
@@ -44,9 +44,11 @@ import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import java.util.TimeZone;
import org.apache.fineract.client.models.BusinessDateRequest;
import
org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
@@ -299,7 +301,7 @@ public class SchedulerJobsTestResults {
final Integer loanProductID = createLoanProduct(null);
Assertions.assertNotNull(loanProductID);
- final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "10 January 2013");
+ final Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), null, "01 January 2013");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap =
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
@@ -329,21 +331,49 @@ public class SchedulerJobsTestResults {
if (!enabled) {
enabled = true;
- configId =
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec,
responseSpec, configId, enabled);
+
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec,
responseSpec, configId, enabled);
}
holidayId = HolidayHelper.activateHolidays(requestSpec, responseSpec,
holidayId.toString());
Assertions.assertNotNull(holidayId);
+ HashMap holidayData = HolidayHelper.getHolidayById(requestSpec,
responseSpec, holidayId.toString());
+ ArrayList<Integer> repaymentsRescheduledDate = (ArrayList<Integer>)
holidayData.get("repaymentsRescheduledTo");
+
+ // Loan Repayment Schedule Before Apply Holidays To Loans
+ LinkedHashMap repaymentScheduleHashMap =
JsonPath.from(loanDetails).get("repaymentSchedule");
+ ArrayList<LinkedHashMap> periods = (ArrayList<LinkedHashMap>)
repaymentScheduleHashMap.get("periods");
+
+ for (LinkedHashMap period : periods) {
+ ArrayList<Integer> fromDate = (ArrayList<Integer>)
period.get("fromDate");
+ if (fromDate != null && Objects.equals(fromDate.get(1),
repaymentsRescheduledDate.get(1))) {
+ Assertions.assertNotEquals(repaymentsRescheduledDate.get(2),
fromDate.get(2),
+ "Verifying Repayment Rescheduled Day before Running
Apply Holidays to Loans Scheduler Job");
+ }
+ }
+
String JobName = "Apply Holidays To Loans";
this.schedulerJobHelper.executeAndAwaitJob(JobName);
- HashMap holidayData = HolidayHelper.getHolidayById(requestSpec,
responseSpec, holidayId.toString());
- ArrayList<Integer> repaymentsRescheduledDate = (ArrayList<Integer>)
holidayData.get("repaymentsRescheduledTo");
+ // Loan Repayment Schedule After Apply Holidays To Loans
+ loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec,
responseSpec, loanID);
+ repaymentScheduleHashMap =
JsonPath.from(loanDetails).get("repaymentSchedule");
+ periods = (ArrayList<LinkedHashMap>)
repaymentScheduleHashMap.get("periods");
+ ArrayList<Integer> dateToApplyHolidays = null;
+
+ for (LinkedHashMap period : periods) {
+ ArrayList<Integer> fromDate = (ArrayList<Integer>)
period.get("fromDate");
+ if (fromDate != null && Objects.equals(fromDate.get(1),
repaymentsRescheduledDate.get(1))) {
+ dateToApplyHolidays = fromDate;
+ }
+ }
- Assertions.assertEquals(repaymentsRescheduledDate,
repaymentsRescheduledDate,
- "Verifying Repayment Rescheduled Date after Running Apply
Holidays to Loans Scheduler Job");
+ Assertions.assertNotNull(dateToApplyHolidays);
+ Assertions.assertEquals(repaymentsRescheduledDate.get(0),
dateToApplyHolidays.get(0),
+ "Verifying Repayment Rescheduled Year after Running Apply
Holidays to Loans Scheduler Job");
+ Assertions.assertEquals(repaymentsRescheduledDate.get(2),
dateToApplyHolidays.get(2),
+ "Verifying Repayment Rescheduled Day after Running Apply
Holidays to Loans Scheduler Job");
}
@Test