From d88f634197688472530a4fa58a92b7fdbce912b6 Mon Sep 17 00:00:00 2001 From: "adam.magyari" Date: Thu, 24 Apr 2025 07:56:57 +0200 Subject: [PATCH] FINERACT-2232: Capitalized income - income type config --- .../domain/LoanCapitalizedIncomeType.java | 33 +++++++++++ .../domain/LoanApplicationTerms.java | 21 +++++-- .../loanproduct/LoanProductConstants.java | 1 + .../api/LoanProductsApiResourceSwagger.java | 12 ++++ .../loanproduct/data/LoanProductData.java | 25 ++++++-- .../loanproduct/domain/LoanProduct.java | 5 +- .../domain/LoanProductRelatedDetail.java | 12 +++- .../loanaccount/api/LoansApiResource.java | 4 +- .../api/LoansApiResourceSwagger.java | 4 ++ .../loanaccount/data/LoanAccountData.java | 12 ++-- .../service/LoanScheduleAssembler.java | 3 +- .../service/LoanProductAssembler.java | 6 +- .../LoanProductRelatedDetailUpdateUtil.java | 8 +++ .../service/LoanReadPlatformServiceImpl.java | 6 +- .../api/LoanProductsApiResource.java | 8 ++- .../LoanProductDataValidator.java | 15 ++++- .../LoanProductReadPlatformServiceImpl.java | 9 ++- .../db/changelog/tenant/changelog-tenant.xml | 1 + ...an_product_add_capitalized_income_type.xml | 37 ++++++++++++ .../DefaultScheduledDateGeneratorTest.java | 4 +- .../integrationtests/LoanProductTest.java | 57 +++++++++++++++---- 21 files changed, 242 insertions(+), 41 deletions(-) create mode 100644 fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCapitalizedIncomeType.java create mode 100644 fineract-provider/src/main/resources/db/changelog/tenant/parts/0174_loan_product_add_capitalized_income_type.xml diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCapitalizedIncomeType.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCapitalizedIncomeType.java new file mode 100644 index 000000000..58d233135 --- /dev/null +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCapitalizedIncomeType.java @@ -0,0 +1,33 @@ +/** + * 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.loanaccount.domain; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.core.api.ApiFacingEnum; + +@Getter +@RequiredArgsConstructor +public enum LoanCapitalizedIncomeType implements ApiFacingEnum { + + FEE("capitalizedIncome.incomeType.fee", "Fee"), INTEREST("capitalizedIncome.incomeType.interest", "Interest"); + + private final String code; + private final String humanReadableName; +} diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java index f517a1b24..2c2cad5bb 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java @@ -48,6 +48,7 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsDataWrapper; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; import org.apache.fineract.portfolio.loanproduct.data.LoanProductRelatedDetailMinimumData; import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod; @@ -237,6 +238,7 @@ public final class LoanApplicationTerms { private boolean enableIncomeCapitalization; private LoanCapitalizedIncomeCalculationType capitalizedIncomeCalculationType; private LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy; + private LoanCapitalizedIncomeType capitalizedIncomeType; private LoanApplicationTerms(Builder builder) { this.currency = builder.currency; @@ -276,6 +278,7 @@ public final class LoanApplicationTerms { this.enableIncomeCapitalization = builder.enableIncomeCapitalization; this.capitalizedIncomeCalculationType = builder.capitalizedIncomeCalculationType; this.capitalizedIncomeStrategy = builder.capitalizedIncomeStrategy; + this.capitalizedIncomeType = builder.capitalizedIncomeType; } public static class Builder { @@ -308,6 +311,7 @@ public final class LoanApplicationTerms { private boolean enableIncomeCapitalization; private LoanCapitalizedIncomeCalculationType capitalizedIncomeCalculationType; private LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy; + private LoanCapitalizedIncomeType capitalizedIncomeType; public Builder currency(CurrencyData currency) { this.currency = currency; @@ -439,6 +443,11 @@ public final class LoanApplicationTerms { return this; } + public Builder capitalizedIncomeType(LoanCapitalizedIncomeType value) { + this.capitalizedIncomeType = value; + return this; + } + public LoanApplicationTerms build() { return new LoanApplicationTerms(this); } @@ -508,7 +517,7 @@ public final class LoanApplicationTerms { final LoanChargeOffBehaviour chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate, final DaysInYearCustomStrategyType daysInYearCustomStrategy, final boolean enableIncomeCapitalization, final LoanCapitalizedIncomeCalculationType capitalizedIncomeCalculationType, - final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy) { + final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType) { final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null; final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null; @@ -529,7 +538,7 @@ public final class LoanApplicationTerms { isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour, interestRecognitionOnDisbursementDate, daysInYearCustomStrategy, enableIncomeCapitalization, - capitalizedIncomeCalculationType, capitalizedIncomeStrategy); + capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType); } @@ -605,7 +614,7 @@ public final class LoanApplicationTerms { loanProductRelatedDetail.getSupportedInterestRefundTypes(), loanProductRelatedDetail.getChargeOffBehaviour(), loanProductRelatedDetail.isInterestRecognitionOnDisbursementDate(), loanProductRelatedDetail.getDaysInYearCustomStrategy(), loanProductRelatedDetail.isEnableIncomeCapitalization(), loanProductRelatedDetail.getCapitalizedIncomeCalculationType(), - loanProductRelatedDetail.getCapitalizedIncomeStrategy()); + loanProductRelatedDetail.getCapitalizedIncomeStrategy(), loanProductRelatedDetail.getCapitalizedIncomeType()); } private LoanApplicationTerms(final CurrencyData currency, final Integer loanTermFrequency, @@ -638,7 +647,7 @@ public final class LoanApplicationTerms { final List supportedInterestRefundTypes, final LoanChargeOffBehaviour chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate, final DaysInYearCustomStrategyType daysInYearCustomStrategy, final boolean enableIncomeCapitalization, final LoanCapitalizedIncomeCalculationType capitalizedIncomeCalculationType, - final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy) { + final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType) { this.currency = currency; this.loanTermFrequency = loanTermFrequency; @@ -743,6 +752,7 @@ public final class LoanApplicationTerms { this.enableIncomeCapitalization = enableIncomeCapitalization; this.capitalizedIncomeCalculationType = capitalizedIncomeCalculationType; this.capitalizedIncomeStrategy = capitalizedIncomeStrategy; + this.capitalizedIncomeType = capitalizedIncomeType; } public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate, @@ -1605,7 +1615,8 @@ public final class LoanApplicationTerms { this.disbursedAmountPercentageForDownPayment, this.isAutoRepaymentForDownPaymentEnabled, this.loanScheduleType, this.loanScheduleProcessingType, this.fixedLength, this.enableAccrualActivityPosting, this.supportedInterestRefundTypes, this.chargeOffBehaviour, this.interestRecognitionOnDisbursementDate, this.daysInYearCustomStrategy, - this.enableIncomeCapitalization, this.capitalizedIncomeCalculationType, this.capitalizedIncomeStrategy); + this.enableIncomeCapitalization, this.capitalizedIncomeCalculationType, this.capitalizedIncomeStrategy, + this.capitalizedIncomeType); } public LoanProductMinimumRepaymentScheduleRelatedDetail toLoanProductRelatedDetailMinimumData() { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java index 1e803ab0a..bda183949 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java @@ -176,4 +176,5 @@ public interface LoanProductConstants { String ENABLE_INCOME_CAPITALIZATION_PARAM_NAME = "enableIncomeCapitalization"; String CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME = "capitalizedIncomeCalculationType"; String CAPITALIZED_INCOME_STRATEGY_PARAM_NAME = "capitalizedIncomeStrategy"; + String CAPITALIZED_INCOME_TYPE_PARAM_NAME = "capitalizedIncomeType"; } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java index 0ccc7ffed..3e12aca89 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java @@ -201,6 +201,8 @@ public final class LoanProductsApiResourceSwagger { public String capitalizedIncomeCalculationType; @Schema(example = "EQUAL_AMORTIZATION", allowableValues = "EQUAL_AMORTIZATION") public String capitalizedIncomeStrategy; + @Schema(example = "FEE", allowableValues = { "FEE", "INTEREST" }) + public String capitalizedIncomeType; // Interest Recalculation @Schema(example = "false") @@ -667,6 +669,8 @@ public final class LoanProductsApiResourceSwagger { public StringEnumOptionData capitalizedIncomeCalculationType; @Schema(example = "EQUAL_AMORTIZATION") public StringEnumOptionData capitalizedIncomeStrategy; + @Schema(example = "FEE") + public StringEnumOptionData capitalizedIncomeType; } @Schema(description = "GetLoanProductsTemplateResponse") @@ -1119,8 +1123,11 @@ public final class LoanProductsApiResourceSwagger { public StringEnumOptionData capitalizedIncomeCalculationType; @Schema(example = "EQUAL_AMORTIZATION") public StringEnumOptionData capitalizedIncomeStrategy; + @Schema(example = "FEE") + public StringEnumOptionData capitalizedIncomeType; public List capitalizedIncomeCalculationTypeOptions; public List capitalizedIncomeStrategyOptions; + public List capitalizedIncomeTypeOptions; } @Schema(description = "GetLoanProductsProductIdResponse") @@ -1448,8 +1455,11 @@ public final class LoanProductsApiResourceSwagger { public StringEnumOptionData capitalizedIncomeCalculationType; @Schema(example = "EQUAL_AMORTIZATION") public StringEnumOptionData capitalizedIncomeStrategy; + @Schema(example = "FEE") + public StringEnumOptionData capitalizedIncomeType; public List capitalizedIncomeCalculationTypeOptions; public List capitalizedIncomeStrategyOptions; + public List capitalizedIncomeTypeOptions; } @Schema(description = "PutLoanProductsProductIdRequest") @@ -1713,6 +1723,8 @@ public final class LoanProductsApiResourceSwagger { public String capitalizedIncomeCalculationType; @Schema(example = "EQUAL_AMORTIZATION", allowableValues = "EQUAL_AMORTIZATION") public String capitalizedIncomeStrategy; + @Schema(example = "FEE", allowableValues = { "FEE", "INTEREST" }) + public String capitalizedIncomeType; } public static final class AdvancedPaymentData { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java index bcece9c7a..a9e0bfbcc 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java @@ -51,6 +51,7 @@ import org.apache.fineract.portfolio.fund.data.FundData; import org.apache.fineract.portfolio.loanaccount.data.LoanInterestRecalculationData; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -244,8 +245,10 @@ public class LoanProductData implements Serializable { private Boolean enableIncomeCapitalization; private StringEnumOptionData capitalizedIncomeCalculationType; private StringEnumOptionData capitalizedIncomeStrategy; + private final StringEnumOptionData capitalizedIncomeType; private List capitalizedIncomeCalculationTypeOptions; private List capitalizedIncomeStrategyOptions; + private List capitalizedIncomeTypeOptions; /** * Used when returning lookup information about loan product for dropdowns. @@ -353,6 +356,7 @@ public class LoanProductData implements Serializable { final boolean enableIncomeCapitalization = false; final StringEnumOptionData capitalizedIncomeCalculationType = null; final StringEnumOptionData capitalizedIncomeStrategy = null; + final StringEnumOptionData capitalizedIncomeType = null; return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -375,7 +379,7 @@ public class LoanProductData implements Serializable { paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour, interestRecognitionOnDisbursementDate, daysInYearTypeCustomStrategy, enableIncomeCapitalization, - capitalizedIncomeCalculationType, capitalizedIncomeStrategy); + capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType); } @@ -483,6 +487,7 @@ public class LoanProductData implements Serializable { final boolean enableIncomeCapitalization = false; final StringEnumOptionData capitalizedIncomeCalculationType = null; final StringEnumOptionData capitalizedIncomeStrategy = null; + final StringEnumOptionData capitalizedIncomeType = null; return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -505,7 +510,7 @@ public class LoanProductData implements Serializable { paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour, interestRecognitionOnDisbursementDate, daysInYearTypeCustomStrategy, enableIncomeCapitalization, - capitalizedIncomeCalculationType, capitalizedIncomeStrategy); + capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType); } @@ -620,6 +625,7 @@ public class LoanProductData implements Serializable { final boolean enableIncomeCapitalization = false; final StringEnumOptionData capitalizedIncomeCalculationType = null; final StringEnumOptionData capitalizedIncomeStrategy = null; + final StringEnumOptionData capitalizedIncomeType = null; return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -642,7 +648,7 @@ public class LoanProductData implements Serializable { paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour, interestRecognitionOnDisbursementDate, daysInYearTypeCustomStrategy, enableIncomeCapitalization, - capitalizedIncomeCalculationType, capitalizedIncomeStrategy); + capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType); } @@ -751,6 +757,7 @@ public class LoanProductData implements Serializable { final boolean enableIncomeCapitalization = false; final StringEnumOptionData capitalizedIncomeCalculationType = null; final StringEnumOptionData capitalizedIncomeStrategy = null; + final StringEnumOptionData capitalizedIncomeType = null; return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -773,7 +780,7 @@ public class LoanProductData implements Serializable { paymentAllocation, creditAllocationData, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour, interestRecognitionOnDisbursementDate, daysInYearTypeCustomStrategy, enableIncomeCapitalization, - capitalizedIncomeCalculationType, capitalizedIncomeStrategy); + capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType); } public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map accountingMappings, @@ -829,7 +836,8 @@ public class LoanProductData implements Serializable { final boolean enableAccrualActivityPosting, final List supportedInterestRefundTypes, StringEnumOptionData chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate, final StringEnumOptionData daysInYearCustomStrategy, final boolean enableIncomeCapitalization, - final StringEnumOptionData capitalizedIncomeCalculationType, final StringEnumOptionData capitalizedIncomeStrategy) { + final StringEnumOptionData capitalizedIncomeCalculationType, final StringEnumOptionData capitalizedIncomeStrategy, + final StringEnumOptionData capitalizedIncomeType) { this.id = id; this.name = name; this.shortName = shortName; @@ -889,6 +897,7 @@ public class LoanProductData implements Serializable { this.enableIncomeCapitalization = enableIncomeCapitalization; this.capitalizedIncomeCalculationType = capitalizedIncomeCalculationType; this.capitalizedIncomeStrategy = capitalizedIncomeStrategy; + this.capitalizedIncomeType = capitalizedIncomeType; this.chargeOptions = null; this.penaltyOptions = null; @@ -981,6 +990,7 @@ public class LoanProductData implements Serializable { this.capitalizedIncomeCalculationTypeOptions = ApiFacingEnum .getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeCalculationType.class); this.capitalizedIncomeStrategyOptions = ApiFacingEnum.getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeStrategy.class); + this.capitalizedIncomeTypeOptions = ApiFacingEnum.getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeType.class); } public LoanProductData(final LoanProductData productData, final Collection chargeOptions, @@ -1007,7 +1017,8 @@ public class LoanProductData implements Serializable { final List chargeOffBehaviourOptions, final List chargeOffReasonOptions, final List daysInYearCustomStrategyOptions, final List capitalizedIncomeCalculationTypeOptions, - final List capitalizedIncomeStrategyOptions) { + final List capitalizedIncomeStrategyOptions, + final List capitalizedIncomeTypeOptions) { this.id = productData.id; this.name = productData.name; @@ -1174,8 +1185,10 @@ public class LoanProductData implements Serializable { this.enableIncomeCapitalization = productData.enableIncomeCapitalization; this.capitalizedIncomeCalculationType = productData.capitalizedIncomeCalculationType; this.capitalizedIncomeStrategy = productData.capitalizedIncomeStrategy; + this.capitalizedIncomeType = productData.capitalizedIncomeType; this.capitalizedIncomeCalculationTypeOptions = capitalizedIncomeCalculationTypeOptions; this.capitalizedIncomeStrategyOptions = capitalizedIncomeStrategyOptions; + this.capitalizedIncomeTypeOptions = capitalizedIncomeTypeOptions; } private Collection nullIfEmpty(final Collection charges) { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java index 31e4ab8a1..d9f7dbd71 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java @@ -61,6 +61,7 @@ import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate; import org.apache.fineract.portfolio.fund.domain.Fund; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -284,7 +285,7 @@ public class LoanProduct extends AbstractPersistableCustom { final LoanChargeOffBehaviour chargeOffBehaviour, final boolean isInterestRecognitionOnDisbursementDate, final DaysInYearCustomStrategyType daysInYearCustomStrategy, final boolean enableIncomeCapitalization, final LoanCapitalizedIncomeCalculationType capitalizedIncomeCalculationType, - final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy) { + final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType) { this.fund = fund; this.transactionProcessingStrategyCode = transactionProcessingStrategyCode; @@ -335,7 +336,7 @@ public class LoanProduct extends AbstractPersistableCustom { isInterestRecalculationEnabled, isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour, isInterestRecognitionOnDisbursementDate, daysInYearCustomStrategy, - enableIncomeCapitalization, capitalizedIncomeCalculationType, capitalizedIncomeStrategy); + enableIncomeCapitalization, capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType); this.loanProductMinMaxConstraints = new LoanProductMinMaxConstraints(defaultMinPrincipal, defaultMaxPrincipal, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultMinNumberOfInstallments, diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java index 29b18e6ce..6ca788655 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java @@ -38,6 +38,7 @@ import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -181,6 +182,10 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche @Column(name = "capitalized_income_strategy") private LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy; + @Enumerated(EnumType.STRING) + @Column(name = "capitalized_income_type") + private LoanCapitalizedIncomeType capitalizedIncomeType; + public static LoanProductRelatedDetail createFrom(final CurrencyData currencyData, final BigDecimal principal, final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod, @@ -197,7 +202,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche final LoanChargeOffBehaviour chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate, final DaysInYearCustomStrategyType daysInYearCustomStrategy, final boolean enableIncomeCapitalization, final LoanCapitalizedIncomeCalculationType capitalizedIncomeCalculationType, - final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy) { + final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType) { final MonetaryCurrency currency = MonetaryCurrency.fromCurrencyData(currencyData); return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType, @@ -208,7 +213,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour, interestRecognitionOnDisbursementDate, daysInYearCustomStrategy, enableIncomeCapitalization, - capitalizedIncomeCalculationType, capitalizedIncomeStrategy); + capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType); } protected LoanProductRelatedDetail() { @@ -231,7 +236,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche final LoanChargeOffBehaviour chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate, final DaysInYearCustomStrategyType daysInYearCustomStrategy, final boolean enableIncomeCapitalization, final LoanCapitalizedIncomeCalculationType capitalizedIncomeCalculationType, - final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy) { + final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType) { this.currency = currency; this.principal = defaultPrincipal; this.nominalInterestRatePerPeriod = defaultNominalInterestRatePerPeriod; @@ -272,6 +277,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche this.enableIncomeCapitalization = enableIncomeCapitalization; this.capitalizedIncomeCalculationType = capitalizedIncomeCalculationType; this.capitalizedIncomeStrategy = capitalizedIncomeStrategy; + this.capitalizedIncomeType = capitalizedIncomeType; } private Integer defaultToNullIfZero(final Integer value) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java index 04dde0975..295142664 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java @@ -135,6 +135,7 @@ import org.apache.fineract.portfolio.loanaccount.data.PaidInAdvanceData; import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryBalancesRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType; @@ -1160,7 +1161,8 @@ public class LoansApiResource { LoanScheduleType.getValuesAsEnumOptionDataList(), LoanScheduleProcessingType.getValuesAsEnumOptionDataList(), loanTermVariations, ApiFacingEnum.getValuesAsStringEnumOptionDataList(DaysInYearCustomStrategyType.class), ApiFacingEnum.getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeCalculationType.class), - ApiFacingEnum.getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeStrategy.class)); + ApiFacingEnum.getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeStrategy.class), + ApiFacingEnum.getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeType.class)); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(), mandatoryResponseParameters); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java index 17787426d..0b146908a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java @@ -1212,6 +1212,8 @@ final class LoansApiResourceSwagger { public StringEnumOptionData capitalizedIncomeCalculationType; @Schema(example = "EQUAL_AMORTIZATION") public StringEnumOptionData capitalizedIncomeStrategy; + @Schema(example = "FEE") + public StringEnumOptionData capitalizedIncomeType; } @Schema(description = "GetLoansResponse") @@ -1321,6 +1323,8 @@ final class LoansApiResourceSwagger { public String capitalizedIncomeCalculationType; @Schema(example = "EQUAL_AMORTIZATION", allowableValues = "EQUAL_AMORTIZATION") public String capitalizedIncomeStrategy; + @Schema(example = "FEE") + public StringEnumOptionData capitalizedIncomeType; public List charges; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java index 4376cf077..f2e4b2f35 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java @@ -174,6 +174,7 @@ public class LoanAccountData { private List daysInYearCustomStrategyOptions; private List capitalizedIncomeCalculationTypeOptions; private List capitalizedIncomeStrategyOptions; + private List capitalizedIncomeTypeOptions; @Transient private BigDecimal feeChargesAtDisbursementCharged; @@ -279,6 +280,7 @@ public class LoanAccountData { private Boolean enableIncomeCapitalization; private StringEnumOptionData capitalizedIncomeCalculationType; private StringEnumOptionData capitalizedIncomeStrategy; + private StringEnumOptionData capitalizedIncomeType; public static LoanAccountData importInstanceIndividual(EnumOptionData loanTypeEnumOption, Long clientId, Long productId, Long loanOfficerId, LocalDate submittedOnDate, Long fundId, BigDecimal principal, Integer numberOfRepayments, @@ -472,7 +474,7 @@ public class LoanAccountData { final EnumOptionData loanScheduleProcessingType, final Integer fixedLength, final StringEnumOptionData chargeOffBehaviour, final boolean isInterestRecognitionOnDisbursementDate, final StringEnumOptionData daysInYearCustomStrategy, final boolean enableIncomeCapitalization, final StringEnumOptionData capitalizedIncomeCalculationType, - final StringEnumOptionData capitalizedIncomeStrategy) { + final StringEnumOptionData capitalizedIncomeStrategy, StringEnumOptionData capitalizedIncomeType) { final CollectionData delinquent = CollectionData.template(); @@ -520,7 +522,7 @@ public class LoanAccountData { .setChargeOffBehaviour(chargeOffBehaviour).setInterestRecognitionOnDisbursementDate(isInterestRecognitionOnDisbursementDate) .setDaysInYearCustomStrategy(daysInYearCustomStrategy).setEnableIncomeCapitalization(enableIncomeCapitalization) .setCapitalizedIncomeCalculationType(capitalizedIncomeCalculationType) - .setCapitalizedIncomeStrategy(capitalizedIncomeStrategy); + .setCapitalizedIncomeStrategy(capitalizedIncomeStrategy).setCapitalizedIncomeType(capitalizedIncomeType); } /* @@ -548,7 +550,8 @@ public class LoanAccountData { final List loanScheduleProcessingTypeOptions, final List loanTermVariations, final List daysInYearCustomStrategyOptions, final List capitalizedIncomeCalculationTypeOptions, - final List capitalizedIncomeStrategyOptions) { + final List capitalizedIncomeStrategyOptions, + final List capitalizedIncomeTypeOptions) { // TODO: why are these variables 'calendarData', 'chargeTemplate' never used (see original private constructor) @@ -571,7 +574,8 @@ public class LoanAccountData { .setLoanScheduleProcessingTypeOptions(loanScheduleProcessingTypeOptions).setLoanTermVariations(loanTermVariations) .setDaysInYearCustomStrategyOptions(daysInYearCustomStrategyOptions) .setCapitalizedIncomeCalculationTypeOptions(capitalizedIncomeCalculationTypeOptions) - .setCapitalizedIncomeStrategyOptions(capitalizedIncomeStrategyOptions); + .setCapitalizedIncomeStrategyOptions(capitalizedIncomeStrategyOptions) + .setCapitalizedIncomeTypeOptions(capitalizedIncomeTypeOptions); } public LoanAccountData associationsAndTemplate(final Collection productOptions, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java index fe27ecb80..2db86adb9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java @@ -547,7 +547,8 @@ public class LoanScheduleAssembler { loanProduct.getLoanProductRelatedDetail().getDaysInYearCustomStrategy(), loanProduct.getLoanProductRelatedDetail().isEnableIncomeCapitalization(), loanProduct.getLoanProductRelatedDetail().getCapitalizedIncomeCalculationType(), - loanProduct.getLoanProductRelatedDetail().getCapitalizedIncomeStrategy()); + loanProduct.getLoanProductRelatedDetail().getCapitalizedIncomeStrategy(), + loanProduct.getLoanProductRelatedDetail().getCapitalizedIncomeType()); } private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java index 85522bed1..2e2a3beb6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java @@ -42,6 +42,7 @@ import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate; import org.apache.fineract.portfolio.fund.domain.Fund; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; @@ -313,6 +314,8 @@ public class LoanProductAssembler { LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME, LoanCapitalizedIncomeCalculationType.class); final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy = command.enumValueOfParameterNamed( LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME, LoanCapitalizedIncomeStrategy.class); + final LoanCapitalizedIncomeType capitalizedIncomeType = command + .enumValueOfParameterNamed(LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME, LoanCapitalizedIncomeType.class); return new LoanProduct(fund, loanTransactionProcessingStrategy, loanProductPaymentAllocationRules, loanProductCreditAllocationRules, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod, @@ -334,7 +337,8 @@ public class LoanProductAssembler { overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour, interestRecognitionOnDisbursementDate, - daysInYearCustomStrategy, enableIncomeCapitalization, capitalizedIncomeCalculationType, capitalizedIncomeStrategy); + daysInYearCustomStrategy, enableIncomeCapitalization, capitalizedIncomeCalculationType, capitalizedIncomeStrategy, + capitalizedIncomeType); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java index da78ccf98..b84cc31e0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java @@ -28,6 +28,7 @@ import org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType; import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -320,6 +321,13 @@ public class LoanProductRelatedDetailUpdateUtil { loanRepaymentScheduleDetail.setCapitalizedIncomeStrategy(newValue); } + if (command.parameterExists(LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME)) { + final LoanCapitalizedIncomeType newValue = command + .enumValueOfParameterNamed(LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME, LoanCapitalizedIncomeType.class); + actualChanges.put(LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME, newValue); + loanRepaymentScheduleDetail.setCapitalizedIncomeType(newValue); + } + return actualChanges; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index f853b38d5..1ec838ec7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -109,6 +109,7 @@ import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; @@ -737,6 +738,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa + " l.enable_income_capitalization as enableIncomeCapitalization, " + " l.capitalized_income_calculation_type as capitalizedIncomeCalculationType, " + " l.capitalized_income_strategy as capitalizedIncomeStrategy, " + + " l.capitalized_income_type as capitalizedIncomeType, " // + " l.create_standing_instruction_at_disbursement as createStandingInstructionAtDisbursement, " + " lpvi.minimum_gap as minimuminstallmentgap, lpvi.maximum_gap as maximuminstallmentgap, " + " lp.can_use_for_topup as canUseForTopup, l.is_topup as isTopup, topup.closure_loan_id as closureLoanId, " @@ -1118,6 +1120,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa .getStringEnumOptionData(LoanCapitalizedIncomeCalculationType.class, rs.getString("capitalizedIncomeCalculationType")); final StringEnumOptionData capitalizedIncomeStrategy = ApiFacingEnum .getStringEnumOptionData(LoanCapitalizedIncomeStrategy.class, rs.getString("capitalizedIncomeStrategy")); + final StringEnumOptionData capitalizedIncomeType = ApiFacingEnum.getStringEnumOptionData(LoanCapitalizedIncomeType.class, + rs.getString("capitalizedIncomeType")); return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, clientExternalId, groupData, loanType, loanProductId, loanProductName, loanProductDescription, @@ -1138,7 +1142,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa enableAutoRepaymentForDownPayment, enableInstallmentLevelDelinquency, loanScheduleType.asEnumOptionData(), loanScheduleProcessingType.asEnumOptionData(), fixedLength, chargeOffBehaviour.getValueAsStringEnumOptionData(), interestRecognitionOnDisbursementDate, daysInYearCustomStrategy, enableIncomeCapitalization, - capitalizedIncomeCalculationType, capitalizedIncomeStrategy); + capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java index eb41c4228..5604d7ff5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -84,6 +84,7 @@ import org.apache.fineract.portfolio.fund.service.FundReadPlatformService; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -133,7 +134,7 @@ public class LoanProductsApiResource { LoanProductConstants.REPAYMENT_START_DATE_TYPE, LoanProductConstants.DAYS_IN_YEAR_CUSTOM_STRATEGY_TYPE_PARAMETER_NAME, LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME, LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME, - LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME)); + LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME, LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME)); private static final Set PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>( Arrays.asList("productId", "productName", "restrictedProducts", "allowedProducts", "productOptions")); @@ -450,6 +451,8 @@ public class LoanProductsApiResource { .getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeCalculationType.class); final List capitalizedIncomeStrategyOptions = ApiFacingEnum .getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeStrategy.class); + final List capitalizedIncomeTypeOptions = ApiFacingEnum + .getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeType.class); return new LoanProductData(productData, chargeOptions, penaltyOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions, @@ -462,7 +465,8 @@ public class LoanProductsApiResource { advancedPaymentAllocationTypes, LoanScheduleType.getValuesAsEnumOptionDataList(), LoanScheduleProcessingType.getValuesAsEnumOptionDataList(), creditAllocationTransactionTypes, creditAllocationAllocationTypes, supportedInterestRefundTypesOptions, chargeOffBehaviourOptions, chargeOffReasonOptions, - daysInYearCustomStrategyOptions, capitalizedIncomeCalculationTypeOptions, capitalizedIncomeStrategyOptions); + daysInYearCustomStrategyOptions, capitalizedIncomeCalculationTypeOptions, capitalizedIncomeStrategyOptions, + capitalizedIncomeTypeOptions); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java index ae62944b9..3a298ce89 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java @@ -51,6 +51,7 @@ import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor; @@ -193,7 +194,7 @@ public final class LoanProductDataValidator { LoanProductConstants.DAYS_IN_YEAR_CUSTOM_STRATEGY_TYPE_PARAMETER_NAME, LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME, LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME, - LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME)); + LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME, LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME)); private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { LoanProductConstants.amortizationTypeParamName, LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName, @@ -2688,6 +2689,13 @@ public final class LoanProductDataValidator { .value(capitalizedIncomeStrategy).isOneOfEnumValues(LoanCapitalizedIncomeStrategy.class); } + if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME, element)) { + final String capitalizedIncomeType = this.fromApiJsonHelper + .extractStringNamed(LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME, element); + baseDataValidator.reset().parameter(LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME).value(capitalizedIncomeType) + .isOneOfEnumValues(LoanCapitalizedIncomeType.class); + } + if (AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY.equals(transactionProcessingStrategyCode) && this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME, element)) { Boolean enableIncomeCapitalization = this.fromApiJsonHelper @@ -2705,6 +2713,11 @@ public final class LoanProductDataValidator { baseDataValidator.reset().parameter(LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME) .value(capitalizedIncomeStrategy).isOneOfEnumValues(LoanCapitalizedIncomeStrategy.class) .cantBeBlankWhenParameterProvidedIs(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME, true); + final String capitalizedIncomeType = this.fromApiJsonHelper + .extractStringNamed(LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME, element); + baseDataValidator.reset().parameter(LoanProductConstants.CAPITALIZED_INCOME_TYPE_PARAM_NAME).value(capitalizedIncomeType) + .isOneOfEnumValues(LoanCapitalizedIncomeType.class) + .cantBeBlankWhenParameterProvidedIs(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME, true); // Accounting if (AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) { final Long deferredIncomeLiabilityAccountId = this.fromApiJsonHelper diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java index 7c316aa18..91aad12ab 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java @@ -48,6 +48,7 @@ import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData; import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -294,7 +295,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo + "lp.charge_off_behaviour as chargeOffBehaviour, " // + "lp.enable_income_capitalization as enableIncomeCapitalization, " // + "lp.capitalized_income_calculation_type as capitalizedIncomeCalculationType, " // - + "lp.capitalized_income_strategy as capitalizedIncomeStrategy " // + + "lp.capitalized_income_strategy as capitalizedIncomeStrategy, " // + + "lp.capitalized_income_type as capitalizedIncomeType " // + " from m_product_loan lp " + " left join m_fund f on f.id = lp.fund_id " + " left join m_product_loan_recalculation_details lpr on lpr.product_id=lp.id " + " left join m_product_loan_guarantee_details lpg on lpg.loan_product_id=lp.id " @@ -563,6 +565,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo .getStringEnumOptionData(LoanCapitalizedIncomeCalculationType.class, rs.getString("capitalizedIncomeCalculationType")); final StringEnumOptionData capitalizedIncomeStrategy = ApiFacingEnum .getStringEnumOptionData(LoanCapitalizedIncomeStrategy.class, rs.getString("capitalizedIncomeStrategy")); + final StringEnumOptionData capitalizedIncome = ApiFacingEnum.getStringEnumOptionData(LoanCapitalizedIncomeType.class, + rs.getString("capitalizedIncomeType")); return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -587,7 +591,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo enableInstallmentLevelDelinquency, loanScheduleType.asEnumOptionData(), loanScheduleProcessingType.asEnumOptionData(), fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, loanChargeOffBehaviour.getValueAsStringEnumOptionData(), interestRecognitionOnDisbursementDate, - daysInYearCustomStrategy, enableIncomeCapitalization, capitalizedIncomeCalculationType, capitalizedIncomeStrategy); + daysInYearCustomStrategy, enableIncomeCapitalization, capitalizedIncomeCalculationType, capitalizedIncomeStrategy, + capitalizedIncome); } } diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index e677629f1..6e48c15a4 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -192,4 +192,5 @@ + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0174_loan_product_add_capitalized_income_type.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0174_loan_product_add_capitalized_income_type.xml new file mode 100644 index 000000000..e3e3d2042 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0174_loan_product_add_capitalized_income_type.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java index d0d83caa6..43052d0f8 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java @@ -98,7 +98,7 @@ public class DefaultScheduledDateGeneratorTest { Money.of(fromApplicationCurrency(dollarCurrency), ZERO), false, null, EMPTY_LIST, BigDecimal.valueOf(36_000L), null, DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null, null, ZERO, null, NONE, null, ZERO, EMPTY_LIST, true, 0, false, holidayDetailDTO, false, false, false, null, false, false, null, false, DISBURSEMENT_DATE, - submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null, false, null, null, false, null, false, null, + submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null, false, null, null, false, null, false, null, null, null); // when @@ -180,7 +180,7 @@ public class DefaultScheduledDateGeneratorTest { EMPTY_LIST, BigDecimal.valueOf(36_000L), null, DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null, null, ZERO, null, NONE, null, ZERO, EMPTY_LIST, true, 0, false, holidayDetailDTO, false, false, false, null, false, false, null, false, DISBURSEMENT_DATE, submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null, false, null, null, - false, null, false, null, null); + false, null, false, null, null, null); } private HolidayDetailDTO createHolidayDTO() { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductTest.java index 0a6e22cf9..6d2b2f33b 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductTest.java @@ -28,6 +28,7 @@ import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -46,7 +47,8 @@ public class LoanProductTest extends BaseLoanIntegrationTest { .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) - .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())); + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()) + .capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE)); final GetLoanProductsProductIdResponse loanProductsProductIdResponse = loanProductHelper .retrieveLoanProductById(loanProductsResponse.getResourceId()); @@ -57,6 +59,9 @@ public class LoanProductTest extends BaseLoanIntegrationTest { Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeStrategy()); Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(), loanProductsProductIdResponse.getCapitalizedIncomeStrategy().getCode()); + Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeType()); + Assertions.assertEquals(LoanCapitalizedIncomeType.FEE.getCode(), + loanProductsProductIdResponse.getCapitalizedIncomeType().getCode()); runAt("20 December 2024", () -> { Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "20 December 2024", @@ -70,6 +75,8 @@ public class LoanProductTest extends BaseLoanIntegrationTest { Assertions.assertNotNull(loanDetails.getCapitalizedIncomeStrategy()); Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(), loanDetails.getCapitalizedIncomeStrategy().getCode()); + Assertions.assertNotNull(loanDetails.getCapitalizedIncomeType()); + Assertions.assertEquals(LoanCapitalizedIncomeType.FEE.getCode(), loanDetails.getCapitalizedIncomeType().getCode()); Assertions.assertDoesNotThrow(() -> disburseLoan(loanId, BigDecimal.valueOf(430), "20 December 2024")); }); @@ -84,7 +91,8 @@ public class LoanProductTest extends BaseLoanIntegrationTest { .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) - .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())); + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()) + .capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE)); final GetLoanProductsProductIdResponse loanProductsProductIdResponse = loanProductHelper .retrieveLoanProductById(loanProductsResponse.getResourceId()); @@ -95,6 +103,9 @@ public class LoanProductTest extends BaseLoanIntegrationTest { Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeStrategy()); Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(), loanProductsProductIdResponse.getCapitalizedIncomeStrategy().getCode()); + Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeType()); + Assertions.assertEquals(LoanCapitalizedIncomeType.FEE.getCode(), + loanProductsProductIdResponse.getCapitalizedIncomeType().getCode()); runAt("20 December 2024", () -> { Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "20 December 2024", @@ -108,6 +119,8 @@ public class LoanProductTest extends BaseLoanIntegrationTest { Assertions.assertNotNull(loanDetails.getCapitalizedIncomeStrategy()); Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(), loanDetails.getCapitalizedIncomeStrategy().getCode()); + Assertions.assertNotNull(loanDetails.getCapitalizedIncomeType()); + Assertions.assertEquals(LoanCapitalizedIncomeType.FEE.getCode(), loanDetails.getCapitalizedIncomeType().getCode()); Assertions.assertDoesNotThrow(() -> disburseLoan(loanId, BigDecimal.valueOf(430), "20 December 2024")); }); @@ -120,7 +133,8 @@ public class LoanProductTest extends BaseLoanIntegrationTest { .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) - .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())); + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()) + .capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE)); final GetLoanProductsProductIdResponse loanProductsProductIdResponse = loanProductHelper .retrieveLoanProductById(loanProductsResponse.getResourceId()); @@ -134,9 +148,14 @@ public class LoanProductTest extends BaseLoanIntegrationTest { Assertions.assertNotNull(loanProductsProductIdResponse.getAccountingMappings()); Assertions.assertEquals(feeIncomeAccount.getAccountID().longValue(), loanProductsProductIdResponse.getAccountingMappings().getIncomeFromCapitalizationAccount().getId()); + Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeType()); + Assertions.assertEquals(LoanCapitalizedIncomeType.FEE.getCode(), + loanProductsProductIdResponse.getCapitalizedIncomeType().getCode()); - loanProductHelper.updateLoanProductById(loanProductsResponse.getResourceId(), new PutLoanProductsProductIdRequest() - .enableIncomeCapitalization(false).incomeFromCapitalizationAccountId(interestIncomeAccount.getAccountID().longValue())); + loanProductHelper.updateLoanProductById(loanProductsResponse.getResourceId(), + new PutLoanProductsProductIdRequest().enableIncomeCapitalization(false) + .incomeFromCapitalizationAccountId(interestIncomeAccount.getAccountID().longValue()) + .capitalizedIncomeType(PutLoanProductsProductIdRequest.CapitalizedIncomeTypeEnum.INTEREST)); final GetLoanProductsProductIdResponse updatedLoanProductsProductIdResponse = loanProductHelper .retrieveLoanProductById(loanProductsResponse.getResourceId()); @@ -150,6 +169,9 @@ public class LoanProductTest extends BaseLoanIntegrationTest { Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getAccountingMappings()); Assertions.assertEquals(interestIncomeAccount.getAccountID().longValue(), updatedLoanProductsProductIdResponse.getAccountingMappings().getIncomeFromCapitalizationAccount().getId()); + Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getCapitalizedIncomeType()); + Assertions.assertEquals(LoanCapitalizedIncomeType.INTEREST.getCode(), + updatedLoanProductsProductIdResponse.getCapitalizedIncomeType().getCode()); } @Test @@ -161,7 +183,8 @@ public class LoanProductTest extends BaseLoanIntegrationTest { .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) - .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()))); + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()) + .capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE))); } @Test @@ -170,7 +193,8 @@ public class LoanProductTest extends BaseLoanIntegrationTest { () -> loanProductHelper.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) - .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()))); + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()) + .capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE))); } @Test @@ -179,7 +203,8 @@ public class LoanProductTest extends BaseLoanIntegrationTest { () -> loanProductHelper.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) - .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()))); + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()) + .capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE))); } @Test @@ -188,7 +213,8 @@ public class LoanProductTest extends BaseLoanIntegrationTest { () -> loanProductHelper.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) - .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()))); + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()) + .capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE))); } @Test @@ -197,7 +223,18 @@ public class LoanProductTest extends BaseLoanIntegrationTest { () -> loanProductHelper.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) - .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()))); + .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) + .capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE))); + } + + @Test + public void testIncomeCapitalizationEnabledIncomeTypeNotProvided() { + Assertions.assertThrows(RuntimeException.class, + () -> loanProductHelper.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) + .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) + .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) + .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()))); } } }