FINERACT-2412: Full term tranche - Schedule handling and Calculations
This commit is contained in:
committed by
Adam Saghy
parent
3e197e367b
commit
09031aa5a7
+11
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
|
||||
/**
|
||||
@@ -34,10 +35,19 @@ public class RepaymentScheduleRelatedLoanData {
|
||||
private final BigDecimal netDisbursalAmount;
|
||||
private final BigDecimal inArrearsTolerance;
|
||||
private final BigDecimal totalFeeChargesAtDisbursement;
|
||||
@Getter
|
||||
private final boolean allowFullTermForTranche;
|
||||
|
||||
public RepaymentScheduleRelatedLoanData(final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate,
|
||||
final CurrencyData currency, final BigDecimal principal, final BigDecimal inArrearsTolerance,
|
||||
final BigDecimal totalFeeChargesAtDisbursement) {
|
||||
this(expectedDisbursementDate, actualDisbursementDate, currency, principal, inArrearsTolerance, totalFeeChargesAtDisbursement,
|
||||
false);
|
||||
}
|
||||
|
||||
public RepaymentScheduleRelatedLoanData(final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate,
|
||||
final CurrencyData currency, final BigDecimal principal, final BigDecimal inArrearsTolerance,
|
||||
final BigDecimal totalFeeChargesAtDisbursement, final boolean allowFullTermForTranche) {
|
||||
this.expectedDisbursementDate = expectedDisbursementDate;
|
||||
this.actualDisbursementDate = actualDisbursementDate;
|
||||
this.currency = currency;
|
||||
@@ -45,6 +55,7 @@ public class RepaymentScheduleRelatedLoanData {
|
||||
this.inArrearsTolerance = inArrearsTolerance;
|
||||
this.totalFeeChargesAtDisbursement = totalFeeChargesAtDisbursement;
|
||||
this.netDisbursalAmount = this.principal.subtract(this.totalFeeChargesAtDisbursement);
|
||||
this.allowFullTermForTranche = allowFullTermForTranche;
|
||||
}
|
||||
|
||||
public LocalDate disbursementDate() {
|
||||
|
||||
+1
-4
@@ -427,6 +427,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
@Column(name = "enable_installment_level_delinquency", nullable = false)
|
||||
private boolean enableInstallmentLevelDelinquency = false;
|
||||
|
||||
@Getter
|
||||
@Column(name = "allow_full_term_for_tranche", nullable = false)
|
||||
private boolean allowFullTermForTranche = false;
|
||||
|
||||
@@ -1787,10 +1788,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
this.enableInstallmentLevelDelinquency = enableInstallmentLevelDelinquency;
|
||||
}
|
||||
|
||||
public boolean isAllowFullTermForTranche() {
|
||||
return this.allowFullTermForTranche;
|
||||
}
|
||||
|
||||
public void updateAllowFullTermForTranche(boolean allowFullTermForTranche) {
|
||||
this.allowFullTermForTranche = allowFullTermForTranche;
|
||||
}
|
||||
|
||||
+4
@@ -253,6 +253,10 @@ public class LoanRepaymentScheduleProcessingWrapper {
|
||||
: DateUtils.isDateInRangeFromExclusiveToInclusive(targetDate, fromDate, toDate);
|
||||
}
|
||||
|
||||
public static boolean isInPeriodFromInclusiveToExclusive(final LocalDate targetDate, final LocalDate fromDate, final LocalDate toDate) {
|
||||
return DateUtils.isDateInRangeFromInclusiveToExclusive(fromDate, toDate, targetDate);
|
||||
}
|
||||
|
||||
public static boolean isBeforePeriod(LocalDate targetDate, LoanRepaymentScheduleInstallment installment, boolean isFirstPeriod) {
|
||||
LocalDate fromDate = installment.getFromDate();
|
||||
return isFirstPeriod ? DateUtils.isBefore(targetDate, fromDate) : !DateUtils.isAfter(targetDate, fromDate);
|
||||
|
||||
+19
-7
@@ -27,6 +27,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
@@ -247,6 +248,8 @@ public final class LoanApplicationTerms {
|
||||
private LoanBuyDownFeeStrategy buyDownFeeStrategy;
|
||||
private LoanBuyDownFeeIncomeType buyDownFeeIncomeType;
|
||||
private boolean merchantBuyDownFee;
|
||||
@Getter
|
||||
private boolean allowFullTermForTranche = false;
|
||||
|
||||
private LoanApplicationTerms(Builder builder) {
|
||||
this.currency = builder.currency;
|
||||
@@ -292,6 +295,7 @@ public final class LoanApplicationTerms {
|
||||
this.buyDownFeeStrategy = builder.buyDownFeeStrategy;
|
||||
this.buyDownFeeIncomeType = builder.buyDownFeeIncomeType;
|
||||
this.merchantBuyDownFee = builder.merchantBuyDownFee;
|
||||
this.allowFullTermForTranche = builder.allowFullTermForTranche;
|
||||
this.interestMethod = builder.interestMethod;
|
||||
this.allowPartialPeriodInterestCalculation = builder.allowPartialPeriodInterestCalculation;
|
||||
}
|
||||
@@ -333,6 +337,7 @@ public final class LoanApplicationTerms {
|
||||
private LoanBuyDownFeeStrategy buyDownFeeStrategy;
|
||||
private LoanBuyDownFeeIncomeType buyDownFeeIncomeType;
|
||||
private boolean merchantBuyDownFee;
|
||||
private boolean allowFullTermForTranche;
|
||||
private boolean allowPartialPeriodInterestCalculation;
|
||||
|
||||
public Builder interestMethod(InterestMethod interestMethod) {
|
||||
@@ -500,6 +505,11 @@ public final class LoanApplicationTerms {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder allowFullTermForTranche(boolean value) {
|
||||
this.allowFullTermForTranche = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanApplicationTerms build() {
|
||||
return new LoanApplicationTerms(this);
|
||||
}
|
||||
@@ -542,7 +552,8 @@ public final class LoanApplicationTerms {
|
||||
.submittedOnDate(modelData.scheduleGenerationStartDate()).seedDate(seedDate)
|
||||
.interestRecognitionOnDisbursementDate(modelData.interestRecognitionOnDisbursementDate())
|
||||
.daysInYearCustomStrategy(modelData.daysInYearCustomStrategy()).interestMethod(modelData.interestMethod())
|
||||
.allowPartialPeriodInterestCalculation(modelData.allowPartialPeriodInterestCalculation()).mc(mc).build();
|
||||
.allowPartialPeriodInterestCalculation(modelData.allowPartialPeriodInterestCalculation())
|
||||
.allowFullTermForTranche(modelData.allowFullTermForTranche()).mc(mc).build();
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final CurrencyData currency, final Integer loanTermFrequency,
|
||||
@@ -579,7 +590,7 @@ public final class LoanApplicationTerms {
|
||||
final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType,
|
||||
final boolean enableBuyDownFee, final LoanBuyDownFeeCalculationType buyDownFeeCalculationType,
|
||||
final LoanBuyDownFeeStrategy buyDownFeeStrategy, final LoanBuyDownFeeIncomeType buyDownFeeIncomeType,
|
||||
final boolean merchantBuyDownFee) {
|
||||
final boolean merchantBuyDownFee, final boolean allowFullTermForTranche) {
|
||||
|
||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||
@@ -601,7 +612,7 @@ public final class LoanApplicationTerms {
|
||||
fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour,
|
||||
interestRecognitionOnDisbursementDate, daysInYearCustomStrategy, enableIncomeCapitalization,
|
||||
capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType, enableBuyDownFee,
|
||||
buyDownFeeCalculationType, buyDownFeeStrategy, buyDownFeeIncomeType, merchantBuyDownFee);
|
||||
buyDownFeeCalculationType, buyDownFeeStrategy, buyDownFeeIncomeType, merchantBuyDownFee, allowFullTermForTranche);
|
||||
|
||||
}
|
||||
|
||||
@@ -622,7 +633,7 @@ public final class LoanApplicationTerms {
|
||||
final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
|
||||
final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI,
|
||||
final BigDecimal fixedPrincipalPercentagePerInstallment, final boolean isPrincipalCompoundingDisabledForOverdueLoans,
|
||||
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate) {
|
||||
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate, final boolean allowFullTermForTranche) {
|
||||
|
||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||
@@ -680,7 +691,7 @@ public final class LoanApplicationTerms {
|
||||
loanProductRelatedDetail.getCapitalizedIncomeStrategy(), loanProductRelatedDetail.getCapitalizedIncomeType(),
|
||||
loanProductRelatedDetail.isEnableBuyDownFee(), loanProductRelatedDetail.getBuyDownFeeCalculationType(),
|
||||
loanProductRelatedDetail.getBuyDownFeeStrategy(), loanProductRelatedDetail.getBuyDownFeeIncomeType(),
|
||||
loanProductRelatedDetail.isMerchantBuyDownFee());
|
||||
loanProductRelatedDetail.isMerchantBuyDownFee(), allowFullTermForTranche);
|
||||
}
|
||||
|
||||
private LoanApplicationTerms(final CurrencyData currency, final Integer loanTermFrequency,
|
||||
@@ -716,7 +727,7 @@ public final class LoanApplicationTerms {
|
||||
final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType,
|
||||
final boolean enableBuyDownFee, final LoanBuyDownFeeCalculationType buyDownFeeCalculationType,
|
||||
final LoanBuyDownFeeStrategy buyDownFeeStrategy, final LoanBuyDownFeeIncomeType buyDownFeeIncomeType,
|
||||
final boolean merchantBuyDownFee) {
|
||||
final boolean merchantBuyDownFee, final boolean allowFullTermForTranche) {
|
||||
|
||||
this.currency = currency;
|
||||
this.loanTermFrequency = loanTermFrequency;
|
||||
@@ -827,6 +838,7 @@ public final class LoanApplicationTerms {
|
||||
this.buyDownFeeStrategy = buyDownFeeStrategy;
|
||||
this.buyDownFeeIncomeType = buyDownFeeIncomeType;
|
||||
this.merchantBuyDownFee = merchantBuyDownFee;
|
||||
this.allowFullTermForTranche = allowFullTermForTranche;
|
||||
}
|
||||
|
||||
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
||||
@@ -1703,7 +1715,7 @@ public final class LoanApplicationTerms {
|
||||
repaymentEvery, numberOfRepayments,
|
||||
isInterestChargedFromDateSameAsDisbursalDateEnabled != null && isInterestChargedFromDateSameAsDisbursalDateEnabled,
|
||||
daysInYearCustomStrategy, allowPartialPeriodInterestCalculation, interestRecalculationEnabled, recalculationFrequencyType,
|
||||
preClosureInterestCalculationStrategy);
|
||||
preClosureInterestCalculationStrategy, allowFullTermForTranche);
|
||||
}
|
||||
|
||||
public Integer getLoanTermFrequency() {
|
||||
|
||||
+2
-1
@@ -35,5 +35,6 @@ public record LoanRepaymentScheduleModelData(@NotNull LocalDate scheduleGenerati
|
||||
@NotNull boolean downPaymentEnabled, @NotNull DaysInMonthType daysInMonth, @NotNull DaysInYearType daysInYear,
|
||||
BigDecimal downPaymentPercentage, Integer installmentAmountInMultiplesOf, Integer fixedLength,
|
||||
@NotNull Boolean interestRecognitionOnDisbursementDate, @Nullable DaysInYearCustomStrategyType daysInYearCustomStrategy,
|
||||
@NotNull InterestMethod interestMethod, @NotNull boolean allowPartialPeriodInterestCalculation) {
|
||||
@NotNull InterestMethod interestMethod, @NotNull boolean allowPartialPeriodInterestCalculation,
|
||||
@NotNull boolean allowFullTermForTranche) {
|
||||
}
|
||||
|
||||
+2
-1
@@ -120,7 +120,8 @@ public class LoanTermVariationsMapper {
|
||||
scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(), holidayDetailDTO,
|
||||
allowCompoundingOnEod, scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday(),
|
||||
scheduleGeneratorDTO.isInterestToBeRecoveredFirstWhenGreaterThanEMI(), loan.getFixedPrincipalPercentagePerInstallment(),
|
||||
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans(), repaymentStartDateType, loan.getSubmittedOnDate());
|
||||
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans(), repaymentStartDateType, loan.getSubmittedOnDate(),
|
||||
loan.isAllowFullTermForTranche());
|
||||
}
|
||||
|
||||
private BigDecimal constructFloatingInterestRates(final BigDecimal annualNominalInterestRate, final FloatingRateDTO floatingRateDTO,
|
||||
|
||||
+4
-1
@@ -58,6 +58,8 @@ public class LoanConfigurationDetails implements ILoanConfigurationDetails {
|
||||
private final RecalculationFrequencyType restFrequencyType;
|
||||
@Getter
|
||||
private final LoanPreCloseInterestCalculationStrategy preCloseInterestCalculationStrategy;
|
||||
@Getter
|
||||
private final boolean allowFullTermForTranche;
|
||||
|
||||
public LoanConfigurationDetails(CurrencyData currency, BigDecimal interestRatePerPeriod, BigDecimal annualNominalInterestRate,
|
||||
Integer interestChargingGrace, Integer interestPaymentGrace, Integer principalGrace,
|
||||
@@ -67,7 +69,7 @@ public class LoanConfigurationDetails implements ILoanConfigurationDetails {
|
||||
Integer numberOfRepayments, boolean interestRecognitionOnDisbursementDate,
|
||||
DaysInYearCustomStrategyType daysInYearCustomStrategy, boolean allowPartialPeriodInterestCalculation,
|
||||
boolean isInterestRecalculationEnabled, RecalculationFrequencyType restFrequencyType,
|
||||
LoanPreCloseInterestCalculationStrategy preCloseInterestCalculationStrategy) {
|
||||
LoanPreCloseInterestCalculationStrategy preCloseInterestCalculationStrategy, boolean allowFullTermForTranche) {
|
||||
this.currency = currency;
|
||||
this.interestRatePerPeriod = interestRatePerPeriod;
|
||||
this.annualNominalInterestRate = annualNominalInterestRate;
|
||||
@@ -89,6 +91,7 @@ public class LoanConfigurationDetails implements ILoanConfigurationDetails {
|
||||
this.isInterestRecalculationEnabled = isInterestRecalculationEnabled;
|
||||
this.restFrequencyType = restFrequencyType;
|
||||
this.preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy;
|
||||
this.allowFullTermForTranche = allowFullTermForTranche;
|
||||
}
|
||||
|
||||
private Integer defaultToNullIfZero(final Integer value) {
|
||||
|
||||
+2
@@ -73,4 +73,6 @@ public interface ILoanConfigurationDetails {
|
||||
RecalculationFrequencyType getRestFrequencyType();
|
||||
|
||||
LoanPreCloseInterestCalculationStrategy getPreCloseInterestCalculationStrategy();
|
||||
|
||||
boolean isAllowFullTermForTranche();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user