Center Rescheduling

This commit is contained in:
sachinkulkarni12
2016-03-02 17:12:31 +05:30
parent 8d160d3e7d
commit a01c1e361f
11 changed files with 635 additions and 39 deletions
@@ -0,0 +1,61 @@
/**
* 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.Set;
import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
import org.joda.time.LocalDate;
public class CalendarHistoryDataWrapper {
private final List<CalendarHistory> calendarHistoryList;
public CalendarHistoryDataWrapper(final Set<CalendarHistory> calendarHistoryList){
this.calendarHistoryList = new ArrayList<>();
this.calendarHistoryList.addAll(calendarHistoryList);
final Comparator<CalendarHistory> orderByDate = new Comparator<CalendarHistory>() {
@Override
public int compare(CalendarHistory calendarHistory1, CalendarHistory calendarHistory2) {
return calendarHistory1.getEndDateLocalDate().compareTo(calendarHistory2.getEndDateLocalDate());
}
};
Collections.sort(this.calendarHistoryList, orderByDate);
}
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;
}
}
@@ -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() {
@@ -581,4 +581,12 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
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;
}
}
@@ -24,6 +24,7 @@ import java.util.Collection;
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;
@@ -239,7 +240,6 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
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);
@@ -288,12 +288,12 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
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()) {
@@ -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;
@@ -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;
@@ -50,6 +55,9 @@ public class ScheduleGeneratorDTO {
this.overdurPenaltyWaitPeriod = overdurPenaltyWaitPeriod;
this.holidayDetailDTO = holidayDetailDTO;
this.floatingRateDTO = floatingRateDTO;
this.calendar = calendar;
this.calendarHistoryDataWrapper = calendarHistoryDataWrapper;
}
public LoanScheduleGeneratorFactory getLoanScheduleFactory() {
@@ -99,5 +107,13 @@ public class ScheduleGeneratorDTO {
public FloatingRateDTO getFloatingRateDTO() {
return this.floatingRateDTO;
}
public Calendar getCalendar(){
return this.calendar;
}
public CalendarHistoryDataWrapper getCalendarHistoryDataWrapper(){
return this.calendarHistoryDataWrapper;
}
}
@@ -71,7 +71,9 @@ import org.apache.fineract.organisation.staff.domain.Staff;
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;
@@ -5032,6 +5034,8 @@ public class Loan extends AbstractPersistable<Long> {
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();
@@ -5039,6 +5043,8 @@ public class Loan extends AbstractPersistable<Long> {
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
calendar = scheduleGeneratorDTO.getCalendar();
calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
}
BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
@@ -5053,7 +5059,7 @@ public class Loan extends AbstractPersistable<Long> {
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;
}
@@ -5269,6 +5275,12 @@ public class Loan extends AbstractPersistable<Long> {
final BigDecimal maxOutstandingBalance = getMaxOutstandingLoanBalance();
final List<DisbursementData> disbursementData = getDisbursmentData();
CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
if (loanCalendar != null) {
Set<CalendarHistory> calendarHistory = loanCalendar.getCalendarHistory();
calendarHistoryDataWrapper = new CalendarHistoryDataWrapper(calendarHistory);
}
RecalculationFrequencyType recalculationFrequencyType = null;
InterestRecalculationCompoundingMethod compoundingMethod = null;
@@ -5290,7 +5302,8 @@ public class Loan extends AbstractPersistable<Long> {
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);
}
/**
@@ -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;
@@ -68,9 +71,25 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
// 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){
calendarHistory = loanApplicationTerms.getCalendarHistoryDataWrapper().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());
@@ -27,6 +27,7 @@ import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
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.common.domain.DayOfWeekType;
@@ -177,6 +178,8 @@ public final class LoanApplicationTerms {
private Money adjustPrincipalForFlatLoans;
private final LocalDate seedDate;
private final CalendarHistoryDataWrapper calendarHistoryDataWrapper;
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
@@ -198,6 +201,7 @@ public final class LoanApplicationTerms {
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery,
repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod,
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
@@ -207,7 +211,7 @@ public final class LoanApplicationTerms {
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper);
}
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
@@ -224,13 +228,14 @@ public final class LoanApplicationTerms {
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, BigDecimal approvedAmount, BigDecimal annualNominalInterestRate,
List<LoanTermVariationsData> loanTermVariations) {
final Calendar loanCalendar = null;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
return assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDay, dayOfWeek,
expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, inArrearsTolerance,
loanProductRelatedDetail, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, interestChargedFromDate,
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType, restCalendarInstance,
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, loanPreClosureInterestCalculationStrategy,
rescheduleStrategyMethod, loanCalendar, approvedAmount, annualNominalInterestRate, loanTermVariations);
rescheduleStrategyMethod, loanCalendar, approvedAmount, annualNominalInterestRate, loanTermVariations, calendarHistoryDataWrapper);
}
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
@@ -245,7 +250,8 @@ public final class LoanApplicationTerms {
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar, BigDecimal approvedAmount,
BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations) {
BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations,
final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
@@ -277,7 +283,7 @@ public final class LoanApplicationTerms {
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper);
}
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
@@ -289,8 +295,8 @@ public final class LoanApplicationTerms {
final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType,
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy, BigDecimal approvedAmount,
final BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations) {
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy, final Calendar loanCalendar,
BigDecimal approvedAmount, final BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations) {
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
@@ -319,7 +325,8 @@ public final class LoanApplicationTerms {
rescheduleStrategyMethod = interestRecalculationDetails.getRescheduleStrategyMethod();
interestRecalculationCompoundingMethod = interestRecalculationDetails.getInterestRecalculationCompoundingMethod();
}
final Calendar loanCalendar = null;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, null, null, amortizationMethod, interestMethod, interestRatePerPeriod,
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
@@ -329,7 +336,7 @@ public final class LoanApplicationTerms {
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType,
compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper);
}
public static LoanApplicationTerms assembleFrom(final LoanApplicationTerms applicationTerms,
@@ -351,7 +358,7 @@ public final class LoanApplicationTerms {
applicationTerms.compoundingCalendarInstance, applicationTerms.compoundingFrequencyType,
applicationTerms.principalThresholdForLastInstalment, applicationTerms.installmentAmountInMultiplesOf,
applicationTerms.preClosureInterestCalculationStrategy, applicationTerms.loanCalendar,
applicationTerms.approvedPrincipal.getAmount(), loanTermVariations);
applicationTerms.approvedPrincipal.getAmount(), loanTermVariations, applicationTerms.calendarHistoryDataWrapper);
}
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
@@ -372,7 +379,7 @@ public final class LoanApplicationTerms {
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar,
BigDecimal approvedAmount, List<LoanTermVariationsData> loanTermVariations) {
BigDecimal approvedAmount, List<LoanTermVariationsData> loanTermVariations, final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
this.currency = currency;
this.loanTermFrequency = loanTermFrequency;
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
@@ -430,6 +437,7 @@ public final class LoanApplicationTerms {
} else {
this.seedDate = this.calculatedRepaymentsStartingFromDate;
}
this.calendarHistoryDataWrapper = calendarHistoryDataWrapper;
}
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -1421,5 +1429,9 @@ public final class LoanApplicationTerms {
public LocalDate getSeedDate() {
return this.seedDate;
}
public CalendarHistoryDataWrapper getCalendarHistoryDataWrapper(){
return this.calendarHistoryDataWrapper;
}
}
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.service;
import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.organisation.holiday.domain.Holiday;
@@ -30,8 +31,10 @@ import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepos
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
import org.apache.fineract.portfolio.calendar.domain.Calendar;
import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
@@ -88,8 +91,15 @@ public class LoanUtilService {
ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
CalendarEntityType.LOANS.getValue());
Calendar calendar = null;
CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
if (calendarInstance != null) {
calendar = calendarInstance.getCalendar();
Set<CalendarHistory> calendarHistory = calendar.getCalendarHistory();
calendarHistoryDataWrapper = new CalendarHistoryDataWrapper(calendarHistory);
}
LocalDate calculatedRepaymentsStartingFromDate = this.getCalculatedRepaymentsStartingFromDate(loan.getDisbursementDate(), loan,
calendarInstance);
calendarInstance, calendarHistoryDataWrapper);
CalendarInstance restCalendarInstance = null;
CalendarInstance compoundingCalendarInstance = null;
Long overdurPenaltyWaitPeriod = null;
@@ -103,7 +113,7 @@ public class LoanUtilService {
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
calculatedRepaymentsStartingFromDate, holidayDetails, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
overdurPenaltyWaitPeriod, floatingRateDTO);
overdurPenaltyWaitPeriod, floatingRateDTO, calendar, calendarHistoryDataWrapper);
return scheduleGeneratorDTO;
}
@@ -111,7 +121,8 @@ public class LoanUtilService {
public LocalDate getCalculatedRepaymentsStartingFromDate(final Loan loan) {
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
CalendarEntityType.LOANS.getValue());
return this.getCalculatedRepaymentsStartingFromDate(loan.getDisbursementDate(), loan, calendarInstance);
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
return this.getCalculatedRepaymentsStartingFromDate(loan.getDisbursementDate(), loan, calendarInstance, calendarHistoryDataWrapper);
}
private HolidayDetailDTO constructHolidayDTO(final Loan loan) {
@@ -146,22 +157,33 @@ public class LoanUtilService {
}
private LocalDate getCalculatedRepaymentsStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan,
final CalendarInstance calendarInstance) {
final CalendarInstance calendarInstance, final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
final Calendar calendar = calendarInstance == null ? null : calendarInstance.getCalendar();
return calculateRepaymentStartingFromDate(actualDisbursementDate, loan, calendar);
return calculateRepaymentStartingFromDate(actualDisbursementDate, loan, calendar, calendarHistoryDataWrapper);
}
public LocalDate getCalculatedRepaymentsStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan,
final Calendar calendar) {
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
if (calendar == null) { return getCalculatedRepaymentsStartingFromDate(loan); }
return calculateRepaymentStartingFromDate(actualDisbursementDate, loan, calendar);
return calculateRepaymentStartingFromDate(actualDisbursementDate, loan, calendar, calendarHistoryDataWrapper);
}
private LocalDate calculateRepaymentStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan, final Calendar calendar) {
private LocalDate calculateRepaymentStartingFromDate(final LocalDate actualDisbursementDate, final Loan loan, final Calendar calendar,
final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
LocalDate calculatedRepaymentsStartingFromDate = loan.getExpectedFirstRepaymentOnDate();
if (calendar != null) {// sync repayments
if (calculatedRepaymentsStartingFromDate == null && !calendar.getCalendarHistory().isEmpty() &&
calendarHistoryDataWrapper != null) {
for (CalendarHistory calendarHistory : calendarHistoryDataWrapper.getCalendarHistoryList()) {
calculatedRepaymentsStartingFromDate = calendarHistory.getStartDateLocalDate();
break;
}
return calculatedRepaymentsStartingFromDate;
}
// TODO: AA - user provided first repayment date takes precedence
// over recalculated meeting date
if (calculatedRepaymentsStartingFromDate == null) {
@@ -83,7 +83,6 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
import org.apache.fineract.portfolio.calendar.domain.CalendarRepository;
import org.apache.fineract.portfolio.calendar.domain.CalendarType;
import org.apache.fineract.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException;
import org.apache.fineract.portfolio.charge.domain.Charge;
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
@@ -130,8 +129,10 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachin
import org.apache.fineract.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTrancheDisbursementCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
@@ -219,6 +220,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final BusinessEventNotifierService businessEventNotifierService;
private final GuarantorDomainService guarantorDomainService;
private final LoanUtilService loanUtilService;
private final LoanSummaryWrapper loanSummaryWrapper;
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy;
@Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -245,7 +248,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final AccountAssociationsRepository accountAssociationRepository,
final AccountTransferDetailRepository accountTransferDetailRepository,
final BusinessEventNotifierService businessEventNotifierService, final GuarantorDomainService guarantorDomainService,
final LoanUtilService loanUtilService) {
final LoanUtilService loanUtilService, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy) {
this.context = context;
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
this.loanAssembler = loanAssembler;
@@ -280,6 +284,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.businessEventNotifierService = businessEventNotifierService;
this.guarantorDomainService = guarantorDomainService;
this.loanUtilService = loanUtilService;
this.loanSummaryWrapper = loanSummaryWrapper;
this.transactionProcessingStrategy = transactionProcessingStrategy;
}
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -1955,6 +1961,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
final WorkingDays workingDays = this.workingDaysRepository.findOne();
final AppUser currentUser = getAppUserIfPresent();
final List<Long> existingTransactionIds = new ArrayList<>();
final List<Long> existingReversedTransactionIds = new ArrayList<>();
final Collection<Integer> loanStatuses = new ArrayList<>(Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),
LoanStatus.APPROVED.getValue(), LoanStatus.ACTIVE.getValue()));
final Collection<Integer> loanTypes = new ArrayList<>(Arrays.asList(AccountType.GROUP.getValue(), AccountType.JLG.getValue()));
@@ -1966,16 +1975,19 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Loan> loans = this.loanRepository.findByIdsAndLoanStatusAndLoanType(loanIds, loanStatuses, loanTypes);
List<Holiday> holidays = null;
final LocalDate recalculateFrom = null;
// loop through each loan to reschedule the repayment dates
for (final Loan loan : loans) {
if (loan != null) {
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
final String defaultUserMessage = "Meeting calendar type update is not supported";
throw new CalendarParameterUpdateNotSupportedException("jlg.loan.recalculation", defaultUserMessage);
}
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
if (reschedulebasedOnMeetingDates != null && reschedulebasedOnMeetingDates) {
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
loan.setHelpers(null, this.loanSummaryWrapper, this.transactionProcessingStrategy);
loan.recalculateScheduleFromLastTransaction(scheduleGeneratorDTO, existingTransactionIds,
existingReversedTransactionIds, currentUser);
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(
loan.fetchRepaymentScheduleInstallments(), loan, null);
} else if (reschedulebasedOnMeetingDates != null && reschedulebasedOnMeetingDates) {
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
holidays, workingDays, reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate);
} else {