This is an automated email from the ASF dual-hosted git repository.

bagrijp pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new b2685ce9c FINERACT-2065: Fixed length loan configuration
b2685ce9c is described below

commit b2685ce9cf9360a6503bcf76e081d6426de9c804
Author: Peter Bagrij <[email protected]>
AuthorDate: Wed Mar 13 14:54:40 2024 +0100

    FINERACT-2065: Fixed length loan configuration
---
 .../loanschedule/domain/LoanApplicationTerms.java  |  18 ++--
 .../loanproduct/LoanProductConstants.java          |   2 +
 .../portfolio/loanproduct/domain/LoanProduct.java  |  14 ++-
 .../domain/LoanProductRelatedDetail.java           |  18 +++-
 .../tenant/module/loan/module-changelog-master.xml |   1 +
 .../module/loan/parts/1019_add_fixed_length.xml    |  33 +++++++
 .../importhandler/loan/LoanImportHandler.java      |   6 +-
 .../loanaccount/api/LoansApiResourceSwagger.java   |   6 ++
 .../loanaccount/data/LoanAccountData.java          |  34 ++++---
 .../service/LoanScheduleAssembler.java             |  17 +++-
 .../LoanApplicationCommandFromApiJsonHelper.java   |   2 +-
 .../service/LoanReadPlatformServiceImpl.java       |   4 +-
 .../api/LoanProductsApiResourceSwagger.java        |   8 ++
 .../loanproduct/data/LoanProductData.java          |  17 +++-
 .../serialization/LoanProductDataValidator.java    |   2 +-
 .../LoanProductReadPlatformServiceImpl.java        |   5 +-
 .../domain/DefaultScheduledDateGeneratorTest.java  |   2 +-
 ...PaymentAllocationLoanRepaymentScheduleTest.java |  16 ++-
 .../FixedLengthLoanProductIntegrationTest.java     | 108 +++++++++++++++++++++
 .../common/loans/LoanProductHelper.java            |   4 +
 20 files changed, 266 insertions(+), 51 deletions(-)

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 f908d0df4..32f855433 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
@@ -68,6 +68,8 @@ public final class LoanApplicationTerms {
     private Integer actualNumberOfRepayments;
     private final Integer repaymentEvery;
     private final PeriodFrequencyType repaymentPeriodFrequencyType;
+
+    private final Integer fixedLength;
     private final Integer nthDay;
 
     private final DayOfWeekType weekDayType;
@@ -249,7 +251,7 @@ public final class LoanApplicationTerms {
             final Boolean enableDownPayment, final BigDecimal 
disbursedAmountPercentageForDownPayment,
             final Boolean isAutoRepaymentForDownPaymentEnabled, final 
RepaymentStartDateType repaymentStartDateType,
             final LocalDate submittedOnDate, final LoanScheduleType 
loanScheduleType,
-            final LoanScheduleProcessingType loanScheduleProcessingType) {
+            final LoanScheduleProcessingType loanScheduleProcessingType, final 
Integer fixedLength) {
 
         final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
         final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
@@ -267,8 +269,8 @@ public final class LoanApplicationTerms {
                 isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, 
allowCompoundingOnEod, isEqualAmortization, false,
                 isInterestToBeRecoveredFirstWhenGreaterThanEMI, 
fixedPrincipalPercentagePerInstallment,
                 isPrincipalCompoundingDisabledForOverdueLoans, 
enableDownPayment, disbursedAmountPercentageForDownPayment,
-                isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, 
submittedOnDate, loanScheduleType,
-                loanScheduleProcessingType);
+                isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, 
submittedOnDate, loanScheduleType, loanScheduleProcessingType,
+                fixedLength);
 
     }
 
@@ -324,6 +326,7 @@ public final class LoanApplicationTerms {
         }
         LoanScheduleType loanScheduleType = 
loanProductRelatedDetail.getLoanScheduleType();
         LoanScheduleProcessingType loanScheduleProcessingType = 
loanProductRelatedDetail.getLoanScheduleProcessingType();
+        final Integer fixedLength = loanProductRelatedDetail.getFixedLength();
         return new LoanApplicationTerms(applicationCurrency, 
loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
                 repaymentEvery, repaymentPeriodFrequencyType, ((nthDay != 
null) ? nthDay.getValue() : null), dayOfWeek, amortizationMethod,
                 interestMethod, interestRatePerPeriod, 
interestRatePeriodFrequencyType, annualNominalInterestRate,
@@ -339,8 +342,8 @@ public final class LoanApplicationTerms {
                 allowCompoundingOnEod, isEqualAmortization, 
isFirstRepaymentDateAllowedOnHoliday,
                 isInterestToBeRecoveredFirstWhenGreaterThanEMI, 
fixedPrincipalPercentagePerInstallment,
                 isPrincipalCompoundingDisabledForOverdueLoans, 
isDownPaymentEnabled, disbursedAmountPercentageForDownPayment,
-                isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, 
submittedOnDate, loanScheduleType,
-                loanScheduleProcessingType);
+                isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, 
submittedOnDate, loanScheduleType, loanScheduleProcessingType,
+                fixedLength);
     }
 
     private LoanApplicationTerms(final ApplicationCurrency currency, final 
Integer loanTermFrequency,
@@ -369,7 +372,7 @@ public final class LoanApplicationTerms {
             final boolean isPrincipalCompoundingDisabledForOverdueLoans, final 
boolean isDownPaymentEnabled,
             final BigDecimal disbursedAmountPercentageForDownPayment, final 
boolean isAutoRepaymentForDownPaymentEnabled,
             final RepaymentStartDateType repaymentStartDateType, final 
LocalDate submittedOnDate, final LoanScheduleType loanScheduleType,
-            final LoanScheduleProcessingType loanScheduleProcessingType) {
+            final LoanScheduleProcessingType loanScheduleProcessingType, final 
Integer fixedLength) {
 
         this.currency = currency;
         this.loanTermFrequency = loanTermFrequency;
@@ -463,6 +466,7 @@ public final class LoanApplicationTerms {
         this.submittedOnDate = submittedOnDate;
         this.loanScheduleType = loanScheduleType;
         this.loanScheduleProcessingType = loanScheduleProcessingType;
+        this.fixedLength = fixedLength;
     }
 
     public Money adjustPrincipalIfLastRepaymentPeriod(final Money 
principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -1326,7 +1330,7 @@ public final class LoanApplicationTerms {
                 this.graceOnArrearsAgeing, this.daysInMonthType.getValue(), 
this.daysInYearType.getValue(),
                 this.interestRecalculationEnabled, this.isEqualAmortization, 
this.isDownPaymentEnabled,
                 this.disbursedAmountPercentageForDownPayment, 
this.isAutoRepaymentForDownPaymentEnabled, this.loanScheduleType,
-                this.loanScheduleProcessingType);
+                this.loanScheduleProcessingType, this.fixedLength);
     }
 
     public Integer getLoanTermFrequency() {
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 532bd5efa..d18c5da69 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
@@ -161,4 +161,6 @@ public interface LoanProductConstants {
 
     // Repayment Strategies
     String ADVANCED_PAYMENT_ALLOCATION_STRATEGY = 
"advanced-payment-allocation-strategy";
+
+    String FIXED_LENGTH = "fixedLength";
 }
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 83a848d60..53abbff42 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
@@ -429,6 +429,8 @@ public class LoanProduct extends AbstractPersistableCustom {
         final boolean enableInstallmentLevelDelinquency = command
                 
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY);
 
+        final Integer fixedLength = 
command.integerValueOfParameterNamed(LoanProductConstants.FIXED_LENGTH);
+
         return new LoanProduct(fund, loanTransactionProcessingStrategy, 
loanProductPaymentAllocationRules, loanProductCreditAllocationRules,
                 name, shortName, description, currency, principal, 
minPrincipal, maxPrincipal, interestRatePerPeriod,
                 minInterestRatePerPeriod, maxInterestRatePerPeriod, 
interestFrequencyType, annualInterestRate, interestMethod,
@@ -447,7 +449,7 @@ public class LoanProduct extends AbstractPersistableCustom {
                 isEqualAmortization, productRates, 
fixedPrincipalPercentagePerInstallment, disallowExpectedDisbursements,
                 allowApprovedDisbursedAmountsOverApplied, 
overAppliedCalculationType, overAppliedNumber, dueDaysForRepaymentEvent,
                 overDueDaysForRepaymentEvent, enableDownPayment, 
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
-                repaymentStartDateType, enableInstallmentLevelDelinquency, 
loanScheduleType, loanScheduleProcessingType);
+                repaymentStartDateType, enableInstallmentLevelDelinquency, 
loanScheduleType, loanScheduleProcessingType, fixedLength);
 
     }
 
@@ -664,7 +666,7 @@ public class LoanProduct extends AbstractPersistableCustom {
             final boolean enableDownPayment, final BigDecimal 
disbursedAmountPercentageForDownPayment,
             final boolean enableAutoRepaymentForDownPayment, final 
RepaymentStartDateType repaymentStartDateType,
             final boolean enableInstallmentLevelDelinquency, final 
LoanScheduleType loanScheduleType,
-            final LoanScheduleProcessingType loanScheduleProcessingType) {
+            final LoanScheduleProcessingType loanScheduleProcessingType, final 
Integer fixedLength) {
         this.fund = fund;
         this.transactionProcessingStrategyCode = 
transactionProcessingStrategyCode;
 
@@ -713,7 +715,7 @@ public class LoanProduct extends AbstractPersistableCustom {
                 recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, 
graceOnInterestCharged, amortizationMethod,
                 inArrearsTolerance, graceOnArrearsAgeing, 
daysInMonthType.getValue(), daysInYearType.getValue(),
                 isInterestRecalculationEnabled, isEqualAmortization, 
enableDownPayment, disbursedAmountPercentageForDownPayment,
-                enableAutoRepaymentForDownPayment, loanScheduleType, 
loanScheduleProcessingType);
+                enableAutoRepaymentForDownPayment, loanScheduleType, 
loanScheduleProcessingType, fixedLength);
 
         
this.loanProductRelatedDetail.validateRepaymentPeriodWithGraceSettings();
 
@@ -1364,6 +1366,12 @@ public class LoanProduct extends 
AbstractPersistableCustom {
             this.updateEnableInstallmentLevelDelinquency(newValue);
         }
 
+        if 
(command.isChangeInIntegerParameterNamed(LoanProductConstants.FIXED_LENGTH, 
loanProductRelatedDetail.getFixedLength())) {
+            final Integer newValue = 
command.integerValueOfParameterNamed(LoanProductConstants.FIXED_LENGTH);
+            actualChanges.put(LoanProductConstants.FIXED_LENGTH, newValue);
+            loanProductRelatedDetail.setFixedLength(newValue);
+        }
+
         return actualChanges;
     }
 
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 f956cf963..6c74c7534 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
@@ -92,6 +92,9 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
     @Column(name = "repayment_period_frequency_enum", nullable = false)
     private PeriodFrequencyType repaymentPeriodFrequencyType;
 
+    @Column(name = "fixed_length", nullable = false)
+    private Integer fixedLength;
+
     @Column(name = "number_of_repayments", nullable = false)
     private Integer numberOfRepayments;
 
@@ -159,7 +162,7 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
             final Integer daysInYearType, final boolean 
isInterestRecalculationEnabled, final boolean isEqualAmortization,
             final boolean enableDownPayment, final BigDecimal 
disbursedAmountPercentageForDownPayment,
             final boolean enableAutoRepaymentForDownPayment, final 
LoanScheduleType loanScheduleType,
-            final LoanScheduleProcessingType loanScheduleProcessingType) {
+            final LoanScheduleProcessingType loanScheduleProcessingType, final 
Integer fixedLength) {
 
         return new LoanProductRelatedDetail(currency, principal, 
nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
                 nominalAnnualInterestRate, interestMethod, 
interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion,
@@ -167,7 +170,7 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
                 recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, 
graceOnInterestCharged, amortizationMethod,
                 inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, 
daysInYearType, isInterestRecalculationEnabled,
                 isEqualAmortization, enableDownPayment, 
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment,
-                loanScheduleType, loanScheduleProcessingType);
+                loanScheduleType, loanScheduleProcessingType, fixedLength);
     }
 
     protected LoanProductRelatedDetail() {
@@ -185,7 +188,7 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
             final Integer daysInYearType, final boolean 
isInterestRecalculationEnabled, final boolean isEqualAmortization,
             final boolean enableDownPayment, final BigDecimal 
disbursedAmountPercentageForDownPayment,
             final boolean enableAutoRepaymentForDownPayment, final 
LoanScheduleType loanScheduleType,
-            final LoanScheduleProcessingType loanScheduleProcessingType) {
+            final LoanScheduleProcessingType loanScheduleProcessingType, final 
Integer fixedLength) {
         this.currency = currency;
         this.principal = defaultPrincipal;
         this.nominalInterestRatePerPeriod = 
defaultNominalInterestRatePerPeriod;
@@ -197,6 +200,7 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
         this.repayEvery = repayEvery;
         this.repaymentPeriodFrequencyType = repaymentFrequencyType;
         this.numberOfRepayments = defaultNumberOfRepayments;
+        this.fixedLength = fixedLength;
         this.graceOnPrincipalPayment = 
defaultToNullIfZero(graceOnPrincipalPayment);
         this.recurringMoratoriumOnPrincipalPeriods = 
recurringMoratoriumOnPrincipalPeriods;
         this.graceOnInterestPayment = 
defaultToNullIfZero(graceOnInterestPayment);
@@ -753,4 +757,12 @@ public class LoanProductRelatedDetail implements 
LoanProductMinimumRepaymentSche
     public LoanScheduleProcessingType getLoanScheduleProcessingType() {
         return loanScheduleProcessingType;
     }
+
+    public Integer getFixedLength() {
+        return this.fixedLength;
+    }
+
+    public void setFixedLength(Integer fixedLength) {
+        this.fixedLength = fixedLength;
+    }
 }
diff --git 
a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
 
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
index b90df0097..530477091 100644
--- 
a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
+++ 
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
@@ -41,4 +41,5 @@
   <include relativeToChangelogFile="true" 
file="parts/1016_add_credit_allocation_rule.xml"/>
   <include relativeToChangelogFile="true" 
file="parts/1017_add_fee_and_penalty_adjustments_to_loan.xml"/>
   <include relativeToChangelogFile="true" 
file="parts/1018_rename_credited_principal_back_to_credits_amount.xml"/>
+  <include relativeToChangelogFile="true" 
file="parts/1019_add_fixed_length.xml"/>
 </databaseChangeLog>
diff --git 
a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1019_add_fixed_length.xml
 
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1019_add_fixed_length.xml
new file mode 100644
index 000000000..e557d9388
--- /dev/null
+++ 
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1019_add_fixed_length.xml
@@ -0,0 +1,33 @@
+<?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_product_loan">
+            <column name="fixed_length" type="SMALLINT"/>
+        </addColumn>
+        <addColumn tableName="m_loan">
+            <column name="fixed_length" type="SMALLINT"/>
+        </addColumn>
+    </changeSet>
+</databaseChangeLog>
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/loan/LoanImportHandler.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/loan/LoanImportHandler.java
index 401cd13ab..dea87fc35 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/loan/LoanImportHandler.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/loan/LoanImportHandler.java
@@ -351,7 +351,7 @@ public class LoanImportHandler implements ImportHandler {
                         nominalInterestRate, submittedOnDate, 
amortizationEnumOption, interestMethodEnum, interestCalculationPeriodEnum,
                         arrearsTolerance, repaymentStrategyCode, 
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
                         interestChargedFromDate, firstRepaymentOnDate, 
row.getRowNum(), externalId, null, charges, linkAccountId, locale,
-                        dateFormat, loanCollateralManagementData);
+                        dateFormat, loanCollateralManagementData, null);
             } else if (loanType.equals("jlg")) {
                 Long clientId = 
ImportHandlerUtils.getIdByName(workbook.getSheet(TemplatePopulateImportConstants.CLIENT_SHEET_NAME),
                         clientOrGroupName);
@@ -360,7 +360,7 @@ public class LoanImportHandler implements ImportHandler {
                         nominalInterestRate, submittedOnDate, 
amortizationEnumOption, interestMethodEnum, interestCalculationPeriodEnum,
                         arrearsTolerance, repaymentStrategyCode, 
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
                         interestChargedFromDate, firstRepaymentOnDate, 
row.getRowNum(), externalId, groupId, charges, linkAccountId, locale,
-                        dateFormat, null);
+                        dateFormat, null, null);
             } else {
                 Long groupIdforGroupLoan = ImportHandlerUtils
                         
.getIdByName(workbook.getSheet(TemplatePopulateImportConstants.GROUP_SHEET_NAME),
 clientOrGroupName);
@@ -369,7 +369,7 @@ public class LoanImportHandler implements ImportHandler {
                         loanTermFrequencyEnum, nominalInterestRate, 
amortizationEnumOption, interestMethodEnum,
                         interestCalculationPeriodEnum, arrearsTolerance, 
repaymentStrategyCode, graceOnPrincipalPayment,
                         graceOnInterestPayment, graceOnInterestCharged, 
interestChargedFromDate, firstRepaymentOnDate, row.getRowNum(),
-                        externalId, linkAccountId, locale, dateFormat);
+                        externalId, linkAccountId, locale, dateFormat, null);
             }
         }
 
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 375d506e2..67002b0d9 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
@@ -1085,6 +1085,8 @@ final class LoansApiResourceSwagger {
         @Schema(example = "1")
         public Integer repaymentEvery;
         public GetLoansLoanIdRepaymentFrequencyType repaymentFrequencyType;
+        @Schema(example = "1")
+        public Integer fixedLength;
         @Schema(example = "24")
         public BigDecimal interestRatePerPeriod;
         public GetLoansLoanIdInterestRateFrequencyType 
interestRateFrequencyType;
@@ -1181,6 +1183,8 @@ final class LoansApiResourceSwagger {
         public Integer repaymentEvery;
         @Schema(example = "2")
         public Integer repaymentFrequencyType;
+        @Schema(example = "1")
+        public Integer fixedLength;
         @Schema(example = "2")
         public BigDecimal interestRatePerPeriod;
         @Schema(example = "1")
@@ -1317,6 +1321,8 @@ final class LoansApiResourceSwagger {
         public Integer repaymentEvery;
         @Schema(example = "0")
         public Integer repaymentFrequencyType;
+        @Schema(example = "1")
+        public Integer fixedLength;
         @Schema(example = "2")
         public BigDecimal interestRatePerPeriod;
         @Schema(example = "0")
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 3e315a2ac..20350f534 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
@@ -104,6 +104,7 @@ public class LoanAccountData {
     private EnumOptionData termPeriodFrequencyType;
     private Integer numberOfRepayments;
     private Integer repaymentEvery;
+    private Integer fixedLength;
     private EnumOptionData repaymentFrequencyType;
     private EnumOptionData repaymentFrequencyNthDayType;
     private EnumOptionData repaymentFrequencyDayOfWeekType;
@@ -274,7 +275,8 @@ public class LoanAccountData {
             BigDecimal inArrearsTolerance, String 
transactionProcessingStrategyCode, Integer graceOnPrincipalPayment,
             Integer graceOnInterestPayment, Integer graceOnInterestCharged, 
LocalDate interestChargedFromDate,
             LocalDate repaymentsStartingFromDate, Integer rowIndex, ExternalId 
externalId, Long groupId, Collection<LoanChargeData> charges,
-            String linkAccountId, String locale, String dateFormat, 
List<LoanCollateralManagementData> loanCollateralManagementData) {
+            String linkAccountId, String locale, String dateFormat, 
List<LoanCollateralManagementData> loanCollateralManagementData,
+            Integer fixedLength) {
 
         return new 
LoanAccountData().setLoanType(loanTypeEnumOption).setClientId(clientId).setProductId(productId)
                 
.setLoanOfficerId(loanOfficerId).setSubmittedOnDate(submittedOnDate).setFundId(fundId).setPrincipal(principal)
@@ -288,7 +290,7 @@ public class LoanAccountData {
                 
.setGraceOnInterestCharged(graceOnInterestCharged).setInterestChargedFromDate(interestChargedFromDate)
                 
.setRepaymentsStartingFromDate(repaymentsStartingFromDate).setRowIndex(rowIndex).setExternalId(externalId)
                 
.setGroupId(groupId).setCharges(charges).setLinkAccountId(linkAccountId).setLocale(locale).setDateFormat(dateFormat)
-                .setCollateral(loanCollateralManagementData);
+                
.setCollateral(loanCollateralManagementData).setFixedLength(fixedLength);
     }
 
     public static LoanAccountData importInstanceGroup(EnumOptionData 
loanTypeEnumOption, Long groupIdforGroupLoan, Long productId,
@@ -298,7 +300,7 @@ public class LoanAccountData {
             EnumOptionData interestMethodEnum, EnumOptionData 
interestCalculationPeriodEnum, BigDecimal arrearsTolerance,
             String transactionProcessingStrategyCode, Integer 
graceOnPrincipalPayment, Integer graceOnInterestPayment,
             Integer graceOnInterestCharged, LocalDate interestChargedFromDate, 
LocalDate repaymentsStartingFromDate, Integer rowIndex,
-            ExternalId externalId, String linkAccountId, String locale, String 
dateFormat) {
+            ExternalId externalId, String linkAccountId, String locale, String 
dateFormat, Integer fixedLength) {
 
         return new 
LoanAccountData().setLoanType(loanTypeEnumOption).setGroupId(groupIdforGroupLoan).setProductId(productId)
                 
.setLoanOfficerId(loanOfficerId).setSubmittedOnDate(submittedOnDate).setFundId(fundId).setPrincipal(principal)
@@ -310,8 +312,8 @@ public class LoanAccountData {
                 
.setTransactionProcessingStrategyCode(transactionProcessingStrategyCode).setGraceOnPrincipalPayment(graceOnPrincipalPayment)
                 
.setGraceOnInterestPayment(graceOnInterestPayment).setGraceOnInterestCharged(graceOnInterestCharged)
                 
.setInterestChargedFromDate(interestChargedFromDate).setRepaymentsStartingFromDate(repaymentsStartingFromDate)
-                
.setRowIndex(rowIndex).setExternalId(externalId).setLinkAccountId(linkAccountId).setLocale(locale)
-                .setDateFormat(dateFormat);
+                
.setRowIndex(rowIndex).setExternalId(externalId).setLinkAccountId(linkAccountId).setLocale(locale).setDateFormat(dateFormat)
+                .setFixedLength(fixedLength);
     }
 
     /**
@@ -350,7 +352,7 @@ public class LoanAccountData {
                 
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
                 
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
                 
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
-                
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
+                
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType).setFixedLength(acc.fixedLength)
                 
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
                 
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
                 
.setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType)
@@ -424,7 +426,7 @@ public class LoanAccountData {
                 
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
                 
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
                 
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
-                
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
+                
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType).setFixedLength(acc.fixedLength)
                 
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
                 
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
                 
.setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType)
@@ -643,7 +645,7 @@ public class LoanAccountData {
                 
.setFixedPrincipalPercentagePerInstallment(product.getFixedPrincipalPercentagePerInstallment()).setDelinquent(delinquent)
                 
.setDisallowExpectedDisbursements(product.getDisallowExpectedDisbursements()).setFraud(acc.fraud)
                 
.setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff).setLoanScheduleType(acc.getLoanScheduleType())
-                
.setLoanScheduleProcessingType(acc.getLoanScheduleProcessingType());
+                
.setLoanScheduleProcessingType(acc.getLoanScheduleProcessingType()).setFixedLength(product.getFixedLength());
     }
 
     /*
@@ -680,7 +682,7 @@ public class LoanAccountData {
             LocalDate lastClosedBusinessDate, LocalDate overpaidOnDate, final 
boolean chargedOff, final boolean enableDownPayment,
             final BigDecimal disbursedAmountPercentageForDownPayment, final 
boolean enableAutoRepaymentForDownPayment,
             final boolean enableInstallmentLevelDelinquency, final 
EnumOptionData loanScheduleType,
-            final EnumOptionData loanScheduleProcessingType) {
+            final EnumOptionData loanScheduleProcessingType, final Integer 
fixedLength) {
 
         final CollectionData delinquent = CollectionData.template();
 
@@ -724,7 +726,7 @@ public class LoanAccountData {
                 
.setEnableDownPayment(enableDownPayment).setDisbursedAmountPercentageForDownPayment(disbursedAmountPercentageForDownPayment)
                 
.setEnableAutoRepaymentForDownPayment(enableAutoRepaymentForDownPayment)
                 
.setEnableInstallmentLevelDelinquency(enableInstallmentLevelDelinquency).setLoanScheduleType(loanScheduleType)
-                .setLoanScheduleProcessingType(loanScheduleProcessingType);
+                
.setLoanScheduleProcessingType(loanScheduleProcessingType).setFixedLength(fixedLength);
     }
 
     /*
@@ -764,7 +766,7 @@ public class LoanAccountData {
                 
.setPrincipal(acc.principal).setApprovedPrincipal(acc.approvedPrincipal).setNetDisbursalAmount(acc.netDisbursalAmount)
                 
.setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency)
                 
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
-                
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
+                
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType).setFixedLength(acc.fixedLength)
                 
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
                 
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
                 
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
@@ -848,7 +850,7 @@ public class LoanAccountData {
                 
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
                 
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
                 
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
-                
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
+                
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType).setFixedLength(acc.fixedLength)
                 
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
                 
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
                 
.setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType)
@@ -947,7 +949,7 @@ public class LoanAccountData {
                 
.setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency)
                 
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
                 
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
-                
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
+                
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType).setFixedLength(acc.fixedLength)
                 
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
                 
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
                 
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
@@ -1016,7 +1018,7 @@ public class LoanAccountData {
                 
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
                 
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
                 
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
-                
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
+                
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType).setFixedLength(acc.fixedLength)
                 
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
                 
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
                 
.setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType)
@@ -1094,7 +1096,7 @@ public class LoanAccountData {
                 
.setMeeting(acc.meeting).setProductOptions(acc.productOptions).setTermFrequencyTypeOptions(acc.termFrequencyTypeOptions)
                 
.setRepaymentFrequencyTypeOptions(acc.repaymentFrequencyTypeOptions)
                 
.setRepaymentFrequencyNthDayTypeOptions(acc.repaymentFrequencyNthDayTypeOptions)
-                
.setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions)
+                
.setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions).setFixedLength(acc.fixedLength)
                 
.setTransactionProcessingStrategyOptions(acc.transactionProcessingStrategyOptions)
                 
.setInterestRateFrequencyTypeOptions(acc.interestRateFrequencyTypeOptions)
                 
.setAmortizationTypeOptions(acc.amortizationTypeOptions).setInterestTypeOptions(acc.interestTypeOptions)
@@ -1141,7 +1143,7 @@ public class LoanAccountData {
                 
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
                 
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
                 
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
-                
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
+                
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType).setFixedLength(acc.fixedLength)
                 
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
                 
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
                 
.setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType)
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 946d1e565..ba296caf0 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
@@ -469,14 +469,21 @@ public class LoanScheduleAssembler {
 
         LoanScheduleType loanScheduleType = 
loanProduct.getLoanProductRelatedDetail().getLoanScheduleType();
         if 
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.LOAN_SCHEDULE_TYPE,
 element)) {
-            
LoanScheduleType.valueOf(this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.LOAN_SCHEDULE_TYPE,
 element));
+            loanScheduleType = LoanScheduleType
+                    
.valueOf(this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.LOAN_SCHEDULE_TYPE,
 element));
         }
-        LoanScheduleProcessingType loanScheduleProcessingType = 
loanProduct.getLoanProductRelatedDetail().getLoanScheduleProcessingType();
 
-        if 
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.LOAN_SCHEDULE_TYPE,
 element)) {
-            LoanScheduleProcessingType
+        LoanScheduleProcessingType loanScheduleProcessingType = 
loanProduct.getLoanProductRelatedDetail().getLoanScheduleProcessingType();
+        if 
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE,
 element)) {
+            loanScheduleProcessingType = LoanScheduleProcessingType
                     
.valueOf(this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE,
 element));
         }
+
+        Integer fixedLength = 
loanProduct.getLoanProductRelatedDetail().getFixedLength();
+        if 
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.FIXED_LENGTH, 
element)) {
+            fixedLength = 
this.fromApiJsonHelper.extractIntegerWithLocaleNamed(LoanProductConstants.FIXED_LENGTH,
 element);
+        }
+
         return LoanApplicationTerms.assembleFrom(applicationCurrency, 
loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
                 repaymentEvery, repaymentPeriodFrequencyType, nthDay, 
weekDayType, amortizationMethod, interestMethod,
                 interestRatePerPeriod, interestRatePeriodFrequencyType, 
annualNominalInterestRate, interestCalculationPeriodMethod,
@@ -491,7 +498,7 @@ public class LoanScheduleAssembler {
                 allowCompoundingOnEod, isEqualAmortization, 
isInterestToBeRecoveredFirstWhenGreaterThanEMI,
                 fixedPrincipalPercentagePerInstallment, 
isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled,
                 disbursedAmountPercentageForDownPayment, 
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate,
-                loanScheduleType, loanScheduleProcessingType);
+                loanScheduleType, loanScheduleProcessingType, fixedLength);
     }
 
     private CalendarInstance createCalendarForSameAsRepayment(final Integer 
repaymentEvery,
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
index f075d7fbe..2c1251f49 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
@@ -104,7 +104,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
             LoanApiConstants.lastApplication, // glim specific
             LoanApiConstants.daysInYearTypeParameterName, 
LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName,
             LoanApiConstants.DISALLOW_EXPECTED_DISBURSEMENTS, 
LoanApiConstants.FRAUD_ATTRIBUTE_NAME,
-            LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE));
+            LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, 
LoanProductConstants.FIXED_LENGTH));
     public static final String LOANAPPLICATION_UNDO = "loanapplication.undo";
 
     private final FromJsonHelper fromApiJsonHelper;
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 a84d4127b..bfa5b96b5 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
@@ -637,6 +637,7 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService, Loa
                     + " l.grace_on_principal_periods as 
graceOnPrincipalPayment, l.recurring_moratorium_principal_periods as 
recurringMoratoriumOnPrincipalPeriods, l.grace_on_interest_periods as 
graceOnInterestPayment, l.grace_interest_free_periods as 
graceOnInterestCharged,l.grace_on_arrears_ageing as graceOnArrearsAgeing,"
                     + " l.nominal_interest_rate_per_period as 
interestRatePerPeriod, l.annual_nominal_interest_rate as annualInterestRate, "
                     + " l.repayment_period_frequency_enum as 
repaymentFrequencyType, l.interest_period_frequency_enum as 
interestRateFrequencyType, "
+                    + " l.fixed_length as fixedLength, "
                     + " l.term_frequency as termFrequency, 
l.term_period_frequency_enum as termPeriodFrequencyType, "
                     + " l.amortization_method_enum as amortizationType, 
l.interest_method_enum as interestType, l.is_equal_amortization as 
isEqualAmortization, l.interest_calculated_in_period_enum as 
interestCalculationPeriodType,"
                     + " l.fixed_principal_percentage_per_installment 
fixedPrincipalPercentagePerInstallment, "
@@ -1059,6 +1060,7 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService, Loa
             final LoanScheduleType loanScheduleType = 
LoanScheduleType.valueOf(loanScheduleTypeStr);
             final String loanScheduleProcessingTypeStr = 
rs.getString("loanScheduleProcessingType");
             final LoanScheduleProcessingType loanScheduleProcessingType = 
LoanScheduleProcessingType.valueOf(loanScheduleProcessingTypeStr);
+            final Integer fixedLength = JdbcSupport.getInteger(rs, 
"fixedLength");
 
             return LoanAccountData.basicLoanDetails(id, accountNo, status, 
externalId, clientId, clientAccountNo, clientName,
                     clientOfficeId, clientExternalId, groupData, loanType, 
loanProductId, loanProductName, loanProductDescription,
@@ -1077,7 +1079,7 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService, Loa
                     fixedPrincipalPercentagePerInstallment, delinquencyRange, 
disallowExpectedDisbursements, isFraud,
                     lastClosedBusinessDate, overpaidOnDate, isChargedOff, 
enableDownPayment, disbursedAmountPercentageForDownPayment,
                     enableAutoRepaymentForDownPayment, 
enableInstallmentLevelDelinquency, loanScheduleType.asEnumOptionData(),
-                    loanScheduleProcessingType.asEnumOptionData());
+                    loanScheduleProcessingType.asEnumOptionData(), 
fixedLength);
         }
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
index ed031bb64..c96e00148 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
@@ -95,6 +95,8 @@ final class LoanProductsApiResourceSwagger {
         public BigDecimal fixedPrincipalPercentagePerInstallment;
         @Schema(example = "true")
         public Boolean canDefineInstallmentAmount;
+        @Schema(example = "10")
+        public Integer fixedLength;
 
         // Settings
         @Schema(example = "false")
@@ -555,6 +557,8 @@ final class LoanProductsApiResourceSwagger {
         @Schema(example = "7")
         public Integer repaymentEvery;
         public GetLoanProductsRepaymentFrequencyType repaymentFrequencyType;
+        @Schema(example = "10")
+        public Integer fixedLength;
         @Schema(example = "15.000000")
         public Double interestRatePerPeriod;
         public 
GetLoanProductsResponse.GetLoanProductsInterestRateFrequencyType 
interestRateFrequencyType;
@@ -1210,6 +1214,8 @@ final class LoanProductsApiResourceSwagger {
         @Schema(example = "7")
         public Integer repaymentEvery;
         public GetLoanProductsResponse.GetLoanProductsRepaymentFrequencyType 
repaymentFrequencyType;
+        @Schema(example = "10")
+        public Integer fixedLength;
         @Schema(example = "5.000000")
         public Double interestRatePerPeriod;
         public 
GetLoanProductsProductIdResponse.GetLoanProductsInterestRateFrequencyType 
interestRateFrequencyType;
@@ -1332,6 +1338,8 @@ final class LoanProductsApiResourceSwagger {
         public BigDecimal fixedPrincipalPercentagePerInstallment;
         @Schema(example = "true")
         public Boolean canDefineInstallmentAmount;
+        @Schema(example = "10.0")
+        public Integer fixedLength;
 
         // Settings
         @Schema(example = "false")
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
index ddded6d7c..7403e82e4 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
@@ -89,6 +89,7 @@ public class LoanProductData implements Serializable {
     private final Integer maxNumberOfRepayments;
     private final Integer repaymentEvery;
     private final EnumOptionData repaymentFrequencyType;
+    private final Integer fixedLength;
     private final BigDecimal interestRatePerPeriod;
     private final BigDecimal minInterestRatePerPeriod;
     private final BigDecimal maxInterestRatePerPeriod;
@@ -237,6 +238,7 @@ public class LoanProductData implements Serializable {
         final Integer minNumberOfRepayments = null;
         final Integer maxNumberOfRepayments = null;
         final Integer repaymentEvery = null;
+        final Integer fixedLength = null;
         final BigDecimal interestRatePerPeriod = null;
         final BigDecimal minInterestRatePerPeriod = null;
         final BigDecimal maxInterestRatePerPeriod = null;
@@ -341,7 +343,7 @@ public class LoanProductData implements Serializable {
                 fixedPrincipalPercentagePerInstallment, 
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
                 overDueDaysForRepaymentEvent, enableDownPayment, 
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
                 paymentAllocation, creditAllocation, repaymentStartDateType, 
enableInstallmentLevelDelinquency, loanScheduleType,
-                loanScheduleProcessingType);
+                loanScheduleProcessingType, fixedLength);
 
     }
 
@@ -356,6 +358,7 @@ public class LoanProductData implements Serializable {
         final Integer minNumberOfRepayments = null;
         final Integer maxNumberOfRepayments = null;
         final Integer repaymentEvery = null;
+        final Integer fixedLength = null;
         final BigDecimal interestRatePerPeriod = null;
         final BigDecimal minInterestRatePerPeriod = null;
         final BigDecimal maxInterestRatePerPeriod = null;
@@ -460,7 +463,7 @@ public class LoanProductData implements Serializable {
                 fixedPrincipalPercentagePerInstallment, 
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
                 overDueDaysForRepaymentEvent, enableDownPayment, 
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
                 paymentAllocation, creditAllocation, repaymentStartDateType, 
enableInstallmentLevelDelinquency, loanScheduleType,
-                loanScheduleProcessingType);
+                loanScheduleProcessingType, fixedLength);
 
     }
 
@@ -479,6 +482,7 @@ public class LoanProductData implements Serializable {
         final Integer maxNumberOfRepayments = null;
 
         final Integer repaymentEvery = null;
+        final Integer fixedLength = null;
         final BigDecimal interestRatePerPeriod = null;
         final BigDecimal minInterestRatePerPeriod = null;
         final BigDecimal maxInterestRatePerPeriod = null;
@@ -586,7 +590,7 @@ public class LoanProductData implements Serializable {
                 fixedPrincipalPercentagePerInstallment, 
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
                 overDueDaysForRepaymentEvent, enableDownPayment, 
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
                 paymentAllocation, creditAllocation, repaymentStartDateType, 
enableInstallmentLevelDelinquency, loanScheduleType,
-                loanScheduleProcessingType);
+                loanScheduleProcessingType, fixedLength);
 
     }
 
@@ -607,6 +611,7 @@ public class LoanProductData implements Serializable {
         final Integer maxNumberOfRepayments = null;
 
         final Integer repaymentEvery = null;
+        final Integer fixedLength = null;
         final BigDecimal interestRatePerPeriod = null;
         final BigDecimal minInterestRatePerPeriod = null;
         final BigDecimal maxInterestRatePerPeriod = null;
@@ -706,7 +711,7 @@ public class LoanProductData implements Serializable {
                 fixedPrincipalPercentagePerInstallment, 
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
                 overDueDaysForRepaymentEvent, enableDownPayment, 
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
                 paymentAllocation, creditAllocationData, 
repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
-                loanScheduleProcessingType);
+                loanScheduleProcessingType, fixedLength);
     }
 
     public static LoanProductData withAccountingDetails(final LoanProductData 
productData, final Map<String, Object> accountingMappings,
@@ -756,7 +761,7 @@ public class LoanProductData implements Serializable {
             final BigDecimal disbursedAmountPercentageForDownPayment, final 
boolean enableAutoRepaymentForDownPayment,
             final Collection<AdvancedPaymentData> paymentAllocation, final 
Collection<CreditAllocationData> creditAllocation,
             final EnumOptionData repaymentStartDateType, final boolean 
enableInstallmentLevelDelinquency,
-            final EnumOptionData loanScheduleType, final EnumOptionData 
loanScheduleProcessingType) {
+            final EnumOptionData loanScheduleType, final EnumOptionData 
loanScheduleProcessingType, final Integer fixedLength) {
         this.id = id;
         this.name = name;
         this.shortName = shortName;
@@ -774,6 +779,7 @@ public class LoanProductData implements Serializable {
         this.graceOnInterestPayment = graceOnInterestPayment;
         this.graceOnInterestCharged = graceOnInterestCharged;
         this.repaymentEvery = repaymentEvery;
+        this.fixedLength = fixedLength;
         this.interestRatePerPeriod = interestRatePerPeriod;
         this.minInterestRatePerPeriod = minInterestRatePerPeriod;
         this.maxInterestRatePerPeriod = maxInterestRatePerPeriod;
@@ -929,6 +935,7 @@ public class LoanProductData implements Serializable {
         this.minNumberOfRepayments = productData.minNumberOfRepayments;
         this.maxNumberOfRepayments = productData.maxNumberOfRepayments;
         this.repaymentEvery = productData.repaymentEvery;
+        this.fixedLength = productData.fixedLength;
         this.interestRatePerPeriod = productData.interestRatePerPeriod;
         this.minInterestRatePerPeriod = productData.minInterestRatePerPeriod;
         this.maxInterestRatePerPeriod = productData.maxInterestRatePerPeriod;
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 c5ee18fbf..625c7de60 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
@@ -171,7 +171,7 @@ public final class LoanProductDataValidator {
             LoanProductConstants.ENABLE_DOWN_PAYMENT, 
LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
             LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, 
LoanProductConstants.REPAYMENT_START_DATE_TYPE,
             LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY, 
LoanProductConstants.LOAN_SCHEDULE_TYPE,
-            LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE));
+            LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, 
LoanProductConstants.FIXED_LENGTH));
 
     private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { 
LoanProductConstants.amortizationTypeParamName,
             LoanProductConstants.interestTypeParamName, 
LoanProductConstants.transactionProcessingStrategyCodeParamName,
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 a09ac1f58..31b776163 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
@@ -234,6 +234,7 @@ public class LoanProductReadPlatformServiceImpl implements 
LoanProductReadPlatfo
                     + "lp.nominal_interest_rate_per_period as 
interestRatePerPeriod, lp.min_nominal_interest_rate_per_period as 
minInterestRatePerPeriod, lp.max_nominal_interest_rate_per_period as 
maxInterestRatePerPeriod, lp.interest_period_frequency_enum as 
interestRatePerPeriodFreq, "
                     + "lp.annual_nominal_interest_rate as annualInterestRate, 
lp.interest_method_enum as interestMethod, 
lp.interest_calculated_in_period_enum as 
interestCalculationInPeriodMethod,lp.allow_partial_period_interest_calcualtion 
as allowPartialPeriodInterestCalcualtion, "
                     + "lp.repay_every as repaidEvery, 
lp.repayment_period_frequency_enum as repaymentPeriodFrequency, 
lp.number_of_repayments as numberOfRepayments, lp.min_number_of_repayments as 
minNumberOfRepayments, lp.max_number_of_repayments as maxNumberOfRepayments, "
+                    + "lp.fixed_length as fixedLength, "
                     + "lp.grace_on_principal_periods as 
graceOnPrincipalPayment, lp.recurring_moratorium_principal_periods as 
recurringMoratoriumOnPrincipalPeriods, lp.grace_on_interest_periods as 
graceOnInterestPayment, lp.grace_interest_free_periods as 
graceOnInterestCharged,lp.grace_on_arrears_ageing as 
graceOnArrearsAgeing,lp.overdue_days_for_npa as overdueDaysForNPA, "
                     + "lp.min_days_between_disbursal_and_first_repayment As 
minimumDaysBetweenDisbursalAndFirstRepayment, "
                     + "lp.amortization_method_enum as amortizationMethod, 
lp.arrearstolerance_amount as tolerance, "
@@ -319,6 +320,7 @@ public class LoanProductReadPlatformServiceImpl implements 
LoanProductReadPlatfo
             final Integer minNumberOfRepayments = JdbcSupport.getInteger(rs, 
"minNumberOfRepayments");
             final Integer maxNumberOfRepayments = JdbcSupport.getInteger(rs, 
"maxNumberOfRepayments");
             final Integer repaymentEvery = JdbcSupport.getInteger(rs, 
"repaidEvery");
+            final Integer fixedLength = JdbcSupport.getInteger(rs, 
"fixedLength");
 
             final Integer graceOnPrincipalPayment = 
JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnPrincipalPayment");
             final Integer recurringMoratoriumOnPrincipalPeriods = 
JdbcSupport.getIntegerDefaultToNullIfZero(rs,
@@ -544,7 +546,8 @@ public class LoanProductReadPlatformServiceImpl implements 
LoanProductReadPlatfo
                     isRatesEnabled, fixedPrincipalPercentagePerInstallment, 
delinquencyBucketOptions, delinquencyBucket,
                     dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent, 
enableDownPayment, disbursedAmountPercentageForDownPayment,
                     enableAutoRepaymentForDownPayment, advancedPaymentData, 
creditAllocationData, repaymentStartDateType,
-                    enableInstallmentLevelDelinquency, 
loanScheduleType.asEnumOptionData(), 
loanScheduleProcessingType.asEnumOptionData());
+                    enableInstallmentLevelDelinquency, 
loanScheduleType.asEnumOptionData(), 
loanScheduleProcessingType.asEnumOptionData(),
+                    fixedLength);
         }
     }
 
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 82421fa84..10d966e4d 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
@@ -123,7 +123,7 @@ public class DefaultScheduledDateGeneratorTest {
                 null, null, null, null, null, 
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);
+                DISBURSEMENT_DATE, submittedOnDate, CUMULATIVE, 
LoanScheduleProcessingType.HORIZONTAL, null);
     }
 
     private HolidayDetailDTO createHolidayDTO() {
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
index 7a25c2e47..e42afa47a 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
@@ -1962,7 +1962,8 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
             Integer localLoanProductId = createLoanProduct("500", "15", "4", 
true, "25", false, LoanScheduleType.PROGRESSIVE,
                     LoanScheduleProcessingType.VERTICAL, assetAccount, 
incomeAccount, expenseAccount, overpaymentAccount);
             final PostLoansResponse loanResponse = 
applyForLoanApplication(client.getClientId(), localLoanProductId,
-                    BigDecimal.valueOf(500.0), 45, 15, 3, BigDecimal.ZERO, "01 
January 2023", "01 January 2023");
+                    BigDecimal.valueOf(500.0), 45, 15, 3, BigDecimal.ZERO, "01 
January 2023", "01 January 2023",
+                    LoanScheduleProcessingType.VERTICAL);
 
             loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
                     new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(500)).dateFormat(DATETIME_PATTERN)
@@ -2489,7 +2490,8 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
             Integer localLoanProductId = createLoanProduct("1000", "15", "3", 
true, "25", false, LoanScheduleType.PROGRESSIVE,
                     LoanScheduleProcessingType.VERTICAL, assetAccount, 
incomeAccount, expenseAccount, overpaymentAccount);
             final PostLoansResponse loanResponse = 
applyForLoanApplication(client.getClientId(), localLoanProductId,
-                    BigDecimal.valueOf(1000.0), 45, 15, 3, BigDecimal.ZERO, 
"01 September 2023", "01 September 2023");
+                    BigDecimal.valueOf(1000.0), 45, 15, 3, BigDecimal.ZERO, 
"01 September 2023", "01 September 2023",
+                    LoanScheduleProcessingType.VERTICAL);
 
             loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
                     new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000)).dateFormat(DATETIME_PATTERN)
@@ -3621,11 +3623,17 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
     private static PostLoansResponse applyForLoanApplication(final Long 
clientId, final Integer loanProductId, final BigDecimal principal,
             final int loanTermFrequency, final int repaymentAfterEvery, final 
int numberOfRepayments, final BigDecimal interestRate,
             final String expectedDisbursementDate, final String 
submittedOnDate) {
+        return applyForLoanApplication(clientId, loanProductId, principal, 
loanTermFrequency, repaymentAfterEvery, numberOfRepayments,
+                interestRate, expectedDisbursementDate, submittedOnDate, 
LoanScheduleProcessingType.HORIZONTAL);
+    }
+
+    private static PostLoansResponse applyForLoanApplication(final Long 
clientId, final Integer loanProductId, final BigDecimal principal,
+            final int loanTermFrequency, final int repaymentAfterEvery, final 
int numberOfRepayments, final BigDecimal interestRate,
+            final String expectedDisbursementDate, final String 
submittedOnDate, LoanScheduleProcessingType loanScheduleProcessingType) {
         LOG.info("--------------------------------APPLYING FOR LOAN 
APPLICATION--------------------------------");
         return applyForLoanApplication(clientId, loanProductId, principal, 
loanTermFrequency, repaymentAfterEvery, numberOfRepayments,
                 interestRate, expectedDisbursementDate, submittedOnDate,
-                
AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY,
-                LoanScheduleProcessingType.HORIZONTAL.name());
+                
AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY,
 loanScheduleProcessingType.name());
     }
 
     private static void validateLoanTransaction(GetLoansLoanIdResponse 
loanDetails, int index, double transactionAmount,
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedLengthLoanProductIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedLengthLoanProductIntegrationTest.java
new file mode 100644
index 000000000..a85931ed5
--- /dev/null
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedLengthLoanProductIntegrationTest.java
@@ -0,0 +1,108 @@
+/**
+ * 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 org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
+import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+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.client.models.PutLoanProductsProductIdResponse;
+import org.apache.fineract.integrationtests.common.ClientHelper;
+import 
org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+@ExtendWith(LoanTestLifecycleExtension.class)
+public class FixedLengthLoanProductIntegrationTest extends 
BaseLoanIntegrationTest {
+
+    @Test
+    public void testCreateReadUpdateReadLoanProductWithFixedLength() {
+        // create with 5
+        PostLoanProductsRequest loanProductsRequest = 
fixedLengthLoanProduct(5);
+        PostLoanProductsResponse loanProduct = 
loanProductHelper.createLoanProduct(loanProductsRequest);
+        Assertions.assertNotNull(loanProduct.getResourceId());
+
+        // read
+        GetLoanProductsProductIdResponse getLoanProductsProductIdResponse = 
loanProductHelper
+                .retrieveLoanProductById(loanProduct.getResourceId());
+        Assertions.assertEquals(5, 
getLoanProductsProductIdResponse.getFixedLength());
+
+        // update to 6
+        PutLoanProductsProductIdRequest updateRequest = new 
PutLoanProductsProductIdRequest().fixedLength(6).locale("en");
+        PutLoanProductsProductIdResponse putLoanProductsProductIdResponse = 
loanProductHelper
+                .updateLoanProductById(loanProduct.getResourceId(), 
updateRequest);
+        
Assertions.assertNotNull(putLoanProductsProductIdResponse.getResourceId());
+
+        // read again
+        getLoanProductsProductIdResponse = 
loanProductHelper.retrieveLoanProductById(loanProduct.getResourceId());
+        Assertions.assertEquals(6, 
getLoanProductsProductIdResponse.getFixedLength());
+
+        // update to null
+        
loanTransactionHelper.updateLoanProduct(putLoanProductsProductIdResponse.getResourceId(),
 """
+                {
+                    "fixedLength": null,
+                    "locale": "en"
+                }
+                """);
+
+        // read again
+        getLoanProductsProductIdResponse = 
loanProductHelper.retrieveLoanProductById(loanProduct.getResourceId());
+        
Assertions.assertNull(getLoanProductsProductIdResponse.getFixedLength());
+    }
+
+    @Test
+    public void testLoanApplicationWithFixedLengthInheritedFromLoanProduct() {
+        runAt("01 January 2023", () -> {
+            Long clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
+
+            PostLoanProductsResponse loanProduct = 
loanProductHelper.createLoanProduct(fixedLengthLoanProduct(6));
+            Assertions.assertNotNull(loanProduct.getResourceId());
+
+            Long loanId = applyAndApproveLoan(clientId, 
loanProduct.getResourceId(), "01 January 2023", 1000.0);
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId);
+            Assertions.assertEquals(6, loanDetails.getFixedLength());
+        });
+    }
+
+    @Test
+    public void 
testLoanApplicationWithFixedLengthOverriddenByLoanApplication() {
+        runAt("01 January 2023", () -> {
+            Long clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
+
+            PostLoanProductsResponse loanProduct = 
loanProductHelper.createLoanProduct(fixedLengthLoanProduct(6));
+            Assertions.assertNotNull(loanProduct.getResourceId());
+
+            Long loanId = applyAndApproveLoan(clientId, 
loanProduct.getResourceId(), "01 January 2023", 1000.0, 1, //
+                    loanApplication -> loanApplication.fixedLength(5) //
+            );
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId);
+            Assertions.assertEquals(5, loanDetails.getFixedLength());
+        });
+    }
+
+    private PostLoanProductsRequest fixedLengthLoanProduct(Integer 
fixedLength) {
+        return 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct().numberOfRepayments(4)//
+                .repaymentEvery(1)//
+                
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue())//
+                
.transactionProcessingStrategyCode("mifos-standard-strategy").fixedLength(fixedLength);
+    }
+
+}
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductHelper.java
index b899f20d1..5e20943e6 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductHelper.java
@@ -46,6 +46,10 @@ public class LoanProductHelper extends IntegrationTest {
         return ok(fineract().loanProducts.updateLoanProduct1(externalId, 
request));
     }
 
+    public PutLoanProductsProductIdResponse updateLoanProductById(Long 
loanProductId, PutLoanProductsProductIdRequest request) {
+        return ok(fineract().loanProducts.updateLoanProduct(loanProductId, 
request));
+    }
+
     public GetLoanProductsTemplateResponse getLoanProductTemplate(boolean 
isProductMixTemplate) {
         return 
ok(fineract().loanProducts.retrieveTemplate11(isProductMixTemplate));
     }

Reply via email to