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

arnold 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 ee72978a4 FINERACT-1840: Fee income is not realised if the loan got 
fully repaid
ee72978a4 is described below

commit ee72978a49a89f641fb5b9322485f3e06c5d1523
Author: Adam Saghy <[email protected]>
AuthorDate: Mon Feb 27 19:45:07 2023 +0100

    FINERACT-1840: Fee income is not realised if the loan got fully repaid
---
 .../portfolio/loanaccount/domain/Loan.java         | 43 ++--------
 .../domain/LoanAccountDomainService.java           |  2 +
 .../domain/LoanAccountDomainServiceJpa.java        | 92 ++++++++++++++++++++++
 .../portfolio/loanaccount/domain/LoanCharge.java   |  2 +-
 .../loanaccount/domain/LoanInstallmentCharge.java  |  2 +-
 .../LoanStatusChangePlatformServiceImpl.java       |  9 ++-
 ...AccountDelinquencyRangeEventSerializerTest.java |  2 +-
 .../ClientLoanIntegrationTest.java                 | 88 +++++++++++++++++++++
 8 files changed, 195 insertions(+), 45 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index f65136457..eca63486e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -3506,43 +3506,6 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
         updateLoanOutstandingBalances();
     }
 
-    public void applyIncomeAccrualTransaction(LocalDate closedDate) {
-        ExternalId externalId = ExternalId.empty();
-        boolean isExternalIdAutoGenerationEnabled = 
TemporaryConfigurationServiceContainer.isExternalIdAutoGenerationEnabled();
-        if (isPeriodicAccrualAccountingEnabledOnLoanProduct()
-                // to avoid collision with 
processIncomeAccrualTransactionOnLoanClosure()
-                // TODO: review after interest calculation implemented
-                && !(this.loanInterestRecalculationDetails != null
-                        && 
this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction())) {
-            List<LoanTransaction> updatedAccrualTransactions = 
retrieveListOfAccrualTransactions();
-            LocalDate lastAccruedDate = this.getDisbursementDate();
-            if (!updatedAccrualTransactions.isEmpty()) {
-                lastAccruedDate = 
updatedAccrualTransactions.get(updatedAccrualTransactions.size() - 
1).getTransactionDate();
-            }
-            HashMap<String, Object> feeDetails = new HashMap<>();
-            determineFeeDetails(lastAccruedDate, closedDate, feeDetails);
-            if (isExternalIdAutoGenerationEnabled) {
-                externalId = ExternalId.generate();
-            }
-            BigDecimal fee = (BigDecimal) feeDetails.get(FEE);
-            if (fee == null) {
-                fee = BigDecimal.ZERO;
-            }
-            BigDecimal penalty = (BigDecimal) feeDetails.get(PENALTIES);
-            if (penalty == null) {
-                penalty = BigDecimal.ZERO;
-            }
-            BigDecimal total = fee.add(penalty);
-            // TODO: calculate interest?
-            if (total.compareTo(BigDecimal.ZERO) > 0) {
-                LoanTransaction accrualTransaction = 
LoanTransaction.accrueTransaction(this, this.getOffice(), closedDate, total, 
null, fee,
-                        penalty, externalId);
-                updateLoanChargesPaidBy(accrualTransaction, feeDetails, null);
-                addLoanTransaction(accrualTransaction);
-            }
-        }
-    }
-
     private void determineCumulativeIncomeFromInstallments(HashMap<String, 
BigDecimal> cumulativeIncomeFromInstallments) {
         BigDecimal interest = BigDecimal.ZERO;
         BigDecimal fee = BigDecimal.ZERO;
@@ -5484,7 +5447,7 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
             for (LoanInstallmentCharge loanInstallmentCharge : 
loanInstallmentCharges) {
                 Integer installmentNumber = null == 
loanInstallmentCharge.getInstallment() ? null
                         : 
loanInstallmentCharge.getInstallment().getInstallmentNumber();
-                final LoanChargePaidBy loanChargePaidBy = new 
LoanChargePaidBy(accrual, loanInstallmentCharge.getLoancharge(),
+                final LoanChargePaidBy loanChargePaidBy = new 
LoanChargePaidBy(accrual, loanInstallmentCharge.getLoanCharge(),
                         
loanInstallmentCharge.getAmount(getCurrency()).getAmount(), installmentNumber);
                 accrual.getLoanChargesPaid().add(loanChargePaidBy);
             }
@@ -7060,4 +7023,8 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
     public LocalDate getChargedOffOnDate() {
         return chargedOffOnDate;
     }
+
+    public LoanInterestRecalculationDetails 
getLoanInterestRecalculationDetails() {
+        return loanInterestRecalculationDetails;
+    }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
index e10c3a841..1eb1bb464 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
@@ -98,4 +98,6 @@ public interface LoanAccountDomainService {
 
     LoanTransaction creditBalanceRefund(Loan loan, LocalDate transactionDate, 
BigDecimal transactionAmount, String noteText,
             ExternalId externalId, PaymentDetail paymentDetail);
+
+    void applyIncomeAccrualTransaction(Loan loan);
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
index c402fc1a9..8351a8070 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
@@ -25,6 +25,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -61,6 +62,7 @@ import 
org.apache.fineract.infrastructure.event.business.domain.loan.transaction
 import 
org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionRecoveryPaymentPostBusinessEvent;
 import 
org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionRecoveryPaymentPreBusinessEvent;
 import 
org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
+import org.apache.fineract.interoperation.util.MathUtil;
 import org.apache.fineract.organisation.holiday.domain.Holiday;
 import org.apache.fineract.organisation.holiday.domain.HolidayRepository;
 import org.apache.fineract.organisation.holiday.domain.HolidayStatusType;
@@ -865,4 +867,94 @@ public class LoanAccountDomainServiceJpa implements 
LoanAccountDomainService {
         }
     }
 
+    @Override
+    public void applyIncomeAccrualTransaction(Loan loan) {
+        if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()
+                // to avoid collision with 
processIncomeAccrualTransactionOnLoanClosure()
+                && !(loan.getLoanInterestRecalculationDetails() != null
+                        && 
loan.getLoanInterestRecalculationDetails().isCompoundingToBePostedAsTransaction()))
 {
+
+            MonetaryCurrency currency = loan.getCurrency();
+            Money interestPortion = Money.zero(currency);
+            Money feePortion = Money.zero(currency);
+            Money penaltyPortion = Money.zero(currency);
+
+            for (LoanRepaymentScheduleInstallment 
loanRepaymentScheduleInstallment : loan.getRepaymentScheduleInstallments()) {
+                interestPortion = 
interestPortion.add(loanRepaymentScheduleInstallment.getInterestCharged(currency))
+                        
.minus(loanRepaymentScheduleInstallment.getInterestAccrued(currency))
+                        
.minus(loanRepaymentScheduleInstallment.getInterestWaived(currency));
+                feePortion = 
feePortion.add(loanRepaymentScheduleInstallment.getFeeChargesCharged(currency))
+                        
.minus(loanRepaymentScheduleInstallment.getFeeAccrued(currency))
+                        
.minus(loanRepaymentScheduleInstallment.getFeeChargesWaived(currency));
+                penaltyPortion = 
penaltyPortion.add(loanRepaymentScheduleInstallment.getPenaltyChargesCharged(currency))
+                        
.minus(loanRepaymentScheduleInstallment.getPenaltyAccrued(currency))
+                        
.minus(loanRepaymentScheduleInstallment.getPenaltyChargesWaived(currency));
+            }
+            Money total = 
interestPortion.plus(feePortion).plus(penaltyPortion);
+
+            if (total.isGreaterThanZero()) {
+                ExternalId externalId = externalIdFactory.create();
+
+                LoanTransaction accrualTransaction = 
LoanTransaction.accrueTransaction(loan, loan.getOffice(), 
loan.getClosedOnDate(),
+                        total.getAmount(), interestPortion.getAmount(), 
feePortion.getAmount(), penaltyPortion.getAmount(), externalId);
+
+                Set<LoanChargePaidBy> accrualCharges = 
accrualTransaction.getLoanChargesPaid();
+
+                Map<Long, Money> accrualDetails = 
loan.getActiveCharges().stream()
+                        .collect(Collectors.toMap(LoanCharge::getId, v -> 
Money.zero(currency)));
+
+                
loan.getLoanTransactions(LoanTransaction::isAccrual).forEach(transaction -> {
+                    transaction.getLoanChargesPaid().forEach(loanChargePaid -> 
{
+                        
accrualDetails.computeIfPresent(loanChargePaid.getLoanCharge().getId(),
+                                (mappedKey, mappedValue) -> 
mappedValue.add(Money.of(currency, loanChargePaid.getAmount())));
+                    });
+                });
+
+                loan.getActiveCharges().forEach(loanCharge -> {
+                    Money amount = 
loanCharge.getAmount(currency).minus(loanCharge.getAmountWaived(currency));
+                    if (!loanCharge.isInstalmentFee() && loanCharge.isActive()
+                            && 
accrualDetails.get(loanCharge.getId()).isLessThan(amount)) {
+                        Money amountToBeAccrued = 
amount.minus(accrualDetails.get(loanCharge.getId()));
+                        final LoanChargePaidBy loanChargePaidBy = new 
LoanChargePaidBy(accrualTransaction, loanCharge,
+                                amountToBeAccrued.getAmount(), null);
+                        accrualCharges.add(loanChargePaidBy);
+                    }
+                });
+
+                for (LoanRepaymentScheduleInstallment 
loanRepaymentScheduleInstallment : loan.getRepaymentScheduleInstallments()) {
+                    for (LoanInstallmentCharge installmentCharge : 
loanRepaymentScheduleInstallment.getInstallmentCharges()) {
+                        if (installmentCharge.getLoanCharge().isActive()) {
+                            Money notWaivedAmount = 
installmentCharge.getAmount(currency)
+                                    
.minus(installmentCharge.getAmountWaived(currency));
+                            if (notWaivedAmount.isGreaterThanZero()) {
+                                Money amountToBeAccrued = notWaivedAmount
+                                        
.minus(accrualDetails.get(installmentCharge.getLoanCharge().getId()));
+                                if (amountToBeAccrued.isGreaterThanZero()) {
+                                    final LoanChargePaidBy loanChargePaidBy = 
new LoanChargePaidBy(accrualTransaction,
+                                            installmentCharge.getLoanCharge(), 
amountToBeAccrued.getAmount(),
+                                            
installmentCharge.getInstallment().getInstallmentNumber());
+                                    accrualCharges.add(loanChargePaidBy);
+                                    
accrualDetails.computeIfPresent(installmentCharge.getLoanCharge().getId(),
+                                            (mappedKey, mappedValue) -> 
mappedValue.add(amountToBeAccrued));
+                                }
+                                
accrualDetails.computeIfPresent(installmentCharge.getLoanCharge().getId(),
+                                        (mappedKey, mappedValue) -> MathUtil
+                                                
.negativeToZero(mappedValue.minus(Money.of(currency, 
installmentCharge.getAmount()))));
+                            }
+                        }
+                    }
+                }
+                
saveLoanTransactionWithDataIntegrityViolationChecks(accrualTransaction);
+                loan.addLoanTransaction(accrualTransaction);
+
+                loan.getRepaymentScheduleInstallments().forEach(installment -> 
{
+                    installment.updateAccrualPortion(
+                            
installment.getInterestCharged(currency).minus(installment.getInterestWaived(currency)),
+                            
installment.getFeeChargesCharged(currency).minus(installment.getFeeChargesWaived(currency)),
+                            
installment.getPenaltyChargesCharged(currency).minus(installment.getPenaltyChargesWaived(currency)));
+                });
+            }
+        }
+    }
+
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
index 3ab6dbb79..601c0bacd 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
@@ -140,7 +140,7 @@ public class LoanCharge extends AbstractPersistableCustom {
     private LoanTrancheDisbursementCharge loanTrancheDisbursementCharge;
 
     @OneToMany(mappedBy = "loanCharge", cascade = CascadeType.ALL, 
orphanRemoval = true, fetch = FetchType.EAGER)
-    private Set<LoanChargePaidBy> loanChargePaidBySet;
+    private Set<LoanChargePaidBy> loanChargePaidBySet = new HashSet<>();
 
     protected LoanCharge() {
         //
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInstallmentCharge.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInstallmentCharge.java
index ca1190b6e..e40d98247 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInstallmentCharge.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInstallmentCharge.java
@@ -312,7 +312,7 @@ public class LoanInstallmentCharge extends 
AbstractPersistableCustom implements
         return amountToDeductOnThisCharge;
     }
 
-    public LoanCharge getLoancharge() {
+    public LoanCharge getLoanCharge() {
         return this.loancharge;
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanStatusChangePlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanStatusChangePlatformServiceImpl.java
index d34c98f8b..4f3dab667 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanStatusChangePlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanStatusChangePlatformServiceImpl.java
@@ -25,6 +25,7 @@ import 
org.apache.fineract.infrastructure.event.business.BusinessEventListener;
 import 
org.apache.fineract.infrastructure.event.business.domain.loan.LoanStatusChangedBusinessEvent;
 import 
org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainServiceJpa;
 import org.springframework.stereotype.Service;
 
 @Slf4j
@@ -33,22 +34,22 @@ import org.springframework.stereotype.Service;
 public class LoanStatusChangePlatformServiceImpl implements 
LoanStatusChangePlatformService {
 
     private final BusinessEventNotifierService businessEventNotifierService;
+    private final LoanAccountDomainServiceJpa loanAccountDomainService;
 
     @PostConstruct
     public void addListeners() {
         
businessEventNotifierService.addPostBusinessEventListener(LoanStatusChangedBusinessEvent.class,
 new LoanStatusChangedListener());
     }
 
-    private static class LoanStatusChangedListener implements 
BusinessEventListener<LoanStatusChangedBusinessEvent> {
+    private class LoanStatusChangedListener implements 
BusinessEventListener<LoanStatusChangedBusinessEvent> {
 
         @Override
         public void onBusinessEvent(LoanStatusChangedBusinessEvent event) {
             final Loan loan = event.get();
             log.debug("Loan Status change for loan {}", loan.getId());
-            // Apply common actions on Loan account closed
-            if (loan.isClosed()) {
+            if (loan.getStatus().isClosedObligationsMet()) {
                 log.debug("Loan Status {} for loan {}", 
loan.getStatus().getCode(), loan.getId());
-                loan.applyIncomeAccrualTransaction(loan.getClosedOnDate());
+                loanAccountDomainService.applyIncomeAccrualTransaction(loan);
             }
             if (loan.isOpen()) {
                 loan.handleMaturityDateActivate();
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
index c92d22c4b..22995aaa7 100644
--- 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
@@ -133,7 +133,7 @@ public class LoanAccountDelinquencyRangeEventSerializerTest 
{
                 BigDecimal.valueOf(30), BigDecimal.valueOf(50), 
BigDecimal.valueOf(185), new BigDecimal("100.5"), new BigDecimal("200.3")));
         
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
         
when(loanChargeReadPlatformService.retrieveLoanCharges(anyLong())).thenAnswer(a 
-> repaymentScheduleInstallments.get(0)
-                .getInstallmentCharges().stream().map(c -> 
c.getLoancharge().toData()).collect(Collectors.toList()));
+                .getInstallmentCharges().stream().map(c -> 
c.getLoanCharge().toData()).collect(Collectors.toList()));
 
         moneyHelper.when(() -> 
MoneyHelper.getRoundingMode()).thenReturn(RoundingMode.UP);
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
index 64cf20c4a..b410ca345 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
@@ -7669,6 +7669,94 @@ public class ClientLoanIntegrationTest {
         }
     }
 
+    @Test
+    public void accrualIsCalculatedWhenTheLoanIsClosed() {
+        try {
+            
GlobalConfigurationHelper.updateIsAutomaticExternalIdGenerationEnabled(this.requestSpec,
 this.responseSpec, true);
+            
GlobalConfigurationHelper.updateIsBusinessDateEnabled(this.requestSpec, 
this.responseSpec, true);
+            businessDateHelper.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("2022.10.10").dateFormat("yyyy.MM.dd").locale("en"));
+
+            final Account assetAccount = 
this.accountHelper.createAssetAccount();
+            final Account incomeAccount = 
this.accountHelper.createIncomeAccount();
+            final Account expenseAccount = 
this.accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = 
this.accountHelper.createLiabilityAccount();
+
+            final Integer loanProductID = 
createLoanProductWithPeriodicAccrualAccountingNoInterest(assetAccount, 
incomeAccount,
+                    expenseAccount, overpaymentAccount);
+
+            final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, "01 January 2011");
+            List<HashMap> charges = new ArrayList<>();
+            Integer installmentFee = ChargesHelper.createCharges(requestSpec, 
responseSpec,
+                    
ChargesHelper.getLoanInstallmentJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "10", false));
+            addCharges(charges, installmentFee, "10", null);
+
+            final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, charges);
+
+            HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
+            LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
+
+            loanStatusHashMap = this.loanTransactionHelper.approveLoan("02 
September 2022", loanID);
+            LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
+            
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
+
+            loanStatusHashMap = 
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("03 September 
2022", loanID, "1000");
+            LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
+
+            this.loanTransactionHelper.makeRepayment("04 September 2022", 
Float.parseFloat("5"), loanID);
+
+            
this.periodicAccrualAccountingHelper.runPeriodicAccrualAccounting("04 September 
2022");
+
+            Integer penalty = ChargesHelper.createCharges(requestSpec, 
responseSpec,
+                    
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "11", true));
+            LocalDate targetDate = LocalDate.of(2022, 9, 6);
+            final String penaltyCharge1AddedDate = 
dateFormatter.format(targetDate);
+
+            Integer penalty1LoanChargeId = 
this.loanTransactionHelper.addChargesForLoan(loanID,
+                    
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty),
 penaltyCharge1AddedDate, "11"));
+
+            this.loanTransactionHelper.waiveLoanCharge((long) loanID, (long) 
penalty1LoanChargeId,
+                    new PostLoansLoanIdChargesChargeIdRequest());
+
+            this.loanTransactionHelper.makeRepayment("08 September 2022", 
Float.parseFloat("1010"), loanID);
+
+            GetLoansLoanIdResponse loanDetails = 
this.loanTransactionHelper.getLoanDetails((long) loanID);
+
+            GetLoansLoanIdTransactions lastAccrualTransaction = 
loanDetails.getTransactions().stream()
+                    .filter(t -> 
Boolean.TRUE.equals(t.getType().getAccrual())).findFirst().get();
+            assertEquals(15, lastAccrualTransaction.getAmount());
+            assertEquals(5, lastAccrualTransaction.getPenaltyChargesPortion());
+            assertEquals(10, lastAccrualTransaction.getFeeChargesPortion());
+
+            GetLoansLoanIdTransactionsTransactionIdResponse 
accrualTransactionDetails = this.loanTransactionHelper
+                    .getLoanTransactionDetails((long) loanID, 
lastAccrualTransaction.getId());
+
+            assertEquals(2, 
accrualTransactionDetails.getLoanChargePaidByList().size());
+            
accrualTransactionDetails.getLoanChargePaidByList().forEach(loanCharge -> {
+                if (loanCharge.getChargeId().equals((long) 
penalty1LoanChargeId)) {
+                    assertEquals(5, loanCharge.getAmount());
+                } else {
+                    assertEquals(10, loanCharge.getAmount());
+                }
+            });
+
+        } finally {
+            
GlobalConfigurationHelper.updateIsAutomaticExternalIdGenerationEnabled(this.requestSpec,
 this.responseSpec, false);
+            
GlobalConfigurationHelper.updateIsBusinessDateEnabled(this.requestSpec, 
this.responseSpec, false);
+        }
+    }
+
+    private Integer applyForLoanApplication(final Integer clientID, final 
Integer loanProductID, final List<HashMap> charges) {
+        LOG.info("--------------------------------APPLYING FOR LOAN 
APPLICATION--------------------------------");
+        final String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1")
+                
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1")
+                
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance()
+                
.withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod()
+                .withCharges(charges).withExpectedDisbursementDate("03 
September 2022").withSubmittedOnDate("01 September 2022")
+                .withLoanType("individual").build(clientID.toString(), 
loanProductID.toString(), null);
+        return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
+    }
+
     private Integer applyForLoanApplication(final Integer clientID, final 
Integer loanProductID) {
         LOG.info("--------------------------------APPLYING FOR LOAN 
APPLICATION--------------------------------");
         final String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1")

Reply via email to