FINERACT-2017: Fix apply holidays to loans job
This commit is contained in:
committed by
Adam Saghy
parent
aff009c400
commit
8d6528408d
+18
@@ -352,6 +352,24 @@ public final class DateUtils {
|
|||||||
return dateTime == null ? null : dateTime.format(getDateTimeFormatter(format, 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
|
@NotNull
|
||||||
private static DateTimeFormatter getDateFormatter(String format, Locale locale) {
|
private static DateTimeFormatter getDateFormatter(String format, Locale locale) {
|
||||||
DateTimeFormatter formatter = DEFAULT_DATE_FORMATTER;
|
DateTimeFormatter formatter = DEFAULT_DATE_FORMATTER;
|
||||||
|
|||||||
+5
-3
@@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.loanaccount.jobs.applyholidaystoloans;
|
package org.apache.fineract.portfolio.loanaccount.jobs.applyholidaystoloans;
|
||||||
|
|
||||||
|
import static org.apache.fineract.infrastructure.core.service.DateUtils.isDateWithinRange;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -129,13 +131,13 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
|
|||||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
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.
|
// FIXME: AA do we need to apply non-working days.
|
||||||
// Assuming holiday's repayment reschedule to date cannot be
|
// Assuming holiday's repayment reschedule to date cannot be
|
||||||
// created on a non-working day.
|
// created on a non-working day.
|
||||||
|
|
||||||
adjustedRescheduleToDate = scheduledDateGenerator.generateNextRepaymentDate(adjustedRescheduleToDate, loanApplicationTerms,
|
adjustedRescheduleToDate = scheduledDateGenerator.generateNextRepaymentDateWhenHolidayApply(adjustedRescheduleToDate,
|
||||||
false);
|
loanApplicationTerms);
|
||||||
loanRepaymentScheduleInstallment.updateDueDate(adjustedRescheduleToDate);
|
loanRepaymentScheduleInstallment.updateDueDate(adjustedRescheduleToDate);
|
||||||
}
|
}
|
||||||
tmpFromDate = loanRepaymentScheduleInstallment.getDueDate();
|
tmpFromDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||||
|
|||||||
+38
@@ -358,4 +358,42 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
}
|
}
|
||||||
return adjustedDate;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-6
@@ -44,9 +44,11 @@ import java.time.temporal.ChronoUnit;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import org.apache.fineract.client.models.BusinessDateRequest;
|
import org.apache.fineract.client.models.BusinessDateRequest;
|
||||||
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
||||||
@@ -299,7 +301,7 @@ public class SchedulerJobsTestResults {
|
|||||||
final Integer loanProductID = createLoanProduct(null);
|
final Integer loanProductID = createLoanProduct(null);
|
||||||
Assertions.assertNotNull(loanProductID);
|
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);
|
Assertions.assertNotNull(loanID);
|
||||||
|
|
||||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
@@ -329,21 +331,49 @@ public class SchedulerJobsTestResults {
|
|||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
enabled = true;
|
enabled = true;
|
||||||
configId = GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, configId, enabled);
|
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, configId, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
holidayId = HolidayHelper.activateHolidays(requestSpec, responseSpec, holidayId.toString());
|
holidayId = HolidayHelper.activateHolidays(requestSpec, responseSpec, holidayId.toString());
|
||||||
Assertions.assertNotNull(holidayId);
|
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";
|
String JobName = "Apply Holidays To Loans";
|
||||||
|
|
||||||
this.schedulerJobHelper.executeAndAwaitJob(JobName);
|
this.schedulerJobHelper.executeAndAwaitJob(JobName);
|
||||||
|
|
||||||
HashMap holidayData = HolidayHelper.getHolidayById(requestSpec, responseSpec, holidayId.toString());
|
// Loan Repayment Schedule After Apply Holidays To Loans
|
||||||
ArrayList<Integer> repaymentsRescheduledDate = (ArrayList<Integer>) holidayData.get("repaymentsRescheduledTo");
|
loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
|
||||||
|
repaymentScheduleHashMap = JsonPath.from(loanDetails).get("repaymentSchedule");
|
||||||
|
periods = (ArrayList<LinkedHashMap>) repaymentScheduleHashMap.get("periods");
|
||||||
|
ArrayList<Integer> dateToApplyHolidays = null;
|
||||||
|
|
||||||
Assertions.assertEquals(repaymentsRescheduledDate, repaymentsRescheduledDate,
|
for (LinkedHashMap period : periods) {
|
||||||
"Verifying Repayment Rescheduled Date after Running Apply Holidays to Loans Scheduler Job");
|
ArrayList<Integer> fromDate = (ArrayList<Integer>) period.get("fromDate");
|
||||||
|
if (fromDate != null && Objects.equals(fromDate.get(1), repaymentsRescheduledDate.get(1))) {
|
||||||
|
dateToApplyHolidays = fromDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user