| /** |
| * 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); |
| } |
| } |