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())));
         }
     }
 }

Reply via email to