Skip to content

Commit

Permalink
FINERACT-2017: Fix apply holidays to loans job
Browse files Browse the repository at this point in the history
  • Loading branch information
mariiaKraievska authored and adamsaghy committed Dec 19, 2023
1 parent aff009c commit 8d65284
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,24 @@ public static String format(LocalDateTime dateTime, String format, Locale locale
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -129,13 +131,13 @@ private void adjustRepaymentSchedules(Loan loan, Holiday holiday, LocalDate adju
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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,4 +358,42 @@ public LocalDate generateNextScheduleDateStartingFromDisburseDateOrRescheduleDat
}
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@
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;
Expand Down Expand Up @@ -299,7 +301,7 @@ public void testApplyHolidaysToLoansJobOutcome() throws InterruptedException {
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);
Expand Down Expand Up @@ -329,21 +331,49 @@ public void testApplyHolidaysToLoansJobOutcome() throws InterruptedException {

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
Expand Down

0 comments on commit 8d65284

Please sign in to comment.