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 7df7be2b16dc3ec4b80dd252d901fc7b49a23052
Author: adam.magyari <[email protected]>
AuthorDate: Thu Apr 10 09:04:43 2025 +0200

    FINERACT-2232: Progressive loan income capitalization config
---
 .../LoanCapitalizedIncomeCalculationType.java      |  48 +++++++
 .../domain/LoanCapitalizedIncomeStrategy.java      |  47 +++++++
 .../loanschedule/domain/LoanApplicationTerms.java  |  47 ++++++-
 .../loanproduct/LoanProductConstants.java          |   5 +
 .../api/LoanProductsApiResourceSwagger.java        |  34 +++++
 .../loanproduct/data/LoanProductData.java          |  48 ++++++-
 .../portfolio/loanproduct/domain/LoanProduct.java  |   9 +-
 .../domain/LoanProductRelatedDetail.java           |  27 +++-
 .../loanaccount/api/LoansApiResource.java          |   6 +-
 .../loanaccount/api/LoansApiResourceSwagger.java   |  12 ++
 .../loanaccount/data/LoanAccountData.java          |  21 ++-
 .../service/LoanScheduleAssembler.java             |   5 +-
 .../loanaccount/service/LoanProductAssembler.java  |  11 +-
 .../LoanProductRelatedDetailUpdateUtil.java        |  24 ++++
 .../service/LoanReadPlatformServiceImpl.java       |  13 +-
 .../loanproduct/api/LoanProductsApiResource.java   |  13 +-
 .../serialization/LoanProductDataValidator.java    |  45 ++++++-
 .../LoanProductReadPlatformServiceImpl.java        |  16 ++-
 .../db/changelog/tenant/changelog-tenant.xml       |   1 +
 .../tenant/parts/0171_loan_capitalized_income.xml  |  49 +++++++
 .../domain/DefaultScheduledDateGeneratorTest.java  |   5 +-
 .../fineract/integrationtests/LoanProductTest.java | 147 +++++++++++++++++++++
 22 files changed, 601 insertions(+), 32 deletions(-)

diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCapitalizedIncomeCalculationType.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCapitalizedIncomeCalculationType.java
new file mode 100644
index 0000000000..5916b0074e
--- /dev/null
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCapitalizedIncomeCalculationType.java
@@ -0,0 +1,48 @@
+/**
+ * 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 java.util.Arrays;
+import java.util.List;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.infrastructure.core.data.StringEnumOptionData;
+
+@Getter
+@RequiredArgsConstructor
+public enum LoanCapitalizedIncomeCalculationType {
+
+    FLAT("loanCapitalizedIncomeCalculationType.flat", "Flat");
+
+    private final String code;
+    private final String humanReadableName;
+
+    public static List<StringEnumOptionData> 
getValuesAsStringEnumOptionDataList() {
+        return Arrays.stream(values()).map(v -> new 
StringEnumOptionData(v.name(), v.getCode(), v.getHumanReadableName())).toList();
+    }
+
+    public StringEnumOptionData getValueAsStringEnumOptionData() {
+        return new StringEnumOptionData(name(), getCode(), 
getHumanReadableName());
+    }
+
+    public static StringEnumOptionData getStringEnumOptionData(String name) {
+        return name == null || name.trim().isEmpty() ? null
+                : 
LoanCapitalizedIncomeCalculationType.valueOf(name).getValueAsStringEnumOptionData();
+    }
+}
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCapitalizedIncomeStrategy.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCapitalizedIncomeStrategy.java
new file mode 100644
index 0000000000..b0d489ce6b
--- /dev/null
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCapitalizedIncomeStrategy.java
@@ -0,0 +1,47 @@
+/**
+ * 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 java.util.Arrays;
+import java.util.List;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.infrastructure.core.data.StringEnumOptionData;
+
+@Getter
+@RequiredArgsConstructor
+public enum LoanCapitalizedIncomeStrategy {
+
+    EQUAL_AMORTIZATION("capitalizedIncome.strategy.equalAmortization", "Equal 
amortization");
+
+    private final String code;
+    private final String humanReadableName;
+
+    public static List<StringEnumOptionData> 
getValuesAsStringEnumOptionDataList() {
+        return Arrays.stream(values()).map(v -> new 
StringEnumOptionData(v.name(), v.getCode(), v.getHumanReadableName())).toList();
+    }
+
+    public StringEnumOptionData getValueAsStringEnumOptionData() {
+        return new StringEnumOptionData(name(), getCode(), 
getHumanReadableName());
+    }
+
+    public static StringEnumOptionData getStringEnumOptionData(String name) {
+        return name == null || name.trim().isEmpty() ? null : 
LoanCapitalizedIncomeStrategy.valueOf(name).getValueAsStringEnumOptionData();
+    }
+}
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 0dcc262483..f517a1b240 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
@@ -46,6 +46,8 @@ import 
org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
 import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
 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.LoanChargeOffBehaviour;
 import 
org.apache.fineract.portfolio.loanproduct.data.LoanProductRelatedDetailMinimumData;
 import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
@@ -232,6 +234,9 @@ public final class LoanApplicationTerms {
     private LoanChargeOffBehaviour chargeOffBehaviour;
     private boolean interestRecognitionOnDisbursementDate;
     private DaysInYearCustomStrategyType daysInYearCustomStrategy;
+    private boolean enableIncomeCapitalization;
+    private LoanCapitalizedIncomeCalculationType 
capitalizedIncomeCalculationType;
+    private LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy;
 
     private LoanApplicationTerms(Builder builder) {
         this.currency = builder.currency;
@@ -268,6 +273,9 @@ public final class LoanApplicationTerms {
         } else {
             this.downPaymentAmount = Money.zero(getCurrency(), builder.mc);
         }
+        this.enableIncomeCapitalization = builder.enableIncomeCapitalization;
+        this.capitalizedIncomeCalculationType = 
builder.capitalizedIncomeCalculationType;
+        this.capitalizedIncomeStrategy = builder.capitalizedIncomeStrategy;
     }
 
     public static class Builder {
@@ -297,6 +305,9 @@ public final class LoanApplicationTerms {
         private MathContext mc;
         private Boolean interestRecognitionOnDisbursementDate;
         private DaysInYearCustomStrategyType daysInYearCustomStrategy;
+        private boolean enableIncomeCapitalization;
+        private LoanCapitalizedIncomeCalculationType 
capitalizedIncomeCalculationType;
+        private LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy;
 
         public Builder currency(CurrencyData currency) {
             this.currency = currency;
@@ -413,6 +424,21 @@ public final class LoanApplicationTerms {
             return this;
         }
 
+        public Builder enableIncomeCapitalization(boolean value) {
+            this.enableIncomeCapitalization = value;
+            return this;
+        }
+
+        public Builder 
capitalizedIncomeCalculationType(LoanCapitalizedIncomeCalculationType value) {
+            this.capitalizedIncomeCalculationType = value;
+            return this;
+        }
+
+        public Builder capitalizedIncomeStrategy(LoanCapitalizedIncomeStrategy 
value) {
+            this.capitalizedIncomeStrategy = value;
+            return this;
+        }
+
         public LoanApplicationTerms build() {
             return new LoanApplicationTerms(this);
         }
@@ -480,7 +506,9 @@ public final class LoanApplicationTerms {
             final LoanScheduleProcessingType loanScheduleProcessingType, final 
Integer fixedLength,
             final boolean enableAccrualActivityPosting, final 
List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
             final LoanChargeOffBehaviour chargeOffBehaviour, final boolean 
interestRecognitionOnDisbursementDate,
-            final DaysInYearCustomStrategyType daysInYearCustomStrategy) {
+            final DaysInYearCustomStrategyType daysInYearCustomStrategy, final 
boolean enableIncomeCapitalization,
+            final LoanCapitalizedIncomeCalculationType 
capitalizedIncomeCalculationType,
+            final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy) {
 
         final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
         final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
@@ -500,7 +528,8 @@ public final class LoanApplicationTerms {
                 isPrincipalCompoundingDisabledForOverdueLoans, 
enableDownPayment, disbursedAmountPercentageForDownPayment,
                 isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, 
submittedOnDate, loanScheduleType, loanScheduleProcessingType,
                 fixedLength, enableAccrualActivityPosting, 
supportedInterestRefundTypes, chargeOffBehaviour,
-                interestRecognitionOnDisbursementDate, 
daysInYearCustomStrategy);
+                interestRecognitionOnDisbursementDate, 
daysInYearCustomStrategy, enableIncomeCapitalization,
+                capitalizedIncomeCalculationType, capitalizedIncomeStrategy);
 
     }
 
@@ -574,7 +603,9 @@ public final class LoanApplicationTerms {
                 disbursedAmountPercentageForDownPayment, 
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate,
                 loanScheduleType, loanScheduleProcessingType, fixedLength, 
loanProductRelatedDetail.isEnableAccrualActivityPosting(),
                 loanProductRelatedDetail.getSupportedInterestRefundTypes(), 
loanProductRelatedDetail.getChargeOffBehaviour(),
-                
loanProductRelatedDetail.isInterestRecognitionOnDisbursementDate(), 
loanProductRelatedDetail.getDaysInYearCustomStrategy());
+                
loanProductRelatedDetail.isInterestRecognitionOnDisbursementDate(), 
loanProductRelatedDetail.getDaysInYearCustomStrategy(),
+                loanProductRelatedDetail.isEnableIncomeCapitalization(), 
loanProductRelatedDetail.getCapitalizedIncomeCalculationType(),
+                loanProductRelatedDetail.getCapitalizedIncomeStrategy());
     }
 
     private LoanApplicationTerms(final CurrencyData currency, final Integer 
loanTermFrequency,
@@ -605,7 +636,9 @@ public final class LoanApplicationTerms {
             final RepaymentStartDateType repaymentStartDateType, final 
LocalDate submittedOnDate, final LoanScheduleType loanScheduleType,
             final LoanScheduleProcessingType loanScheduleProcessingType, final 
Integer fixedLength, boolean enableAccrualActivityPosting,
             final List<LoanSupportedInterestRefundTypes> 
supportedInterestRefundTypes, final LoanChargeOffBehaviour chargeOffBehaviour,
-            final boolean interestRecognitionOnDisbursementDate, final 
DaysInYearCustomStrategyType daysInYearCustomStrategy) {
+            final boolean interestRecognitionOnDisbursementDate, final 
DaysInYearCustomStrategyType daysInYearCustomStrategy,
+            final boolean enableIncomeCapitalization, final 
LoanCapitalizedIncomeCalculationType capitalizedIncomeCalculationType,
+            final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy) {
 
         this.currency = currency;
         this.loanTermFrequency = loanTermFrequency;
@@ -707,6 +740,9 @@ public final class LoanApplicationTerms {
         this.chargeOffBehaviour = chargeOffBehaviour;
         this.interestRecognitionOnDisbursementDate = 
interestRecognitionOnDisbursementDate;
         this.daysInYearCustomStrategy = daysInYearCustomStrategy;
+        this.enableIncomeCapitalization = enableIncomeCapitalization;
+        this.capitalizedIncomeCalculationType = 
capitalizedIncomeCalculationType;
+        this.capitalizedIncomeStrategy = capitalizedIncomeStrategy;
     }
 
     public Money adjustPrincipalIfLastRepaymentPeriod(final Money 
principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -1568,7 +1604,8 @@ public final class LoanApplicationTerms {
                 this.interestRecalculationEnabled, this.isEqualAmortization, 
this.isDownPaymentEnabled,
                 this.disbursedAmountPercentageForDownPayment, 
this.isAutoRepaymentForDownPaymentEnabled, this.loanScheduleType,
                 this.loanScheduleProcessingType, this.fixedLength, 
this.enableAccrualActivityPosting, this.supportedInterestRefundTypes,
-                this.chargeOffBehaviour, 
this.interestRecognitionOnDisbursementDate, this.daysInYearCustomStrategy);
+                this.chargeOffBehaviour, 
this.interestRecognitionOnDisbursementDate, this.daysInYearCustomStrategy,
+                this.enableIncomeCapitalization, 
this.capitalizedIncomeCalculationType, this.capitalizedIncomeStrategy);
     }
 
     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 7ee57241e7..1e803ab0af 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
@@ -171,4 +171,9 @@ public interface LoanProductConstants {
     String CHARGE_OFF_BEHAVIOUR = "chargeOffBehaviour";
 
     String INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE = 
"interestRecognitionOnDisbursementDate";
+
+    // Capitalized income
+    String ENABLE_INCOME_CAPITALIZATION_PARAM_NAME = 
"enableIncomeCapitalization";
+    String CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME = 
"capitalizedIncomeCalculationType";
+    String CAPITALIZED_INCOME_STRATEGY_PARAM_NAME = 
"capitalizedIncomeStrategy";
 }
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 8e01a143cc..caf9183f79 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
@@ -195,6 +195,12 @@ public final class LoanProductsApiResourceSwagger {
         public Boolean enableAccrualActivityPosting;
         @Schema(example = "false")
         public Boolean interestRecognitionOnDisbursementDate;
+        @Schema(example = "false")
+        public Boolean enableIncomeCapitalization;
+        @Schema(example = "FLAT", allowableValues = "FLAT")
+        public String capitalizedIncomeCalculationType;
+        @Schema(example = "EQUAL_AMORTIZATION", allowableValues = 
"EQUAL_AMORTIZATION")
+        public String capitalizedIncomeStrategy;
 
         // Interest Recalculation
         @Schema(example = "false")
@@ -651,6 +657,12 @@ public final class LoanProductsApiResourceSwagger {
         public StringEnumOptionData chargeOffBehaviour;
         @Schema(example = "false")
         public Boolean interestRecognitionOnDisbursementDate;
+        @Schema(example = "false")
+        public Boolean enableIncomeCapitalization;
+        @Schema(example = "FLAT")
+        public StringEnumOptionData capitalizedIncomeCalculationType;
+        @Schema(example = "EQUAL_AMORTIZATION")
+        public StringEnumOptionData capitalizedIncomeStrategy;
     }
 
     @Schema(description = "GetLoanProductsTemplateResponse")
@@ -1097,6 +1109,14 @@ public final class LoanProductsApiResourceSwagger {
         public List<GetLoanProductsChargeOffReasonOptions> 
chargeOffReasonOptions;
         public StringEnumOptionData chargeOffBehaviour;
         public List<StringEnumOptionData> chargeOffBehaviourOptions;
+        @Schema(example = "false")
+        public Boolean enableIncomeCapitalization;
+        @Schema(example = "FLAT")
+        public StringEnumOptionData capitalizedIncomeCalculationType;
+        @Schema(example = "EQUAL_AMORTIZATION")
+        public StringEnumOptionData capitalizedIncomeStrategy;
+        public List<StringEnumOptionData> 
capitalizedIncomeCalculationTypeOptions;
+        public List<StringEnumOptionData> capitalizedIncomeStrategyOptions;
     }
 
     @Schema(description = "GetLoanProductsProductIdResponse")
@@ -1416,6 +1436,14 @@ public final class LoanProductsApiResourceSwagger {
         public StringEnumOptionData chargeOffBehaviour;
         @Schema(example = "false")
         public Boolean interestRecognitionOnDisbursementDate;
+        @Schema(example = "false")
+        public Boolean enableIncomeCapitalization;
+        @Schema(example = "FLAT")
+        public StringEnumOptionData capitalizedIncomeCalculationType;
+        @Schema(example = "EQUAL_AMORTIZATION")
+        public StringEnumOptionData capitalizedIncomeStrategy;
+        public List<StringEnumOptionData> 
capitalizedIncomeCalculationTypeOptions;
+        public List<StringEnumOptionData> capitalizedIncomeStrategyOptions;
     }
 
     @Schema(description = "PutLoanProductsProductIdRequest")
@@ -1669,6 +1697,12 @@ public final class LoanProductsApiResourceSwagger {
         public List<String> supportedInterestRefundTypes;
         @Schema(example = "REGULAR")
         public String chargeOffBehaviour;
+        @Schema(example = "false")
+        public Boolean enableIncomeCapitalization;
+        @Schema(example = "FLAT", allowableValues = "FLAT")
+        public String capitalizedIncomeCalculationType;
+        @Schema(example = "EQUAL_AMORTIZATION", allowableValues = 
"EQUAL_AMORTIZATION")
+        public String capitalizedIncomeStrategy;
     }
 
     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 bd579d9840..4ed7c23820 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
@@ -48,6 +48,8 @@ import 
org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
 import org.apache.fineract.portfolio.floatingrates.data.FloatingRateData;
 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.LoanChargeOffBehaviour;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
@@ -238,6 +240,11 @@ public class LoanProductData implements Serializable {
     private final boolean interestRecognitionOnDisbursementDate;
     private final List<StringEnumOptionData> daysInYearCustomStrategyOptions;
     private final StringEnumOptionData daysInYearCustomStrategy;
+    private Boolean enableIncomeCapitalization;
+    private StringEnumOptionData capitalizedIncomeCalculationType;
+    private StringEnumOptionData capitalizedIncomeStrategy;
+    private List<StringEnumOptionData> capitalizedIncomeCalculationTypeOptions;
+    private List<StringEnumOptionData> capitalizedIncomeStrategyOptions;
 
     /**
      * Used when returning lookup information about loan product for dropdowns.
@@ -342,6 +349,9 @@ public class LoanProductData implements Serializable {
         final StringEnumOptionData chargeOffBehaviour = null;
         final boolean interestRecognitionOnDisbursementDate = false;
         final StringEnumOptionData daysInYearTypeCustomStrategy = null;
+        final boolean enableIncomeCapitalization = false;
+        final StringEnumOptionData capitalizedIncomeCalculationType = null;
+        final StringEnumOptionData capitalizedIncomeStrategy = null;
 
         return new LoanProductData(id, name, shortName, description, currency, 
principal, minPrincipal, maxPrincipal, tolerance,
                 numberOfRepayments, minNumberOfRepayments, 
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -363,7 +373,8 @@ public class LoanProductData implements Serializable {
                 overDueDaysForRepaymentEvent, enableDownPayment, 
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
                 paymentAllocation, creditAllocation, repaymentStartDateType, 
enableInstallmentLevelDelinquency, loanScheduleType,
                 loanScheduleProcessingType, fixedLength, 
enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour,
-                interestRecognitionOnDisbursementDate, 
daysInYearTypeCustomStrategy);
+                interestRecognitionOnDisbursementDate, 
daysInYearTypeCustomStrategy, enableIncomeCapitalization,
+                capitalizedIncomeCalculationType, capitalizedIncomeStrategy);
 
     }
 
@@ -468,6 +479,9 @@ public class LoanProductData implements Serializable {
         final StringEnumOptionData chargeOffBehaviour = null;
         final boolean interestRecognitionOnDisbursementDate = false;
         final StringEnumOptionData daysInYearTypeCustomStrategy = null;
+        final boolean enableIncomeCapitalization = false;
+        final StringEnumOptionData capitalizedIncomeCalculationType = null;
+        final StringEnumOptionData capitalizedIncomeStrategy = null;
 
         return new LoanProductData(id, name, shortName, description, currency, 
principal, minPrincipal, maxPrincipal, tolerance,
                 numberOfRepayments, minNumberOfRepayments, 
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -489,7 +503,8 @@ public class LoanProductData implements Serializable {
                 overDueDaysForRepaymentEvent, enableDownPayment, 
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
                 paymentAllocation, creditAllocation, repaymentStartDateType, 
enableInstallmentLevelDelinquency, loanScheduleType,
                 loanScheduleProcessingType, fixedLength, 
enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour,
-                interestRecognitionOnDisbursementDate, 
daysInYearTypeCustomStrategy);
+                interestRecognitionOnDisbursementDate, 
daysInYearTypeCustomStrategy, enableIncomeCapitalization,
+                capitalizedIncomeCalculationType, capitalizedIncomeStrategy);
 
     }
 
@@ -601,6 +616,9 @@ public class LoanProductData implements Serializable {
         final StringEnumOptionData chargeOffBehaviour = 
LoanChargeOffBehaviour.REGULAR.getValueAsStringEnumOptionData();
         final boolean interestRecognitionOnDisbursementDate = false;
         final StringEnumOptionData daysInYearTypeCustomStrategy = null;
+        final boolean enableIncomeCapitalization = false;
+        final StringEnumOptionData capitalizedIncomeCalculationType = null;
+        final StringEnumOptionData capitalizedIncomeStrategy = null;
 
         return new LoanProductData(id, name, shortName, description, currency, 
principal, minPrincipal, maxPrincipal, tolerance,
                 numberOfRepayments, minNumberOfRepayments, 
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -622,7 +640,8 @@ public class LoanProductData implements Serializable {
                 overDueDaysForRepaymentEvent, enableDownPayment, 
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
                 paymentAllocation, creditAllocation, repaymentStartDateType, 
enableInstallmentLevelDelinquency, loanScheduleType,
                 loanScheduleProcessingType, fixedLength, 
enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour,
-                interestRecognitionOnDisbursementDate, 
daysInYearTypeCustomStrategy);
+                interestRecognitionOnDisbursementDate, 
daysInYearTypeCustomStrategy, enableIncomeCapitalization,
+                capitalizedIncomeCalculationType, capitalizedIncomeStrategy);
 
     }
 
@@ -728,6 +747,9 @@ public class LoanProductData implements Serializable {
         final StringEnumOptionData chargeOffBehaviour = null;
         final boolean interestRecognitionOnDisbursementDate = false;
         final StringEnumOptionData daysInYearTypeCustomStrategy = null;
+        final boolean enableIncomeCapitalization = false;
+        final StringEnumOptionData capitalizedIncomeCalculationType = null;
+        final StringEnumOptionData capitalizedIncomeStrategy = null;
 
         return new LoanProductData(id, name, shortName, description, currency, 
principal, minPrincipal, maxPrincipal, tolerance,
                 numberOfRepayments, minNumberOfRepayments, 
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -749,7 +771,8 @@ public class LoanProductData implements Serializable {
                 overDueDaysForRepaymentEvent, enableDownPayment, 
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
                 paymentAllocation, creditAllocationData, 
repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
                 loanScheduleProcessingType, fixedLength, 
enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour,
-                interestRecognitionOnDisbursementDate, 
daysInYearTypeCustomStrategy);
+                interestRecognitionOnDisbursementDate, 
daysInYearTypeCustomStrategy, enableIncomeCapitalization,
+                capitalizedIncomeCalculationType, capitalizedIncomeStrategy);
     }
 
     public static LoanProductData withAccountingDetails(final LoanProductData 
productData, final Map<String, Object> accountingMappings,
@@ -804,7 +827,8 @@ public class LoanProductData implements Serializable {
             final EnumOptionData loanScheduleType, final EnumOptionData 
loanScheduleProcessingType, final Integer fixedLength,
             final boolean enableAccrualActivityPosting, final 
List<StringEnumOptionData> supportedInterestRefundTypes,
             StringEnumOptionData chargeOffBehaviour, final boolean 
interestRecognitionOnDisbursementDate,
-            final StringEnumOptionData daysInYearCustomStrategy) {
+            final StringEnumOptionData daysInYearCustomStrategy, final boolean 
enableIncomeCapitalization,
+            final StringEnumOptionData capitalizedIncomeCalculationType, final 
StringEnumOptionData capitalizedIncomeStrategy) {
         this.id = id;
         this.name = name;
         this.shortName = shortName;
@@ -861,6 +885,9 @@ public class LoanProductData implements Serializable {
         this.rates = rates;
         this.isRatesEnabled = isRatesEnabled;
         this.daysInYearCustomStrategy = daysInYearCustomStrategy;
+        this.enableIncomeCapitalization = enableIncomeCapitalization;
+        this.capitalizedIncomeCalculationType = 
capitalizedIncomeCalculationType;
+        this.capitalizedIncomeStrategy = capitalizedIncomeStrategy;
 
         this.chargeOptions = null;
         this.penaltyOptions = null;
@@ -950,6 +977,8 @@ public class LoanProductData implements Serializable {
         this.chargeOffReasonOptions = null;
         this.interestRecognitionOnDisbursementDate = 
interestRecognitionOnDisbursementDate;
         this.daysInYearCustomStrategyOptions = 
DaysInYearCustomStrategyType.getValuesAsStringEnumOptionDataList();
+        this.capitalizedIncomeCalculationTypeOptions = 
LoanCapitalizedIncomeCalculationType.getValuesAsStringEnumOptionDataList();
+        this.capitalizedIncomeStrategyOptions = 
LoanCapitalizedIncomeStrategy.getValuesAsStringEnumOptionDataList();
     }
 
     public LoanProductData(final LoanProductData productData, final 
Collection<ChargeData> chargeOptions,
@@ -974,7 +1003,9 @@ public class LoanProductData implements Serializable {
             final List<EnumOptionData> creditAllocationAllocationTypes,
             final List<StringEnumOptionData> 
supportedInterestRefundTypesOptions,
             final List<StringEnumOptionData> chargeOffBehaviourOptions, final 
List<CodeValueData> chargeOffReasonOptions,
-            final List<StringEnumOptionData> daysInYearCustomStrategyOptions) {
+            final List<StringEnumOptionData> daysInYearCustomStrategyOptions,
+            final List<StringEnumOptionData> 
capitalizedIncomeCalculationTypeOptions,
+            final List<StringEnumOptionData> capitalizedIncomeStrategyOptions) 
{
 
         this.id = productData.id;
         this.name = productData.name;
@@ -1138,6 +1169,11 @@ public class LoanProductData implements Serializable {
         this.interestRecognitionOnDisbursementDate = 
productData.interestRecognitionOnDisbursementDate;
         this.daysInYearCustomStrategyOptions = daysInYearCustomStrategyOptions;
         this.daysInYearCustomStrategy = productData.daysInYearCustomStrategy;
+        this.enableIncomeCapitalization = 
productData.enableIncomeCapitalization;
+        this.capitalizedIncomeCalculationType = 
productData.capitalizedIncomeCalculationType;
+        this.capitalizedIncomeStrategy = productData.capitalizedIncomeStrategy;
+        this.capitalizedIncomeCalculationTypeOptions = 
capitalizedIncomeCalculationTypeOptions;
+        this.capitalizedIncomeStrategyOptions = 
capitalizedIncomeStrategyOptions;
     }
 
     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 c9b85ac25f..31e4ab8a1d 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
@@ -59,6 +59,8 @@ import 
org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
 import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
 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.LoanChargeOffBehaviour;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
@@ -280,7 +282,9 @@ public class LoanProduct extends 
AbstractPersistableCustom<Long> {
             final LoanScheduleProcessingType loanScheduleProcessingType, final 
Integer fixedLength,
             final boolean enableAccrualActivityPosting, final 
List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
             final LoanChargeOffBehaviour chargeOffBehaviour, final boolean 
isInterestRecognitionOnDisbursementDate,
-            final DaysInYearCustomStrategyType daysInYearCustomStrategy) {
+            final DaysInYearCustomStrategyType daysInYearCustomStrategy, final 
boolean enableIncomeCapitalization,
+            final LoanCapitalizedIncomeCalculationType 
capitalizedIncomeCalculationType,
+            final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy) {
         this.fund = fund;
         this.transactionProcessingStrategyCode = 
transactionProcessingStrategyCode;
 
@@ -330,7 +334,8 @@ public class LoanProduct extends 
AbstractPersistableCustom<Long> {
                 inArrearsTolerance, graceOnArrearsAgeing, 
daysInMonthType.getValue(), daysInYearType.getValue(),
                 isInterestRecalculationEnabled, isEqualAmortization, 
enableDownPayment, disbursedAmountPercentageForDownPayment,
                 enableAutoRepaymentForDownPayment, loanScheduleType, 
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting,
-                supportedInterestRefundTypes, chargeOffBehaviour, 
isInterestRecognitionOnDisbursementDate, daysInYearCustomStrategy);
+                supportedInterestRefundTypes, chargeOffBehaviour, 
isInterestRecognitionOnDisbursementDate, daysInYearCustomStrategy,
+                enableIncomeCapitalization, capitalizedIncomeCalculationType, 
capitalizedIncomeStrategy);
 
         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 a1a68ae214..29b18e6cea 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
@@ -36,6 +36,8 @@ import 
org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType;
 import org.apache.fineract.portfolio.common.domain.DaysInYearType;
 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.LoanChargeOffBehaviour;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
@@ -168,6 +170,17 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
     @Column(name = "days_in_year_custom_strategy")
     private DaysInYearCustomStrategyType daysInYearCustomStrategy;
 
+    @Column(name = "enable_income_capitalization")
+    private boolean enableIncomeCapitalization = false;
+
+    @Enumerated(EnumType.STRING)
+    @Column(name = "capitalized_income_calculation_type")
+    private LoanCapitalizedIncomeCalculationType 
capitalizedIncomeCalculationType;
+
+    @Enumerated(EnumType.STRING)
+    @Column(name = "capitalized_income_strategy")
+    private LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy;
+
     public static LoanProductRelatedDetail createFrom(final CurrencyData 
currencyData, final BigDecimal principal,
             final BigDecimal nominalInterestRatePerPeriod, final 
PeriodFrequencyType interestRatePeriodFrequencyType,
             final BigDecimal nominalAnnualInterestRate, final InterestMethod 
interestMethod,
@@ -182,7 +195,9 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
             final LoanScheduleProcessingType loanScheduleProcessingType, final 
Integer fixedLength,
             final boolean enableAccrualActivityPosting, final 
List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
             final LoanChargeOffBehaviour chargeOffBehaviour, final boolean 
interestRecognitionOnDisbursementDate,
-            final DaysInYearCustomStrategyType daysInYearCustomStrategy) {
+            final DaysInYearCustomStrategyType daysInYearCustomStrategy, final 
boolean enableIncomeCapitalization,
+            final LoanCapitalizedIncomeCalculationType 
capitalizedIncomeCalculationType,
+            final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy) {
 
         final MonetaryCurrency currency = 
MonetaryCurrency.fromCurrencyData(currencyData);
         return new LoanProductRelatedDetail(currency, principal, 
nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
@@ -192,7 +207,8 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
                 inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, 
daysInYearType, isInterestRecalculationEnabled,
                 isEqualAmortization, enableDownPayment, 
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment,
                 loanScheduleType, loanScheduleProcessingType, fixedLength, 
enableAccrualActivityPosting, supportedInterestRefundTypes,
-                chargeOffBehaviour, interestRecognitionOnDisbursementDate, 
daysInYearCustomStrategy);
+                chargeOffBehaviour, interestRecognitionOnDisbursementDate, 
daysInYearCustomStrategy, enableIncomeCapitalization,
+                capitalizedIncomeCalculationType, capitalizedIncomeStrategy);
     }
 
     protected LoanProductRelatedDetail() {
@@ -213,7 +229,9 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
             final LoanScheduleProcessingType loanScheduleProcessingType, final 
Integer fixedLength,
             final boolean enableAccrualActivityPosting, 
List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
             final LoanChargeOffBehaviour chargeOffBehaviour, final boolean 
interestRecognitionOnDisbursementDate,
-            final DaysInYearCustomStrategyType daysInYearCustomStrategy) {
+            final DaysInYearCustomStrategyType daysInYearCustomStrategy, final 
boolean enableIncomeCapitalization,
+            final LoanCapitalizedIncomeCalculationType 
capitalizedIncomeCalculationType,
+            final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy) {
         this.currency = currency;
         this.principal = defaultPrincipal;
         this.nominalInterestRatePerPeriod = 
defaultNominalInterestRatePerPeriod;
@@ -251,6 +269,9 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
         this.chargeOffBehaviour = chargeOffBehaviour;
         this.interestRecognitionOnDisbursementDate = 
interestRecognitionOnDisbursementDate;
         this.daysInYearCustomStrategy = daysInYearCustomStrategy;
+        this.enableIncomeCapitalization = enableIncomeCapitalization;
+        this.capitalizedIncomeCalculationType = 
capitalizedIncomeCalculationType;
+        this.capitalizedIncomeStrategy = capitalizedIncomeStrategy;
     }
 
     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 ef4a8c075f..b57888bc03 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
@@ -132,6 +132,8 @@ import 
org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
 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.LoanStatus;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryBalancesRepository;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
@@ -1135,7 +1137,9 @@ public class LoansApiResource {
                 loanCollateralOptions, calendarOptions, notes, 
accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
                 overdueCharges, paidInAdvanceTemplate, interestRatesPeriods, 
clientActiveLoanOptions, rates, isRatesEnabled, collectionData,
                 LoanScheduleType.getValuesAsEnumOptionDataList(), 
LoanScheduleProcessingType.getValuesAsEnumOptionDataList(),
-                loanTermVariations, 
DaysInYearCustomStrategyType.getValuesAsStringEnumOptionDataList());
+                loanTermVariations, 
DaysInYearCustomStrategyType.getValuesAsStringEnumOptionDataList(),
+                
LoanCapitalizedIncomeCalculationType.getValuesAsStringEnumOptionDataList(),
+                
LoanCapitalizedIncomeStrategy.getValuesAsStringEnumOptionDataList());
 
         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 d549371e4f..17787426d8 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
@@ -1206,6 +1206,12 @@ final class LoansApiResourceSwagger {
         public StringEnumOptionData chargeOffBehaviour;
         @Schema(example = "false")
         public Boolean interestRecognitionOnDisbursementDate;
+        @Schema(example = "false")
+        public Boolean enableIncomeCapitalization;
+        @Schema(example = "FLAT")
+        public StringEnumOptionData capitalizedIncomeCalculationType;
+        @Schema(example = "EQUAL_AMORTIZATION")
+        public StringEnumOptionData capitalizedIncomeStrategy;
     }
 
     @Schema(description = "GetLoansResponse")
@@ -1309,6 +1315,12 @@ final class LoansApiResourceSwagger {
         public BigDecimal fixedEmiAmount;
         @Schema(example = "false")
         public Boolean interestRecognitionOnDisbursementDate;
+        @Schema(example = "false")
+        public Boolean enableIncomeCapitalization;
+        @Schema(example = "FLAT", allowableValues = "FLAT")
+        public String capitalizedIncomeCalculationType;
+        @Schema(example = "EQUAL_AMORTIZATION", allowableValues = 
"EQUAL_AMORTIZATION")
+        public String capitalizedIncomeStrategy;
 
         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 1d7a6f21c0..825293fdb6 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
@@ -172,6 +172,8 @@ public class LoanAccountData {
     private List<EnumOptionData> loanScheduleTypeOptions;
     private List<EnumOptionData> loanScheduleProcessingTypeOptions;
     private List<StringEnumOptionData> daysInYearCustomStrategyOptions;
+    private List<StringEnumOptionData> capitalizedIncomeCalculationTypeOptions;
+    private List<StringEnumOptionData> capitalizedIncomeStrategyOptions;
 
     @Transient
     private BigDecimal feeChargesAtDisbursementCharged;
@@ -274,6 +276,9 @@ public class LoanAccountData {
     private EnumOptionData loanScheduleProcessingType;
 
     private StringEnumOptionData chargeOffBehaviour;
+    private Boolean enableIncomeCapitalization;
+    private StringEnumOptionData capitalizedIncomeCalculationType;
+    private StringEnumOptionData capitalizedIncomeStrategy;
 
     public static LoanAccountData importInstanceIndividual(EnumOptionData 
loanTypeEnumOption, Long clientId, Long productId,
             Long loanOfficerId, LocalDate submittedOnDate, Long fundId, 
BigDecimal principal, Integer numberOfRepayments,
@@ -464,7 +469,9 @@ public class LoanAccountData {
             final BigDecimal disbursedAmountPercentageForDownPayment, final 
boolean enableAutoRepaymentForDownPayment,
             final boolean enableInstallmentLevelDelinquency, final 
EnumOptionData loanScheduleType,
             final EnumOptionData loanScheduleProcessingType, final Integer 
fixedLength, final StringEnumOptionData chargeOffBehaviour,
-            final boolean isInterestRecognitionOnDisbursementDate, final 
StringEnumOptionData daysInYearCustomStrategy) {
+            final boolean isInterestRecognitionOnDisbursementDate, final 
StringEnumOptionData daysInYearCustomStrategy,
+            final boolean enableIncomeCapitalization, final 
StringEnumOptionData capitalizedIncomeCalculationType,
+            final StringEnumOptionData capitalizedIncomeStrategy) {
 
         final CollectionData delinquent = CollectionData.template();
 
@@ -510,7 +517,9 @@ public class LoanAccountData {
                 
.setEnableInstallmentLevelDelinquency(enableInstallmentLevelDelinquency).setLoanScheduleType(loanScheduleType)
                 
.setLoanScheduleProcessingType(loanScheduleProcessingType).setFixedLength(fixedLength)
                 
.setChargeOffBehaviour(chargeOffBehaviour).setInterestRecognitionOnDisbursementDate(isInterestRecognitionOnDisbursementDate)
-                .setDaysInYearCustomStrategy(daysInYearCustomStrategy);
+                
.setDaysInYearCustomStrategy(daysInYearCustomStrategy).setEnableIncomeCapitalization(enableIncomeCapitalization)
+                
.setCapitalizedIncomeCalculationType(capitalizedIncomeCalculationType)
+                .setCapitalizedIncomeStrategy(capitalizedIncomeStrategy);
     }
 
     /*
@@ -536,7 +545,9 @@ public class LoanAccountData {
             final Collection<LoanAccountSummaryData> clientActiveLoanOptions, 
final List<RateData> rates, final Boolean isRatesEnabled,
             final CollectionData delinquent, final List<EnumOptionData> 
loanScheduleTypeOptions,
             final List<EnumOptionData> loanScheduleProcessingTypeOptions, 
final List<LoanTermVariationsData> loanTermVariations,
-            final List<StringEnumOptionData> daysInYearCustomStrategyOptions) {
+            final List<StringEnumOptionData> daysInYearCustomStrategyOptions,
+            final List<StringEnumOptionData> 
capitalizedIncomeCalculationTypeOptions,
+            final List<StringEnumOptionData> capitalizedIncomeStrategyOptions) 
{
 
         // TODO: why are these variables 'calendarData', 'chargeTemplate' 
never used (see original private constructor)
 
@@ -557,7 +568,9 @@ public class LoanAccountData {
                 
.setClientActiveLoanOptions(clientActiveLoanOptions).setRates(rates).setIsRatesEnabled(isRatesEnabled)
                 
.setDelinquent(delinquent).setLoanScheduleTypeOptions(loanScheduleTypeOptions)
                 
.setLoanScheduleProcessingTypeOptions(loanScheduleProcessingTypeOptions).setLoanTermVariations(loanTermVariations)
-                
.setDaysInYearCustomStrategyOptions(daysInYearCustomStrategyOptions);
+                
.setDaysInYearCustomStrategyOptions(daysInYearCustomStrategyOptions)
+                
.setCapitalizedIncomeCalculationTypeOptions(capitalizedIncomeCalculationTypeOptions)
+                
.setCapitalizedIncomeStrategyOptions(capitalizedIncomeStrategyOptions);
     }
 
     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 f6fb5578f3..b4ac0b05c5 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
@@ -544,7 +544,10 @@ public class LoanScheduleAssembler {
                 
loanProduct.getLoanProductRelatedDetail().isEnableAccrualActivityPosting(),
                 
loanProduct.getLoanProductRelatedDetail().getSupportedInterestRefundTypes(),
                 
loanProduct.getLoanProductRelatedDetail().getChargeOffBehaviour(), 
interestRecognitionOnDisbursementDate,
-                
loanProduct.getLoanProductRelatedDetail().getDaysInYearCustomStrategy());
+                
loanProduct.getLoanProductRelatedDetail().getDaysInYearCustomStrategy(),
+                
loanProduct.getLoanProductRelatedDetail().isEnableIncomeCapitalization(),
+                
loanProduct.getLoanProductRelatedDetail().getCapitalizedIncomeCalculationType(),
+                
loanProduct.getLoanProductRelatedDetail().getCapitalizedIncomeStrategy());
     }
 
     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 67b748065d..85522bed1a 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
@@ -40,6 +40,8 @@ import 
org.apache.fineract.portfolio.common.domain.DaysInYearType;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 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.LoanChargeOffBehaviour;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
@@ -305,6 +307,13 @@ public class LoanProductAssembler {
             chargeOffBehaviour = LoanChargeOffBehaviour.REGULAR;
         }
 
+        final boolean enableIncomeCapitalization = command
+                
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME);
+        final LoanCapitalizedIncomeCalculationType 
capitalizedIncomeCalculationType = command.enumValueOfParameterNamed(
+                
LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME, 
LoanCapitalizedIncomeCalculationType.class);
+        final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy = 
command.enumValueOfParameterNamed(
+                LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME, 
LoanCapitalizedIncomeStrategy.class);
+
         return new LoanProduct(fund, loanTransactionProcessingStrategy, 
loanProductPaymentAllocationRules, loanProductCreditAllocationRules,
                 name, shortName, description, currency, principal, 
minPrincipal, maxPrincipal, interestRatePerPeriod,
                 minInterestRatePerPeriod, maxInterestRatePerPeriod, 
interestFrequencyType, annualInterestRate, interestMethod,
@@ -325,7 +334,7 @@ public class LoanProductAssembler {
                 overDueDaysForRepaymentEvent, enableDownPayment, 
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
                 repaymentStartDateType, enableInstallmentLevelDelinquency, 
loanScheduleType, loanScheduleProcessingType, fixedLength,
                 enableAccrualActivityPosting, supportedInterestRefundTypes, 
chargeOffBehaviour, interestRecognitionOnDisbursementDate,
-                daysInYearCustomStrategy);
+                daysInYearCustomStrategy, enableIncomeCapitalization, 
capitalizedIncomeCalculationType, capitalizedIncomeStrategy);
 
     }
 
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 9e286fe24d..da78ccf984 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
@@ -26,6 +26,8 @@ import 
org.apache.fineract.infrastructure.core.api.JsonCommand;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 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.loanschedule.domain.AprCalculator;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
@@ -296,6 +298,28 @@ public class LoanProductRelatedDetailUpdateUtil {
             
loanRepaymentScheduleDetail.updateInterestRecognitionOnDisbursementDate(newValue);
         }
 
+        if 
(command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME,
+                loanRepaymentScheduleDetail.isEnableIncomeCapitalization())) {
+            final boolean newValue = command
+                    
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME);
+            
actualChanges.put(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME, 
newValue);
+            
loanRepaymentScheduleDetail.setEnableIncomeCapitalization(newValue);
+        }
+
+        if 
(command.parameterExists(LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME))
 {
+            final LoanCapitalizedIncomeCalculationType newValue = 
command.enumValueOfParameterNamed(
+                    
LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME, 
LoanCapitalizedIncomeCalculationType.class);
+            
actualChanges.put(LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME,
 newValue);
+            
loanRepaymentScheduleDetail.setCapitalizedIncomeCalculationType(newValue);
+        }
+
+        if 
(command.parameterExists(LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME))
 {
+            final LoanCapitalizedIncomeStrategy newValue = 
command.enumValueOfParameterNamed(
+                    
LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME, 
LoanCapitalizedIncomeStrategy.class);
+            
actualChanges.put(LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME, 
newValue);
+            loanRepaymentScheduleDetail.setCapitalizedIncomeStrategy(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 f5f61cdf2b..e2399aeeab 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
@@ -106,6 +106,8 @@ import 
org.apache.fineract.portfolio.loanaccount.data.PaidInAdvanceData;
 import 
org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
 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.LoanChargeOffBehaviour;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
@@ -722,6 +724,9 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService, Loa
                     + " l.is_floating_interest_rate as isFloatingInterestRate, 
"
                     + " l.interest_rate_differential as 
interestRateDifferential, "
                     + " l.days_in_year_custom_strategy as 
daysInYearCustomStrategy, "
+                    + " l.enable_income_capitalization as 
enableIncomeCapitalization, "
+                    + " l.capitalized_income_calculation_type as 
capitalizedIncomeCalculationType, "
+                    + " l.capitalized_income_strategy as 
capitalizedIncomeStrategy, "
                     + " 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, "
@@ -1098,6 +1103,11 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService, Loa
             final boolean interestRecognitionOnDisbursementDate = 
rs.getBoolean("interestRecognitionOnDisbursementDate");
             final StringEnumOptionData daysInYearCustomStrategy = 
DaysInYearCustomStrategyType
                     
.getStringEnumOptionData(rs.getString("daysInYearCustomStrategy"));
+            final boolean enableIncomeCapitalization = 
rs.getBoolean("enableIncomeCapitalization");
+            final StringEnumOptionData capitalizedIncomeCalculationType = 
LoanCapitalizedIncomeCalculationType
+                    
.getStringEnumOptionData(rs.getString("capitalizedIncomeCalculationType"));
+            final StringEnumOptionData capitalizedIncomeStrategy = 
LoanCapitalizedIncomeStrategy
+                    
.getStringEnumOptionData(rs.getString("capitalizedIncomeStrategy"));
 
             return LoanAccountData.basicLoanDetails(id, accountNo, status, 
externalId, clientId, clientAccountNo, clientName,
                     clientOfficeId, clientExternalId, groupData, loanType, 
loanProductId, loanProductName, loanProductDescription,
@@ -1117,7 +1127,8 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService, Loa
                     lastClosedBusinessDate, overpaidOnDate, isChargedOff, 
enableDownPayment, disbursedAmountPercentageForDownPayment,
                     enableAutoRepaymentForDownPayment, 
enableInstallmentLevelDelinquency, loanScheduleType.asEnumOptionData(),
                     loanScheduleProcessingType.asEnumOptionData(), 
fixedLength, chargeOffBehaviour.getValueAsStringEnumOptionData(),
-                    interestRecognitionOnDisbursementDate, 
daysInYearCustomStrategy);
+                    interestRecognitionOnDisbursementDate, 
daysInYearCustomStrategy, enableIncomeCapitalization,
+                    capitalizedIncomeCalculationType, 
capitalizedIncomeStrategy);
         }
     }
 
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 f45322979d..271b1f7107 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
@@ -81,6 +81,8 @@ import 
org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlat
 import org.apache.fineract.portfolio.fund.data.FundData;
 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.LoanChargeOffBehaviour;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
@@ -127,7 +129,10 @@ public class LoanProductsApiResource {
             LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, 
LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT,
             LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT, 
LoanProductConstants.ENABLE_DOWN_PAYMENT,
             LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT, 
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
-            LoanProductConstants.REPAYMENT_START_DATE_TYPE, 
LoanProductConstants.DAYS_IN_YEAR_CUSTOM_STRATEGY_TYPE_PARAMETER_NAME));
+            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));
 
     private static final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new 
HashSet<>(
             Arrays.asList("productId", "productName", "restrictedProducts", 
"allowedProducts", "productOptions"));
@@ -439,6 +444,10 @@ public class LoanProductsApiResource {
                 .retrieveCodeValuesByCode(LoanApiConstants.CHARGE_OFF_REASONS);
         final List<StringEnumOptionData> daysInYearCustomStrategyOptions = 
DaysInYearCustomStrategyType
                 .getValuesAsStringEnumOptionDataList();
+        final List<StringEnumOptionData> 
capitalizedIncomeCalculationTypeOptions = LoanCapitalizedIncomeCalculationType
+                .getValuesAsStringEnumOptionDataList();
+        final List<StringEnumOptionData> capitalizedIncomeStrategyOptions = 
LoanCapitalizedIncomeStrategy
+                .getValuesAsStringEnumOptionDataList();
 
         return new LoanProductData(productData, chargeOptions, penaltyOptions, 
paymentTypeOptions, currencyOptions, amortizationTypeOptions,
                 interestTypeOptions, interestCalculationPeriodTypeOptions, 
repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions,
@@ -451,7 +460,7 @@ public class LoanProductsApiResource {
                 advancedPaymentAllocationTypes, 
LoanScheduleType.getValuesAsEnumOptionDataList(),
                 LoanScheduleProcessingType.getValuesAsEnumOptionDataList(), 
creditAllocationTransactionTypes,
                 creditAllocationAllocationTypes, 
supportedInterestRefundTypesOptions, chargeOffBehaviourOptions, 
chargeOffReasonOptions,
-                daysInYearCustomStrategyOptions);
+                daysInYearCustomStrategyOptions, 
capitalizedIncomeCalculationTypeOptions, capitalizedIncomeStrategyOptions);
     }
 
 }
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 d2e29d0add..81c8d5b878 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
@@ -49,6 +49,8 @@ import 
org.apache.fineract.infrastructure.core.service.MathUtil;
 import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
 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.LoanChargeOffBehaviour;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
@@ -186,7 +188,10 @@ public final class LoanProductDataValidator {
             LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, 
LoanProductConstants.FIXED_LENGTH,
             LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING, 
LoanProductConstants.SUPPORTED_INTEREST_REFUND_TYPES,
             LoanProductConstants.CHARGE_OFF_BEHAVIOUR, 
LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE,
-            
LoanProductConstants.DAYS_IN_YEAR_CUSTOM_STRATEGY_TYPE_PARAMETER_NAME));
+            
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));
 
     private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { 
LoanProductConstants.amortizationTypeParamName,
             LoanProductConstants.interestTypeParamName, 
LoanProductConstants.transactionProcessingStrategyCodeParamName,
@@ -877,6 +882,8 @@ public final class LoanProductDataValidator {
                     "Charge off behaviour is only supported for Progressive 
loans");
         }
 
+        validateIncomeCapitalization(transactionProcessingStrategyCode, 
element, baseDataValidator);
+
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
     }
 
@@ -1922,6 +1929,9 @@ public final class LoanProductDataValidator {
 
         validateRepaymentPeriodWithGraceSettings(numberOfRepayments, 
graceOnPrincipalPayment, graceOnInterestPayment,
                 graceOnInterestCharged, recurringMoratoriumOnPrincipalPeriods, 
baseDataValidator);
+
+        validateIncomeCapitalization(transactionProcessingStrategyCode, 
element, baseDataValidator);
+
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
     }
 
@@ -2660,6 +2670,39 @@ public final class LoanProductDataValidator {
         }
     }
 
+    private void validateIncomeCapitalization(String 
transactionProcessingStrategyCode, JsonElement element,
+            DataValidatorBuilder baseDataValidator) {
+        if 
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME,
 element)) {
+            final String capitalizedIncomeCalculationType = 
this.fromApiJsonHelper
+                    
.extractStringNamed(LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME,
 element);
+            
baseDataValidator.reset().parameter(LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME)
+                    
.value(capitalizedIncomeCalculationType).isOneOfEnumValues(LoanCapitalizedIncomeCalculationType.class);
+        }
+
+        if 
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME,
 element)) {
+            final String capitalizedIncomeStrategy = this.fromApiJsonHelper
+                    
.extractStringNamed(LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME,
 element);
+            
baseDataValidator.reset().parameter(LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME)
+                    
.value(capitalizedIncomeStrategy).isOneOfEnumValues(LoanCapitalizedIncomeStrategy.class);
+        }
+
+        if 
(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY.equals(transactionProcessingStrategyCode)
+                && 
this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME,
 element)) {
+            Boolean enableIncomeCapitalization = this.fromApiJsonHelper
+                    
.extractBooleanNamed(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME,
 element);
+            
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME)
+                    
.value(enableIncomeCapitalization).ignoreIfNull().validateForBooleanValue();
+        } else if 
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME,
 element)) {
+            Boolean enableIncomeCapitalization = this.fromApiJsonHelper
+                    
.extractBooleanNamed(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME,
 element);
+            if (Boolean.TRUE.equals(enableIncomeCapitalization)) {
+                
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME).failWithCode(
+                        
"supported.only.for.progressive.loan.income.capitalization",
+                        "Income capitalization is only supported for 
Progressive loans");
+            }
+        }
+    }
+
     private Integer defaultToZeroIfNull(Integer value) {
         return value != null ? value : 0;
     }
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 c3fe4c728f..4c436216c1 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
@@ -45,6 +45,8 @@ import 
org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType;
 import org.apache.fineract.portfolio.common.service.CommonEnumerations;
 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.LoanChargeOffBehaviour;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
@@ -288,8 +290,11 @@ public class LoanProductReadPlatformServiceImpl implements 
LoanProductReadPlatfo
                     + "lp.allow_variabe_installments as 
isVariableIntallmentsAllowed, " + "lvi.minimum_gap as minimumGap, "
                     + "lvi.maximum_gap as maximumGap, dbuc.id as 
delinquencyBucketId, dbuc.name as delinquencyBucketName, "
                     + "lp.can_use_for_topup as canUseForTopup, 
lp.is_equal_amortization as isEqualAmortization, lp.loan_schedule_type as 
loanScheduleType, lp.loan_schedule_processing_type as 
loanScheduleProcessingType, lp.supported_interest_refund_types as 
supportedInterestRefundTypes, "
-                    + "lp.charge_off_behaviour as chargeOffBehaviour" + " from 
m_product_loan lp "
-                    + " left join m_fund f on f.id = lp.fund_id "
+                    + "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 " //
+                    + " 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 "
                     + " left join m_product_loan_configurable_attributes lca 
on lca.loan_product_id = lp.id "
@@ -552,6 +557,11 @@ public class LoanProductReadPlatformServiceImpl implements 
LoanProductReadPlatfo
             final String chargeOffBehaviourStr = 
rs.getString("chargeOffBehaviour");
             final LoanChargeOffBehaviour loanChargeOffBehaviour = 
LoanChargeOffBehaviour.valueOf(chargeOffBehaviourStr);
             final boolean interestRecognitionOnDisbursementDate = 
rs.getBoolean("interestRecognitionOnDisbursementDate");
+            final boolean enableIncomeCapitalization = 
rs.getBoolean("enableIncomeCapitalization");
+            final StringEnumOptionData capitalizedIncomeCalculationType = 
LoanCapitalizedIncomeCalculationType
+                    
.getStringEnumOptionData(rs.getString("capitalizedIncomeCalculationType"));
+            final StringEnumOptionData capitalizedIncomeStrategy = 
LoanCapitalizedIncomeStrategy
+                    
.getStringEnumOptionData(rs.getString("capitalizedIncomeStrategy"));
 
             return new LoanProductData(id, name, shortName, description, 
currency, principal, minPrincipal, maxPrincipal, tolerance,
                     numberOfRepayments, minNumberOfRepayments, 
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -576,7 +586,7 @@ public class LoanProductReadPlatformServiceImpl implements 
LoanProductReadPlatfo
                     enableInstallmentLevelDelinquency, 
loanScheduleType.asEnumOptionData(), 
loanScheduleProcessingType.asEnumOptionData(),
                     fixedLength, enableAccrualActivityPosting, 
supportedInterestRefundTypes,
                     loanChargeOffBehaviour.getValueAsStringEnumOptionData(), 
interestRecognitionOnDisbursementDate,
-                    daysInYearCustomStrategy);
+                    daysInYearCustomStrategy, enableIncomeCapitalization, 
capitalizedIncomeCalculationType, capitalizedIncomeStrategy);
         }
     }
 
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 2f294c33ce..09a9f0e42e 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
@@ -189,4 +189,5 @@
     <include 
file="parts/0168_transaction_summary_with_asset_owner_report_add_active_intermediate_filtering.xml"
 relativeToChangelogFile="true" />
     <include file="parts/0169_add_missing_permissions.xml" 
relativeToChangelogFile="true" />
     <include file="parts/0170_days_in_year_custom_strategy.xml" 
relativeToChangelogFile="true"/>
+    <include file="parts/0171_loan_capitalized_income.xml" 
relativeToChangelogFile="true"/>
 </databaseChangeLog>
diff --git 
a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0171_loan_capitalized_income.xml
 
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0171_loan_capitalized_income.xml
new file mode 100644
index 0000000000..3ac0cf5a20
--- /dev/null
+++ 
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0171_loan_capitalized_income.xml
@@ -0,0 +1,49 @@
+<?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="enable_income_capitalization" type="boolean" 
defaultValueBoolean="false">
+                <constraints nullable="false"/>
+            </column>
+            <column name="capitalized_income_calculation_type" 
type="VARCHAR(100)">
+                <constraints nullable="true"/>
+            </column>
+            <column name="capitalized_income_strategy" type="VARCHAR(100)">
+                <constraints nullable="true"/>
+            </column>
+        </addColumn>
+        <addColumn tableName="m_product_loan">
+            <column name="enable_income_capitalization" type="boolean" 
defaultValueBoolean="false">
+                <constraints nullable="false"/>
+            </column>
+            <column name="capitalized_income_calculation_type" 
type="VARCHAR(100)">
+                <constraints nullable="true"/>
+            </column>
+            <column name="capitalized_income_strategy" type="VARCHAR(100)">
+                <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 a7574fd5f2..d0d83caa6c 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,8 @@ 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);
+                submittedOnDate, CUMULATIVE, 
LoanScheduleProcessingType.HORIZONTAL, null, false, null, null, false, null, 
false, null,
+                null);
 
         // when
         List<? extends LoanScheduleModelPeriod> result = 
underTest.generateRepaymentPeriods(mathContext, expectedDisbursementDate,
@@ -179,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, false, 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
new file mode 100644
index 0000000000..ea49812563
--- /dev/null
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductTest.java
@@ -0,0 +1,147 @@
+/**
+ * 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.integrationtests;
+
+import java.math.BigDecimal;
+import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
+import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.client.models.PostClientsResponse;
+import org.apache.fineract.client.models.PostLoanProductsRequest;
+import org.apache.fineract.client.models.PostLoanProductsResponse;
+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.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class LoanProductTest extends BaseLoanIntegrationTest {
+
+    @Test
+    public void testIncomeCapitalizationEnabled() {
+        final PostClientsResponse client = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
+
+        final PostLoanProductsResponse loanProductsResponse = loanProductHelper
+                
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
+                        
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
+                        
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION));
+
+        final GetLoanProductsProductIdResponse loanProductsProductIdResponse = 
loanProductHelper
+                .retrieveLoanProductById(loanProductsResponse.getResourceId());
+        Assertions.assertEquals(Boolean.TRUE, 
loanProductsProductIdResponse.getEnableIncomeCapitalization());
+        
Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeCalculationType());
+        
Assertions.assertEquals(LoanCapitalizedIncomeCalculationType.FLAT.getCode(),
+                
loanProductsProductIdResponse.getCapitalizedIncomeCalculationType().getCode());
+        
Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeStrategy());
+        
Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(),
+                
loanProductsProductIdResponse.getCapitalizedIncomeStrategy().getCode());
+
+        runAt("20 December 2024", () -> {
+            Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), 
loanProductsResponse.getResourceId(), "20 December 2024",
+                    430.0, 7.0, 6, null);
+
+            final GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId);
+            Assertions.assertEquals(Boolean.TRUE, 
loanDetails.getEnableIncomeCapitalization());
+            
Assertions.assertNotNull(loanDetails.getCapitalizedIncomeCalculationType());
+            
Assertions.assertEquals(LoanCapitalizedIncomeCalculationType.FLAT.getCode(),
+                    
loanDetails.getCapitalizedIncomeCalculationType().getCode());
+            
Assertions.assertNotNull(loanDetails.getCapitalizedIncomeStrategy());
+            
Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(),
+                    loanDetails.getCapitalizedIncomeStrategy().getCode());
+
+            Assertions.assertDoesNotThrow(() -> disburseLoan(loanId, 
BigDecimal.valueOf(430), "20 December 2024"));
+        });
+    }
+
+    @Test
+    public void testIncomeCapitalizationDisabled() {
+        final PostClientsResponse client = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
+
+        final PostLoanProductsResponse loanProductsResponse = loanProductHelper
+                
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(false)
+                        
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
+                        
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION));
+
+        final GetLoanProductsProductIdResponse loanProductsProductIdResponse = 
loanProductHelper
+                .retrieveLoanProductById(loanProductsResponse.getResourceId());
+        Assertions.assertEquals(Boolean.FALSE, 
loanProductsProductIdResponse.getEnableIncomeCapitalization());
+        
Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeCalculationType());
+        
Assertions.assertEquals(LoanCapitalizedIncomeCalculationType.FLAT.getCode(),
+                
loanProductsProductIdResponse.getCapitalizedIncomeCalculationType().getCode());
+        
Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeStrategy());
+        
Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(),
+                
loanProductsProductIdResponse.getCapitalizedIncomeStrategy().getCode());
+
+        runAt("20 December 2024", () -> {
+            Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), 
loanProductsResponse.getResourceId(), "20 December 2024",
+                    430.0, 7.0, 6, null);
+
+            final GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId);
+            Assertions.assertEquals(Boolean.FALSE, 
loanDetails.getEnableIncomeCapitalization());
+            
Assertions.assertNotNull(loanDetails.getCapitalizedIncomeCalculationType());
+            
Assertions.assertEquals(LoanCapitalizedIncomeCalculationType.FLAT.getCode(),
+                    
loanDetails.getCapitalizedIncomeCalculationType().getCode());
+            
Assertions.assertNotNull(loanDetails.getCapitalizedIncomeStrategy());
+            
Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(),
+                    loanDetails.getCapitalizedIncomeStrategy().getCode());
+
+            Assertions.assertDoesNotThrow(() -> disburseLoan(loanId, 
BigDecimal.valueOf(430), "20 December 2024"));
+        });
+    }
+
+    @Test
+    public void testIncomeCapitalizationUpdateProduct() {
+        final PostLoanProductsResponse loanProductsResponse = loanProductHelper
+                
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
+                        
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
+                        
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION));
+
+        final GetLoanProductsProductIdResponse loanProductsProductIdResponse = 
loanProductHelper
+                .retrieveLoanProductById(loanProductsResponse.getResourceId());
+        Assertions.assertEquals(Boolean.TRUE, 
loanProductsProductIdResponse.getEnableIncomeCapitalization());
+        
Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeCalculationType());
+        
Assertions.assertEquals(LoanCapitalizedIncomeCalculationType.FLAT.getCode(),
+                
loanProductsProductIdResponse.getCapitalizedIncomeCalculationType().getCode());
+        
Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeStrategy());
+        
Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(),
+                
loanProductsProductIdResponse.getCapitalizedIncomeStrategy().getCode());
+
+        
loanProductHelper.updateLoanProductById(loanProductsResponse.getResourceId(),
+                new 
PutLoanProductsProductIdRequest().enableIncomeCapitalization(false));
+
+        final GetLoanProductsProductIdResponse 
updatedLoanProductsProductIdResponse = loanProductHelper
+                .retrieveLoanProductById(loanProductsResponse.getResourceId());
+        Assertions.assertEquals(Boolean.FALSE, 
updatedLoanProductsProductIdResponse.getEnableIncomeCapitalization());
+        
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getCapitalizedIncomeCalculationType());
+        
Assertions.assertEquals(LoanCapitalizedIncomeCalculationType.FLAT.getCode(),
+                
updatedLoanProductsProductIdResponse.getCapitalizedIncomeCalculationType().getCode());
+        
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getCapitalizedIncomeStrategy());
+        
Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(),
+                
updatedLoanProductsProductIdResponse.getCapitalizedIncomeStrategy().getCode());
+    }
+
+    @Test
+    public void testIncomeCapitalizationCumulativeNotSupported() {
+        Assertions.assertThrows(RuntimeException.class,
+                () -> 
loanProductHelper.createLoanProduct(createOnePeriod30DaysPeriodicAccrualProduct(7.0).enableIncomeCapitalization(true)
+                        
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
+                        
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)));
+    }
+
+}


Reply via email to