Center Rescheduling
This commit is contained in:
+61
@@ -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;
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -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()) {
|
||||
|
||||
+17
-1
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-2
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+22
-3
@@ -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());
|
||||
|
||||
+22
-10
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+29
-7
@@ -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) {
|
||||
|
||||
+20
-8
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user