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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 629d2da7f FINERACT-1724: Fee's are not included in total balance 
amount, when we have multiple disbursements on first day
629d2da7f is described below

commit 629d2da7f9ed2ed3e3d914052ff75d1016e3affb
Author: Adam Saghy <[email protected]>
AuthorDate: Tue May 2 20:57:48 2023 +0200

    FINERACT-1724: Fee's are not included in total balance amount, when we have 
multiple disbursements on first day
---
 .../portfolio/loanaccount/domain/Loan.java         | 30 +++++-----
 .../domain/LoanAccountDomainServiceJpa.java        | 12 ++--
 .../portfolio/loanaccount/domain/LoanCharge.java   | 15 ++++-
 .../LoanRepaymentScheduleProcessingWrapper.java    | 62 ++++++++++----------
 ...tLoanRepaymentScheduleTransactionProcessor.java |  8 +--
 .../loanschedule/data/LoanScheduleParams.java      |  4 ++
 .../domain/AbstractLoanScheduleGenerator.java      | 56 +++++++++---------
 .../LoanChargeSpecificDueDateTest.java             | 67 +++++++++++++++++++++-
 ...LoanSpecificDueDateChargeAfterMaturityTest.java | 61 --------------------
 9 files changed, 167 insertions(+), 148 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 6b030c295..3773ff3b5 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
@@ -655,7 +655,7 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
                     getId(), loanCharge.name());
         }
 
-        validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, 
getDisbursementDate(), getLastRepaymentPeriodDueDate(false));
+        validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, 
getDisbursementDate());
 
         loanCharge.update(this);
 
@@ -770,18 +770,18 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
         final LoanRepaymentScheduleTransactionProcessor 
loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
                 .determineProcessor(this.transactionProcessingStrategyCode);
         final List<LoanRepaymentScheduleInstallment> chargePaymentInstallments 
= new ArrayList<>();
-        LocalDate startDate = getDisbursementDate();
         List<LoanRepaymentScheduleInstallment> installments = 
getRepaymentScheduleInstallments();
         for (final LoanRepaymentScheduleInstallment installment : 
installments) {
-            if (installmentNumber == null && 
charge.isDueForCollectionFromAndUpToAndIncluding(startDate, 
installment.getDueDate())) {
-
+            boolean isDue = installment.isFirstPeriod()
+                    ? 
charge.isDueForCollectionFromIncludingAndUpToAndIncluding(installment.getFromDate(),
 installment.getDueDate())
+                    : 
charge.isDueForCollectionFromAndUpToAndIncluding(installment.getFromDate(), 
installment.getDueDate());
+            if (installmentNumber == null && isDue) {
                 chargePaymentInstallments.add(installment);
                 break;
             } else if (installmentNumber != null && 
installment.getInstallmentNumber().equals(installmentNumber)) {
                 chargePaymentInstallments.add(installment);
                 break;
             }
-            startDate = installment.getDueDate();
         }
         final Set<LoanCharge> loanCharges = new HashSet<>(1);
         loanCharges.add(charge);
@@ -808,13 +808,11 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
         }
     }
 
-    private void validateChargeHasValidSpecifiedDateIfApplicable(final 
LoanCharge loanCharge, final LocalDate disbursementDate,
-            final LocalDate lastRepaymentPeriodDueDate) {
-        if (isInterestBearing() && loanCharge.isSpecifiedDueDate()
-                && 
!loanCharge.isDueForCollectionFromAndUpToAndIncluding(disbursementDate, 
lastRepaymentPeriodDueDate)) {
+    private void validateChargeHasValidSpecifiedDateIfApplicable(final 
LoanCharge loanCharge, final LocalDate disbursementDate) {
+        if (loanCharge.isSpecifiedDueDate() && 
loanCharge.getDueLocalDate().isBefore(disbursementDate)) {
             final String defaultUserMessage = "This charge with specified due 
date cannot be added as the it is not in schedule range.";
             throw new LoanChargeCannotBeAddedException("loanCharge", 
"specified.due.date.outside.range", defaultUserMessage,
-                    getDisbursementDate(), lastRepaymentPeriodDueDate, 
loanCharge.name());
+                    getDisbursementDate(), loanCharge.name());
         }
     }
 
@@ -1745,7 +1743,7 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
         if (loanCharge.isActive()) {
             clearLoanInstallmentChargesBeforeRegeneration(loanCharge);
             loanCharge.update(chargeAmt, loanCharge.getDueLocalDate(), amount, 
fetchNumberOfInstallmensAfterExceptions(), totalChargeAmt);
-            validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, 
getDisbursementDate(), getLastRepaymentPeriodDueDate(false));
+            validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, 
getDisbursementDate());
         }
 
     }
@@ -5560,7 +5558,10 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
         List<LoanCharge> loanCharges = new ArrayList<>();
         List<LoanInstallmentCharge> loanInstallmentCharges = new ArrayList<>();
         for (LoanCharge loanCharge : this.getActiveCharges()) {
-            if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(fromDate, 
toDate)) {
+            boolean isDue = fromDate.isEqual(this.getDisbursementDate())
+                    ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(fromDate, toDate)
+                    : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(fromDate, toDate);
+            if (isDue) {
                 if (loanCharge.isPenaltyCharge() && 
!loanCharge.isInstalmentFee()) {
                     penalties = penalties.add(loanCharge.amount());
                     loanCharges.add(loanCharge);
@@ -6569,7 +6570,10 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
         interestAccountedForCurrentPeriod = 
installment.getInterestWaived(getCurrency()).plus(installment.getInterestPaid(getCurrency()));
         for (LoanCharge loanCharge : this.charges) {
             if (loanCharge.isActive() && !loanCharge.isDueAtDisbursement()) {
-                if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(installment.getFromDate(),
 paymentDate)) {
+                boolean isDue = installment.isFirstPeriod()
+                        ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(installment.getFromDate(),
 paymentDate)
+                        : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(installment.getFromDate(), 
paymentDate);
+                if (isDue) {
                     if (loanCharge.isPenaltyCharge()) {
                         penaltyForCurrentPeriod = 
penaltyForCurrentPeriod.plus(loanCharge.getAmount(getCurrency()));
                         penaltyAccoutedForCurrentPeriod = 
penaltyAccoutedForCurrentPeriod
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 b7a6e3dc8..b49497411 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
@@ -641,7 +641,10 @@ public class LoanAccountDomainServiceJpa implements 
LoanAccountDomainService {
             }
 
             for (final LoanCharge loanCharge : loanCharges) {
-                if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(installment.getFromDate(),
 chargesTillDate)) {
+                boolean isDue = installment.isFirstPeriod()
+                        ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(installment.getFromDate(),
 chargesTillDate)
+                        : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(installment.getFromDate(), 
chargesTillDate);
+                if (isDue) {
                     if (loanCharge.isFeeCharge()) {
                         dueDateFeeIncome = 
dueDateFeeIncome.add(loanCharge.amount());
                     } else if (loanCharge.isPenaltyCharge()) {
@@ -792,9 +795,10 @@ public class LoanAccountDomainServiceJpa implements 
LoanAccountDomainService {
                 loan.addLoanTransaction(accrualTransaction);
                 Set<LoanChargePaidBy> accrualCharges = 
accrualTransaction.getLoanChargesPaid();
                 for (LoanCharge loanCharge : loan.getActiveCharges()) {
-                    if (loanCharge.isActive() && !loanCharge.isPaid()
-                            && 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(fromDate, foreClosureDate)
-                                    || loanCharge.isInstalmentFee())) {
+                    boolean isDue = 
fromDate.isEqual(loan.getDisbursementDate())
+                            ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(fromDate, 
foreClosureDate)
+                            : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(fromDate, foreClosureDate);
+                    if (loanCharge.isActive() && !loanCharge.isPaid() && 
(isDue || loanCharge.isInstalmentFee())) {
                         final LoanChargePaidBy loanChargePaidBy = new 
LoanChargePaidBy(accrualTransaction, loanCharge,
                                 
loanCharge.getAmountOutstanding(currency).getAmount(), null);
                         accrualCharges.add(loanChargePaidBy);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
index eea10227a..905a8ae81 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
@@ -625,14 +625,25 @@ public class LoanCharge extends AbstractPersistableCustom 
{
 
     public boolean isDueForCollectionFromAndUpToAndIncluding(final LocalDate 
fromNotInclusive, final LocalDate upToAndInclusive) {
         final LocalDate dueDate = getDueLocalDate();
-        return occursOnDayFromAndUpToAndIncluding(fromNotInclusive, 
upToAndInclusive, dueDate);
+        return occursOnDayFromExclusiveAndUpToAndIncluding(fromNotInclusive, 
upToAndInclusive, dueDate);
     }
 
-    private boolean occursOnDayFromAndUpToAndIncluding(final LocalDate 
fromNotInclusive, final LocalDate upToAndInclusive,
+    public boolean isDueForCollectionFromIncludingAndUpToAndIncluding(final 
LocalDate fromAndInclusive, final LocalDate upToAndInclusive) {
+        final LocalDate dueDate = getDueLocalDate();
+        return occursOnDayFromAndUpToAndIncluding(fromAndInclusive, 
upToAndInclusive, dueDate);
+    }
+
+    private boolean occursOnDayFromExclusiveAndUpToAndIncluding(final 
LocalDate fromNotInclusive, final LocalDate upToAndInclusive,
             final LocalDate target) {
         return target != null && target.isAfter(fromNotInclusive) && 
!target.isAfter(upToAndInclusive);
     }
 
+    private boolean occursOnDayFromAndUpToAndIncluding(final LocalDate 
fromAndInclusive, final LocalDate upToAndInclusive,
+            final LocalDate target) {
+        return target != null && (target.isEqual(fromAndInclusive) || 
target.isAfter(fromAndInclusive))
+                && !target.isAfter(upToAndInclusive);
+    }
+
     public boolean isFeeCharge() {
         return !this.penaltyCharge;
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
index f65f6c703..04ded2c13 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
@@ -47,14 +47,14 @@ public class LoanRepaymentScheduleProcessingWrapper {
             final Money feeChargesWaivedForRepaymentPeriod = 
cumulativeFeeChargesWaivedWithin(startDate, period.getDueDate(), loanCharges,
                     currency, !period.isRecalculatedInterestComponent(), 
period.isFirstPeriod());
             final Money feeChargesWrittenOffForRepaymentPeriod = 
cumulativeFeeChargesWrittenOffWithin(startDate, period.getDueDate(),
-                    loanCharges, currency, 
!period.isRecalculatedInterestComponent());
+                    loanCharges, currency, 
!period.isRecalculatedInterestComponent(), period.isFirstPeriod());
 
             final Money penaltyChargesDueForRepaymentPeriod = 
cumulativePenaltyChargesDueWithin(startDate, period.getDueDate(), loanCharges,
                     currency, period, totalPrincipal, totalInterest, 
!period.isRecalculatedInterestComponent());
             final Money penaltyChargesWaivedForRepaymentPeriod = 
cumulativePenaltyChargesWaivedWithin(startDate, period.getDueDate(),
                     loanCharges, currency, 
!period.isRecalculatedInterestComponent(), period.isFirstPeriod());
             final Money penaltyChargesWrittenOffForRepaymentPeriod = 
cumulativePenaltyChargesWrittenOffWithin(startDate,
-                    period.getDueDate(), loanCharges, currency, 
!period.isRecalculatedInterestComponent());
+                    period.getDueDate(), loanCharges, currency, 
!period.isRecalculatedInterestComponent(), period.isFirstPeriod());
 
             period.updateChargePortion(feeChargesDueForRepaymentPeriod, 
feeChargesWaivedForRepaymentPeriod,
                     feeChargesWrittenOffForRepaymentPeriod, 
penaltyChargesDueForRepaymentPeriod, penaltyChargesWaivedForRepaymentPeriod,
@@ -71,6 +71,9 @@ public class LoanRepaymentScheduleProcessingWrapper {
         Money cumulative = Money.zero(monetaryCurrency);
         for (final LoanCharge loanCharge : loanCharges) {
             if (loanCharge.isFeeCharge() && !loanCharge.isDueAtDisbursement()) 
{
+                boolean isDue = period.isFirstPeriod()
+                        ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, 
periodEnd)
+                        : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
                 if (loanCharge.isInstalmentFee() && 
isInstallmentChargeApplicable) {
                     if (loanCharge.getChargeCalculation().isPercentageBased()) 
{
                         BigDecimal amount = BigDecimal.ZERO;
@@ -87,12 +90,9 @@ public class LoanRepaymentScheduleProcessingWrapper {
                     } else {
                         cumulative = 
cumulative.plus(loanCharge.amountOrPercentage());
                     }
-                } else if (loanCharge.isOverdueInstallmentCharge()
-                        && 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
-                        && 
loanCharge.getChargeCalculation().isPercentageBased()) {
+                } else if (loanCharge.isOverdueInstallmentCharge() && isDue && 
loanCharge.getChargeCalculation().isPercentageBased()) {
                     cumulative = cumulative.plus(loanCharge.chargeAmount());
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
-                        && 
loanCharge.getChargeCalculation().isPercentageBased()) {
+                } else if (isDue && 
loanCharge.getChargeCalculation().isPercentageBased()) {
                     BigDecimal amount = BigDecimal.ZERO;
                     if 
(loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) {
                         amount = 
amount.add(totalPrincipal.getAmount()).add(totalInterest.getAmount());
@@ -116,10 +116,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
                     }
                     BigDecimal loanChargeAmt = 
amount.multiply(loanCharge.getPercentage()).divide(BigDecimal.valueOf(100));
                     cumulative = cumulative.plus(loanChargeAmt);
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
-                    cumulative = cumulative.plus(loanCharge.amount());
-                    // Special case for Loan Charges (Due Date) added the same 
disbursement date
-                } else if (period.isFirstPeriod() && 
periodStart.equals(loanCharge.getDueDate())) {
+                } else if (isDue) {
                     cumulative = cumulative.plus(loanCharge.amount());
                 }
             }
@@ -136,15 +133,14 @@ public class LoanRepaymentScheduleProcessingWrapper {
 
         for (final LoanCharge loanCharge : loanCharges) {
             if (loanCharge.isFeeCharge() && !loanCharge.isDueAtDisbursement()) 
{
+                boolean isDue = isFirstPeriod ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, 
periodEnd)
+                        : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
                 if (loanCharge.isInstalmentFee() && 
isInstallmentChargeApplicable) {
                     LoanInstallmentCharge loanChargePerInstallment = 
loanCharge.getInstallmentLoanCharge(periodEnd);
                     if (loanChargePerInstallment != null) {
                         cumulative = 
cumulative.plus(loanChargePerInstallment.getAmountWaived(currency));
                     }
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
-                    cumulative = 
cumulative.plus(loanCharge.getAmountWaived(currency));
-                    // Special case for Loan Charges (Due Date) added the same 
disbursement date
-                } else if (isFirstPeriod && 
periodStart.equals(loanCharge.getDueDate())) {
+                } else if (isDue) {
                     cumulative = 
cumulative.plus(loanCharge.getAmountWaived(currency));
                 }
             }
@@ -154,18 +150,21 @@ public class LoanRepaymentScheduleProcessingWrapper {
     }
 
     private Money cumulativeFeeChargesWrittenOffWithin(final LocalDate 
periodStart, final LocalDate periodEnd,
-            final Set<LoanCharge> loanCharges, final MonetaryCurrency 
currency, boolean isInstallmentChargeApplicable) {
+            final Set<LoanCharge> loanCharges, final MonetaryCurrency 
currency, boolean isInstallmentChargeApplicable,
+            boolean isFirstPeriod) {
 
         Money cumulative = Money.zero(currency);
 
         for (final LoanCharge loanCharge : loanCharges) {
             if (loanCharge.isFeeCharge() && !loanCharge.isDueAtDisbursement()) 
{
+                boolean isDue = isFirstPeriod ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, 
periodEnd)
+                        : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
                 if (loanCharge.isInstalmentFee() && 
isInstallmentChargeApplicable) {
                     LoanInstallmentCharge loanChargePerInstallment = 
loanCharge.getInstallmentLoanCharge(periodEnd);
                     if (loanChargePerInstallment != null) {
                         cumulative = 
cumulative.plus(loanChargePerInstallment.getAmountWrittenOff(currency));
                     }
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
+                } else if (isDue) {
                     cumulative = 
cumulative.plus(loanCharge.getAmountWrittenOff(currency));
                 }
             }
@@ -182,6 +181,9 @@ public class LoanRepaymentScheduleProcessingWrapper {
 
         for (final LoanCharge loanCharge : loanCharges) {
             if (loanCharge.isPenaltyCharge()) {
+                boolean isDue = period.isFirstPeriod()
+                        ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, 
periodEnd)
+                        : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
                 if (loanCharge.isInstalmentFee() && 
isInstallmentChargeApplicable) {
                     if (loanCharge.getChargeCalculation().isPercentageBased()) 
{
                         BigDecimal amount = BigDecimal.ZERO;
@@ -198,12 +200,9 @@ public class LoanRepaymentScheduleProcessingWrapper {
                     } else {
                         cumulative = 
cumulative.plus(loanCharge.amountOrPercentage());
                     }
-                } else if (loanCharge.isOverdueInstallmentCharge()
-                        && 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
-                        && 
loanCharge.getChargeCalculation().isPercentageBased()) {
+                } else if (loanCharge.isOverdueInstallmentCharge() && isDue && 
loanCharge.getChargeCalculation().isPercentageBased()) {
                     cumulative = cumulative.plus(loanCharge.chargeAmount());
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
-                        && 
loanCharge.getChargeCalculation().isPercentageBased()) {
+                } else if (isDue && 
loanCharge.getChargeCalculation().isPercentageBased()) {
                     BigDecimal amount = BigDecimal.ZERO;
                     if 
(loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) {
                         amount = 
amount.add(totalPrincipal.getAmount()).add(totalInterest.getAmount());
@@ -214,10 +213,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
                     }
                     BigDecimal loanChargeAmt = 
amount.multiply(loanCharge.getPercentage()).divide(BigDecimal.valueOf(100));
                     cumulative = cumulative.plus(loanChargeAmt);
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
-                    cumulative = cumulative.plus(loanCharge.amount());
-                    // Special case for Loan Charges (Due Date) added the same 
disbursement date
-                } else if (period.isFirstPeriod() && 
periodStart.equals(loanCharge.getDueDate())) {
+                } else if (isDue) {
                     cumulative = cumulative.plus(loanCharge.amount());
                 }
             }
@@ -234,15 +230,14 @@ public class LoanRepaymentScheduleProcessingWrapper {
 
         for (final LoanCharge loanCharge : loanCharges) {
             if (loanCharge.isPenaltyCharge()) {
+                boolean isDue = isFirstPeriod ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, 
periodEnd)
+                        : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
                 if (loanCharge.isInstalmentFee() && 
isInstallmentChargeApplicable) {
                     LoanInstallmentCharge loanChargePerInstallment = 
loanCharge.getInstallmentLoanCharge(periodEnd);
                     if (loanChargePerInstallment != null) {
                         cumulative = 
cumulative.plus(loanChargePerInstallment.getAmountWaived(currency));
                     }
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
-                    cumulative = 
cumulative.plus(loanCharge.getAmountWaived(currency));
-                    // Special case for Loan Charges (Due Date) added the same 
disbursement date
-                } else if (isFirstPeriod && 
periodStart.equals(loanCharge.getDueDate())) {
+                } else if (isDue) {
                     cumulative = 
cumulative.plus(loanCharge.getAmountWaived(currency));
                 }
             }
@@ -252,18 +247,21 @@ public class LoanRepaymentScheduleProcessingWrapper {
     }
 
     private Money cumulativePenaltyChargesWrittenOffWithin(final LocalDate 
periodStart, final LocalDate periodEnd,
-            final Set<LoanCharge> loanCharges, final MonetaryCurrency 
currency, boolean isInstallmentChargeApplicable) {
+            final Set<LoanCharge> loanCharges, final MonetaryCurrency 
currency, boolean isInstallmentChargeApplicable,
+            final boolean isFirstPeriod) {
 
         Money cumulative = Money.zero(currency);
 
         for (final LoanCharge loanCharge : loanCharges) {
             if (loanCharge.isPenaltyCharge()) {
+                boolean isDue = isFirstPeriod ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, 
periodEnd)
+                        : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
                 if (loanCharge.isInstalmentFee() && 
isInstallmentChargeApplicable) {
                     LoanInstallmentCharge loanChargePerInstallment = 
loanCharge.getInstallmentLoanCharge(periodEnd);
                     if (loanChargePerInstallment != null) {
                         cumulative = 
cumulative.plus(loanChargePerInstallment.getAmountWrittenOff(currency));
                     }
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
+                } else if (isDue) {
                     cumulative = 
cumulative.plus(loanCharge.getAmountWrittenOff(currency));
                 }
             }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
index 6994ed8bd..72750cb1a 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
@@ -110,10 +110,10 @@ public abstract class 
AbstractLoanRepaymentScheduleTransactionProcessor implemen
                 LocalDate startDate = disbursementDate;
                 for (final LoanRepaymentScheduleInstallment installment : 
installments) {
                     for (final LoanCharge loanCharge : transferCharges) {
-                        if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(startDate, 
installment.getDueDate())
-                                // Special case for Loan Charges (Due Date) 
added the same disbursement date
-                                || (startDate.equals(disbursementDate) && 
loanCharge.getDueDate() != null
-                                        && 
loanCharge.getDueDate().equals(disbursementDate))) {
+                        boolean isDue = installment.isFirstPeriod()
+                                ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(startDate, 
installment.getDueDate())
+                                : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(startDate, 
installment.getDueDate());
+                        if (isDue) {
                             Money amountForProcess = 
loanCharge.getAmount(currency);
                             if 
(amountForProcess.isGreaterThan(loanTransaction.getAmount(currency))) {
                                 amountForProcess = 
loanTransaction.getAmount(currency);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
index c5c0bec83..0f28b88a7 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
@@ -477,4 +477,8 @@ public final class LoanScheduleParams {
     public void setUnCompoundedAmount(Money unCompoundedAmount) {
         this.unCompoundedAmount = unCompoundedAmount;
     }
+
+    public boolean isFirstPeriod() {
+        return 1 == instalmentNumber;
+    }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
index 796508e59..f6193dfe2 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
@@ -437,12 +437,12 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
             LoanScheduleParams scheduleParams, LocalDate scheduledDueDate, 
ScheduleCurrentPeriodParams currentPeriodParams) {
         PrincipalInterest principalInterest = new 
PrincipalInterest(currentPeriodParams.getPrincipalForThisPeriod(),
                 currentPeriodParams.getInterestForThisPeriod(), null);
-        currentPeriodParams.setFeeChargesForInstallment(
-                
cumulativeFeeChargesDueWithin(scheduleParams.getPeriodStartDate(), 
scheduledDueDate, loanCharges, currency,
-                        principalInterest, 
scheduleParams.getPrincipalToBeScheduled(), 
scheduleParams.getTotalCumulativeInterest(), true));
-        currentPeriodParams.setPenaltyChargesForInstallment(
-                
cumulativePenaltyChargesDueWithin(scheduleParams.getPeriodStartDate(), 
scheduledDueDate, loanCharges, currency,
-                        principalInterest, 
scheduleParams.getPrincipalToBeScheduled(), 
scheduleParams.getTotalCumulativeInterest(), true));
+        
currentPeriodParams.setFeeChargesForInstallment(cumulativeFeeChargesDueWithin(scheduleParams.getPeriodStartDate(),
 scheduledDueDate,
+                loanCharges, currency, principalInterest, 
scheduleParams.getPrincipalToBeScheduled(),
+                scheduleParams.getTotalCumulativeInterest(), true, 
scheduleParams.isFirstPeriod()));
+        
currentPeriodParams.setPenaltyChargesForInstallment(cumulativePenaltyChargesDueWithin(scheduleParams.getPeriodStartDate(),
+                scheduledDueDate, loanCharges, currency, principalInterest, 
scheduleParams.getPrincipalToBeScheduled(),
+                scheduleParams.getTotalCumulativeInterest(), true, 
scheduleParams.isFirstPeriod()));
         
scheduleParams.addTotalFeeChargesCharged(currentPeriodParams.getFeeChargesForInstallment());
         
scheduleParams.addTotalPenaltyChargesCharged(currentPeriodParams.getPenaltyChargesForInstallment());
     }
@@ -456,11 +456,11 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
                 Money feeChargesForInstallment = 
cumulativeFeeChargesDueWithin(loanScheduleModelPeriod.periodFromDate(),
                         loanScheduleModelPeriod.periodDueDate(), 
nonCompoundingCharges, currency, principalInterest,
                         scheduleParams.getPrincipalToBeScheduled(), 
scheduleParams.getTotalCumulativeInterest(),
-                        
!loanScheduleModelPeriod.isRecalculatedInterestComponent());
+                        
!loanScheduleModelPeriod.isRecalculatedInterestComponent(), 
scheduleParams.isFirstPeriod());
                 Money penaltyChargesForInstallment = 
cumulativePenaltyChargesDueWithin(loanScheduleModelPeriod.periodFromDate(),
                         loanScheduleModelPeriod.periodDueDate(), 
nonCompoundingCharges, currency, principalInterest,
                         scheduleParams.getPrincipalToBeScheduled(), 
scheduleParams.getTotalCumulativeInterest(),
-                        
!loanScheduleModelPeriod.isRecalculatedInterestComponent());
+                        
!loanScheduleModelPeriod.isRecalculatedInterestComponent(), 
scheduleParams.isFirstPeriod());
                 
scheduleParams.addTotalFeeChargesCharged(feeChargesForInstallment);
                 
scheduleParams.addTotalPenaltyChargesCharged(penaltyChargesForInstallment);
                 
scheduleParams.addTotalRepaymentExpected(feeChargesForInstallment.plus(penaltyChargesForInstallment));
@@ -561,10 +561,10 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
                 currentPeriodParams.getInterestForThisPeriod(), null);
         oustanding = 
oustanding.minus(cumulativeFeeChargesDueWithin(transactionDate, 
scheduledDueDate, loanCharges,
                 totalInterestChargedForFullLoanTerm.getCurrency(), 
tempPrincipalInterest, scheduleParams.getPrincipalToBeScheduled(),
-                scheduleParams.getTotalCumulativeInterest(), true));
+                scheduleParams.getTotalCumulativeInterest(), true, 
scheduleParams.isFirstPeriod()));
         oustanding = 
oustanding.minus(cumulativePenaltyChargesDueWithin(transactionDate, 
scheduledDueDate, loanCharges,
                 totalInterestChargedForFullLoanTerm.getCurrency(), 
tempPrincipalInterest, scheduleParams.getPrincipalToBeScheduled(),
-                scheduleParams.getTotalCumulativeInterest(), true));
+                scheduleParams.getTotalCumulativeInterest(), true, 
scheduleParams.isFirstPeriod()));
 
         if 
(!oustanding.isGreaterThan(currentPeriodParams.getInterestForThisPeriod()) && 
!scheduledDueDate.equals(transactionDate)) {
             final Collection<LoanTermVariationsData> interestRates = 
loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
@@ -717,7 +717,7 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
                         processTransactions.clear();
                         
currentTransactions.addAll(createCurrentTransactionList(detail));
 
-                        if 
(!transactionDate.isEqual(scheduleParams.getPeriodStartDate()) || 
scheduleParams.getInstalmentNumber() == 1) {
+                        if 
(!transactionDate.isEqual(scheduleParams.getPeriodStartDate()) || 
scheduleParams.isFirstPeriod()) {
 
                             int periodDays = 
Math.toIntExact(ChronoUnit.DAYS.between(scheduleParams.getPeriodStartDate(), 
transactionDate));
                             // calculates period start date for interest
@@ -758,10 +758,10 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
                                     null);
                             Money feeChargesForInstallment = 
cumulativeFeeChargesDueWithin(scheduleParams.getPeriodStartDate(),
                                     transactionDate, loanCharges, currency, 
principalInterest, scheduleParams.getPrincipalToBeScheduled(),
-                                    
scheduleParams.getTotalCumulativeInterest(), false);
+                                    
scheduleParams.getTotalCumulativeInterest(), false, 
scheduleParams.isFirstPeriod());
                             Money penaltyChargesForInstallment = 
cumulativePenaltyChargesDueWithin(scheduleParams.getPeriodStartDate(),
                                     transactionDate, loanCharges, currency, 
principalInterest, scheduleParams.getPrincipalToBeScheduled(),
-                                    
scheduleParams.getTotalCumulativeInterest(), false);
+                                    
scheduleParams.getTotalCumulativeInterest(), false, 
scheduleParams.isFirstPeriod());
 
                             // sum up real totalInstallmentDue from
                             // components
@@ -1788,9 +1788,9 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
 
                 if (compoundingDate.isBefore(endDate)) {
                     Money feeChargesForInstallment = 
cumulativeFeeChargesDueWithin(lastCompoundingDate, compoundingDate, charges, 
currency,
-                            null, loanApplicationTerms.getPrincipal(), null, 
false);
+                            null, loanApplicationTerms.getPrincipal(), null, 
false, lastCompoundingDate.isEqual(startDate));
                     Money penaltyChargesForInstallment = 
cumulativePenaltyChargesDueWithin(lastCompoundingDate, compoundingDate, charges,
-                            currency, null, 
loanApplicationTerms.getPrincipal(), null, false);
+                            currency, null, 
loanApplicationTerms.getPrincipal(), null, false, 
lastCompoundingDate.isEqual(startDate));
                     Money compoundAmount = 
feeChargesForInstallment.plus(penaltyChargesForInstallment);
                     if (addUncompounded) {
                         compoundAmount = 
compoundAmount.plus(scheduleParams.getUnCompoundedAmount());
@@ -1987,23 +1987,22 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
 
     private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, 
final LocalDate periodEnd, final Set<LoanCharge> loanCharges,
             final MonetaryCurrency monetaryCurrency, final PrincipalInterest 
principalInterestForThisPeriod, final Money principalDisbursed,
-            final Money totalInterestChargedForFullLoanTerm, boolean 
isInstallmentChargeApplicable) {
+            final Money totalInterestChargedForFullLoanTerm, boolean 
isInstallmentChargeApplicable, final boolean isFirstPeriod) {
 
         Money cumulative = Money.zero(monetaryCurrency);
 
         for (final LoanCharge loanCharge : loanCharges) {
             if (!loanCharge.isDueAtDisbursement() && loanCharge.isFeeCharge()) 
{
+                boolean isDue = isFirstPeriod ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, 
periodEnd)
+                        : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
                 if (loanCharge.isInstalmentFee() && 
isInstallmentChargeApplicable) {
                     cumulative = 
calculateInstallmentCharge(principalInterestForThisPeriod, cumulative, 
loanCharge);
-                } else if (loanCharge.isOverdueInstallmentCharge()
-                        && 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
-                        && 
loanCharge.getChargeCalculation().isPercentageBased()) {
+                } else if (loanCharge.isOverdueInstallmentCharge() && isDue && 
loanCharge.getChargeCalculation().isPercentageBased()) {
                     cumulative = cumulative.plus(loanCharge.chargeAmount());
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
-                        && 
loanCharge.getChargeCalculation().isPercentageBased()) {
+                } else if (isDue && 
loanCharge.getChargeCalculation().isPercentageBased()) {
                     cumulative = 
calculateSpecificDueDateChargeWithPercentage(principalDisbursed, 
totalInterestChargedForFullLoanTerm,
                             cumulative, loanCharge);
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
+                } else if (isDue) {
                     cumulative = cumulative.plus(loanCharge.amount());
                 }
             }
@@ -2050,23 +2049,22 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
     private Money cumulativePenaltyChargesDueWithin(final LocalDate 
periodStart, final LocalDate periodEnd,
             final Set<LoanCharge> loanCharges, final MonetaryCurrency 
monetaryCurrency,
             final PrincipalInterest principalInterestForThisPeriod, final 
Money principalDisbursed,
-            final Money totalInterestChargedForFullLoanTerm, boolean 
isInstallmentChargeApplicable) {
+            final Money totalInterestChargedForFullLoanTerm, boolean 
isInstallmentChargeApplicable, final boolean isFirstPeriod) {
 
         Money cumulative = Money.zero(monetaryCurrency);
 
         for (final LoanCharge loanCharge : loanCharges) {
             if (loanCharge.isPenaltyCharge()) {
+                boolean isDue = isFirstPeriod ? 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, 
periodEnd)
+                        : 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
                 if (loanCharge.isInstalmentFee() && 
isInstallmentChargeApplicable) {
                     cumulative = 
calculateInstallmentCharge(principalInterestForThisPeriod, cumulative, 
loanCharge);
-                } else if (loanCharge.isOverdueInstallmentCharge()
-                        && 
loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
-                        && 
loanCharge.getChargeCalculation().isPercentageBased()) {
+                } else if (loanCharge.isOverdueInstallmentCharge() && isDue && 
loanCharge.getChargeCalculation().isPercentageBased()) {
                     cumulative = cumulative.plus(loanCharge.chargeAmount());
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
-                        && 
loanCharge.getChargeCalculation().isPercentageBased()) {
+                } else if (isDue && 
loanCharge.getChargeCalculation().isPercentageBased()) {
                     cumulative = 
calculateSpecificDueDateChargeWithPercentage(principalDisbursed, 
totalInterestChargedForFullLoanTerm,
                             cumulative, loanCharge);
-                } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
+                } else if (isDue) {
                     cumulative = cumulative.plus(loanCharge.amount());
                 }
             }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
index d52f64dc9..7e942b3fb 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
@@ -26,6 +26,7 @@ import io.restassured.builder.ResponseSpecBuilder;
 import io.restassured.http.ContentType;
 import io.restassured.specification.RequestSpecification;
 import io.restassured.specification.ResponseSpecification;
+import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.util.HashMap;
 import java.util.List;
@@ -37,6 +38,7 @@ import 
org.apache.fineract.client.models.JournalEntryTransactionItem;
 import org.apache.fineract.client.models.PostChargesResponse;
 import 
org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdResponse;
 import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse;
+import org.apache.fineract.client.models.PostLoansLoanIdRequest;
 import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
 import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
 import org.apache.fineract.integrationtests.common.BusinessDateHelper;
@@ -505,6 +507,64 @@ public class LoanChargeSpecificDueDateTest {
         }
     }
 
+    @Test
+    public void 
testApplyLoanSpecificDueDatePenaltyWithDisbursementDateWithMultipleDisbursement()
 {
+
+        final LocalDate todaysDate = Utils.getLocalDateOfTenant();
+
+        // Client and Loan account creation
+        final Integer clientId = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, "01 January 2012");
+        final GetLoanProductsProductIdResponse getLoanProductsProductResponse 
= createLoanProductWithPeriodicAccrual(loanTransactionHelper,
+                null);
+        assertNotNull(getLoanProductsProductResponse);
+
+        // Older date to have more than one overdue installment
+        LocalDate transactionDate = todaysDate;
+        String operationDate = Utils.dateFormatter.format(transactionDate);
+        log.info("Operation date {}", transactionDate);
+
+        // Create Loan Account
+        final Integer loanId = createLoanAccount(loanTransactionHelper, 
clientId.toString(),
+                getLoanProductsProductResponse.getId().toString(), 
operationDate, "12", "0");
+
+        // Get loan details
+        GetLoansLoanIdResponse getLoansLoanIdResponse = 
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+        validateLoanAccount(getLoansLoanIdResponse, 
Double.valueOf(principalAmount), Double.valueOf("0.00"), true);
+
+        // Apply Loan Charge with specific due date
+
+        final String feeAmount = "10.00";
+        String payloadJSON = 
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 feeAmount, true);
+        final PostChargesResponse postChargesResponse = 
ChargesHelper.createLoanCharge(requestSpec, responseSpec, payloadJSON);
+        assertNotNull(postChargesResponse);
+        final Long loanChargeId = postChargesResponse.getResourceId();
+        assertNotNull(loanChargeId);
+
+        payloadJSON = 
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(loanChargeId.toString(),
 operationDate, feeAmount);
+        PostLoansLoanIdChargesResponse postLoansLoanIdChargesResponse = 
loanTransactionHelper.addChargeForLoan(loanId, payloadJSON,
+                responseSpec);
+        assertNotNull(postLoansLoanIdChargesResponse);
+
+        // Get loan details expecting to have a delinquency classification
+        getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, 
responseSpec, loanId);
+        validateLoanAccount(getLoansLoanIdResponse, 
Double.valueOf(principalAmount), Double.valueOf("10.00"), true);
+
+        loanTransactionHelper.disburseLoan((long) loanId, new 
PostLoansLoanIdRequest().actualDisbursementDate(operationDate)
+                .transactionAmount(new 
BigDecimal("1000")).locale("en").dateFormat("dd MMMM yyyy"));
+
+        // Get loan details expecting to have a delinquency classification
+        getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, 
responseSpec, loanId);
+        validateLoanAccount(getLoansLoanIdResponse, 
Double.parseDouble(principalAmount) * 2, Double.valueOf("10.00"), true);
+
+        operationDate = 
Utils.dateFormatter.format(transactionDate.plusMonths(1));
+        payloadJSON = 
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(loanChargeId.toString(),
 operationDate, feeAmount);
+        postLoansLoanIdChargesResponse = 
loanTransactionHelper.addChargeForLoan(loanId, payloadJSON, responseSpec);
+
+        // Get loan details expecting to have a delinquency classification
+        getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, 
responseSpec, loanId);
+        validateLoanAccount(getLoansLoanIdResponse, 
Double.parseDouble(principalAmount) * 2, Double.valueOf("20.00"), true);
+    }
+
     private GetLoanProductsProductIdResponse createLoanProduct(final 
LoanTransactionHelper loanTransactionHelper,
             final Integer delinquencyBucketId) {
         final HashMap<String, Object> loanProductMap = new 
LoanProductTestBuilder().build(null, delinquencyBucketId);
@@ -515,13 +575,14 @@ public class LoanChargeSpecificDueDateTest {
     private GetLoanProductsProductIdResponse 
createLoanProductWithPeriodicAccrual(final LoanTransactionHelper 
loanTransactionHelper,
             final Integer delinquencyBucketId) {
         final Account assetAccount = this.accountHelper.createAssetAccount();
-        final Account assetFeeAndPenaltyAccount = 
this.accountHelper.createAssetAccount();
         final Account incomeAccount = this.accountHelper.createIncomeAccount();
         final Account expenseAccount = 
this.accountHelper.createExpenseAccount();
         final Account overpaymentAccount = 
this.accountHelper.createLiabilityAccount();
 
-        final HashMap<String, Object> loanProductMap = new 
LoanProductTestBuilder()
+        final HashMap<String, Object> loanProductMap = new 
LoanProductTestBuilder().withMultiDisburse()
+                
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withInterestTypeAsDecliningBalance()
                 .withAccountingRulePeriodicAccrual(new Account[] { 
assetAccount, incomeAccount, expenseAccount, overpaymentAccount })
+                .withDisallowExpectedDisbursements(true) //
                 .build(null, delinquencyBucketId);
         final Integer loanProductId = 
loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
         return loanTransactionHelper.getLoanProduct(loanProductId);
@@ -539,7 +600,7 @@ public class LoanChargeSpecificDueDateTest {
                 .build(clientId, loanProductId, null);
         final Integer loanId = 
loanTransactionHelper.getLoanId(loanApplicationJSON);
         loanTransactionHelper.approveLoan(operationDate, principalAmount, 
loanId, null);
-        
loanTransactionHelper.disburseLoanWithNetDisbursalAmount(operationDate, loanId, 
principalAmount);
+        loanTransactionHelper.disburseLoanWithTransactionAmount(operationDate, 
loanId, principalAmount);
         return loanId;
     }
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
index 243595c5c..6945f57d1 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
@@ -95,53 +95,6 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
         this.periodicAccrualAccountingHelper = new 
PeriodicAccrualAccountingHelper(requestSpec, responseSpec);
     }
 
-    @Test
-    public void onlyNonInterestBearingLoanCanAcceptChargeAfterMaturity() {
-        final Account assetAccount = this.accountHelper.createAssetAccount();
-        final Account incomeAccount = this.accountHelper.createIncomeAccount();
-        final Account expenseAccount = 
this.accountHelper.createExpenseAccount();
-        final Account overpaymentAccount = 
this.accountHelper.createLiabilityAccount();
-
-        final Integer loanProductID = 
createLoanProductWithPeriodicAccrualAccountingWithInterestRecalculationEnabled(assetAccount,
-                incomeAccount, expenseAccount, overpaymentAccount);
-
-        final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, DATE_OF_JOINING);
-
-        final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, "1");
-
-        final float PENALTY_PORTION = 100.0f;
-
-        Integer flatSpecifiedDueDate = 
ChargesHelper.createCharges(requestSpec, responseSpec, ChargesHelper
-                
.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, 
String.valueOf(PENALTY_PORTION), true));
-
-        HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
-        LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
-
-        loanStatusHashMap = 
this.loanTransactionHelper.approveLoan(EXPECTED_DISBURSAL_DATE, loanID);
-        LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
-        LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
-
-        LocalDate targetDate = LocalDate.of(2011, 3, 4);
-        final String loanDisbursementDate = dateFormatter.format(targetDate);
-
-        String loanDetails = 
this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
-        loanStatusHashMap = 
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(loanDisbursementDate,
 loanID,
-                
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
-        LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
-
-        targetDate = LocalDate.of(2011, 4, 5);
-        final String penaltyCharge1AddedDate = 
dateFormatter.format(targetDate);
-
-        final String ADD_CHARGES_URL = "/fineract-provider/api/v1/loans/" + 
loanID + "/charges?" + Utils.TENANT_IDENTIFIER;
-        ResponseSpecification response403Spec = new 
ResponseSpecBuilder().expectStatusCode(403).build();
-        final HashMap response = Utils.performServerPost(requestSpec, 
response403Spec, ADD_CHARGES_URL,
-                
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flatSpecifiedDueDate),
 penaltyCharge1AddedDate,
-                        String.valueOf(PENALTY_PORTION)),
-                "");
-        assertEquals("validation.msg.domain.rule.violation", 
response.get("userMessageGlobalisationCode"));
-
-    }
-
     @Test
     public void checkPeriodicAccrualAccountingAPIFlow() {
         final Account assetAccount = this.accountHelper.createAssetAccount();
@@ -458,20 +411,6 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
         return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
     }
 
-    private Integer 
createLoanProductWithPeriodicAccrualAccountingWithInterestRecalculationEnabled(final
 Account... accounts) {
-        LOG.info("------------------------------CREATING NEW LOAN PRODUCT 
---------------------------------------");
-        final String loanProductJSON = new 
LoanProductTestBuilder().withPrincipal("10000.0").withNumberOfRepayments("1")
-                
.withinterestRatePerPeriod("1").withInterestRateFrequencyTypeAsYear().withInterestTypeAsDecliningBalance()
-                .withInterestCalculationPeriodTypeAsDays()
-                
.withInterestRecalculationDetails(LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
-                        
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
-                        
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE)
-                
.withInterestRecalculationRestFrequencyDetails(LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY,
 "0", null, null)
-                .withInterestRecalculationCompoundingFrequencyDetails(null, 
null, null, null).withMoratorium("0", "0")
-                
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withAccountingRulePeriodicAccrual(accounts).build(null);
-        return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
-    }
-
     private Integer 
createLoanProductWithPeriodicAccrualAccountingNoInterest(final Account... 
accounts) {
         LOG.info("------------------------------CREATING NEW LOAN PRODUCT 
---------------------------------------");
         final String loanProductJSON = new 
LoanProductTestBuilder().withPrincipal(LP_PRINCIPAL.toString()).withRepaymentTypeAsMonth()

Reply via email to