blob: 09b721932ffce1891482847f3ffd62553a4b2315 [file] [log] [blame]
/**
* 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.savings.domain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
import org.apache.fineract.portfolio.savings.domain.interest.CompoundInterestHelper;
import org.apache.fineract.portfolio.savings.domain.interest.PostingPeriod;
import org.joda.time.LocalDate;
public final class SavingsHelper {
AccountTransfersReadPlatformService accountTransfersReadPlatformService = null;
public SavingsHelper(AccountTransfersReadPlatformService accountTransfersReadPlatformService) {
this.accountTransfersReadPlatformService = accountTransfersReadPlatformService;
}
private final CompoundInterestHelper compoundInterestHelper = new CompoundInterestHelper();
public List<LocalDateInterval> determineInterestPostingPeriods(final LocalDate startInterestCalculationLocalDate,
final LocalDate interestPostingUpToDate, final SavingsPostingInterestPeriodType postingPeriodType,
final Integer financialYearBeginningMonth) {
final List<LocalDateInterval> postingPeriods = new ArrayList<>();
LocalDate periodStartDate = startInterestCalculationLocalDate;
LocalDate periodEndDate = periodStartDate;
while (!periodStartDate.isAfter(interestPostingUpToDate) && !periodEndDate.isAfter(interestPostingUpToDate)) {
final LocalDate interestPostingLocalDate = determineInterestPostingPeriodEndDateFrom(periodStartDate, postingPeriodType,
interestPostingUpToDate, financialYearBeginningMonth);
periodEndDate = interestPostingLocalDate.minusDays(1);
postingPeriods.add(LocalDateInterval.create(periodStartDate, periodEndDate));
periodEndDate = interestPostingLocalDate;
periodStartDate = interestPostingLocalDate;
}
return postingPeriods;
}
private LocalDate determineInterestPostingPeriodEndDateFrom(final LocalDate periodStartDate,
final SavingsPostingInterestPeriodType interestPostingPeriodType, final LocalDate interestPostingUpToDate,
Integer financialYearBeginningMonth) {
LocalDate periodEndDate = interestPostingUpToDate;
final Integer monthOfYear = periodStartDate.getMonthOfYear();
financialYearBeginningMonth--;
if (financialYearBeginningMonth == 0) financialYearBeginningMonth = 12;
final ArrayList<LocalDate> quarterlyDates = new ArrayList<>();
quarterlyDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth).dayOfMonth().withMaximumValue());
quarterlyDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth).plusMonths(3).withYear(periodStartDate.getYear())
.dayOfMonth().withMaximumValue());
quarterlyDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth).plusMonths(6).withYear(periodStartDate.getYear())
.dayOfMonth().withMaximumValue());
quarterlyDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth).plusMonths(9).withYear(periodStartDate.getYear())
.dayOfMonth().withMaximumValue());
Collections.sort(quarterlyDates);
final ArrayList<LocalDate> biannualDates = new ArrayList<>();
biannualDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth).dayOfMonth().withMaximumValue());
biannualDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth).plusMonths(6).withYear(periodStartDate.getYear())
.dayOfMonth().withMaximumValue());
Collections.sort(biannualDates);
boolean isEndDateSet = false;
switch (interestPostingPeriodType) {
case INVALID:
break;
case MONTHLY:
// produce period end date on last day of current month
periodEndDate = periodStartDate.dayOfMonth().withMaximumValue();
break;
case QUATERLY:
for (LocalDate quarterlyDate : quarterlyDates) {
if (quarterlyDate.isAfter(periodStartDate)) {
periodEndDate = quarterlyDate;
isEndDateSet = true;
break;
}
}
if (!isEndDateSet) periodEndDate = quarterlyDates.get(0).plusYears(1).dayOfMonth().withMaximumValue();
break;
case BIANNUAL:
for (LocalDate biannualDate : biannualDates) {
if (biannualDate.isAfter(periodStartDate)) {
periodEndDate = biannualDate;
isEndDateSet = true;
break;
}
}
if (!isEndDateSet) periodEndDate = biannualDates.get(0).plusYears(1).dayOfMonth().withMaximumValue();
break;
case ANNUAL:
if (financialYearBeginningMonth < monthOfYear) {
periodEndDate = periodStartDate.withMonthOfYear(financialYearBeginningMonth);
periodEndDate = periodEndDate.plusYears(1);
} else {
periodEndDate = periodStartDate.withMonthOfYear(financialYearBeginningMonth);
}
periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
break;
}
// interest posting always occurs on next day after the period end date.
periodEndDate = periodEndDate.plusDays(1);
return periodEndDate;
}
public Money calculateInterestForAllPostingPeriods(final MonetaryCurrency currency, final List<PostingPeriod> allPeriods,
LocalDate accountLockedUntil, Boolean immediateWithdrawalOfInterest) {
return this.compoundInterestHelper.calculateInterestForAllPostingPeriods(currency, allPeriods, accountLockedUntil,
immediateWithdrawalOfInterest);
}
public Collection<Long> fetchPostInterestTransactionIds(Long accountId) {
return this.accountTransfersReadPlatformService.fetchPostInterestTransactionIds(accountId);
}
}