Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Center rescheduling #16

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public class CalendarHelper {
private static final String BASE_URL = "/fineract-provider/api/v1/";
private static final String PARENT_ENTITY_NAME = "groups/";
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,
final Integer groupId, final String startDate, final String frequency, final String interval, final String repeatsOnDay) {
Expand Down Expand Up @@ -86,4 +88,43 @@ public static void verifyCalendarCreatedOnServer(final RequestSpecification requ
final Integer responseCalendarId = from(responseCalendarDetailsinJSON).get("id");
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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* 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.ListIterator;

import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
import org.joda.time.LocalDate;


public class CalendarHistoryDataWrapper {

private final List<CalendarHistory> calendarHistoryList;
private final ListIterator<CalendarHistory> iterator;

public CalendarHistoryDataWrapper(final List<CalendarHistory> calendarHistoryList){
if(calendarHistoryList == null){
this.calendarHistoryList = new ArrayList<>();
}else{
this.calendarHistoryList = calendarHistoryList;
final Comparator<CalendarHistory> orderByDate = new Comparator<CalendarHistory>() {
@Override
public int compare(CalendarHistory calendarHistory1, CalendarHistory calendarHistory2) {
return calendarHistory1.getEndDateLocalDate().compareTo(calendarHistory2.getEndDateLocalDate());
}
};
Collections.sort(calendarHistoryList, orderByDate);
}
iterator = this.calendarHistoryList.listIterator();
}

public boolean hasVariation(final LocalDate date) {
ListIterator<CalendarHistory> iterator = this.iterator;
return hasNext(date, iterator);
}

private boolean hasNext(final LocalDate date, ListIterator<CalendarHistory> iterator) {
boolean hasVariation = false;
if (iterator.hasNext()) {
CalendarHistory calendarHistory = iterator.next();
if (!calendarHistory.getEndDateLocalDate().isAfter(date)) {
hasVariation = true;
}
iterator.previous();
}
return hasVariation;
}


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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {

@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "calendar_id")
private final Set<CalendarHistory> calendarHistory = new HashSet<>();
private Set<CalendarHistory> calendarHistory = new HashSet<>();

protected Calendar() {

Expand Down Expand Up @@ -581,4 +581,12 @@ public void updateStartAndEndDate(final LocalDate startDate, final LocalDate end
this.startDate = startDate.toDate();
this.endDate = endDate.toDate();
}

public Set<CalendarHistory> getCalendarHistory(){
return this.calendarHistory;
}

public void updateCalendarHistory(final Set<CalendarHistory> calendarHistory){
this.calendarHistory = calendarHistory;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
Expand Down Expand Up @@ -239,7 +240,6 @@ public CommandProcessingResult updateCalendar(final JsonCommand command) {
if (calendarForUpdate == null) { throw new CalendarNotFoundException(calendarId); }

final Date oldStartDate = calendarForUpdate.getStartDate();
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
// create calendar history before updating calendar
final CalendarHistory calendarHistory = new CalendarHistory(calendarForUpdate, oldStartDate);

Expand Down Expand Up @@ -288,12 +288,12 @@ public CommandProcessingResult updateCalendar(final JsonCommand command) {
if (!changes.isEmpty()) {
// update calendar history table only if there is a change in
// calendar start date.
if (currentDate.isAfter(new LocalDate(oldStartDate))) {
final Date endDate = calendarForUpdate.getStartDateLocalDate().minusDays(1).toDate();
calendarHistory.updateEndDate(endDate);
this.calendarHistoryRepository.save(calendarHistory);
}

final Date endDate = presentMeetingDate.minusDays(1).toDate();
calendarHistory.updateEndDate(endDate);
this.calendarHistoryRepository.save(calendarHistory);
Set<CalendarHistory> history = calendarForUpdate.getCalendarHistory();
history.add(calendarHistory);
calendarForUpdate.updateCalendarHistory(history);
this.calendarRepository.saveAndFlush(calendarForUpdate);

if (this.configurationDomainService.isRescheduleFutureRepaymentsEnabled() && calendarForUpdate.isRepeating()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
package org.apache.fineract.portfolio.loanaccount.data;

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.floatingrates.data.FloatingRateDTO;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
Expand All @@ -35,11 +37,14 @@ public class ScheduleGeneratorDTO {
LocalDate recalculateFrom;
final Long overdurPenaltyWaitPeriod;
final FloatingRateDTO floatingRateDTO;
final Calendar calendar;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper;

public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
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.applicationCurrency = applicationCurrency;
Expand All @@ -50,6 +55,9 @@ public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFacto
this.overdurPenaltyWaitPeriod = overdurPenaltyWaitPeriod;
this.holidayDetailDTO = holidayDetailDTO;
this.floatingRateDTO = floatingRateDTO;
this.calendar = calendar;
this.calendarHistoryDataWrapper = calendarHistoryDataWrapper;

}

public LoanScheduleGeneratorFactory getLoanScheduleFactory() {
Expand Down Expand Up @@ -99,5 +107,13 @@ public CalendarInstance getCompoundingCalendarInstance() {
public FloatingRateDTO getFloatingRateDTO() {
return this.floatingRateDTO;
}

public Calendar getCalendar(){
return this.calendar;
}

public CalendarHistoryDataWrapper getCalendarHistoryDataWrapper(){
return this.calendarHistoryDataWrapper;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
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.CalendarHistory;
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
import org.apache.fineract.portfolio.charge.domain.Charge;
Expand Down Expand Up @@ -5032,13 +5034,17 @@ public LoanApplicationTerms constructLoanApplicationTerms(final ScheduleGenerato
InterestRecalculationCompoundingMethod compoundingMethod = null;
RecalculationFrequencyType compoundingFrequencyType = null;
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
Calendar calendar = null;
CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
compoundingCalendarInstance = scheduleGeneratorDTO.getCompoundingCalendarInstance();
recalculationFrequencyType = this.loanInterestRecalculationDetails.getRestFrequencyType();
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
calendar = scheduleGeneratorDTO.getCalendar();
calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
}

BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
Expand All @@ -5053,7 +5059,7 @@ loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDi
this.maxOutstandingLoanBalance, getInterestChargedFromDate(), this.loanProduct.getPrincipalThresholdForLastInstallment(),
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
rescheduleStrategyMethod, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations);
rescheduleStrategyMethod, calendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations, calendarHistoryDataWrapper);
return loanApplicationTerms;
}

Expand Down Expand Up @@ -5269,6 +5275,13 @@ public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency ap
final BigDecimal maxOutstandingBalance = getMaxOutstandingLoanBalance();

final List<DisbursementData> disbursementData = getDisbursmentData();

CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
if (loanCalendar != null) {
Set<CalendarHistory> calendarHistories = loanCalendar.getCalendarHistory();
List<CalendarHistory> calendarHistoryList = new ArrayList<>(calendarHistories);
calendarHistoryDataWrapper = new CalendarHistoryDataWrapper(calendarHistoryList);
}

RecalculationFrequencyType recalculationFrequencyType = null;
InterestRecalculationCompoundingMethod compoundingMethod = null;
Expand All @@ -5290,7 +5303,8 @@ public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency ap
maxOutstandingBalance, interestChargedFromDate, this.loanProduct.getPrincipalThresholdForLastInstallment(),
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations);
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
calendarHistoryDataWrapper);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
*/
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;


import org.apache.fineract.organisation.holiday.service.HolidayUtil;
import org.apache.fineract.organisation.workingdays.domain.RepaymentRescheduleType;
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.CalendarHistory;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
Expand Down Expand Up @@ -68,9 +71,26 @@ public LocalDate generateNextRepaymentDate(final LocalDate lastRepaymentDate, fi
// calendar associated with
// the loan, and we should use it in order to calculate next
// repayment
LocalDate seedDate = currentCalendar.getStartDateLocalDate();
String reccuringString = currentCalendar.getRecurrence();
dueRepaymentPeriodDate = CalendarUtils.getNewRepaymentMeetingDate(reccuringString, seedDate, dueRepaymentPeriodDate,

CalendarHistory calendarHistory = null;
CalendarHistoryDataWrapper calendarHistoryDataWrapper = loanApplicationTerms.getCalendarHistoryDataWrapper();
if(calendarHistoryDataWrapper != null &&
loanApplicationTerms.getCalendarHistoryDataWrapper().hasVariation(dueRepaymentPeriodDate)){
calendarHistory = calendarHistoryDataWrapper.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(),
CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(loanApplicationTerms.getLoanTermPeriodFrequencyType()),
holidayDetailDTO.getWorkingDays());
Expand Down
Loading