This is an automated email from the ASF dual-hosted git repository. adamsaghy pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract.git
commit d88f634197688472530a4fa58a92b7fdbce912b6 Author: adam.magyari <[email protected]> AuthorDate: Thu Apr 24 07:56:57 2025 +0200 FINERACT-2232: Capitalized income - income type config --- .../domain/LoanCapitalizedIncomeType.java | 33 +++++++++++++ .../loanschedule/domain/LoanApplicationTerms.java | 21 ++++++-- .../loanproduct/LoanProductConstants.java | 1 + .../api/LoanProductsApiResourceSwagger.java | 12 +++++ .../loanproduct/data/LoanProductData.java | 25 +++++++--- .../portfolio/loanproduct/domain/LoanProduct.java | 5 +- .../domain/LoanProductRelatedDetail.java | 12 +++-- .../loanaccount/api/LoansApiResource.java | 4 +- .../loanaccount/api/LoansApiResourceSwagger.java | 4 ++ .../loanaccount/data/LoanAccountData.java | 12 +++-- .../service/LoanScheduleAssembler.java | 3 +- .../loanaccount/service/LoanProductAssembler.java | 6 ++- .../LoanProductRelatedDetailUpdateUtil.java | 8 +++ .../service/LoanReadPlatformServiceImpl.java | 6 ++- .../loanproduct/api/LoanProductsApiResource.java | 8 ++- .../serialization/LoanProductDataValidator.java | 15 +++++- .../LoanProductReadPlatformServiceImpl.java | 9 +++- .../db/changelog/tenant/changelog-tenant.xml | 1 + ...74_loan_product_add_capitalized_income_type.xml | 37 ++++++++++++++ .../domain/DefaultScheduledDateGeneratorTest.java | 4 +- .../fineract/integrationtests/LoanProductTest.java | 57 ++++++++++++++++++---- 21 files changed, 242 insertions(+), 41 deletions(-) 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 0000000000..58d233135e --- /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<LoanCapitalizedIncomeType> { + + 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 f517a1b240..2c2cad5bbc 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<LoanSupportedInterestRefundTypes> 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 1e803ab0af..bda1839495 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 0ccc7ffeda..3e12aca89f 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<StringEnumOptionData> capitalizedIncomeCalculationTypeOptions; public List<StringEnumOptionData> capitalizedIncomeStrategyOptions; + public List<StringEnumOptionData> 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<StringEnumOptionData> capitalizedIncomeCalculationTypeOptions; public List<StringEnumOptionData> capitalizedIncomeStrategyOptions; + public List<StringEnumOptionData> 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 bcece9c7a4..a9e0bfbcc5 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<StringEnumOptionData> capitalizedIncomeCalculationTypeOptions; private List<StringEnumOptionData> capitalizedIncomeStrategyOptions; + private List<StringEnumOptionData> 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<String, Object> accountingMappings, @@ -829,7 +836,8 @@ public class LoanProductData implements Serializable { final boolean enableAccrualActivityPosting, final List<StringEnumOptionData> 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<ChargeData> chargeOptions, @@ -1007,7 +1017,8 @@ public class LoanProductData implements Serializable { final List<StringEnumOptionData> chargeOffBehaviourOptions, final List<CodeValueData> chargeOffReasonOptions, final List<StringEnumOptionData> daysInYearCustomStrategyOptions, final List<StringEnumOptionData> capitalizedIncomeCalculationTypeOptions, - final List<StringEnumOptionData> capitalizedIncomeStrategyOptions) { + final List<StringEnumOptionData> capitalizedIncomeStrategyOptions, + final List<StringEnumOptionData> 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<ChargeData> nullIfEmpty(final Collection<ChargeData> 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 31e4ab8a1d..d9f7dbd713 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<Long> { 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<Long> { 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 29b18e6cea..6ca788655e 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 04dde09757..2951426646 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 17787426d8..0b146908aa 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<PostLoansRequestChargeData> 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 4376cf077c..f2e4b2f355 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<StringEnumOptionData> daysInYearCustomStrategyOptions; private List<StringEnumOptionData> capitalizedIncomeCalculationTypeOptions; private List<StringEnumOptionData> capitalizedIncomeStrategyOptions; + private List<StringEnumOptionData> 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<EnumOptionData> loanScheduleProcessingTypeOptions, final List<LoanTermVariationsData> loanTermVariations, final List<StringEnumOptionData> daysInYearCustomStrategyOptions, final List<StringEnumOptionData> capitalizedIncomeCalculationTypeOptions, - final List<StringEnumOptionData> capitalizedIncomeStrategyOptions) { + final List<StringEnumOptionData> capitalizedIncomeStrategyOptions, + final List<StringEnumOptionData> 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<LoanProductData> 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 fe27ecb806..2db86adb9b 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 85522bed1a..2e2a3beb6b 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 da78ccf984..b84cc31e09 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 f853b38d57..1ec838ec76 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 eb41c4228d..5604d7ff51 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<String> 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<StringEnumOptionData> capitalizedIncomeStrategyOptions = ApiFacingEnum .getValuesAsStringEnumOptionDataList(LoanCapitalizedIncomeStrategy.class); + final List<StringEnumOptionData> 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 ae62944b97..3a298ce89d 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 7c316aa180..91aad12aba 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 e677629f12..6e48c15a4f 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 @@ <include file="parts/0171_loan_capitalized_income.xml" relativeToChangelogFile="true"/> <include file="parts/0172_create_loan_capitalized_income_balance.xml" relativeToChangelogFile="true"/> <include file="parts/0173_user_change_pwd.xml" relativeToChangelogFile="true" /> + <include file="parts/0174_loan_product_add_capitalized_income_type.xml" relativeToChangelogFile="true" /> </databaseChangeLog> 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 0000000000..e3e3d20427 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0174_loan_product_add_capitalized_income_type.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd"> + <changeSet author="fineract" id="1"> + <addColumn tableName="m_loan"> + <column name="capitalized_income_type" type="VARCHAR(10)"> + <constraints nullable="true"/> + </column> + </addColumn> + <addColumn tableName="m_product_loan"> + <column name="capitalized_income_type" type="VARCHAR(10)"> + <constraints nullable="true"/> + </column> + </addColumn> + </changeSet> +</databaseChangeLog> 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 d0d83caa6c..43052d0f80 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 0a6e22cf9d..6d2b2f33b4 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()))); } } }
