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 950f6489f FINERACT-1678: Performance improvement of Apply Charge to 
Overdue Loans COB Business Step
950f6489f is described below

commit 950f6489fe47fb96fdd849417d482e3ac30cd6e8
Author: Adam Saghy <[email protected]>
AuthorDate: Fri Aug 26 13:23:28 2022 +0200

    FINERACT-1678: Performance improvement of Apply Charge to Overdue Loans COB 
Business Step
---
 .../service/AccountingProcessorHelper.java         |  17 +--
 .../ApplyChargeToOverdueLoansBusinessStep.java     |  24 +--
 .../portfolio/loanaccount/domain/Loan.java         |  17 +--
 .../domain/LoanAccountDomainServiceJpa.java        |  21 ++-
 .../domain/LoanOverdueInstallmentCharge.java       |   7 +-
 .../loanaccount/domain/LoanTransaction.java        |   4 +-
 ...nRescheduleRequestWritePlatformServiceImpl.java |  10 +-
 .../LoanAccrualWritePlatformServiceImpl.java       |  12 +-
 .../service/LoanChargeReadPlatformService.java     |   4 +-
 .../service/LoanChargeReadPlatformServiceImpl.java |  23 +--
 .../service/LoanReadPlatformService.java           |   3 +
 .../service/LoanReadPlatformServiceImpl.java       |  53 ++++++-
 .../LoanWritePlatformServiceJpaRepositoryImpl.java | 167 +++++++++------------
 .../domain/DepositAccountDomainServiceJpa.java     |   6 +-
 .../portfolio/savings/domain/SavingsAccount.java   |   9 +-
 .../domain/SavingsAccountDomainServiceJpa.java     |   7 +-
 .../savings/domain/SavingsAccountTransaction.java  |   7 +-
 ...countWritePlatformServiceJpaRepositoryImpl.java |   6 +-
 ...countWritePlatformServiceJpaRepositoryImpl.java |   6 +-
 ...countWritePlatformServiceJpaRepositoryImpl.java |   9 +-
 .../ClientLoanIntegrationTest.java                 |   2 +-
 .../integrationtests/SchedulerJobsTestResults.java |  82 ++++++++--
 .../common/charges/ChargesHelper.java              |   2 +-
 23 files changed, 260 insertions(+), 238 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
index c7a6a8966..f33fb53b6 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
@@ -59,7 +59,6 @@ import 
org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGL
 import 
org.apache.fineract.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
 import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
-import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.organisation.office.domain.Office;
 import org.apache.fineract.organisation.office.domain.OfficeRepository;
 import org.apache.fineract.portfolio.account.PortfolioAccountType;
@@ -105,7 +104,7 @@ public class AccountingProcessorHelper {
         final Long loanId = (Long) accountingBridgeData.get("loanId");
         final Long loanProductId = (Long) 
accountingBridgeData.get("loanProductId");
         final Long officeId = (Long) accountingBridgeData.get("officeId");
-        final CurrencyData currencyData = (CurrencyData) 
accountingBridgeData.get("currency");
+        final String currencyCode = (String) 
accountingBridgeData.get("currencyCode");
         final List<LoanTransactionDTO> newLoanTransactions = new ArrayList<>();
         boolean isAccountTransfer = (Boolean) 
accountingBridgeData.get("isAccountTransfer");
 
@@ -160,8 +159,8 @@ public class AccountingProcessorHelper {
 
         }
 
-        return new LoanDTO(loanId, loanProductId, officeId, 
currencyData.code(), cashBasedAccountingEnabled,
-                upfrontAccrualBasedAccountingEnabled, 
periodicAccrualBasedAccountingEnabled, newLoanTransactions);
+        return new LoanDTO(loanId, loanProductId, officeId, currencyCode, 
cashBasedAccountingEnabled, upfrontAccrualBasedAccountingEnabled,
+                periodicAccrualBasedAccountingEnabled, newLoanTransactions);
     }
 
     public SavingsDTO populateSavingsDtoFromMap(final Map<String, Object> 
accountingBridgeData, final boolean cashBasedAccountingEnabled,
@@ -169,7 +168,7 @@ public class AccountingProcessorHelper {
         final Long loanId = (Long) accountingBridgeData.get("savingsId");
         final Long loanProductId = (Long) 
accountingBridgeData.get("savingsProductId");
         final Long officeId = (Long) accountingBridgeData.get("officeId");
-        final CurrencyData currencyData = (CurrencyData) 
accountingBridgeData.get("currency");
+        final String currencyCode = (String) 
accountingBridgeData.get("currencyCode");
         final List<SavingsTransactionDTO> newSavingsTransactions = new 
ArrayList<>();
         boolean isAccountTransfer = (Boolean) 
accountingBridgeData.get("isAccountTransfer");
 
@@ -230,8 +229,8 @@ public class AccountingProcessorHelper {
 
         }
 
-        return new SavingsDTO(loanId, loanProductId, officeId, 
currencyData.code(), cashBasedAccountingEnabled,
-                accrualBasedAccountingEnabled, newSavingsTransactions);
+        return new SavingsDTO(loanId, loanProductId, officeId, currencyCode, 
cashBasedAccountingEnabled, accrualBasedAccountingEnabled,
+                newSavingsTransactions);
     }
 
     public SharesDTO populateSharesDtoFromMap(final Map<String, Object> 
accountingBridgeData, final boolean cashBasedAccountingEnabled,
@@ -239,7 +238,7 @@ public class AccountingProcessorHelper {
         final Long shareAccountId = (Long) 
accountingBridgeData.get("shareAccountId");
         final Long shareProductId = (Long) 
accountingBridgeData.get("shareProductId");
         final Long officeId = (Long) accountingBridgeData.get("officeId");
-        final CurrencyData currencyData = (CurrencyData) 
accountingBridgeData.get("currency");
+        final String currencyCode = (String) 
accountingBridgeData.get("currencyCode");
         final List<SharesTransactionDTO> newTransactions = new ArrayList<>();
 
         @SuppressWarnings("unchecked")
@@ -275,7 +274,7 @@ public class AccountingProcessorHelper {
 
         }
 
-        return new SharesDTO(shareAccountId, shareProductId, officeId, 
currencyData.code(), cashBasedAccountingEnabled,
+        return new SharesDTO(shareAccountId, shareProductId, officeId, 
currencyCode, cashBasedAccountingEnabled,
                 accrualBasedAccountingEnabled, newTransactions);
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyChargeToOverdueLoansBusinessStep.java
 
b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyChargeToOverdueLoansBusinessStep.java
index 6fed9e74e..42ac49451 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyChargeToOverdueLoansBusinessStep.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyChargeToOverdueLoansBusinessStep.java
@@ -19,11 +19,7 @@
 package org.apache.fineract.cob.loan;
 
 import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
-import 
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
 import 
org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
@@ -34,24 +30,16 @@ import org.springframework.stereotype.Component;
 @RequiredArgsConstructor
 public class ApplyChargeToOverdueLoansBusinessStep implements 
LoanCOBBusinessStep {
 
-    private final ConfigurationDomainService configurationDomainService;
     private final LoanReadPlatformService loanReadPlatformService;
     private final LoanWritePlatformService loanWritePlatformService;
 
     @Override
-    public Loan execute(Loan input) {
-        final Long penaltyWaitPeriodValue = 
configurationDomainService.retrievePenaltyWaitPeriod();
-        final Boolean backdatePenalties = 
configurationDomainService.isBackdatePenaltiesEnabled();
-        final Collection<OverdueLoanScheduleData> 
overdueLoanScheduledInstallments = loanReadPlatformService
-                
.retrieveAllLoansWithOverdueInstallments(penaltyWaitPeriodValue, 
backdatePenalties);
-        // TODO: this is very much not effective to get all overdue 
installments for each loan, a new method needs to be
-        // implemented for it
-        Map<Long, List<OverdueLoanScheduleData>> groupedOverdueData = 
overdueLoanScheduledInstallments.stream()
-                
.collect(Collectors.groupingBy(OverdueLoanScheduleData::getLoanId));
-        for (Long loanId : groupedOverdueData.keySet()) {
-            loanWritePlatformService.applyOverdueChargesForLoan(input.getId(), 
groupedOverdueData.get(loanId));
-        }
-        return input;
+    public Loan execute(Loan loan) {
+        final Collection<OverdueLoanScheduleData> overdueLoanScheduleDataList 
= loanReadPlatformService
+                .retrieveAllOverdueInstallmentsForLoan(loan);
+
+        loanWritePlatformService.applyOverdueChargesForLoan(loan.getId(), 
overdueLoanScheduleDataList);
+        return loan;
     }
 
     @Override
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 974894682..3a2c045bd 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
@@ -71,7 +71,6 @@ import 
org.apache.fineract.infrastructure.core.service.DateUtils;
 import 
org.apache.fineract.infrastructure.security.service.RandomPasswordGenerator;
 import org.apache.fineract.organisation.holiday.domain.Holiday;
 import org.apache.fineract.organisation.holiday.service.HolidayUtil;
-import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
@@ -2394,8 +2393,8 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
         return actualChanges;
     }
 
-    public Collection<Long> findExistingTransactionIds() {
-        final Collection<Long> ids = new ArrayList<>();
+    public List<Long> findExistingTransactionIds() {
+        final List<Long> ids = new ArrayList<>();
         List<LoanTransaction> transactions = getLoanTransactions();
         for (final LoanTransaction transaction : transactions) {
             ids.add(transaction.getId());
@@ -2404,9 +2403,9 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
         return ids;
     }
 
-    public Collection<Long> findExistingReversedTransactionIds() {
+    public List<Long> findExistingReversedTransactionIds() {
 
-        final Collection<Long> ids = new ArrayList<>();
+        final List<Long> ids = new ArrayList<>();
         List<LoanTransaction> transactions = getLoanTransactions();
         for (final LoanTransaction transaction : transactions) {
             if (transaction.isReversed()) {
@@ -4411,14 +4410,14 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
         return this.proposedPrincipal;
     }
 
-    public Map<String, Object> deriveAccountingBridgeData(final CurrencyData 
currencyData, final List<Long> existingTransactionIds,
+    public Map<String, Object> deriveAccountingBridgeData(final String 
currencyCode, final List<Long> existingTransactionIds,
             final List<Long> existingReversedTransactionIds, boolean 
isAccountTransfer) {
 
         final Map<String, Object> accountingBridgeData = new LinkedHashMap<>();
         accountingBridgeData.put("loanId", getId());
         accountingBridgeData.put("loanProductId", productId());
         accountingBridgeData.put("officeId", getOfficeId());
-        accountingBridgeData.put("currency", currencyData);
+        accountingBridgeData.put("currencyCode", currencyCode);
         accountingBridgeData.put("calculatedInterest", 
this.summary.getTotalInterestCharged());
         accountingBridgeData.put("cashBasedAccountingEnabled", 
isCashBasedAccountingEnabledOnLoanProduct());
         accountingBridgeData.put("upfrontAccrualBasedAccountingEnabled", 
isUpfrontAccrualAccountingEnabledOnLoanProduct());
@@ -4429,9 +4428,9 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
         for (final LoanTransaction transaction : this.loanTransactions) {
             if (transaction.isReversed() && 
existingTransactionIds.contains(transaction.getId())
                     && 
!existingReversedTransactionIds.contains(transaction.getId())) {
-                newLoanTransactions.add(transaction.toMapData(currencyData));
+                newLoanTransactions.add(transaction.toMapData(currencyCode));
             } else if (!existingTransactionIds.contains(transaction.getId())) {
-                newLoanTransactions.add(transaction.toMapData(currencyData));
+                newLoanTransactions.add(transaction.toMapData(currencyCode));
             }
         }
 
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 cbc1ba16b..01ce781df 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
@@ -111,7 +111,6 @@ public class LoanAccountDomainServiceJpa implements 
LoanAccountDomainService {
     private final HolidayRepository holidayRepository;
     private final WorkingDaysRepositoryWrapper workingDaysRepository;
 
-    private final ApplicationCurrencyRepositoryWrapper 
applicationCurrencyRepositoryWrapper;
     private final JournalEntryWritePlatformService 
journalEntryWritePlatformService;
     private final NoteRepository noteRepository;
     private final AccountTransferRepository accountTransferRepository;
@@ -417,10 +416,9 @@ public class LoanAccountDomainServiceJpa implements 
LoanAccountDomainService {
             final List<Long> existingReversedTransactionIds, boolean 
isAccountTransfer, boolean isLoanToLoanTransfer) {
 
         final MonetaryCurrency currency = loanAccount.getCurrency();
-        final ApplicationCurrency applicationCurrency = 
this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
 
-        final Map<String, Object> accountingBridgeData = 
loanAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
-                existingTransactionIds, existingReversedTransactionIds, 
isAccountTransfer);
+        final Map<String, Object> accountingBridgeData = 
loanAccount.deriveAccountingBridgeData(currency.getCode(), 
existingTransactionIds,
+                existingReversedTransactionIds, isAccountTransfer);
         accountingBridgeData.put("isLoanToLoanTransfer", isLoanToLoanTransfer);
         
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
     }
@@ -535,14 +533,13 @@ public class LoanAccountDomainServiceJpa implements 
LoanAccountDomainService {
      */
     @Override
     public void recalculateAccruals(Loan loan) {
-        boolean isInterestCalcualtionHappened = 
loan.repaymentScheduleDetail().isInterestRecalculationEnabled();
-        recalculateAccruals(loan, isInterestCalcualtionHappened);
+        recalculateAccruals(loan, 
loan.repaymentScheduleDetail().isInterestRecalculationEnabled());
     }
 
     @Override
-    public void recalculateAccruals(Loan loan, boolean 
isInterestCalcualtionHappened) {
+    public void recalculateAccruals(Loan loan, boolean 
isInterestCalculationHappened) {
         LocalDate accruedTill = loan.getAccruedTill();
-        if (!loan.isPeriodicAccrualAccountingEnabledOnLoanProduct() || 
!isInterestCalcualtionHappened || accruedTill == null || loan.isNpa()
+        if (!loan.isPeriodicAccrualAccountingEnabledOnLoanProduct() || 
!isInterestCalculationHappened || accruedTill == null || loan.isNpa()
                 || !loan.status().isActive()) {
             return;
         }
@@ -552,7 +549,7 @@ public class LoanAccountDomainServiceJpa implements 
LoanAccountDomainService {
         if (isOrganisationDateEnabled) {
             organisationStartDate = 
this.configurationDomainService.retrieveOrganisationStartDate();
         }
-        Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = new 
ArrayList<>();
+        Collection<LoanScheduleAccrualData> loanScheduleAccrualList = new 
ArrayList<>();
         List<LoanRepaymentScheduleInstallment> installments = 
loan.getRepaymentScheduleInstallments();
         Long loanId = loan.getId();
         Long officeId = loan.getOfficeId();
@@ -571,15 +568,15 @@ public class LoanAccountDomainServiceJpa implements 
LoanAccountDomainService {
                 accruedTill = DateUtils.getBusinessLocalDate();
             }
             if (!isOrganisationDateEnabled || 
organisationStartDate.isBefore(installment.getDueDate())) {
-                generateLoanScheduleAccrualData(accruedTill, 
loanScheduleAccrualDatas, loanId, officeId, accrualStartDate,
+                generateLoanScheduleAccrualData(accruedTill, 
loanScheduleAccrualList, loanId, officeId, accrualStartDate,
                         repaymentFrequency, repayEvery, 
interestCalculatedFrom, loanProductId, currency, currencyData, loanCharges,
                         installment);
             }
         }
 
-        if (!loanScheduleAccrualDatas.isEmpty()) {
+        if (!loanScheduleAccrualList.isEmpty()) {
             try {
-                
this.loanAccrualPlatformService.addPeriodicAccruals(accruedTill, 
loanScheduleAccrualDatas);
+                
this.loanAccrualPlatformService.addPeriodicAccruals(accruedTill, 
loanScheduleAccrualList);
             } catch (MultiException e) {
                 String globalisationMessageCode = 
"error.msg.accrual.exception";
                 throw new 
GeneralPlatformDomainRuleException(globalisationMessageCode, e.getMessage(), e);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java
index bbfe1f231..29206fd5d 100755
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanOverdueInstallmentCharge.java
@@ -23,9 +23,11 @@ import javax.persistence.Entity;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.Table;
+import lombok.Getter;
 import 
org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
 
 @Entity
+@Getter
 @Table(name = "m_loan_overdue_installment_charge")
 public class LoanOverdueInstallmentCharge extends AbstractPersistableCustom {
 
@@ -54,9 +56,4 @@ public class LoanOverdueInstallmentCharge extends 
AbstractPersistableCustom {
     public void 
updateLoanRepaymentScheduleInstallment(LoanRepaymentScheduleInstallment 
loanRepaymentScheduleInstallment) {
         this.installment = loanRepaymentScheduleInstallment;
     }
-
-    public LoanRepaymentScheduleInstallment getInstallment() {
-        return this.installment;
-    }
-
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index 60e83ac2a..a4d5d3e00 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -656,7 +656,7 @@ public class LoanTransaction extends 
AbstractAuditableWithUTCDateTimeCustom {
                 transfer, null, outstandingLoanBalance, 
this.unrecognizedIncomePortion, this.manuallyAdjustedOrReversed);
     }
 
-    public Map<String, Object> toMapData(final CurrencyData currencyData) {
+    public Map<String, Object> toMapData(final String currencyCode) {
         final Map<String, Object> thisTransactionData = new LinkedHashMap<>();
 
         final LoanTransactionEnumData transactionType = 
LoanEnumerations.transactionType(this.typeOf);
@@ -666,7 +666,7 @@ public class LoanTransaction extends 
AbstractAuditableWithUTCDateTimeCustom {
         thisTransactionData.put("type", transactionType);
         thisTransactionData.put("reversed", Boolean.valueOf(isReversed()));
         thisTransactionData.put("date", getTransactionDate());
-        thisTransactionData.put("currency", currencyData);
+        thisTransactionData.put("currencyCode", currencyCode);
         thisTransactionData.put("amount", this.amount);
         thisTransactionData.put("netDisbursalAmount", 
this.loan.getNetDisbursalAmount());
         thisTransactionData.put("principalPortion", this.principalPortion);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
index 70dbc7452..78361571d 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
@@ -42,8 +42,6 @@ import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
 import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import 
org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import 
org.apache.fineract.portfolio.account.service.AccountTransfersWritePlatformService;
@@ -99,7 +97,6 @@ public class LoanRescheduleRequestWritePlatformServiceImpl 
implements LoanResche
     private final PlatformSecurityContext platformSecurityContext;
     private final LoanRescheduleRequestDataValidator 
loanRescheduleRequestDataValidator;
     private final LoanRescheduleRequestRepository 
loanRescheduleRequestRepository;
-    private final ApplicationCurrencyRepositoryWrapper 
applicationCurrencyRepository;
     private final LoanRepaymentScheduleHistoryRepository 
loanRepaymentScheduleHistoryRepository;
     private final LoanScheduleHistoryWritePlatformService 
loanScheduleHistoryWritePlatformService;
     private final LoanTransactionRepository loanTransactionRepository;
@@ -125,7 +122,6 @@ public class LoanRescheduleRequestWritePlatformServiceImpl 
implements LoanResche
             final PlatformSecurityContext platformSecurityContext,
             final LoanRescheduleRequestDataValidator 
loanRescheduleRequestDataValidator,
             final LoanRescheduleRequestRepository 
loanRescheduleRequestRepository,
-            final ApplicationCurrencyRepositoryWrapper 
applicationCurrencyRepository,
             final LoanRepaymentScheduleHistoryRepository 
loanRepaymentScheduleHistoryRepository,
             final LoanScheduleHistoryWritePlatformService 
loanScheduleHistoryWritePlatformService,
             final LoanTransactionRepository loanTransactionRepository,
@@ -140,7 +136,6 @@ public class LoanRescheduleRequestWritePlatformServiceImpl 
implements LoanResche
         this.platformSecurityContext = platformSecurityContext;
         this.loanRescheduleRequestDataValidator = 
loanRescheduleRequestDataValidator;
         this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
-        this.applicationCurrencyRepository = applicationCurrencyRepository;
         this.loanRepaymentScheduleHistoryRepository = 
loanRepaymentScheduleHistoryRepository;
         this.loanScheduleHistoryWritePlatformService = 
loanScheduleHistoryWritePlatformService;
         this.loanTransactionRepository = loanTransactionRepository;
@@ -538,10 +533,9 @@ public class LoanRescheduleRequestWritePlatformServiceImpl 
implements LoanResche
 
     private void postJournalEntries(Loan loan, List<Long> 
existingTransactionIds, List<Long> existingReversedTransactionIds) {
         final MonetaryCurrency currency = loan.getCurrency();
-        final ApplicationCurrency applicationCurrency = 
this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
         boolean isAccountTransfer = false;
-        final Map<String, Object> accountingBridgeData = 
loan.deriveAccountingBridgeData(applicationCurrency.toData(),
-                existingTransactionIds, existingReversedTransactionIds, 
isAccountTransfer);
+        final Map<String, Object> accountingBridgeData = 
loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
+                existingReversedTransactionIds, isAccountTransfer);
         
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
index 2f21fffdc..e6bc7002f 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
@@ -33,8 +33,6 @@ import 
org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlat
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import 
org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import 
org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
@@ -49,7 +47,6 @@ import 
org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
 import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
 import org.apache.fineract.useradministration.domain.AppUser;
-import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
 import org.springframework.dao.DataAccessException;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
@@ -64,10 +61,8 @@ public class LoanAccrualWritePlatformServiceImpl implements 
LoanAccrualWritePlat
     private final JdbcTemplate jdbcTemplate;
     private final DatabaseSpecificSQLGenerator sqlGenerator;
     private final JournalEntryWritePlatformService 
journalEntryWritePlatformService;
-    private final AppUserRepositoryWrapper userRepository;
     private final PlatformSecurityContext context;
     private final LoanRepositoryWrapper loanRepositoryWrapper;
-    private final ApplicationCurrencyRepositoryWrapper 
applicationCurrencyRepository;
 
     @Override
     @Transactional
@@ -289,7 +284,7 @@ public class LoanAccrualWritePlatformServiceImpl implements 
LoanAccrualWritePlat
         accountingBridgeData.put("loanId", 
loanScheduleAccrualData.getLoanId());
         accountingBridgeData.put("loanProductId", 
loanScheduleAccrualData.getLoanProductId());
         accountingBridgeData.put("officeId", 
loanScheduleAccrualData.getOfficeId());
-        accountingBridgeData.put("currency", 
loanScheduleAccrualData.getCurrencyData());
+        accountingBridgeData.put("currencyCode", 
loanScheduleAccrualData.getCurrencyData().getCode());
         accountingBridgeData.put("cashBasedAccountingEnabled", false);
         accountingBridgeData.put("upfrontAccrualBasedAccountingEnabled", 
false);
         accountingBridgeData.put("periodicAccrualBasedAccountingEnabled", 
true);
@@ -489,10 +484,9 @@ public class LoanAccrualWritePlatformServiceImpl 
implements LoanAccrualWritePlat
     private void postJournalEntries(final Loan loan, final List<Long> 
existingTransactionIds,
             final List<Long> existingReversedTransactionIds) {
         final MonetaryCurrency currency = loan.getCurrency();
-        final ApplicationCurrency applicationCurrency = 
applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
         boolean isAccountTransfer = false;
-        final Map<String, Object> accountingBridgeData = 
loan.deriveAccountingBridgeData(applicationCurrency.toData(),
-                existingTransactionIds, existingReversedTransactionIds, 
isAccountTransfer);
+        final Map<String, Object> accountingBridgeData = 
loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
+                existingReversedTransactionIds, isAccountTransfer);
         
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
     }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformService.java
index b36cc54ec..e90943e63 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformService.java
@@ -20,9 +20,11 @@ package org.apache.fineract.portfolio.loanaccount.service;
 
 import java.util.Collection;
 import org.apache.fineract.portfolio.charge.data.ChargeData;
+import org.apache.fineract.portfolio.charge.domain.Charge;
 import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData;
 import 
org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
 
 public interface LoanChargeReadPlatformService {
@@ -37,7 +39,7 @@ public interface LoanChargeReadPlatformService {
 
     Collection<LoanInstallmentChargeData> retrieveInstallmentLoanCharges(Long 
loanChargeId, boolean onlyPaymentPendingCharges);
 
-    Collection<Integer> retrieveOverdueInstallmentChargeFrequencyNumber(Long 
loanId, Long chargeId, Integer periodNumber);
+    Collection<Integer> retrieveOverdueInstallmentChargeFrequencyNumber(Loan 
loan, Charge charge, Integer periodNumber);
 
     Collection<LoanChargeData> retrieveLoanChargesForAccural(Long loanId);
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
index 62b95d458..3c5a7f12c 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
@@ -31,15 +31,17 @@ import lombok.RequiredArgsConstructor;
 import org.apache.fineract.accounting.glaccount.data.GLAccountData;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
 import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
-import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.portfolio.charge.data.ChargeData;
+import org.apache.fineract.portfolio.charge.domain.Charge;
 import 
org.apache.fineract.portfolio.charge.service.ChargeDropdownReadPlatformService;
 import org.apache.fineract.portfolio.charge.service.ChargeEnumerations;
 import 
org.apache.fineract.portfolio.common.service.DropdownReadPlatformService;
 import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData;
 import 
org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
 import org.apache.fineract.portfolio.tax.data.TaxGroupData;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -51,7 +53,6 @@ import org.springframework.stereotype.Service;
 public class LoanChargeReadPlatformServiceImpl implements 
LoanChargeReadPlatformService {
 
     private final JdbcTemplate jdbcTemplate;
-    private final PlatformSecurityContext context;
     private final ChargeDropdownReadPlatformService 
chargeDropdownReadPlatformService;
     private final DropdownReadPlatformService dropdownReadPlatformService;
 
@@ -243,16 +244,18 @@ public class LoanChargeReadPlatformServiceImpl implements 
LoanChargeReadPlatform
     }
 
     @Override
-    public Collection<Integer> 
retrieveOverdueInstallmentChargeFrequencyNumber(final Long loanId, final Long 
chargeId,
+    public Collection<Integer> 
retrieveOverdueInstallmentChargeFrequencyNumber(final Loan loan, final Charge 
charge,
             final Integer periodNumber) {
-        String sql = "select oic.frequency_number from 
m_loan_overdue_installment_charge oic  inner join m_loan_charge lc on 
lc.id=oic.loan_charge_id inner join m_loan_repayment_schedule rs on rs.id = 
oic.loan_schedule_id inner join m_loan loan on loan.id=rs.loan_id "
-                + "where lc.is_active = true and loan.id = ? and 
rs.installment=?";
-        Object[] params = { loanId, periodNumber };
-        if (chargeId != null) {
-            sql += " and lc.charge_id = ? ";
-            params = new Object[] { loanId, periodNumber, chargeId };
+
+        List<Integer> frequencyNumbers = new ArrayList<>();
+        for (LoanCharge loanCharge : loan.getLoanCharges()) {
+            if (loanCharge.isOverdueInstallmentCharge() && 
charge.equals(loanCharge.getCharge()) && loanCharge.isActive()
+                    && 
periodNumber.equals(loanCharge.getOverdueInstallmentCharge().getInstallment().getInstallmentNumber()))
 {
+                
frequencyNumbers.add(loanCharge.getOverdueInstallmentCharge().getFrequencyNumber());
+            }
         }
-        return this.jdbcTemplate.queryForList(sql, Integer.class, params);
+
+        return frequencyNumbers;
     }
 
     @Override
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
index f8402066f..f52f20163 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
@@ -38,6 +38,7 @@ import 
org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
 import org.apache.fineract.portfolio.loanaccount.data.PaidInAdvanceData;
 import 
org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
@@ -93,6 +94,8 @@ public interface LoanReadPlatformService {
      */
     Collection<OverdueLoanScheduleData> 
retrieveAllLoansWithOverdueInstallments(Long penaltyWaitPeriod, Boolean 
backdatePenalties);
 
+    Collection<OverdueLoanScheduleData> 
retrieveAllOverdueInstallmentsForLoan(Loan loan);
+
     Integer retriveLoanCounter(Long groupId, Integer loanType, Long productId);
 
     Integer retriveLoanCounter(Long clientId, Long productId);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index b87cb4fb6..01f429879 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -31,7 +31,9 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
+import java.util.Optional;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.accounting.common.AccountingRuleType;
 import org.apache.fineract.infrastructure.codes.data.CodeValueData;
@@ -63,6 +65,7 @@ import 
org.apache.fineract.portfolio.calendar.data.CalendarData;
 import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
 import 
org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService;
 import org.apache.fineract.portfolio.charge.data.ChargeData;
+import org.apache.fineract.portfolio.charge.domain.Charge;
 import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
 import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
 import org.apache.fineract.portfolio.client.data.ClientData;
@@ -151,7 +154,7 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService {
     private final CalendarReadPlatformService calendarReadPlatformService;
     private final StaffReadPlatformService staffReadPlatformService;
     private final PaginationHelper paginationHelper;
-    private final LoanMapper loaanLoanMapper;
+    private final LoanMapper loanMapper;
     private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
     private final PaymentTypeReadPlatformService 
paymentTypeReadPlatformService;
     private final LoanRepaymentScheduleTransactionProcessorFactory 
loanRepaymentScheduleTransactionProcessorFactory;
@@ -199,7 +202,7 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService {
         this.configurationDomainService = configurationDomainService;
         this.accountDetailsReadPlatformService = 
accountDetailsReadPlatformService;
         this.columnValidator = columnValidator;
-        this.loaanLoanMapper = new LoanMapper(sqlGenerator, 
delinquencyReadPlatformService);
+        this.loanMapper = new LoanMapper(sqlGenerator, 
delinquencyReadPlatformService);
         this.sqlGenerator = sqlGenerator;
         this.paginationHelper = paginationHelper;
         this.delinquencyReadPlatformService = delinquencyReadPlatformService;
@@ -303,7 +306,7 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService {
 
         final StringBuilder sqlBuilder = new StringBuilder(200);
         sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
-        sqlBuilder.append(this.loaanLoanMapper.loanSchema());
+        sqlBuilder.append(this.loanMapper.loanSchema());
 
         // TODO - for time being this will data scope list of loans returned to
         // only loans that have a client associated.
@@ -367,7 +370,7 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService {
         }
         final Object[] objectArray = extraCriterias.toArray();
         final Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
-        return this.paginationHelper.fetchPage(this.jdbcTemplate, 
sqlBuilder.toString(), finalObjectArray, this.loaanLoanMapper);
+        return this.paginationHelper.fetchPage(this.jdbcTemplate, 
sqlBuilder.toString(), finalObjectArray, this.loanMapper);
     }
 
     @Override
@@ -1040,7 +1043,7 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService {
             final BigDecimal amount = rs.getBigDecimal("amount");
             final String dateFormat = "yyyy-MM-dd";
             final String dueDate = rs.getString("dueDate");
-            final String locale = "en_GB";
+            final String locale = Locale.ENGLISH.toLanguageTag();
 
             final BigDecimal principalDue = 
JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalDue");
             final BigDecimal principalPaid = 
JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalPaid");
@@ -1558,6 +1561,46 @@ public class LoanReadPlatformServiceImpl implements 
LoanReadPlatformService {
         return this.jdbcTemplate.query(sqlBuilder.toString(), rm, 
penaltyWaitPeriod, penaltyWaitPeriod);
     }
 
+    @Override
+    public Collection<OverdueLoanScheduleData> 
retrieveAllOverdueInstallmentsForLoan(final Loan loan) {
+        Collection<OverdueLoanScheduleData> list = new ArrayList<>();
+
+        if (!loan.isOpen()) {
+            return list;
+        }
+        final Long penaltyWaitPeriod = 
configurationDomainService.retrievePenaltyWaitPeriod();
+        final boolean backdatePenalties = 
configurationDomainService.isBackdatePenaltiesEnabled();
+
+        for (LoanRepaymentScheduleInstallment installment : 
loan.getRepaymentScheduleInstallments()) {
+            if (installment.isObligationsMet() || 
installment.isRecalculatedInterestComponent()) {
+                continue;
+            }
+
+            boolean isPenaltyDue = 
installment.isOverdueOn(DateUtils.getBusinessLocalDate().plusDays(penaltyWaitPeriod
 + 1));
+            boolean isDueToday = 
installment.getDueDate().equals(DateUtils.getBusinessLocalDate().plusDays(penaltyWaitPeriod));
+
+            if (isPenaltyDue) {
+                if (!backdatePenalties && !isDueToday) {
+                    continue;
+                }
+                Optional<Charge> penaltyCharge = 
loan.getLoanProduct().getLoanProductCharges().stream()
+                        .filter((e) -> 
ChargeTimeType.OVERDUE_INSTALLMENT.getValue().equals(e.getChargeTimeType()) && 
e.isLoanCharge())
+                        .findFirst();
+
+                if (penaltyCharge.isEmpty()) {
+                    continue;
+                }
+
+                list.add(new OverdueLoanScheduleData(loan.getId(), 
penaltyCharge.get().getId(),
+                        
DateUtils.DEFAULT_DATE_FORMATTER.format(installment.getDueDate()), 
penaltyCharge.get().getAmount(),
+                        DateUtils.DEFAULT_DATE_FORMAT, 
Locale.ENGLISH.toLanguageTag(),
+                        
installment.getPrincipalOutstanding(loan.getCurrency()).getAmount(),
+                        
installment.getInterestOutstanding(loan.getCurrency()).getAmount(), 
installment.getInstallmentNumber()));
+            }
+        }
+        return list;
+    }
+
     @SuppressWarnings("deprecation")
     @Override
     public Integer retriveLoanCounter(final Long groupId, final Integer 
loanType, Long productId) {
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index aba9c411d..5d50eb2f4 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -33,6 +33,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -57,8 +58,6 @@ import 
org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChe
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.holiday.domain.Holiday;
 import 
org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import 
org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.organisation.office.domain.Office;
@@ -120,6 +119,7 @@ import 
org.apache.fineract.portfolio.calendar.domain.CalendarType;
 import 
org.apache.fineract.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException;
 import org.apache.fineract.portfolio.charge.domain.Charge;
 import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
+import 
org.apache.fineract.portfolio.charge.exception.ChargeCannotBeAppliedToException;
 import 
org.apache.fineract.portfolio.charge.exception.ChargeCannotBeUpdatedException;
 import 
org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeAddedException;
 import 
org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
@@ -235,7 +235,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
     private final LoanAssembler loanAssembler;
     private final ChargeRepositoryWrapper chargeRepository;
     private final LoanChargeRepository loanChargeRepository;
-    private final ApplicationCurrencyRepositoryWrapper 
applicationCurrencyRepository;
     private final JournalEntryWritePlatformService 
journalEntryWritePlatformService;
     private final CalendarInstanceRepository calendarInstanceRepository;
     private final PaymentDetailWritePlatformService 
paymentDetailWritePlatformService;
@@ -828,7 +827,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         final List<Long> existingReversedTransactionIds = new ArrayList<>();
         //
         final MonetaryCurrency currency = loan.getCurrency();
-        final ApplicationCurrency applicationCurrency = 
this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
 
         final LocalDate recalculateFrom = null;
         loan.setActualDisbursementDate(null);
@@ -852,7 +850,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
             }
             loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
             
this.accountTransfersWritePlatformService.reverseAllTransactions(loanId, 
PortfolioAccountType.LOAN);
-            String noteText = null;
+            String noteText;
             if (command.hasParameter("note")) {
                 noteText = command.stringValueOfParameterNamed("note");
                 if (StringUtils.isNotBlank(noteText)) {
@@ -861,8 +859,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                 }
             }
             boolean isAccountTransfer = false;
-            final Map<String, Object> accountingBridgeData = 
loan.deriveAccountingBridgeData(applicationCurrency.toData(),
-                    existingTransactionIds, existingReversedTransactionIds, 
isAccountTransfer);
+            final Map<String, Object> accountingBridgeData = 
loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
+                    existingReversedTransactionIds, isAccountTransfer);
             
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
             businessEventNotifierService.notifyPostBusinessEvent(new 
LoanUndoDisbursalBusinessEvent(loan));
         }
@@ -887,9 +885,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         glimRepository.findById(parentLoanId).orElseThrow();
 
         JsonArray repayments = command.arrayOfParameterNamed("formDataArray");
-        JsonCommand childCommand = null;
+        JsonCommand childCommand;
         CommandProcessingResult result = null;
-        JsonObject jsonObject = null;
+        JsonObject jsonObject;
 
         Long[] childLoanId = new Long[repayments.size()];
         for (int i = 0; i < repayments.size(); i++) {
@@ -982,7 +980,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         List<Long> transactionIds = new ArrayList<>();
         boolean isAccountTransfer = false;
         HolidayDetailDTO holidayDetailDTO = null;
-        Boolean isHolidayValidationDone = false;
+        boolean isHolidayValidationDone = false;
         final boolean allowTransactionsOnHoliday = 
this.configurationDomainService.allowTransactionsOnHolidayEnabled();
         for (final SingleRepaymentCommand singleLoanRepaymentCommand : 
repaymentCommand) {
             if (singleLoanRepaymentCommand != null) {
@@ -991,7 +989,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                         singleLoanRepaymentCommand.getTransactionDate());
                 final WorkingDays workingDays = 
this.workingDaysRepository.findOne();
                 final boolean allowTransactionsOnNonWorkingDay = 
this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
-                boolean isHolidayEnabled = false;
+                boolean isHolidayEnabled;
                 isHolidayEnabled = 
this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
                 holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, 
holidays, workingDays, allowTransactionsOnHoliday,
                         allowTransactionsOnNonWorkingDay);
@@ -1033,7 +1031,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         Loan loan = this.loanAssembler.assembleFrom(loanId);
         if (loan.status().isClosed() && loan.getLoanSubStatus() != null
                 && 
loan.getLoanSubStatus().equals(LoanSubStatus.FORECLOSED.getValue())) {
-            final String defaultUserMessage = "The loan cannot reopend as it 
is foreclosed.";
+            final String defaultUserMessage = "The loan cannot reopened as it 
is foreclosed.";
             throw new 
LoanForeclosureException("loan.cannot.be.reopened.as.it.is.foreclosured", 
defaultUserMessage, loanId);
         }
         checkClientOrGroupActive(loan);
@@ -1121,7 +1119,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         final String noteText = command.stringValueOfParameterNamed("note");
         if (StringUtils.isNotBlank(noteText)) {
             changes.put("note", noteText);
-            Note note = null;
+            Note note;
             /**
              * If a new transaction is not created, associate note with the 
transaction to be adjusted
              **/
@@ -1165,8 +1163,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
     @Override
     public CommandProcessingResult waiveInterestOnLoan(final Long loanId, 
final JsonCommand command) {
 
-        AppUser currentUser = getAppUserIfPresent();
-
         this.loanEventApiJsonValidator.validateTransaction(command.json());
 
         final Map<String, Object> changes = new LinkedHashMap<>();
@@ -1304,8 +1300,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
     @Override
     public CommandProcessingResult closeLoan(final Long loanId, final 
JsonCommand command) {
 
-        AppUser currentUser = getAppUserIfPresent();
-
         
this.loanEventApiJsonValidator.validateTransactionWithNoAmount(command.json());
 
         final Loan loan = this.loanAssembler.assembleFrom(loanId);
@@ -1373,7 +1367,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         // disable all active standing instructions linked to the loan
         
this.loanAccountDomainService.disableStandingInstructionsLinkedToClosedLoan(loan);
 
-        CommandProcessingResult result = null;
+        CommandProcessingResult result;
         if (possibleClosingTransaction != null) {
 
             result = new 
CommandProcessingResultBuilder().withCommandId(command.commandId())
@@ -1485,7 +1479,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         LoanCharge loanCharge = null;
         LocalDate recalculateFrom = loan.fetchInterestRecalculateFromDate();
         if (chargeDefinition.isPercentageOfDisbursementAmount()) {
-            LoanTrancheDisbursementCharge loanTrancheDisbursementCharge = null;
+            LoanTrancheDisbursementCharge loanTrancheDisbursementCharge;
             for (LoanDisbursementDetails disbursementDetail : 
loanDisburseDetails) {
                 if (disbursementDetail.actualDisbursementDate() == null) {
                     loanCharge = 
LoanCharge.createNewWithoutLoan(chargeDefinition, 
disbursementDetail.principal(), null, null, null,
@@ -1501,6 +1495,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                     }
                 }
             }
+            if (loanCharge == null) {
+                final String errorMessage = "Charge with identifier " + 
chargeDefinition.getId()
+                        + " cannot be applied: No valid loan disbursement 
available";
+                throw new ChargeCannotBeAppliedToException("loan", 
errorMessage, chargeDefinition.getId());
+            }
             loan.addTrancheLoanCharge(chargeDefinition);
         } else {
             loanCharge = LoanCharge.createNewFromJson(loan, chargeDefinition, 
command);
@@ -1607,7 +1606,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
 
     private boolean addCharge(final Loan loan, final Charge chargeDefinition, 
final LoanCharge loanCharge) {
 
-        AppUser currentUser = getAppUserIfPresent();
         if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) {
             final String errorMessage = "Charge and Loan must have the same 
currency.";
             throw new InvalidCurrencyException("loanCharge", "attach.to.loan", 
errorMessage);
@@ -1634,11 +1632,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
             final LoanTransaction applyLoanChargeTransaction = 
loan.handleChargeAppliedTransaction(loanCharge, null);
             
this.loanTransactionRepository.saveAndFlush(applyLoanChargeTransaction);
         }
-        boolean isAppliedOnBackDate = false;
-        if (loanCharge.getDueLocalDate() == null || 
DateUtils.getBusinessLocalDate().isAfter(loanCharge.getDueLocalDate())) {
-            isAppliedOnBackDate = true;
-        }
-        return isAppliedOnBackDate;
+        return loanCharge.getDueLocalDate() == null || 
DateUtils.getBusinessLocalDate().isAfter(loanCharge.getDueLocalDate());
     }
 
     @Transactional
@@ -1694,7 +1688,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         }
         final BigDecimal fullRefundAbleAmount = 
loanChargeValidateRefundAmount(loanCharge, installmentChargeEntry, 
transactionAmount);
 
-        JsonCommand repaymentJsonCommand = 
adaptLoanChargeRefundCommandForFutherRepaymentProcessing(command, 
fullRefundAbleAmount);
+        JsonCommand repaymentJsonCommand = 
adaptLoanChargeRefundCommandForFurtherRepaymentProcessing(command, 
fullRefundAbleAmount);
 
         boolean isRecoveryRepayment = false;
         String chargeRefundChargeType = "F";
@@ -1709,7 +1703,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         Long loanChargeRefundTransactionId = result.resourceId();
         LoanTransaction newChargeRefundTxn = null;
         for (LoanTransaction chargeRefundTxn : 
loanCharge.getLoan().getLoanTransactions()) {
-            if (chargeRefundTxn.getId().equals(loanChargeRefundTransactionId)) 
{
+            if (loanChargeRefundTransactionId.equals(chargeRefundTxn.getId())) 
{
                 newChargeRefundTxn = chargeRefundTxn;
                 final BigDecimal appliedRefundAmount = 
newChargeRefundTxn.getAmount(loanCharge.getLoan().getCurrency()).getAmount()
                         .multiply(BigDecimal.valueOf(-1));
@@ -1726,7 +1720,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
 
     }
 
-    private JsonCommand 
adaptLoanChargeRefundCommandForFutherRepaymentProcessing(JsonCommand command, 
BigDecimal fullRefundAbleAmount) {
+    private JsonCommand 
adaptLoanChargeRefundCommandForFurtherRepaymentProcessing(JsonCommand command, 
BigDecimal fullRefundAbleAmount) {
         // creates JsonCommand for onward repayment processing
         JsonObject jsonObject = (JsonObject) 
this.fromApiJsonHelper.parse(command.json());
 
@@ -1748,14 +1742,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         jsonObject.remove("installmentNumber");
         jsonObject.remove("dueDate");
 
-        JsonCommand repaymentJsonCommand = 
JsonCommand.fromExistingCommand(command, jsonObject);
-        return repaymentJsonCommand;
+        return JsonCommand.fromExistingCommand(command, jsonObject);
     }
 
     private BigDecimal loanChargeValidateRefundAmount(LoanCharge loanCharge, 
LoanInstallmentCharge installmentChargeEntry,
             BigDecimal transactionAmount) {
         // if transactionAmount not provided return max refundable amount 
(amount paid minus previous refunds)
-        BigDecimal chargeAmountPaid = BigDecimal.ZERO;
+        BigDecimal chargeAmountPaid;
         BigDecimal chargeAmountRefunded = BigDecimal.ZERO;
         MonetaryCurrency loanCurrency = loanCharge.getLoan().getCurrency();
         if (loanCharge.isInstalmentFee()) {
@@ -1780,7 +1773,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
 
         if (chargeAmountRefunded.compareTo(chargeAmountPaid) > 0) {
             final String errorMessage = 
"loan.charge.more.refunded.than.paid.unexpected.system.error";
-            final String details = "Paid: " + chargeAmountPaid.toString() + "  
Refunded: " + chargeAmountPaid.toString();
+            final String details = "Paid: " + chargeAmountPaid.toString() + "  
Refunded: " + chargeAmountPaid;
             throw new LoanChargeRefundException(errorMessage, details);
         }
 
@@ -1788,8 +1781,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         if (transactionAmount != null) { // refund amount was provided.
             if (transactionAmount.compareTo(refundableAmount) > 0) {
                 final String errorMessage = 
"loan.charge.transaction.amount.is.more.than.is.refundable";
-                final String details = "transactionAmount: " + 
transactionAmount.toString() + "  Refundable: "
-                        + refundableAmount.toString();
+                final String details = "transactionAmount: " + 
transactionAmount + "  Refundable: " + refundableAmount;
                 throw new LoanChargeRefundException(errorMessage, details);
             }
         }
@@ -1900,7 +1892,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         businessEventNotifierService.notifyPreBusinessEvent(new 
LoanWaiveChargeUndoBusinessEvent(loanCharge));
 
         if (loanCharge.isInstalmentFee()) {
-            LoanInstallmentCharge chargePerInstallment = null;
+            LoanInstallmentCharge chargePerInstallment;
 
             // final Integer installmentNumber = 
command.integerValueOfParameterNamed("installmentNumber");
             if (installmentNumber != null) {
@@ -2004,8 +1996,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
     @Override
     public CommandProcessingResult waiveLoanCharge(final Long loanId, final 
Long loanChargeId, final JsonCommand command) {
 
-        AppUser currentUser = getAppUserIfPresent();
-
         final Loan loan = this.loanAssembler.assembleFrom(loanId);
         checkClientOrGroupActive(loan);
         
this.loanEventApiJsonValidator.validateInstallmentChargeTransaction(command.json());
@@ -2056,9 +2046,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
 
         Money accruedCharge = Money.zero(loan.getCurrency());
         if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
-            Collection<LoanChargePaidByData> chargePaidByDatas = 
this.loanChargeReadPlatformService
+            Collection<LoanChargePaidByData> chargePaidByCollection = 
this.loanChargeReadPlatformService
                     .retriveLoanChargesPaidBy(loanCharge.getId(), 
LoanTransactionType.ACCRUAL, loanInstallmentNumber);
-            for (LoanChargePaidByData chargePaidByData : chargePaidByDatas) {
+            for (LoanChargePaidByData chargePaidByData : 
chargePaidByCollection) {
                 accruedCharge = 
accruedCharge.plus(chargePaidByData.getAmount());
             }
         }
@@ -2409,7 +2399,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
 
         loanUpdateCommand.validate();
 
-        final LocalDate dateOfLoanOfficerunAssigned = 
command.localDateValueOfParameterNamed("unassignedDate");
+        final LocalDate dateOfLoanOfficerUnassigned = 
command.localDateValueOfParameterNamed("unassignedDate");
 
         final Loan loan = this.loanAssembler.assembleFrom(loanId);
         checkClientOrGroupActive(loan);
@@ -2419,7 +2409,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         }
         businessEventNotifierService.notifyPreBusinessEvent(new 
LoanRemoveOfficerBusinessEvent(loan));
 
-        loan.removeLoanOfficer(dateOfLoanOfficerunAssigned);
+        loan.removeLoanOfficer(dateOfLoanOfficerUnassigned);
 
         saveLoanWithDataIntegrityViolationChecks(loan);
         businessEventNotifierService.notifyPostBusinessEvent(new 
LoanRemoveOfficerBusinessEvent(loan));
@@ -2438,10 +2428,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
             final List<Long> existingReversedTransactionIds) {
 
         final MonetaryCurrency currency = loan.getCurrency();
-        final ApplicationCurrency applicationCurrency = 
this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
         boolean isAccountTransfer = false;
-        final Map<String, Object> accountingBridgeData = 
loan.deriveAccountingBridgeData(applicationCurrency.toData(),
-                existingTransactionIds, existingReversedTransactionIds, 
isAccountTransfer);
+        final Map<String, Object> accountingBridgeData = 
loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
+                existingReversedTransactionIds, isAccountTransfer);
         
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
     }
 
@@ -2449,22 +2438,21 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
     @Override
     public void applyMeetingDateChanges(final Calendar calendar, final 
Collection<CalendarInstance> loanCalendarInstances) {
 
-        final Boolean reschedulebasedOnMeetingDates = null;
+        final Boolean rescheduleBasedOnMeetingDates = null;
         final LocalDate presentMeetingDate = null;
         final LocalDate newMeetingDate = null;
 
-        applyMeetingDateChanges(calendar, loanCalendarInstances, 
reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate);
+        applyMeetingDateChanges(calendar, loanCalendarInstances, 
rescheduleBasedOnMeetingDates, presentMeetingDate, newMeetingDate);
 
     }
 
     @Transactional
     @Override
     public void applyMeetingDateChanges(final Calendar calendar, final 
Collection<CalendarInstance> loanCalendarInstances,
-            final Boolean reschedulebasedOnMeetingDates, final LocalDate 
presentMeetingDate, final LocalDate newMeetingDate) {
+            final Boolean rescheduleBasedOnMeetingDates, final LocalDate 
presentMeetingDate, final LocalDate newMeetingDate) {
 
         final boolean isHolidayEnabled = 
this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
         final WorkingDays workingDays = this.workingDaysRepository.findOne();
-        final AppUser currentUser = getAppUserIfPresent();
         final List<Long> existingTransactionIds = new ArrayList<>();
         final List<Long> existingReversedTransactionIds = new ArrayList<>();
         final Collection<Integer> loanStatuses = new 
ArrayList<>(Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),
@@ -2477,7 +2465,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         }
 
         final List<Loan> loans = 
this.loanRepositoryWrapper.findByIdsAndLoanStatusAndLoanType(loanIds, 
loanStatuses, loanTypes);
-        List<Holiday> holidays = null;
+        List<Holiday> holidays;
         final LocalDate recalculateFrom = null;
         // loop through each loan to reschedule the repayment dates
         for (final Loan loan : loans) {
@@ -2489,7 +2477,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                 }
 
                 Boolean isSkipRepaymentOnFirstMonth = false;
-                Integer numberOfDays = 0;
+                int numberOfDays = 0;
                 boolean isSkipRepaymentOnFirstMonthEnabled = 
configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
                 if (isSkipRepaymentOnFirstMonthEnabled) {
                     isSkipRepaymentOnFirstMonth = 
this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
@@ -2505,9 +2493,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                     
loan.recalculateScheduleFromLastTransaction(scheduleGeneratorDTO, 
existingTransactionIds,
                             existingReversedTransactionIds);
                     createAndSaveLoanScheduleArchive(loan, 
scheduleGeneratorDTO);
-                } else if (reschedulebasedOnMeetingDates != null && 
reschedulebasedOnMeetingDates) {
+                } else if (rescheduleBasedOnMeetingDates != null && 
rescheduleBasedOnMeetingDates) {
                     
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), 
calendar.getRecurrence(), isHolidayEnabled,
-                            holidays, workingDays, 
reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate,
+                            holidays, workingDays, 
rescheduleBasedOnMeetingDates, presentMeetingDate, newMeetingDate,
                             isSkipRepaymentOnFirstMonth, numberOfDays);
                 } else {
                     
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), 
calendar.getRecurrence(), isHolidayEnabled,
@@ -2603,7 +2591,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                 loanToUpdate.updateClientLoanCounter(++currentLoanCounter);
             }
 
-            if 
(loanToUpdate.loanProduct().getId().equals(loan.loanProduct().getId())) {
+            if (Objects.equals(loan.loanProduct().getId(), 
loanToUpdate.loanProduct().getId())) {
                 Integer loanProductLoanCounter = 
loanToUpdate.getLoanProductLoanCounter();
                 if (newLoanProductCounter > loanProductLoanCounter) {
                     newLoanProductCounter = loanProductLoanCounter;
@@ -2646,17 +2634,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
 
     private void updateLoanCycleCounter(final List<Loan> loansToUpdate, final 
Loan loan) {
 
-        final Integer currentLoancounter = loan.getCurrentLoanCounter();
+        final Integer currentLoanCounter = loan.getCurrentLoanCounter();
         final Integer currentLoanProductCounter = 
loan.getLoanProductLoanCounter();
 
         for (final Loan loanToUpdate : loansToUpdate) {
             if (loan.loanProduct().isIncludeInBorrowerCycle()) {
-                Integer runningLoancounter = 
loanToUpdate.getCurrentLoanCounter();
-                if (runningLoancounter > currentLoancounter) {
-                    loanToUpdate.updateClientLoanCounter(--runningLoancounter);
+                Integer runningLoanCounter = 
loanToUpdate.getCurrentLoanCounter();
+                if (runningLoanCounter > currentLoanCounter) {
+                    loanToUpdate.updateClientLoanCounter(--runningLoanCounter);
                 }
             }
-            if 
(loan.loanProduct().getId().equals(loanToUpdate.loanProduct().getId())) {
+            if (Objects.equals(loan.loanProduct().getId(), 
loanToUpdate.loanProduct().getId())) {
                 Integer runningLoanProductCounter = 
loanToUpdate.getLoanProductLoanCounter();
                 if (runningLoanProductCounter > currentLoanProductCounter) {
                     
loanToUpdate.updateLoanProductLoanCounter(--runningLoanProductCounter);
@@ -2683,21 +2671,21 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
 
     @Override
     @Transactional
-    public void applyOverdueChargesForLoan(final Long loanId, 
Collection<OverdueLoanScheduleData> overdueLoanScheduleDatas) {
+    public void applyOverdueChargesForLoan(final Long loanId, 
Collection<OverdueLoanScheduleData> overdueLoanScheduleDataList) {
 
-        Loan loan = null;
-        final List<Long> existingTransactionIds = new ArrayList<>();
-        final List<Long> existingReversedTransactionIds = new ArrayList<>();
+        Loan loan = this.loanAssembler.assembleFrom(loanId);
+        final List<Long> existingTransactionIds = 
loan.findExistingTransactionIds();
+        final List<Long> existingReversedTransactionIds = 
loan.findExistingReversedTransactionIds();
         boolean runInterestRecalculation = false;
         LocalDate recalculateFrom = DateUtils.getBusinessLocalDate();
         LocalDate lastChargeDate = null;
-        for (final OverdueLoanScheduleData overdueInstallment : 
overdueLoanScheduleDatas) {
+        for (final OverdueLoanScheduleData overdueInstallment : 
overdueLoanScheduleDataList) {
 
             final JsonElement parsedCommand = 
this.fromApiJsonHelper.parse(overdueInstallment.toString());
             final JsonCommand command = 
JsonCommand.from(overdueInstallment.toString(), parsedCommand, 
this.fromApiJsonHelper, null, null,
                     null, null, null, loanId, null, null, null, null, null, 
null);
-            LoanOverdueDTO overdueDTO = 
applyChargeToOverdueLoanInstallment(loanId, overdueInstallment.getChargeId(),
-                    overdueInstallment.getPeriodNumber(), command, loan, 
existingTransactionIds, existingReversedTransactionIds);
+            LoanOverdueDTO overdueDTO = 
applyChargeToOverdueLoanInstallment(loan, overdueInstallment.getChargeId(),
+                    overdueInstallment.getPeriodNumber(), command);
             loan = overdueDTO.getLoan();
             runInterestRecalculation = runInterestRecalculation || 
overdueDTO.isRunInterestRecalculation();
             if (recalculateFrom.isAfter(overdueDTO.getRecalculateFrom())) {
@@ -2735,7 +2723,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                         
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(),
 mapEntry.getValue());
                     }
                 }
-                saveLoanWithDataIntegrityViolationChecks(loan);
             }
 
             postJournalEntries(loan, existingTransactionIds, 
existingReversedTransactionIds);
@@ -2745,7 +2732,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                 this.loanAccountDomainService.recalculateAccruals(loan);
             }
             businessEventNotifierService.notifyPostBusinessEvent(new 
LoanApplyOverdueChargeBusinessEvent(loan));
-
         }
     }
 
@@ -2772,14 +2758,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         }
     }
 
-    public LoanOverdueDTO applyChargeToOverdueLoanInstallment(final Long 
loanId, final Long loanChargeId, final Integer periodNumber,
-            final JsonCommand command, Loan loan, final List<Long> 
existingTransactionIds,
-            final List<Long> existingReversedTransactionIds) {
+    public LoanOverdueDTO applyChargeToOverdueLoanInstallment(final Loan loan, 
final Long loanChargeId, final Integer periodNumber,
+            final JsonCommand command) {
         boolean runInterestRecalculation = false;
         final Charge chargeDefinition = 
this.chargeRepository.findOneWithNotFoundDetection(loanChargeId);
 
-        Collection<Integer> frequencyNumbers = 
loanChargeReadPlatformService.retrieveOverdueInstallmentChargeFrequencyNumber(loanId,
-                chargeDefinition.getId(), periodNumber);
+        Collection<Integer> frequencyNumbers = 
loanChargeReadPlatformService.retrieveOverdueInstallmentChargeFrequencyNumber(loan,
+                chargeDefinition, periodNumber);
 
         Integer feeFrequency = chargeDefinition.feeFrequency();
         final ScheduledDateGenerator scheduledDateGenerator = new 
DefaultScheduledDateGenerator();
@@ -2787,21 +2772,20 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         final Long penaltyWaitPeriodValue = 
this.configurationDomainService.retrievePenaltyWaitPeriod();
         final Long penaltyPostingWaitPeriodValue = 
this.configurationDomainService.retrieveGraceOnPenaltyPostingPeriod();
         final LocalDate dueDate = 
command.localDateValueOfParameterNamed("dueDate");
-        Long diff = penaltyWaitPeriodValue + 1 - penaltyPostingWaitPeriodValue;
+        long diff = penaltyWaitPeriodValue + 1 - penaltyPostingWaitPeriodValue;
         if (diff < 1) {
             diff = 1L;
         }
         LocalDate startDate = 
dueDate.plusDays(penaltyWaitPeriodValue.intValue() + 1);
-        Integer frequencyNunber = 1;
+        int frequencyNumber = 1;
         if (feeFrequency == null) {
-            scheduleDates.put(frequencyNunber++, startDate.minusDays(diff));
+            scheduleDates.put(frequencyNumber++, startDate.minusDays(diff));
         } else {
             while (!startDate.isAfter(DateUtils.getBusinessLocalDate())) {
-                scheduleDates.put(frequencyNunber++, 
startDate.minusDays(diff));
-                LocalDate scheduleDate = 
scheduledDateGenerator.getRepaymentPeriodDate(PeriodFrequencyType.fromInt(feeFrequency),
-                        chargeDefinition.feeInterval(), startDate);
+                scheduleDates.put(frequencyNumber++, 
startDate.minusDays(diff));
 
-                startDate = scheduleDate;
+                startDate = 
scheduledDateGenerator.getRepaymentPeriodDate(PeriodFrequencyType.fromInt(feeFrequency),
+                        chargeDefinition.feeInterval(), startDate);
             }
         }
 
@@ -2812,12 +2796,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         LoanRepaymentScheduleInstallment installment = null;
         LocalDate lastChargeAppliedDate = dueDate;
         if (!scheduleDates.isEmpty()) {
-            if (loan == null) {
-                loan = this.loanAssembler.assembleFrom(loanId);
-                checkClientOrGroupActive(loan);
-                
existingTransactionIds.addAll(loan.findExistingTransactionIds());
-                
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
-            }
             installment = loan.fetchRepaymentScheduleInstallment(periodNumber);
             lastChargeAppliedDate = installment.getDueDate();
         }
@@ -2852,7 +2830,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
 
     @Override
     public CommandProcessingResult undoWriteOff(Long loanId) {
-        final AppUser currentUser = getAppUserIfPresent();
 
         final Loan loan = this.loanAssembler.assembleFrom(loanId);
         checkClientOrGroupActive(loan);
@@ -2972,7 +2949,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         }
 
         if (loan.getDisbursementDetails().size() > 
loan.loanProduct().maxTrancheCount()) {
-            final String errorMessage = "Number of tranche shouldn't be greter 
than " + loan.loanProduct().maxTrancheCount();
+            final String errorMessage = "Number of tranche shouldn't be 
greater than " + loan.loanProduct().maxTrancheCount();
             throw new 
ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName, 
errorMessage,
                     loan.loanProduct().maxTrancheCount(), 
loan.getDisbursementDetails().size());
         }
@@ -2983,16 +2960,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
 
     private CommandProcessingResult processLoanDisbursementDetail(Loan loan, 
Long loanId, JsonCommand command,
             LoanDisbursementDetails loanDisbursementDetails) {
-        final List<Long> existingTransactionIds = new ArrayList<>();
-        final List<Long> existingReversedTransactionIds = new ArrayList<>();
-        existingTransactionIds.addAll(loan.findExistingTransactionIds());
-        
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
+        final List<Long> existingTransactionIds = 
loan.findExistingTransactionIds();
+        final List<Long> existingReversedTransactionIds = 
loan.findExistingReversedTransactionIds();
         final Map<String, Object> changes = new LinkedHashMap<>();
         LocalDate recalculateFrom = null;
         ScheduleGeneratorDTO scheduleGeneratorDTO = 
this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
 
         ChangedTransactionDetail changedTransactionDetail = null;
-        AppUser currentUser = getAppUserIfPresent();
 
         if (command.entityId() != null) {
 
@@ -3302,7 +3276,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         businessEventNotifierService.notifyPreBusinessEvent(new 
LoanUndoLastDisbursalBusinessEvent(loan));
 
         final MonetaryCurrency currency = loan.getCurrency();
-        final ApplicationCurrency applicationCurrency = 
this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
         final List<Long> existingTransactionIds = new ArrayList<>();
         final List<Long> existingReversedTransactionIds = new ArrayList<>();
 
@@ -3312,7 +3285,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                 existingReversedTransactionIds, loan);
         if (!changes.isEmpty()) {
             loan = saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
-            String noteText = null;
+            String noteText;
             if (command.hasParameter("note")) {
                 noteText = command.stringValueOfParameterNamed("note");
                 if (StringUtils.isNotBlank(noteText)) {
@@ -3321,8 +3294,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
                 }
             }
             boolean isAccountTransfer = false;
-            final Map<String, Object> accountingBridgeData = 
loan.deriveAccountingBridgeData(applicationCurrency.toData(),
-                    existingTransactionIds, existingReversedTransactionIds, 
isAccountTransfer);
+            final Map<String, Object> accountingBridgeData = 
loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds,
+                    existingReversedTransactionIds, isAccountTransfer);
             
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
             businessEventNotifierService.notifyPostBusinessEvent(new 
LoanUndoLastDisbursalBusinessEvent(loan));
         }
@@ -3354,7 +3327,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl 
implements LoanWritePlatf
         for (LoanDisbursementDetails loanDisbursementDetails : 
loan.getDisbursementDetails()) {
             if 
(!loanDisbursementDetails.expectedDisbursementDateAsLocalDate().isAfter(transactionDate)
                     && loanDisbursementDetails.actualDisbursementDate() == 
null) {
-                final String defaultUserMessage = "The loan with undisbrsed 
tranche before foreclosure cannot be foreclosed.";
+                final String defaultUserMessage = "The loan with undisbursed 
tranche before foreclosure cannot be foreclosed.";
                 throw new 
LoanForeclosureException("loan.with.undisbursed.tranche.before.foreclosure.cannot.be.foreclosured",
                         defaultUserMessage, transactionDate);
             }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
index 1f1d09bc5..563c4fe5c 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
@@ -40,9 +40,7 @@ import 
org.apache.fineract.infrastructure.core.api.JsonCommand;
 import 
org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
 import 
org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
-import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.portfolio.account.PortfolioAccountType;
 import org.apache.fineract.portfolio.account.data.AccountTransferDTO;
 import org.apache.fineract.portfolio.account.domain.AccountTransferType;
@@ -574,11 +572,9 @@ public class DepositAccountDomainServiceJpa implements 
DepositAccountDomainServi
     private void postJournalEntries(final SavingsAccount savingsAccount, final 
Set<Long> existingTransactionIds,
             final Set<Long> existingReversedTransactionIds, boolean 
isAccountTransfer) {
 
-        final MonetaryCurrency currency = savingsAccount.getCurrency();
         final boolean backdatedTxnsAllowedTill = false;
-        final ApplicationCurrency applicationCurrency = 
this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
 
-        final Map<String, Object> accountingBridgeData = 
savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
+        final Map<String, Object> accountingBridgeData = 
savingsAccount.deriveAccountingBridgeData(savingsAccount.getCurrency().getCode(),
                 existingTransactionIds, existingReversedTransactionIds, 
isAccountTransfer, backdatedTxnsAllowedTill);
         
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
index f5ab802ab..459fac396 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
@@ -82,7 +82,6 @@ import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import 
org.apache.fineract.infrastructure.security.service.RandomPasswordGenerator;
 import org.apache.fineract.interoperation.domain.InteropIdentifier;
-import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
@@ -1878,13 +1877,13 @@ public class SavingsAccount extends 
AbstractPersistableCustom {
         }
     }
 
-    public Map<String, Object> deriveAccountingBridgeData(final CurrencyData 
currencyData, final Set<Long> existingTransactionIds,
+    public Map<String, Object> deriveAccountingBridgeData(final String 
currencyCode, final Set<Long> existingTransactionIds,
             final Set<Long> existingReversedTransactionIds, boolean 
isAccountTransfer, final boolean backdatedTxnsAllowedTill) {
 
         final Map<String, Object> accountingBridgeData = new LinkedHashMap<>();
         accountingBridgeData.put("savingsId", getId());
         accountingBridgeData.put("savingsProductId", productId());
-        accountingBridgeData.put("currency", currencyData);
+        accountingBridgeData.put("currencyCode", currencyCode);
         accountingBridgeData.put("officeId", officeId());
         accountingBridgeData.put("cashBasedAccountingEnabled", 
isCashBasedAccountingEnabledOnSavingsProduct());
         accountingBridgeData.put("accrualBasedAccountingEnabled", 
isAccrualBasedAccountingEnabledOnSavingsProduct());
@@ -1903,9 +1902,9 @@ public class SavingsAccount extends 
AbstractPersistableCustom {
         // Adding new transactions to the array
         for (final SavingsAccountTransaction transaction : trans) {
             if (transaction.isReversed() && 
!existingReversedTransactionIds.contains(transaction.getId())) {
-                
newSavingsTransactions.add(transaction.toMapData(currencyData));
+                
newSavingsTransactions.add(transaction.toMapData(currencyCode));
             } else if (!existingTransactionIds.contains(transaction.getId())) {
-                
newSavingsTransactions.add(transaction.toMapData(currencyData));
+                
newSavingsTransactions.add(transaction.toMapData(currencyCode));
             }
         }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
index 45436ce42..713dd416b 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
@@ -32,9 +32,7 @@ import 
org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlat
 import 
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
 import 
org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
-import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import 
org.apache.fineract.portfolio.businessevent.domain.savings.transaction.SavingsDepositBusinessEvent;
@@ -273,10 +271,7 @@ public class SavingsAccountDomainServiceJpa implements 
SavingsAccountDomainServi
     private void postJournalEntries(final SavingsAccount savingsAccount, final 
Set<Long> existingTransactionIds,
             final Set<Long> existingReversedTransactionIds, boolean 
isAccountTransfer, final boolean backdatedTxnsAllowedTill) {
 
-        final MonetaryCurrency currency = savingsAccount.getCurrency();
-        final ApplicationCurrency applicationCurrency = 
this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
-
-        final Map<String, Object> accountingBridgeData = 
savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
+        final Map<String, Object> accountingBridgeData = 
savingsAccount.deriveAccountingBridgeData(savingsAccount.getCurrency().getCode(),
                 existingTransactionIds, existingReversedTransactionIds, 
isAccountTransfer, backdatedTxnsAllowedTill);
         
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java
index 8459da909..21a5a1ee0 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java
@@ -39,7 +39,6 @@ import javax.persistence.Table;
 import 
org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
 import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
-import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.organisation.office.domain.Office;
@@ -544,7 +543,7 @@ public final class SavingsAccountTransaction extends 
AbstractPersistableCustom {
         return transactionAmount.isNotEqualTo(amountToCheck);
     }
 
-    public Map<String, Object> toMapData(final CurrencyData currencyData) {
+    public Map<String, Object> toMapData(final String currencyCode) {
         final Map<String, Object> thisTransactionData = new LinkedHashMap<>();
 
         final SavingsAccountTransactionEnumData transactionType = 
SavingsEnumerations.transactionType(this.typeOf);
@@ -552,9 +551,9 @@ public final class SavingsAccountTransaction extends 
AbstractPersistableCustom {
         thisTransactionData.put("id", getId());
         thisTransactionData.put("officeId", this.office.getId());
         thisTransactionData.put("type", transactionType);
-        thisTransactionData.put("reversed", Boolean.valueOf(isReversed()));
+        thisTransactionData.put("reversed", isReversed());
         thisTransactionData.put("date", getTransactionLocalDate());
-        thisTransactionData.put("currency", currencyData);
+        thisTransactionData.put("currencyCode", currencyCode);
         thisTransactionData.put("amount", this.amount);
         thisTransactionData.put("overdraftAmount", this.overdraftAmount);
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
index 5d5904e10..c979f8d9a 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
@@ -52,9 +52,7 @@ import 
org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavaila
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import 
org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
 import 
org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
-import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import org.apache.fineract.organisation.office.domain.Office;
@@ -1369,10 +1367,8 @@ public class 
DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
     private void postJournalEntries(final SavingsAccount savingsAccount, final 
Set<Long> existingTransactionIds,
             final Set<Long> existingReversedTransactionIds) {
 
-        final MonetaryCurrency currency = savingsAccount.getCurrency();
-        final ApplicationCurrency applicationCurrency = 
this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
         boolean isAccountTransfer = false;
-        final Map<String, Object> accountingBridgeData = 
savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
+        final Map<String, Object> accountingBridgeData = 
savingsAccount.deriveAccountingBridgeData(savingsAccount.getCurrency().getCode(),
                 existingTransactionIds, existingReversedTransactionIds, 
isAccountTransfer, false);
         
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
index 89e94e749..7d40ce214 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
@@ -64,9 +64,7 @@ import 
org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
 import 
org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import 
org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
 import 
org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
-import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import org.apache.fineract.organisation.office.domain.Office;
@@ -1544,10 +1542,8 @@ public class 
SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
     private void postJournalEntries(final SavingsAccount savingsAccount, final 
Set<Long> existingTransactionIds,
             final Set<Long> existingReversedTransactionIds, final boolean 
backdatedTxnsAllowedTill) {
 
-        final MonetaryCurrency currency = savingsAccount.getCurrency();
-        final ApplicationCurrency applicationCurrency = 
this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
         boolean isAccountTransfer = false;
-        final Map<String, Object> accountingBridgeData = 
savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
+        final Map<String, Object> accountingBridgeData = 
savingsAccount.deriveAccountingBridgeData(savingsAccount.getCurrency().getCode(),
                 existingTransactionIds, existingReversedTransactionIds, 
isAccountTransfer, backdatedTxnsAllowedTill);
         
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java
index ae5932b25..233eaa915 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java
@@ -38,8 +38,6 @@ import 
org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import 
org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
 import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
-import org.apache.fineract.organisation.monetary.data.CurrencyData;
-import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import 
org.apache.fineract.portfolio.accounts.constants.ShareAccountApiConstants;
 import 
org.apache.fineract.portfolio.businessevent.domain.share.ShareAccountApproveBusinessEvent;
 import 
org.apache.fineract.portfolio.businessevent.domain.share.ShareAccountCreateBusinessEvent;
@@ -130,16 +128,13 @@ public class 
ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
 
     private Map<String, Object> populateJournalEntries(final ShareAccount 
account, final Set<ShareAccountTransaction> transactions) {
         final Map<String, Object> accountingBridgeData = new HashMap<>();
-        Boolean cashBasedAccounting = 
account.getShareProduct().getAccountingType().intValue() == 2 ? Boolean.TRUE : 
Boolean.FALSE;
+        Boolean cashBasedAccounting = 
account.getShareProduct().getAccountingType() == 2 ? Boolean.TRUE : 
Boolean.FALSE;
         accountingBridgeData.put("cashBasedAccountingEnabled", 
cashBasedAccounting);
         accountingBridgeData.put("accrualBasedAccountingEnabled", 
Boolean.FALSE);
         accountingBridgeData.put("shareAccountId", account.getId());
         accountingBridgeData.put("shareProductId", 
account.getShareProduct().getId());
         accountingBridgeData.put("officeId", account.getOfficeId());
-        MonetaryCurrency currency = account.getCurrency();
-        final CurrencyData currencyData = new CurrencyData(currency.getCode(), 
"", currency.getDigitsAfterDecimal(),
-                currency.getCurrencyInMultiplesOf(), "", "");
-        accountingBridgeData.put("currency", currencyData);
+        accountingBridgeData.put("currencyCode", 
account.getCurrency().getCode());
         final List<Map<String, Object>> newTransactionsMap = new ArrayList<>();
         accountingBridgeData.put("newTransactions", newTransactionsMap);
 
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 05589ef69..f2a61b0db 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
@@ -4167,7 +4167,7 @@ public class ClientLoanIntegrationTest {
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
 
         Integer overdueFeeChargeId = 
ChargesHelper.createCharges(this.requestSpec, this.responseSpec,
-                
ChargesHelper.getLoanOverdueFeeJSONWithCalculattionTypePercentage("10"));
+                
ChargesHelper.getLoanOverdueFeeJSONWithCalculationTypePercentage("10"));
         Assertions.assertNotNull(overdueFeeChargeId);
 
         final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec);
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
index b7d0435fc..52695379e 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
@@ -230,7 +230,8 @@ public class SchedulerJobsTestResults {
         final Integer loanProductID = createLoanProduct(null);
         Assertions.assertNotNull(loanProductID);
 
-        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), savingsId.toString());
+        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), savingsId.toString(),
+                "10 January 2013");
         Assertions.assertNotNull(loanID);
 
         HashMap loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
@@ -281,7 +282,7 @@ public class SchedulerJobsTestResults {
         final Integer loanProductID = createLoanProduct(null);
         Assertions.assertNotNull(loanProductID);
 
-        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), null);
+        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), null, "10 January 2013");
         Assertions.assertNotNull(loanID);
 
         HashMap loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
@@ -378,7 +379,7 @@ public class SchedulerJobsTestResults {
     }
 
     @Test
-    public void testUpdateAccountingRunningBalancesJobOutcome() throws 
InterruptedException {
+    public void testUpdateAccountingRunningBalancesJobOutcome() {
         this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, 
responseSpec);
 
         final Account assetAccount = this.accountHelper.createAssetAccount();
@@ -421,7 +422,7 @@ public class SchedulerJobsTestResults {
     }
 
     @Test
-    public void testUpdateLoanArrearsAgingJobOutcome() throws 
InterruptedException {
+    public void testUpdateLoanArrearsAgingJobOutcome() {
         loanTransactionHelper = new LoanTransactionHelper(requestSpec, 
responseSpec);
 
         final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec);
@@ -430,7 +431,7 @@ public class SchedulerJobsTestResults {
         final Integer loanProductID = createLoanProduct(null);
         Assertions.assertNotNull(loanProductID);
 
-        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), null);
+        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), null, "10 January 2013");
         Assertions.assertNotNull(loanID);
 
         HashMap loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
@@ -560,18 +561,18 @@ public class SchedulerJobsTestResults {
         final Integer loanProductID = 
createLoanProduct(overdueFeeChargeId.toString());
         Assertions.assertNotNull(loanProductID);
 
-        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), null);
+        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), null, "10 January 2020");
         Assertions.assertNotNull(loanID);
 
         HashMap loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
         LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
 
-        loanStatusHashMap = 
this.loanTransactionHelper.approveLoan(AccountTransferTest.LOAN_APPROVAL_DATE, 
loanID);
+        loanStatusHashMap = this.loanTransactionHelper.approveLoan("01 March 
2020", loanID);
         LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
 
         String loanDetails = 
this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
-        loanStatusHashMap = 
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(AccountTransferTest.LOAN_APPROVAL_DATE_PLUS_ONE,
-                loanID, 
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
+        loanStatusHashMap = 
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("02 March 2020", 
loanID,
+                
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
         LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
 
         String JobName = "Apply penalty to overdue loans";
@@ -592,6 +593,59 @@ public class SchedulerJobsTestResults {
         LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
     }
 
+    @Test
+    public void testLoanCOBJobOutcome() {
+        this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, 
responseSpec);
+        this.loanTransactionHelper = new LoanTransactionHelper(requestSpec, 
responseSpec);
+
+        final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec);
+        Assertions.assertNotNull(clientID);
+
+        Integer overdueFeeChargeId = ChargesHelper.createCharges(requestSpec, 
responseSpec,
+                
ChargesHelper.getLoanOverdueFeeJSONWithCalculationTypePercentage("1"));
+        Assertions.assertNotNull(overdueFeeChargeId);
+
+        final Integer loanProductID = 
createLoanProduct(overdueFeeChargeId.toString());
+        Assertions.assertNotNull(loanProductID);
+        List<Integer> loanIDs = new ArrayList<>();
+        HashMap loanStatusHashMap;
+        for (int i = 0; i < 10; i++) {
+            final Integer loanID = 
applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, 
"10 January 2020");
+
+            Assertions.assertNotNull(loanID);
+
+            loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, 
responseSpec, loanID);
+            LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
+
+            loanStatusHashMap = this.loanTransactionHelper.approveLoan("01 
March 2020", loanID);
+            LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
+
+            String loanDetails = 
this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
+            loanStatusHashMap = 
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("02 March 2020", 
loanID,
+                    
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
+            LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
+            loanIDs.add(loanID);
+
+        }
+
+        String jobName = "Loan COB";
+        this.schedulerJobHelper.executeAndAwaitJob(jobName);
+        for (Integer loanId : loanIDs) {
+            List<HashMap> repaymentScheduleDataAfter = 
this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec,
+                    loanId);
+
+            Assertions.assertEquals(39.39f, (Float) 
repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
+                    "Verifying From Penalty Charges due fot first Repayment 
after Successful completion of Scheduler Job");
+            Assertions.assertEquals(39.39f, (Float) 
repaymentScheduleDataAfter.get(2).get("penaltyChargesDue"),
+                    "Verifying From Penalty Charges due fot first Repayment 
after Successful completion of Scheduler Job");
+            Assertions.assertEquals(39.39f, (Float) 
repaymentScheduleDataAfter.get(3).get("penaltyChargesDue"),
+                    "Verifying From Penalty Charges due fot first Repayment 
after Successful completion of Scheduler Job");
+            Assertions.assertEquals(39.39f, (Float) 
repaymentScheduleDataAfter.get(4).get("penaltyChargesDue"),
+                    "Verifying From Penalty Charges due fot first Repayment 
after Successful completion of Scheduler Job");
+
+        }
+    }
+
     @Test
     public void 
testAvoidUnncessaryPenaltyWhenAmountZeroForOverdueLoansJobOutcome() throws 
InterruptedException {
         this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, 
responseSpec);
@@ -601,13 +655,13 @@ public class SchedulerJobsTestResults {
         Assertions.assertNotNull(clientID);
 
         Integer overdueFeeChargeId = ChargesHelper.createCharges(requestSpec, 
responseSpec,
-                
ChargesHelper.getLoanOverdueFeeJSONWithCalculattionTypePercentage("0.000001"));
+                
ChargesHelper.getLoanOverdueFeeJSONWithCalculationTypePercentage("0.000001"));
         Assertions.assertNotNull(overdueFeeChargeId);
 
         final Integer loanProductID = 
createLoanProduct(overdueFeeChargeId.toString());
         Assertions.assertNotNull(loanProductID);
 
-        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), null);
+        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), null, "10 January 2013");
         Assertions.assertNotNull(loanID);
 
         HashMap loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
@@ -659,7 +713,7 @@ public class SchedulerJobsTestResults {
         final Integer loanProductID = createLoanProduct(null);
         Assertions.assertNotNull(loanProductID);
 
-        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), null);
+        final Integer loanID = applyForLoanApplication(clientID.toString(), 
loanProductID.toString(), null, "10 January 2013");
         Assertions.assertNotNull(loanID);
 
         HashMap loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
@@ -794,7 +848,7 @@ public class SchedulerJobsTestResults {
         return collateral;
     }
 
-    private Integer applyForLoanApplication(final String clientID, final 
String loanProductID, final String savingsID) {
+    private Integer applyForLoanApplication(final String clientID, final 
String loanProductID, final String savingsID, final String date) {
 
         List<HashMap> collaterals = new ArrayList<>();
         final Integer collateralId = 
CollateralManagementHelper.createCollateralProduct(this.requestSpec, 
this.responseSpec);
@@ -808,7 +862,7 @@ public class SchedulerJobsTestResults {
                 
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("4").withRepaymentEveryAfter("1")
                 
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2").withAmortizationTypeAsEqualInstallments()
                 
.withInterestTypeAsDecliningBalance().withInterestCalculationPeriodTypeSameAsRepaymentPeriod()
-                .withExpectedDisbursementDate("10 January 
2013").withSubmittedOnDate("10 January 2013").withCollaterals(collaterals)
+                
.withExpectedDisbursementDate(date).withSubmittedOnDate(date).withCollaterals(collaterals)
                 .build(clientID, loanProductID, savingsID);
         return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
     }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java
index baf1cfa7f..38119c95d 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/charges/ChargesHelper.java
@@ -302,7 +302,7 @@ public final class ChargesHelper {
         return chargesCreateJson;
     }
 
-    public static String 
getLoanOverdueFeeJSONWithCalculattionTypePercentage(String 
penaltyPercentageAmount) {
+    public static String 
getLoanOverdueFeeJSONWithCalculationTypePercentage(String 
penaltyPercentageAmount) {
         final HashMap<String, Object> map = populateDefaultsForLoan();
         map.put("penalty", ChargesHelper.PENALTY);
         map.put("amount", penaltyPercentageAmount);

Reply via email to