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 82eafad8dd344706bf1b5ee68235f8c6c899818e
Author: adam.magyari <[email protected]>
AuthorDate: Tue May 20 11:08:20 2025 +0200

    FINERACT-2232: Capitalized income adjustment
---
 .../commands/service/CommandWrapperBuilder.java    |   9 +
 ...AdjustmentTransactionCreatedBusinessEvent.java} |  20 ++-
 .../loanaccount/data/LoanTransactionEnumData.java  |   2 +
 .../loanaccount/domain/LoanTransaction.java        |   9 +-
 .../domain/LoanTransactionRelationTypeEnum.java    |   4 +-
 .../service/CapitalizedIncomePlatformService.java  |   3 +
 .../domain/PaymentAllocationTransactionType.java   |   3 +-
 ...dvancedPaymentScheduleTransactionProcessor.java |   2 +-
 .../CapitalizedIncomeAdjustmentCommandHandler.java |  53 ++++++
 .../LoanCapitalizedIncomeBalanceRepository.java    |   3 +
 .../CapitalizedIncomeWritePlatformServiceImpl.java |  57 +++++-
 .../ProgressiveLoanTransactionValidator.java       |   2 +
 .../ProgressiveLoanTransactionValidatorImpl.java   |  81 +++++++++
 .../ProgressiveLoanAccountConfiguration.java       |   5 +-
 .../AccrualBasedAccountingProcessorForLoan.java    | 131 ++++++++++++++
 .../api/LoanTransactionsApiResource.java           |   2 +
 .../loanaccount/api/LoansApiResourceSwagger.java   |   2 +
 .../db/changelog/tenant/changelog-tenant.xml       |   1 +
 ...d_capitalized_income_adjustment_transaction.xml |  38 ++++
 ...nalEventConfigurationValidationServiceTest.java |   6 +-
 .../LoanCapitalizedIncomeTest.java                 | 198 +++++++++++++++++++++
 .../common/ExternalEventConfigurationHelper.java   |   6 +
 .../common/loans/LoanTransactionHelper.java        |  30 ++++
 23 files changed, 649 insertions(+), 18 deletions(-)

diff --git 
a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
 
b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
index a3389825db..872835ffd7 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
@@ -3831,4 +3831,13 @@ public class CommandWrapperBuilder {
         this.href = "/loans/" + loanId;
         return this;
     }
+
+    public CommandWrapperBuilder capitalizedIncomeAdjustment(final Long 
loanId, final Long transactionId) {
+        this.actionName = "CAPITALIZEDINCOMEADJUSTMENT";
+        this.entityName = "LOAN";
+        this.entityId = transactionId;
+        this.loanId = loanId;
+        this.href = "/loans/" + loanId + "/transactions/" + transactionId;
+        return this;
+    }
 }
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomePlatformService.java
 
b/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent.java
similarity index 58%
copy from 
fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomePlatformService.java
copy to 
fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent.java
index 0c1879323b..ad9ffd961b 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomePlatformService.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent.java
@@ -16,16 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.portfolio.loanaccount.service;
+package 
org.apache.fineract.infrastructure.event.business.domain.loan.transaction;
 
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
-import org.springframework.transaction.annotation.Transactional;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
 
-public interface CapitalizedIncomePlatformService {
+public class LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent 
extends LoanTransactionBusinessEvent {
 
-    @Transactional
-    CommandProcessingResult addCapitalizedIncome(Long loanId, JsonCommand 
command);
+    private static final String TYPE = 
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent";
 
-    void resetBalance(Long loanId);
+    public 
LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent(LoanTransaction 
value) {
+        super(value);
+    }
+
+    @Override
+    public String getType() {
+        return TYPE;
+    }
 }
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
index 573b45703b..5b520eee54 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
@@ -69,6 +69,7 @@ public class LoanTransactionEnumData implements Serializable {
     private final boolean accrualAdjustment;
     private final boolean capitalizedIncome;
     private final boolean capitalizedIncomeAmortization;
+    private final boolean capitalizedIncomeAdjustment;
 
     public LoanTransactionEnumData(final Long id, final String code, final 
String value) {
         this.id = id;
@@ -107,6 +108,7 @@ public class LoanTransactionEnumData implements 
Serializable {
         this.accrualAdjustment = 
Long.valueOf(LoanTransactionType.ACCRUAL_ADJUSTMENT.getValue()).equals(this.id);
         this.capitalizedIncome = 
Long.valueOf(LoanTransactionType.CAPITALIZED_INCOME.getValue()).equals(this.id);
         this.capitalizedIncomeAmortization = 
Long.valueOf(LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION.getValue()).equals(this.id);
+        this.capitalizedIncomeAdjustment = 
Long.valueOf(LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT.getValue()).equals(this.id);
     }
 
     public boolean isRepaymentType() {
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index 47f4ef5303..80adc30e51 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -322,6 +322,12 @@ public class LoanTransaction extends 
AbstractAuditableWithUTCDateTimeCustom<Long
         };
     }
 
+    public static LoanTransaction capitalizedIncomeAdjustment(final Loan loan, 
final Money amount, final PaymentDetail paymentDetail,
+            final LocalDate transactionDate, final ExternalId externalId) {
+        return new LoanTransaction(loan, loan.getOffice(), 
LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT, transactionDate,
+                amount.getAmount(), amount.getAmount(), null, null, null, 
null, false, paymentDetail, externalId);
+    }
+
     public LoanTransaction copyTransactionPropertiesAndMappings() {
         LoanTransaction newTransaction = copyTransactionProperties(this);
         
newTransaction.updateLoanTransactionToRepaymentScheduleMappings(loanTransactionToRepaymentScheduleMappings);
@@ -570,7 +576,8 @@ public class LoanTransaction extends 
AbstractAuditableWithUTCDateTimeCustom<Long
 
     public boolean isRepaymentLikeType() {
         return isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() 
|| isGoodwillCredit() || isChargeRefund()
-                || isChargeAdjustment() || isDownPayment() || 
isInterestPaymentWaiver() || isInterestRefund();
+                || isChargeAdjustment() || isDownPayment() || 
isInterestPaymentWaiver() || isInterestRefund()
+                || isCapitalizedIncomeAdjustment();
     }
 
     public boolean isTypeAllowedForChargeback() {
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionRelationTypeEnum.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionRelationTypeEnum.java
index 52cbec85e0..85eae4b28c 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionRelationTypeEnum.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionRelationTypeEnum.java
@@ -24,7 +24,9 @@ public enum LoanTransactionRelationTypeEnum {
     CHARGEBACK(1, "loanTransactionRelationType.chargeback"), //
     CHARGE_ADJUSTMENT(2, "loanTransactionRelationType.chargeAdjustment"), //
     REPLAYED(3, "loanTransactionRelationType.replayed"), //
-    RELATED(4, "loanTransactionRelationType.related");
+    RELATED(4, "loanTransactionRelationType.related"), //
+    ADJUSTMENT(5, "loanTransactionRelationType.adjustment"), //
+    ;
 
     private final Integer value;
     private final String code;
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomePlatformService.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomePlatformService.java
index 0c1879323b..b0bacc6d84 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomePlatformService.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomePlatformService.java
@@ -27,5 +27,8 @@ public interface CapitalizedIncomePlatformService {
     @Transactional
     CommandProcessingResult addCapitalizedIncome(Long loanId, JsonCommand 
command);
 
+    @Transactional
+    CommandProcessingResult capitalizedIncomeAdjustment(Long loanId, Long 
capitalizedIncomeTransactionId, JsonCommand command);
+
     void resetBalance(Long loanId);
 }
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationTransactionType.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationTransactionType.java
index 942f3de612..6194a99de2 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationTransactionType.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/PaymentAllocationTransactionType.java
@@ -42,7 +42,8 @@ public enum PaymentAllocationTransactionType {
     CHARGE_PAYMENT(LoanTransactionType.CHARGE_PAYMENT, "Charge payment"), //
     REFUND_FOR_ACTIVE_LOAN(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN, "Refund 
for active loan"), //
     INTEREST_PAYMENT_WAIVER(LoanTransactionType.INTEREST_PAYMENT_WAIVER, 
"Interest payment waiver"), //
-    INTEREST_REFUND(LoanTransactionType.INTEREST_REFUND, "Interest refund");
+    INTEREST_REFUND(LoanTransactionType.INTEREST_REFUND, "Interest refund"), //
+    
CAPITALIZED_INCOME_ADJUSTMENT(LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT,
 "Capitalized income adjustment");
 
     private final LoanTransactionType loanTransactionType;
     private final String humanReadableName;
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
index cfbbe223a5..b728e5f977 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
@@ -335,7 +335,7 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
             case CHARGEBACK -> handleChargeback(loanTransaction, ctx);
             case CREDIT_BALANCE_REFUND -> 
handleCreditBalanceRefund(loanTransaction, ctx);
             case REPAYMENT, MERCHANT_ISSUED_REFUND, PAYOUT_REFUND, 
GOODWILL_CREDIT, CHARGE_REFUND, CHARGE_ADJUSTMENT, DOWN_PAYMENT,
-                    WAIVE_INTEREST, RECOVERY_REPAYMENT, 
INTEREST_PAYMENT_WAIVER ->
+                    WAIVE_INTEREST, RECOVERY_REPAYMENT, 
INTEREST_PAYMENT_WAIVER, CAPITALIZED_INCOME_ADJUSTMENT ->
                 handleRepayment(loanTransaction, ctx);
             case INTEREST_REFUND -> handleInterestRefund(loanTransaction, ctx);
             case CHARGE_OFF -> handleChargeOff(loanTransaction, ctx);
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CapitalizedIncomeAdjustmentCommandHandler.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CapitalizedIncomeAdjustmentCommandHandler.java
new file mode 100644
index 0000000000..1815a98812
--- /dev/null
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CapitalizedIncomeAdjustmentCommandHandler.java
@@ -0,0 +1,53 @@
+/**
+ * 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.handler;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.DataIntegrityErrorHandler;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import 
org.apache.fineract.portfolio.loanaccount.service.CapitalizedIncomePlatformService;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.orm.jpa.JpaSystemException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+@CommandType(entity = "LOAN", action = "CAPITALIZEDINCOMEADJUSTMENT")
+public class CapitalizedIncomeAdjustmentCommandHandler implements 
NewCommandSourceHandler {
+
+    private final CapitalizedIncomePlatformService 
capitalizedIncomePlatformService;
+    private final DataIntegrityErrorHandler dataIntegrityErrorHandler;
+
+    @Transactional
+    @Override
+    public CommandProcessingResult processCommand(final JsonCommand command) {
+
+        try {
+            return 
this.capitalizedIncomePlatformService.capitalizedIncomeAdjustment(command.getLoanId(),
 command.entityId(), command);
+        } catch (final JpaSystemException | DataIntegrityViolationException 
dve) {
+            dataIntegrityErrorHandler.handleDataIntegrityIssues(command, 
dve.getMostSpecificCause(), dve, "loan.capitalized.income",
+                    "Capitalized Income");
+            return CommandProcessingResult.empty();
+        }
+    }
+}
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/repository/LoanCapitalizedIncomeBalanceRepository.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/repository/LoanCapitalizedIncomeBalanceRepository.java
index ab5f0f1ac5..0ba8a15fc9 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/repository/LoanCapitalizedIncomeBalanceRepository.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/repository/LoanCapitalizedIncomeBalanceRepository.java
@@ -43,4 +43,7 @@ public interface LoanCapitalizedIncomeBalanceRepository
 
     @Query("SELECT SUM(lcib.amountAdjustment) FROM 
LoanCapitalizedIncomeBalance lcib WHERE lcib.loan.id = :loanId")
     BigDecimal calculateCapitalizedIncomeAdjustment(Long loanId);
+
+    @Query("SELECT lcib FROM LoanCapitalizedIncomeBalance lcib, 
LoanTransaction lt, LoanTransactionRelation ltr WHERE lt.loan.id = lcib.loan.id 
AND ltr.fromTransaction.id =:transactionId AND ltr.toTransaction.id=lt.id AND 
lcib.loanTransaction.id = lt.id")
+    LoanCapitalizedIncomeBalance findBalanceForAdjustment(Long transactionId);
 }
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
index d0e745756e..a931048cd3 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
@@ -32,10 +33,13 @@ import 
org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuild
 import org.apache.fineract.infrastructure.core.domain.ExternalId;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
+import org.apache.fineract.infrastructure.core.service.MathUtil;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeBalance;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
 import 
org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
 import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
@@ -103,11 +107,60 @@ public class CapitalizedIncomeWritePlatformServiceImpl 
implements CapitalizedInc
                 .build();
     }
 
-    private void recalculateLoanTransactions(Loan loan, LocalDate 
transactionDate, LoanTransaction capitalizedIncomeTransaction) {
+    @Override
+    public CommandProcessingResult capitalizedIncomeAdjustment(final Long 
loanId, final Long capitalizedIncomeTransactionId,
+            final JsonCommand command) {
+        loanTransactionValidator.validateCapitalizedIncomeAdjustment(command, 
loanId, capitalizedIncomeTransactionId);
+        final Loan loan = loanAssembler.assembleFrom(loanId);
+        final List<Long> existingTransactionIds = new 
ArrayList<>(loanTransactionRepository.findTransactionIdsByLoan(loan));
+        final List<Long> existingReversedTransactionIds = new 
ArrayList<>(loanTransactionRepository.findReversedTransactionIdsByLoan(loan));
+        final Map<String, Object> changes = new LinkedHashMap<>();
+        // Create payment details
+        final PaymentDetail paymentDetail = 
this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, 
changes);
+        // Extract transaction details
+        final LocalDate transactionDate = 
command.localDateValueOfParameterNamed("transactionDate");
+        final BigDecimal transactionAmount = 
command.bigDecimalValueOfParameterNamed("transactionAmount");
+        final ExternalId txnExternalId = 
externalIdFactory.createFromCommand(command, "externalId");
+
+        Optional<LoanTransaction> capitalizedIncome = 
loanTransactionRepository.findById(capitalizedIncomeTransactionId);
+        LoanTransaction capitalizedIncomeAdjustment = 
LoanTransaction.capitalizedIncomeAdjustment(loan,
+                Money.of(loan.getCurrency(), transactionAmount), 
paymentDetail, transactionDate, txnExternalId);
+        
capitalizedIncomeAdjustment.getLoanTransactionRelations().add(LoanTransactionRelation.linkToTransaction(capitalizedIncomeAdjustment,
+                capitalizedIncome.get(), 
LoanTransactionRelationTypeEnum.ADJUSTMENT));
+        loan.addLoanTransaction(capitalizedIncomeAdjustment);
+        recalculateLoanTransactions(loan, transactionDate, 
capitalizedIncomeAdjustment);
+        LoanTransaction savedCapitalizedIncomeAdjustment = 
loanTransactionRepository.saveAndFlush(capitalizedIncomeAdjustment);
+
+        // Update outstanding loan balances
+        loan.updateLoanOutstandingBalances();
+
+        // Create a note if provided
+        final String noteText = command.stringValueOfParameterNamed("note");
+        if (noteText != null && !noteText.isEmpty()) {
+            
noteWritePlatformService.createLoanTransactionNote(savedCapitalizedIncomeAdjustment.getId(),
 noteText);
+        }
+        // Post journal entries
+        journalEntryPoster.postJournalEntries(loan, existingTransactionIds, 
existingReversedTransactionIds);
+
+        // Accounting uses the original balance, balance update HAS TO HAPPEN 
AFTER postJournalEntries
+        LoanCapitalizedIncomeBalance capitalizedIncomeBalance = 
capitalizedIncomeBalanceRepository.findByLoanIdAndLoanTransactionId(loanId,
+                capitalizedIncomeTransactionId);
+        capitalizedIncomeBalance
+                
.setAmountAdjustment(MathUtil.nullToZero(capitalizedIncomeBalance.getAmountAdjustment()).add(transactionAmount));
+        capitalizedIncomeBalance.setUnrecognizedAmount(
+                
MathUtil.negativeToZero(capitalizedIncomeBalance.getUnrecognizedAmount().subtract(transactionAmount)));
+        capitalizedIncomeBalanceRepository.save(capitalizedIncomeBalance);
+
+        return new 
CommandProcessingResultBuilder().withLoanId(loan.getId()).withLoanExternalId(loan.getExternalId())
+                .withEntityId(savedCapitalizedIncomeAdjustment.getId())
+                
.withEntityExternalId(savedCapitalizedIncomeAdjustment.getExternalId()).build();
+    }
+
+    private void recalculateLoanTransactions(Loan loan, LocalDate 
transactionDate, LoanTransaction transaction) {
         if (loan.isInterestBearingAndInterestRecalculationEnabled() || 
DateUtils.isBeforeBusinessDate(transactionDate)) {
             reprocessLoanTransactionsService.reprocessTransactions(loan);
         } else {
-            
reprocessLoanTransactionsService.processLatestTransaction(capitalizedIncomeTransaction,
 loan);
+            
reprocessLoanTransactionsService.processLatestTransaction(transaction, loan);
         }
     }
 
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidator.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidator.java
index 192039acd6..0f0d2faa02 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidator.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidator.java
@@ -24,4 +24,6 @@ import 
org.apache.fineract.portfolio.loanaccount.serialization.LoanTransactionVa
 public interface ProgressiveLoanTransactionValidator extends 
LoanTransactionValidator {
 
     void validateCapitalizedIncome(JsonCommand command, Long loanId);
+
+    void validateCapitalizedIncomeAdjustment(JsonCommand command, Long loanId, 
Long capitalizedIncomeTransactionId);
 }
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidatorImpl.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidatorImpl.java
index b2f306d414..dc3d42e6c6 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidatorImpl.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidatorImpl.java
@@ -27,6 +27,7 @@ import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -35,6 +36,7 @@ import 
org.apache.fineract.infrastructure.core.api.JsonCommand;
 import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.core.service.MathUtil;
 import org.apache.fineract.organisation.holiday.domain.Holiday;
 import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
 import org.apache.fineract.portfolio.common.service.Validator;
@@ -45,6 +47,7 @@ import 
org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
 import 
org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
 import 
org.apache.fineract.portfolio.loanaccount.serialization.LoanTransactionValidator;
@@ -57,6 +60,7 @@ public class ProgressiveLoanTransactionValidatorImpl 
implements ProgressiveLoanT
     private final LoanTransactionValidator loanTransactionValidator;
     private final LoanRepositoryWrapper loanRepositoryWrapper;
     private final LoanCapitalizedIncomeBalanceRepository 
loanCapitalizedIncomeBalanceRepository;
+    private final LoanTransactionRepository loanTransactionRepository;
 
     @Override
     public void validateCapitalizedIncome(final JsonCommand command, final 
Long loanId) {
@@ -127,6 +131,78 @@ public class ProgressiveLoanTransactionValidatorImpl 
implements ProgressiveLoanT
         });
     }
 
+    @Override
+    public void validateCapitalizedIncomeAdjustment(JsonCommand command, Long 
loanId, Long capitalizedIncomeTransactionId) {
+        final String json = command.json();
+        if (StringUtils.isBlank(json)) {
+            throw new InvalidJsonException();
+        }
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+        final Type typeOfMap = new TypeToken<Map<String, Object>>() 
{}.getType();
+        this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, 
getCapitalizedIncomeAdjustmentParameters());
+
+        Validator.validateOrThrow("loan.capitalized.incomeAdjustment", 
baseDataValidator -> {
+            final Loan loan = 
this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId, true);
+            validateLoanClientIsActive(loan);
+            validateLoanGroupIsActive(loan);
+
+            // Validate loan is progressive
+            if (!loan.isProgressiveSchedule()) {
+                
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("not.progressive.loan");
+            }
+
+            // Validate income capitalization is enabled
+            if 
(!loan.getLoanProductRelatedDetail().isEnableIncomeCapitalization()) {
+                
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("income.capitalization.not.enabled");
+            }
+
+            // Validate loan is active
+            if (!loan.getStatus().isActive()) {
+                
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("not.active");
+            }
+
+            final LocalDate transactionDate = 
this.fromApiJsonHelper.extractLocalDateNamed("transactionDate", element);
+            
baseDataValidator.reset().parameter("transactionDate").value(transactionDate).notNull();
+
+            // Validate transaction date is not before disbursement date
+            if (transactionDate != null && loan.getDisbursementDate() != null 
&& transactionDate.isBefore(loan.getDisbursementDate())) {
+                
baseDataValidator.reset().parameter("transactionDate").failWithCode("before.disbursement.date",
+                        "Transaction date cannot be before disbursement date");
+            }
+
+            final BigDecimal transactionAmount = 
this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("transactionAmount", 
element);
+            
baseDataValidator.reset().parameter("transactionAmount").value(transactionAmount).notNull().positiveAmount();
+
+            Optional<LoanTransaction> capitalizedIncomeTransactionOpt = 
loanTransactionRepository.findById(capitalizedIncomeTransactionId);
+            if (capitalizedIncomeTransactionOpt.isEmpty()) {
+                
baseDataValidator.reset().parameter("capitalizedIncomeTransactionId").failWithCode("loan.transaction.not.found",
+                        "Capitalized Income transaction not found.");
+            } else {
+                // Validate not before capitalized income transaction
+                if (transactionDate != null && 
transactionDate.isBefore(capitalizedIncomeTransactionOpt.get().getTransactionDate()))
 {
+                    
baseDataValidator.reset().parameter("transactionDate").failWithCode("before.capitalizedIncome.transaction.date",
+                            "Transaction date cannot be before capitalized 
income transaction date");
+
+                }
+                if (transactionAmount != null) {
+                    LoanCapitalizedIncomeBalance capitalizedIncomeBalance = 
loanCapitalizedIncomeBalanceRepository
+                            .findByLoanIdAndLoanTransactionId(loanId, 
capitalizedIncomeTransactionId);
+                    if 
(MathUtil.isLessThan(capitalizedIncomeBalance.getAmount()
+                            
.subtract(MathUtil.nullToZero(capitalizedIncomeBalance.getAmountAdjustment())), 
transactionAmount)) {
+                        
baseDataValidator.reset().parameter("transactionAmount").value(transactionAmount).failWithCode(
+                                "cannot.be.more.than.remaining.amount",
+                                " Capitalized income adjustment amount cannot 
be more than remaining amount");
+                    }
+                }
+            }
+
+            validatePaymentDetails(baseDataValidator, element);
+            validateNote(baseDataValidator, element);
+            validateExternalId(baseDataValidator, element);
+        });
+    }
+
     // Delegates
     @Override
     public void validateDisbursement(JsonCommand command, boolean 
isAccountTransfer, Long loanId) {
@@ -280,4 +356,9 @@ public class ProgressiveLoanTransactionValidatorImpl 
implements ProgressiveLoanT
         return new HashSet<>(
                 Arrays.asList("transactionDate", "dateFormat", "locale", 
"transactionAmount", "paymentTypeId", "note", "externalId"));
     }
+
+    private Set<String> getCapitalizedIncomeAdjustmentParameters() {
+        return new HashSet<>(
+                Arrays.asList("transactionDate", "dateFormat", "locale", 
"transactionAmount", "paymentTypeId", "note", "externalId"));
+    }
 }
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/ProgressiveLoanAccountConfiguration.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/ProgressiveLoanAccountConfiguration.java
index 31e27793b9..6694b9eab0 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/ProgressiveLoanAccountConfiguration.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/ProgressiveLoanAccountConfiguration.java
@@ -60,9 +60,10 @@ public class ProgressiveLoanAccountConfiguration {
     @ConditionalOnMissingBean(ProgressiveLoanTransactionValidator.class)
     public ProgressiveLoanTransactionValidator 
progressiveLoanTransactionValidator(FromJsonHelper fromApiJsonHelper,
             LoanTransactionValidator loanTransactionValidator, 
LoanRepositoryWrapper loanRepositoryWrapper,
-            LoanCapitalizedIncomeBalanceRepository 
loanCapitalizedIncomeBalanceRepository) {
+            LoanCapitalizedIncomeBalanceRepository 
loanCapitalizedIncomeBalanceRepository,
+            LoanTransactionRepository loanTransactionRepository) {
         return new ProgressiveLoanTransactionValidatorImpl(fromApiJsonHelper, 
loanTransactionValidator, loanRepositoryWrapper,
-                loanCapitalizedIncomeBalanceRepository);
+                loanCapitalizedIncomeBalanceRepository, 
loanTransactionRepository);
     }
 
     @Bean
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
index 29830b566b..4aa44b87b1 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
@@ -21,10 +21,12 @@ package org.apache.fineract.accounting.journalentry.service;
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import lombok.RequiredArgsConstructor;
 import org.apache.fineract.accounting.closure.domain.GLClosure;
 import 
org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
@@ -34,11 +36,21 @@ import 
org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
 import org.apache.fineract.accounting.journalentry.data.GLAccountBalanceHolder;
 import org.apache.fineract.accounting.journalentry.data.LoanDTO;
 import org.apache.fineract.accounting.journalentry.data.LoanTransactionDTO;
+import org.apache.fineract.accounting.journalentry.domain.JournalEntry;
+import 
org.apache.fineract.accounting.journalentry.domain.JournalEntryRepository;
 import 
org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
+import 
org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import org.apache.fineract.infrastructure.core.service.MathUtil;
 import org.apache.fineract.organisation.office.domain.Office;
 import org.apache.fineract.portfolio.PortfolioProductType;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeBalance;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
+import 
org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
 import org.springframework.stereotype.Component;
 
 @Component
@@ -47,6 +59,9 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
 
     private final AccountingProcessorHelper helper;
     private final JournalEntryWritePlatformService 
journalEntryWritePlatformService;
+    private final LoanCapitalizedIncomeBalanceRepository 
loanCapitalizedIncomeBalanceRepository;
+    private final JournalEntryRepository journalEntryRepository;
+    private final LoanTransactionRepository loanTransactionRepository;
 
     @Override
     public void createJournalEntriesForLoan(final LoanDTO loanDTO) {
@@ -131,6 +146,10 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
             if (transactionType.isCapitalizedIncomeAmortization()) {
                 createJournalEntriesForCapitalizedIncomeAmortization(loanDTO, 
loanTransactionDTO, office);
             }
+            // Handle Capitalized Income Adjustment
+            if (transactionType.isCapitalizedIncomeAdjustment()) {
+                createJournalEntriesForCapitalizedIncomeAdjustment(loanDTO, 
loanTransactionDTO, office);
+            }
         }
     }
 
@@ -171,6 +190,118 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         }
     }
 
+    private void createJournalEntriesForCapitalizedIncomeAdjustment(final 
LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
+            final Office office) {
+        // loan properties
+        final Long loanProductId = loanDTO.getLoanProductId();
+        final Long loanId = loanDTO.getLoanId();
+        final String currencyCode = loanDTO.getCurrencyCode();
+        // transaction properties
+        final String transactionId = loanTransactionDTO.getTransactionId();
+        final LocalDate transactionDate = 
loanTransactionDTO.getTransactionDate();
+        final BigDecimal transactionAmount = loanTransactionDTO.getAmount();
+        final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
+        final BigDecimal interestAmount = loanTransactionDTO.getInterest();
+        final BigDecimal feesAmount = loanTransactionDTO.getFees();
+        final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
+        final BigDecimal overPaymentAmount = 
loanTransactionDTO.getOverPayment();
+        final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
+        final GLAccountBalanceHolder glAccountBalanceHolder = new 
GLAccountBalanceHolder();
+
+        if (MathUtil.isGreaterThanZero(transactionAmount)) {
+            // Resolve Credit
+            // handle principal payment
+            if (MathUtil.isGreaterThanZero(principalAmount)) {
+                GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                        AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), 
paymentTypeId);
+                glAccountBalanceHolder.addToCredit(account, principalAmount);
+            }
+            // handle interest payment
+            if (MathUtil.isGreaterThanZero(interestAmount)) {
+                GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                        AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), 
paymentTypeId);
+                glAccountBalanceHolder.addToCredit(account, interestAmount);
+            }
+            // handle fee payment
+            if (MathUtil.isGreaterThanZero(feesAmount)) {
+                GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                        AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), 
paymentTypeId);
+                glAccountBalanceHolder.addToCredit(account, feesAmount);
+            }
+            // handle penalty payment
+            if (MathUtil.isGreaterThanZero(penaltiesAmount)) {
+                GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                        
AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), paymentTypeId);
+                glAccountBalanceHolder.addToCredit(account, penaltiesAmount);
+            }
+            // handle overpayment
+            if (MathUtil.isGreaterThanZero(overPaymentAmount)) {
+                GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                        AccrualAccountsForLoan.OVERPAYMENT.getValue(), 
paymentTypeId);
+                glAccountBalanceHolder.addToCredit(account, overPaymentAmount);
+            }
+
+            // Resolve Debit
+            GLAccount accountIncomeFromCapitalization = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                    
AccrualAccountsForLoan.INCOME_FROM_CAPITALIZATION.getValue(), paymentTypeId);
+            GLAccount accountDeferredIncome = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                    
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(), paymentTypeId);
+
+            Optional<LoanTransaction> transactionOpt = 
loanTransactionRepository.findById(Long.parseLong(transactionId));
+            if (transactionOpt.isEmpty()) {
+                throw new 
PlatformDataIntegrityException("transaction.for.accounting.not.found", 
"Transaction for accounting not found");
+            }
+            Optional<LoanTransactionRelation> relationToOriginalTransactionOpt 
= transactionOpt.get().getLoanTransactionRelations().stream()//
+                    .filter(rel -> 
LoanTransactionRelationTypeEnum.REPLAYED.equals(rel.getRelationType()))//
+                    
.min(Comparator.comparing(AbstractPersistableCustom::getId));
+            if (relationToOriginalTransactionOpt.isPresent()) {
+                // Reverse-replay case
+                final LoanTransaction originalTransaction = 
relationToOriginalTransactionOpt.get().getToTransaction();
+                final List<JournalEntry> originalJournalEntries = 
this.journalEntryRepository.findJournalEntries(
+                        AccountingProcessorHelper.LOAN_TRANSACTION_IDENTIFIER 
+ originalTransaction.getId(),
+                        PortfolioProductType.LOAN.getValue());
+
+                for (JournalEntry originalJournalEntry : 
originalJournalEntries) {
+                    if (originalJournalEntry.isDebitEntry()) {
+                        if 
(accountIncomeFromCapitalization.getId().equals(originalJournalEntry.getGlAccount().getId()))
 {
+                            
glAccountBalanceHolder.addToDebit(accountIncomeFromCapitalization, 
originalJournalEntry.getAmount());
+                        } else if 
(accountDeferredIncome.getId().equals(originalJournalEntry.getGlAccount().getId()))
 {
+                            
glAccountBalanceHolder.addToDebit(accountDeferredIncome, 
originalJournalEntry.getAmount());
+                        }
+                    }
+                }
+            } else {
+                LoanCapitalizedIncomeBalance capitalizedIncomeBalance = 
loanCapitalizedIncomeBalanceRepository
+                        
.findBalanceForAdjustment(Long.parseLong(loanTransactionDTO.getTransactionId()));
+                if (MathUtil.isGreaterThan(transactionAmount, 
capitalizedIncomeBalance.getUnrecognizedAmount())) {
+                    BigDecimal amortizedAmount = 
transactionAmount.subtract(capitalizedIncomeBalance.getUnrecognizedAmount());
+
+                    
glAccountBalanceHolder.addToDebit(accountIncomeFromCapitalization, 
amortizedAmount);
+                    glAccountBalanceHolder.addToDebit(accountDeferredIncome, 
transactionAmount.subtract(amortizedAmount));
+                } else {
+                    glAccountBalanceHolder.addToDebit(accountDeferredIncome, 
transactionAmount);
+                }
+            }
+        }
+
+        // create credit entries
+        for (Map.Entry<Long, BigDecimal> creditEntry : 
glAccountBalanceHolder.getCreditBalances().entrySet()) {
+            if (MathUtil.isGreaterThanZero(creditEntry.getValue())) {
+                GLAccount glAccount = 
glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
+                this.helper.createCreditJournalEntryForLoan(office, 
currencyCode, loanId, transactionId, transactionDate,
+                        creditEntry.getValue(), glAccount);
+            }
+        }
+        // create debit entries
+        for (Map.Entry<Long, BigDecimal> debitEntry : 
glAccountBalanceHolder.getDebitBalances().entrySet()) {
+            if (MathUtil.isGreaterThanZero(debitEntry.getValue())) {
+                GLAccount glAccount = 
glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
+                this.helper.createDebitJournalEntryForLoan(office, 
currencyCode, loanId, transactionId, transactionDate,
+                        debitEntry.getValue(), glAccount);
+            }
+        }
+    }
+
     private void createJournalEntriesForCapitalizedIncomeAmortization(final 
LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
             final Office office) {
         final boolean isMarkedAsChargeOff = loanDTO.isMarkedAsChargeOff();
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
index 89a1c58983..33e9da65e2 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
@@ -700,6 +700,8 @@ public class LoanTransactionsApiResource {
         CommandWrapper commandRequest;
         if (CommandParameterUtil.is(commandParam, 
LoanApiConstants.CHARGEBACK_TRANSACTION_COMMAND)) {
             commandRequest = builder.chargebackTransaction(resolvedLoanId, 
resolvedTransactionId).build();
+        } else if (CommandParameterUtil.is(commandParam, 
LoanApiConstants.CAPITALIZED_INCOME_ADJUSTMENT_TRANSACTION_COMMAND)) {
+            commandRequest = 
builder.capitalizedIncomeAdjustment(resolvedLoanId, 
resolvedTransactionId).build();
         } else { // Default to adjust the Loan Transaction
             commandRequest = builder.adjustTransaction(resolvedLoanId, 
resolvedTransactionId).build();
         }
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 dfc38b76f7..39a37a81de 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
@@ -730,6 +730,8 @@ final class LoansApiResourceSwagger {
                 public boolean capitalizedIncome;
                 @Schema(example = "false")
                 public boolean capitalizedIncomeAmortization;
+                @Schema(example = "false")
+                public boolean capitalizedIncomeAdjustment;
             }
 
             static final class GetLoansLoanIdPaymentDetailData {
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 af37175c51..ce67fcb5da 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
@@ -197,4 +197,5 @@
     <include 
file="parts/0176_add_capitalized_income_amortization_transaction.xml" 
relativeToChangelogFile="true" />
     <include file="parts/0177_acc_journal_entry_index.xml" 
relativeToChangelogFile="true" />
     <include 
file="parts/0178_add_principal_from_capitalized_income_to_loan_summary.xml" 
relativeToChangelogFile="true" />
+    <include 
file="parts/0179_add_capitalized_income_adjustment_transaction.xml" 
relativeToChangelogFile="true" />
 </databaseChangeLog>
diff --git 
a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0179_add_capitalized_income_adjustment_transaction.xml
 
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0179_add_capitalized_income_adjustment_transaction.xml
new file mode 100644
index 0000000000..6005567757
--- /dev/null
+++ 
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0179_add_capitalized_income_adjustment_transaction.xml
@@ -0,0 +1,38 @@
+<?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.1.xsd";>
+    <changeSet id="1" author="fineract">
+        <insert tableName="m_external_event_configuration">
+            <column name="type" 
value="LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent"/>
+            <column name="enabled" valueBoolean="false"/>
+        </insert>
+        <insert tableName="r_enum_value">
+            <column name="enum_name" value="transaction_type_enum"/>
+            <column name="enum_id" valueNumeric="37"/>
+            <column name="enum_message_property" value="Capitalized Income 
Adjustment"/>
+            <column name="enum_value" value="Capitalized Income Adjustment"/>
+            <column name="enum_type" valueBoolean="false"/>
+        </insert>
+    </changeSet>
+</databaseChangeLog>
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
index 00e59f0afd..141e406ac8 100644
--- 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
@@ -106,7 +106,8 @@ public class 
ExternalEventConfigurationValidationServiceTest {
                 "LoanTransactionInterestPaymentWaiverPostBusinessEvent", 
"LoanTransactionAccrualActivityPostBusinessEvent",
                 "LoanTransactionAccrualActivityPreBusinessEvent", 
"LoanTransactionInterestRefundPostBusinessEvent",
                 "LoanTransactionInterestRefundPreBusinessEvent", 
"LoanAccrualAdjustmentTransactionBusinessEvent",
-                
"LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent");
+                
"LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent",
+                
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent");
 
         List<FineractPlatformTenant> tenants = Arrays
                 .asList(new FineractPlatformTenant(1L, "default", "Default 
Tenant", "Europe/Budapest", null));
@@ -193,7 +194,8 @@ public class 
ExternalEventConfigurationValidationServiceTest {
                 "LoanTransactionInterestPaymentWaiverPostBusinessEvent", 
"LoanTransactionAccrualActivityPostBusinessEvent",
                 "LoanTransactionAccrualActivityPreBusinessEvent", 
"LoanTransactionInterestRefundPostBusinessEvent",
                 "LoanTransactionInterestRefundPreBusinessEvent", 
"LoanAccrualAdjustmentTransactionBusinessEvent",
-                
"LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent");
+                
"LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent",
+                
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent");
 
         List<FineractPlatformTenant> tenants = Arrays
                 .asList(new FineractPlatformTenant(1L, "default", "Default 
Tenant", "Europe/Budapest", null));
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCapitalizedIncomeTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCapitalizedIncomeTest.java
index 8d96e0b5ef..7e5ad02f8a 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCapitalizedIncomeTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCapitalizedIncomeTest.java
@@ -19,12 +19,17 @@
 package org.apache.fineract.integrationtests;
 
 import java.math.BigDecimal;
+import java.util.Optional;
 import java.util.concurrent.atomic.AtomicReference;
+import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
 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.PostLoansLoanIdTransactionsResponse;
 import org.apache.fineract.integrationtests.common.BusinessStepHelper;
 import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
@@ -96,4 +101,197 @@ public class LoanCapitalizedIncomeTest extends 
BaseLoanIntegrationTest {
             );
         });
     }
+
+    @Test
+    public void testLoanCapitalizedIncomeAdjustment() {
+        final AtomicReference<Long> loanIdRef = new AtomicReference<>();
+        final AtomicReference<Long> capitalizedIncomeIdRef = new 
AtomicReference<>();
+
+        final PostClientsResponse client = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
+
+        final PostLoanProductsResponse loanProductsResponse = loanProductHelper
+                
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
+                        
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
+                        
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
+                        
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
+                        
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
+                        
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
+
+        runAt("1 April 2024", () -> {
+            Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), 
loanProductsResponse.getResourceId(), "1 January 2024",
+                    500.0, 7.0, 3, null);
+            loanIdRef.set(loanId);
+
+            disburseLoan(loanId, BigDecimal.valueOf(100), "1 January 2024");
+            PostLoansLoanIdTransactionsResponse capitalizedIncomeResponse = 
loanTransactionHelper.addCapitalizedIncome(loanId,
+                    "1 January 2024", 50.0);
+            
capitalizedIncomeIdRef.set(capitalizedIncomeResponse.getResourceId());
+
+            loanTransactionHelper.capitalizedIncomeAdjustment(loanId, 
capitalizedIncomeIdRef.get(), "1 April 2024", 50.0);
+
+            verifyTransactions(loanId, //
+                    transaction(100.0, "Disbursement", "01 January 2024"), //
+                    transaction(50.0, "Capitalized Income", "01 January 
2024"), //
+                    transaction(50.0, "Capitalized Income Adjustment", "01 
April 2024") //
+            );
+
+            verifyJournalEntries(loanId, //
+                    journalEntry(100, loansReceivableAccount, "DEBIT"), //
+                    journalEntry(100, fundSource, "CREDIT"), //
+                    journalEntry(50, loansReceivableAccount, "DEBIT"), //
+                    journalEntry(50, deferredIncomeLiabilityAccount, 
"CREDIT"), //
+                    journalEntry(50.0, deferredIncomeLiabilityAccount, 
"DEBIT"), //
+                    journalEntry(49.71, loansReceivableAccount, "CREDIT"), //
+                    journalEntry(0.29, interestReceivableAccount, "CREDIT") //
+            );
+        });
+    }
+
+    @Test
+    public void testLoanCapitalizedIncomeAdjustmentValidations() {
+        final AtomicReference<Long> loanIdRef = new AtomicReference<>();
+        final AtomicReference<Long> capitalizedIncomeIdRef = new 
AtomicReference<>();
+
+        final PostClientsResponse client = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
+
+        final PostLoanProductsResponse loanProductsResponse = loanProductHelper
+                
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
+                        
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
+                        
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
+                        
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
+                        
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
+                        
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
+
+        runAt("3 January 2024", () -> {
+            Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), 
loanProductsResponse.getResourceId(), "1 January 2024",
+                    500.0, 7.0, 3, null);
+            loanIdRef.set(loanId);
+
+            disburseLoan(loanId, BigDecimal.valueOf(100), "1 January 2024");
+            PostLoansLoanIdTransactionsResponse capitalizedIncomeResponse = 
loanTransactionHelper.addCapitalizedIncome(loanId,
+                    "3 January 2024", 50.0);
+            
capitalizedIncomeIdRef.set(capitalizedIncomeResponse.getResourceId());
+
+            // Amount more than remaining
+            Assertions.assertThrows(RuntimeException.class,
+                    () -> 
loanTransactionHelper.capitalizedIncomeAdjustment(loanId, 
capitalizedIncomeIdRef.get(), "3 January 2024", 60.0));
+
+            loanTransactionHelper.capitalizedIncomeAdjustment(loanId, 
capitalizedIncomeIdRef.get(), "3 January 2024", 30.0);
+            Assertions.assertThrows(RuntimeException.class,
+                    () -> 
loanTransactionHelper.capitalizedIncomeAdjustment(loanId, 
capitalizedIncomeIdRef.get(), "3 January 2024", 30.0));
+
+            // Capitalized income transaction with given id doesn't exist for 
this loan
+            Assertions.assertThrows(RuntimeException.class,
+                    () -> 
loanTransactionHelper.capitalizedIncomeAdjustment(loanId, 1L, "3 January 2024", 
30.0));
+
+            // Cannot be earlier than capitalized income transaction
+            Assertions.assertThrows(RuntimeException.class,
+                    () -> 
loanTransactionHelper.capitalizedIncomeAdjustment(loanId, 
capitalizedIncomeIdRef.get(), "2 January 2024", 30.0));
+        });
+    }
+
+    @Test
+    public void 
testLoanCapitalizedIncomeAdjustmentWithAmortizationAccounting() {
+        final AtomicReference<Long> loanIdRef = new AtomicReference<>();
+        final AtomicReference<Long> capitalizedIncomeIdRef = new 
AtomicReference<>();
+
+        final PostClientsResponse client = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
+
+        final PostLoanProductsResponse loanProductsResponse = loanProductHelper
+                
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
+                        
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
+                        
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
+                        
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
+                        
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
+                        
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
+
+        runAt("1 January 2024", () -> {
+            Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), 
loanProductsResponse.getResourceId(), "1 January 2024",
+                    500.0, 7.0, 3, null);
+            loanIdRef.set(loanId);
+
+            disburseLoan(loanId, BigDecimal.valueOf(100), "1 January 2024");
+            PostLoansLoanIdTransactionsResponse capitalizedIncomeResponse = 
loanTransactionHelper.addCapitalizedIncome(loanId,
+                    "1 January 2024", 100.0);
+            
capitalizedIncomeIdRef.set(capitalizedIncomeResponse.getResourceId());
+        });
+        runAt("2 January 2024", () -> {
+            Long loanId = loanIdRef.get();
+            executeInlineCOB(loanId);
+
+            verifyTransactions(loanId, //
+                    transaction(100.0, "Disbursement", "01 January 2024"), //
+                    transaction(100.0, "Capitalized Income", "01 January 
2024"), //
+                    transaction(1.10, "Capitalized Income Amortization", "01 
January 2024") //
+            );
+        });
+        runAt("3 January 2024", () -> {
+            Long loanId = loanIdRef.get();
+            executeInlineCOB(loanId);
+
+            verifyTransactions(loanId, //
+                    transaction(100.0, "Disbursement", "01 January 2024"), //
+                    transaction(100.0, "Capitalized Income", "01 January 
2024"), //
+                    transaction(1.10, "Capitalized Income Amortization", "01 
January 2024"), //
+                    transaction(0.04, "Accrual", "02 January 2024"), //
+                    transaction(1.10, "Capitalized Income Amortization", "02 
January 2024") //
+            );
+
+            verifyJournalEntries(loanId, //
+                    journalEntry(100, loansReceivableAccount, "DEBIT"), //
+                    journalEntry(100, fundSource, "CREDIT"), //
+                    journalEntry(100, loansReceivableAccount, "DEBIT"), //
+                    journalEntry(100, deferredIncomeLiabilityAccount, 
"CREDIT"), //
+                    journalEntry(1.10, deferredIncomeLiabilityAccount, 
"DEBIT"), //
+                    journalEntry(1.10, feeIncomeAccount, "CREDIT"), //
+                    journalEntry(0.04, interestReceivableAccount, "DEBIT"), //
+                    journalEntry(0.04, interestIncomeAccount, "CREDIT"), //
+                    journalEntry(1.10, deferredIncomeLiabilityAccount, 
"DEBIT"), //
+                    journalEntry(1.10, feeIncomeAccount, "CREDIT") //
+            );
+
+            loanTransactionHelper.capitalizedIncomeAdjustment(loanId, 
capitalizedIncomeIdRef.get(), "3 January 2024", 100.0);
+
+            verifyTransactions(loanId, //
+                    transaction(100.0, "Disbursement", "01 January 2024"), //
+                    transaction(100.0, "Capitalized Income", "01 January 
2024"), //
+                    transaction(1.10, "Capitalized Income Amortization", "01 
January 2024"), //
+                    transaction(0.04, "Accrual", "02 January 2024"), //
+                    transaction(1.10, "Capitalized Income Amortization", "02 
January 2024"), //
+                    transaction(100.0, "Capitalized Income Adjustment", "03 
January 2024") //
+            );
+
+            verifyJournalEntries(loanId, //
+                    journalEntry(100, loansReceivableAccount, "DEBIT"), //
+                    journalEntry(100, fundSource, "CREDIT"), //
+                    journalEntry(100, loansReceivableAccount, "DEBIT"), //
+                    journalEntry(100, deferredIncomeLiabilityAccount, 
"CREDIT"), //
+                    journalEntry(1.10, deferredIncomeLiabilityAccount, 
"DEBIT"), //
+                    journalEntry(1.10, feeIncomeAccount, "CREDIT"), //
+                    journalEntry(0.04, interestReceivableAccount, "DEBIT"), //
+                    journalEntry(0.04, interestIncomeAccount, "CREDIT"), //
+                    journalEntry(1.10, deferredIncomeLiabilityAccount, 
"DEBIT"), //
+                    journalEntry(1.10, feeIncomeAccount, "CREDIT"), //
+                    journalEntry(99.92, loansReceivableAccount, "CREDIT"), //
+                    journalEntry(0.08, interestReceivableAccount, "CREDIT"), //
+                    journalEntry(2.20, feeIncomeAccount, "DEBIT"), //
+                    journalEntry(97.80, deferredIncomeLiabilityAccount, 
"DEBIT") //
+            );
+
+            // Reverse-replay
+            addRepaymentForLoan(loanId, 67.45, "2 January 2024");
+
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanId);
+            Optional<GetLoansLoanIdTransactions> 
replayedCapitalizedIncomeAdjustmentOpt = loanDetails.getTransactions().stream()
+                    .filter(t -> 
t.getType().getCapitalizedIncomeAdjustment()).findFirst();
+            
Assertions.assertTrue(replayedCapitalizedIncomeAdjustmentOpt.isPresent(), 
"Capitalized income adjustment not found");
+
+            
verifyTRJournalEntries(replayedCapitalizedIncomeAdjustmentOpt.get().getId(), //
+                    journalEntry(99.98, loansReceivableAccount, "CREDIT"), //
+                    journalEntry(0.02, interestReceivableAccount, "CREDIT"), //
+                    journalEntry(2.20, feeIncomeAccount, "DEBIT"), //
+                    journalEntry(97.80, deferredIncomeLiabilityAccount, 
"DEBIT") //
+            );
+        });
+    }
 }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java
index 03f91075df..8682ba92ed 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java
@@ -589,6 +589,12 @@ public class ExternalEventConfigurationHelper {
         
loanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent.put("enabled", 
false);
         
defaults.add(loanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent);
 
+        Map<String, Object> 
loanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent = new 
HashMap<>();
+        
loanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent.put("type",
+                
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent");
+        
loanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent.put("enabled", 
false);
+        
defaults.add(loanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent);
+
         return defaults;
     }
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
index b66700b9d6..da5059b6c8 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
@@ -933,6 +933,36 @@ public class LoanTransactionHelper {
                 new 
InterestPauseRequestDto().startDate(startDate).endDate(endDate).dateFormat(DATE_FORMAT).locale("en")));
     }
 
+    public PostLoansLoanIdTransactionsResponse 
capitalizedIncomeAdjustment(final Long loanId, final Long 
capitalizedIncomeTransactionId,
+            final PostLoansLoanIdTransactionsTransactionIdRequest request) {
+        return 
Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.adjustLoanTransaction(loanId,
+                capitalizedIncomeTransactionId, request, 
"capitalizedIncomeAdjustment"));
+    }
+
+    public PostLoansLoanIdTransactionsResponse 
capitalizedIncomeAdjustment(final String loanExternalId, final Long 
transactionId,
+            final PostLoansLoanIdTransactionsTransactionIdRequest request) {
+        return 
Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.adjustLoanTransaction2(loanExternalId,
 transactionId,
+                request, "capitalizedIncomeAdjustment"));
+    }
+
+    public PostLoansLoanIdTransactionsResponse 
capitalizedIncomeAdjustment(final String loanExternalId, final String 
transactionExternalId,
+            final PostLoansLoanIdTransactionsTransactionIdRequest request) {
+        return 
Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.adjustLoanTransaction3(loanExternalId,
+                transactionExternalId, request, 
"capitalizedIncomeAdjustment"));
+    }
+
+    public PostLoansLoanIdTransactionsResponse 
capitalizedIncomeAdjustment(final Long loanId, final String 
transactionExternalId,
+            final PostLoansLoanIdTransactionsTransactionIdRequest request) {
+        return 
Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.adjustLoanTransaction1(loanId,
 transactionExternalId,
+                request, "capitalizedIncomeAdjustment"));
+    }
+
+    public PostLoansLoanIdTransactionsResponse 
capitalizedIncomeAdjustment(final Long loanId, final Long 
capitalizedIncomeTransactionId,
+            final String transactionDate, final double amount) {
+        return capitalizedIncomeAdjustment(loanId, 
capitalizedIncomeTransactionId, new 
PostLoansLoanIdTransactionsTransactionIdRequest()
+                
.transactionAmount(amount).transactionDate(transactionDate).dateFormat("dd MMMM 
yyyy").locale("en"));
+    }
+
     // TODO: Rewrite to use fineract-client instead!
     // Example: 
org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper.disburseLoan(java.lang.Long,
     // org.apache.fineract.client.models.PostLoansLoanIdRequest)

Reply via email to