diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm
index d4f4e59b8..a36cab86c 100644
--- a/api-docs/apiLive.htm
+++ b/api-docs/apiLive.htm
@@ -6839,18 +6839,10 @@ An enumeration that indicates the type of transaction processing strategy to be
- | recalculationFrequencyType |
+ recalculationRestFrequencyDate |
- Frequency at which Outstanding Principal is recalculated. This field is mandatory when interest interest recalculation is enabled for product.
- Available calculation types:
-
- - 1 = Same as repayment period
- - 2 = Daily
- - 3 = Weekly
- - 4 = Fortnightly
- - 5 = Monthly
-
+ | Specifies rest frequency start date for interest recalculation. This date must be before or equal to disbursement date
|
@@ -7024,7 +7016,12 @@ GET https://DomainName/api/v1/loans/template?templateType=individual&clientId=1&
"id": 2,
"code": "loanRescheduleStrategyMethod.reduce.number.of.installments",
"value": "Reduce number of installments"
- }
+ },
+ "recalculationRestFrequencyType": {
+ "id":1,
+ "code":"interestRecalculationFrequencyType.same.as.repayment.period",
+ "value":"Same as repayment period"
+ }
}
"charges": [],
"productOptions": [
@@ -7215,32 +7212,7 @@ GET https://DomainName/api/v1/loans/template?templateType=individual&clientId=1&
"fieldOfficerId":0,
"currency":{"code":"USD","name":"US Dollar","decimalPlaces":2,"displaySymbol":"$","nameCode":"currency.USD","displayLabel":"US Dollar ($)"}
}
- ],
- "interestRecalculationFrequencyTypeOptions": [{
- "id": 1,
- "code": "interestRecalculationFrequencyType.same.as.repayment.period",
- "value": "Same as repayment period"
- },
- {
- "id": 2,
- "code": "interestRecalculationFrequencyType.daily",
- "value": "Daily"
- },
- {
- "id": 3,
- "code": "interestRecalculationFrequencyType.weekly",
- "value": "Weekly"
- },
- {
- "id": 4,
- "code": "interestRecalculationFrequencyType.fortnightly",
- "value": "Fortnightly"
- },
- {
- "id": 5,
- "code": "interestRecalculationFrequencyType.monthly",
- "value": "Monthly"
- }],
+ ]
}
@@ -7271,6 +7243,12 @@ GET https://DomainName/api/v1/loans/template?templateType=individual&clientId=1&
'repaymentSchedule': Loan schedule data.
+
+ 'originalSchedule': Loan schedule data without interest recalculations.
+
+
+ 'futureSchedule': Loan schedule data from today date(will be displayed only for interest first repayment strategy processors)
+
'transactions': Loan transactions data.
@@ -7980,10 +7958,10 @@ Request Body:
- Additional Mandatory Fields if interest recalculation is enabled for product |
+ Additional Mandatory Fields if interest recalculation is enabled for product and Rest frequency not same as repayment period |
- | recalculationFrequencyType |
+ recalculationRestFrequencyDate |
@@ -8027,7 +8005,6 @@ Request Body:
"submittedOnDate": "10 Jun 2013",
"linkAccountId" : "1",
"fixedEmiAmount":1100,
- "recalculationFrequencyType":"1",
"maxOutstandingLoanBalance":"35000",
"disbursementData":[{"expectedDisbursementDate":"01 November 2013",
"principal":22000,"approvedPrincipal":22000}]
@@ -10874,6 +10851,25 @@ An enumeration that indicates the type of transaction processing strategy to be
Specifies what action should perform on loan repayment schedule for advance payments.
Example Values:1=Reschedule next repayments, 2=Reduce number of installments, 3=Reduce EMI amount |
+
+ | recalculationRestFrequencyType |
+
+
+ Specifies effective date from which the late or advanced payment amounts will be considered in recalculation.
+ Example Values:1=Same as repayment period, 2=Daily, 3=Weekly, 4=Monthly |
+
+
+ | recalculationRestFrequencyInterval |
+
+
+ Specifies rest frequency interval for interest recalculation.
+ |
+
+ | recalculationRestFrequencyDate |
+
+
+ Specifies rest frequency start date for interest recalculation.
+ |
@@ -10983,7 +10979,12 @@ GET https://DomainName/api/v1/loanproducts
"id": 2,
"code": "loanRescheduleStrategyMethod.reduce.number.of.installments",
"value": "Reduce number of installments"
- }
+ },
+ "recalculationRestFrequencyType": {
+ "id":1,
+ "code":"interestRecalculationFrequencyType.same.as.repayment.period",
+ "value":"Same as repayment period"
+ }
},
"accountingRule": {
"id": 2,
@@ -11831,7 +11832,28 @@ GET https://DomainName/api/v1/loanproducts/template
"id": 1,
"code": "loanRescheduleStrategyMethod.reschedule.next.repayments",
"value": "Reschedule next repayments"
- }]
+ }],
+ "interestRecalculationFrequencyTypeOptions": [
+ {
+ "id":1,
+ "code":"interestRecalculationFrequencyType.same.as.repayment.period",
+ "value":"Same as repayment period"
+ },
+ {
+ "id":2,
+ "code":"interestRecalculationFrequencyType.daily",
+ "value":"Daily"
+ },
+ {
+ "id":3,
+ "code":"interestRecalculationFrequencyType.weekly",
+ "value":"Weekly"
+ },
+ {
+ "id":4,
+ "code":"interestRecalculationFrequencyType.monthly",
+ "value":"Monthly"
+ }]
}
@@ -12120,7 +12142,15 @@ GET https://DomainName/api/v1/loanproducts/{productId}
Additional Mandatory Fields if interest recalculation is enabled(true) |
- | interestRecalculationCompoundingMethod,rescheduleStrategyMethod |
+ interestRecalculationCompoundingMethod, rescheduleStrategyMethod, recalculationRestFrequencyType |
+
+
+
+
+ Additional Optional Fields if interest recalculation is enabled(true) and recalculationRestFrequencyType is not same as repayment period |
+
+
+ | recalculationRestFrequencyInterval, recalculationRestFrequencyDate |
@@ -12219,6 +12249,7 @@ Request Body:
"isInterestRecalculationEnabled":"true",
"interestRecalculationCompoundingMethod":"0",
"rescheduleStrategyMethod":"3",
+ "recalculationRestFrequencyType":"1",
"accountingRule":"2",
"fundSourceAccountId":"4",
"loanPortfolioAccountId":"8",
@@ -12341,6 +12372,7 @@ Request Body:
"isInterestRecalculationEnabled":"true",
"interestRecalculationCompoundingMethod":"0",
"rescheduleStrategyMethod":"3",
+ "recalculationRestFrequencyType":"1"
}
@@ -12351,6 +12383,7 @@ Request Body:
"isInterestRecalculationEnabled":"true",
"interestRecalculationCompoundingMethod":"0",
"rescheduleStrategyMethod":"3",
+ "recalculationRestFrequencyType":"1"
}
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java
index fefed4eb7..28b8cac87 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java
@@ -365,8 +365,7 @@ public class LoansApiResource {
this.calculationPlatformService.updateFutureSchedule(repaymentSchedule, loanId);
}
- if (associationParameters.contains("originalSchedule") && loanBasicDetails.isInterestRecalculationEnabled()
- && loanBasicDetails.isInterestRecalculationEnabled()) {
+ if (associationParameters.contains("originalSchedule") && loanBasicDetails.isInterestRecalculationEnabled()) {
mandatoryResponseParameters.add("originalSchedule");
LoanScheduleData loanScheduleData = this.loanScheduleHistoryReadPlatformService.retrieveRepaymentArchiveSchedule(
loanId, repaymentScheduleRelatedData, disbursementData);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java
index b3a967a4b..53a4deab0 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java
@@ -1820,24 +1820,11 @@ public class Loan extends AbstractPersistable {
validateDisbursementDateIsOnNonWorkingDay(workingDays, allowTransactionsOnNonWorkingDay);
validateDisbursementDateIsOnHoliday(allowTransactionsOnHoliday, holidays);
- BigDecimal emiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName);
- boolean isEmiAmountChanged = false;
- if (this.loanProduct.isMultiDisburseLoan() && emiAmount != null && emiAmount.compareTo(retriveLastEmiAmount()) != 0) {
- LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(),
- actualDisbursementDate.toDate(), emiAmount, this);
- this.loanTermVariations.add(loanVariationTerms);
- isEmiAmountChanged = true;
- }
-
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
&& (fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now()) || isDisbursementMissed())) {
LocalDate recalculateFrom = null;
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
- } else if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule
- || isEmiAmountChanged) {
- regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
- workingDays);
}
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
@@ -1863,6 +1850,24 @@ public class Loan extends AbstractPersistable {
}
+ public void regenerateScheduleOnDisbursement(final LoanScheduleGeneratorFactory loanScheduleFactory,
+ final ApplicationCurrency currency, final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled,
+ final List holidays, final WorkingDays workingDays, final boolean recalculateSchedule,
+ final LocalDate actualDisbursementDate, BigDecimal emiAmount) {
+ boolean isEmiAmountChanged = false;
+ if (this.loanProduct.isMultiDisburseLoan() && emiAmount != null && emiAmount.compareTo(retriveLastEmiAmount()) != 0) {
+ LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(),
+ actualDisbursementDate.toDate(), emiAmount, this);
+ this.loanTermVariations.add(loanVariationTerms);
+ isEmiAmountChanged = true;
+ }
+
+ if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged) {
+ regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
+ workingDays);
+ }
+ }
+
public boolean canDisburse(final LocalDate actualDisbursementDate) {
Date lastDusburseDate = this.actualDisbursementDate;
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED,
@@ -1991,7 +1996,7 @@ public class Loan extends AbstractPersistable {
return isDisbursementMissed;
}
- private BigDecimal getDisbursedAmount() {
+ public BigDecimal getDisbursedAmount() {
BigDecimal principal = BigDecimal.ZERO;
for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) {
if (disbursementDetail.actualDisbursementDate() != null) {
@@ -4282,7 +4287,7 @@ public class Loan extends AbstractPersistable {
this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate());
installment = loanScheduleGenerator.calculatePrepaymentAmount(this.repaymentScheduleInstallments, getCurrency(),
- LocalDate.now(), getInterestChargedFromDate(), loanApplicationTerms, mc);
+ LocalDate.now(), getInterestChargedFromDate(), loanApplicationTerms, mc, charges());
} else {
installment = this.getTotalOutstandingOnLoan();
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
index 1861ed2fc..38bc2bb76 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
@@ -436,7 +436,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
Money waivedFeeChargesPortionOfTransaction = Money.zero(currency);
- final Money feesDue = getPenaltyChargesOutstanding(currency);
+ final Money feesDue = getFeeChargesOutstanding(currency);
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feesDue)) {
this.feeChargesWaived = getFeeChargesWaived(currency).plus(feesDue).getAmount();
waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(feesDue);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanSummary.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanSummary.java
index 2e04f05f5..463121248 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanSummary.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanSummary.java
@@ -301,4 +301,9 @@ public final class LoanSummary {
public BigDecimal getTotalPenaltyChargesCharged() {
return this.totalPenaltyChargesCharged;
}
+
+
+ public BigDecimal getTotalPrincipalWrittenOff() {
+ return this.totalPrincipalWrittenOff;
+ }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
index 415522881..2abf84fbc 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
@@ -123,7 +123,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
transactionstoBeProcessed.add(loanTransaction);
}
}
-
+
for (final LoanTransaction loanTransaction : transactionstoBeProcessed) {
if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
@@ -451,11 +451,13 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
transactionDate = recalculationDates.get(transactionDate);
}
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
- newLoanTransaction.resetDerivedComponents();
+ if (newLoanTransaction.isRepayment() || newLoanTransaction.isInterestWaiver() || newLoanTransaction.isRecoveryRepayment()) {
+ newLoanTransaction.resetDerivedComponents();
+ }
Money unProcessed = processTransaction(newLoanTransaction, currency, installments, amountToProcess);
if (transactionDate.isAfter(installment.getFromDate()) && transactionDate.isBefore(installment.getDueDate())) {
Money earlyPayment = currentInstallmentOutstanding.minus(installment.getTotalOutstanding(currency));
- if (earlyPayment.isGreaterThanZero()) {
+ if (earlyPayment.isGreaterThanZero() && (newLoanTransaction.isRepayment() || newLoanTransaction.isInterestWaiver() || newLoanTransaction.isRecoveryRepayment())) {
earlypaymentDetail.add(new RecalculationDetail(false, transactionDate, null, earlyPayment, false));
}
currentInstallmentOutstanding = installment.getTotalOutstanding(currency);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
index 4bdca5d96..f4c5bdda3 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
@@ -53,12 +53,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final LoanApplicationTerms loanApplicationTerms, final Set loanCharges, final boolean isHolidayEnabled,
final List holidays, final WorkingDays workingDays) {
final List diffAmt = null;
- return generate(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled, holidays, workingDays, diffAmt);
+ final LocalDate prepayDate = null;
+ return generate(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled, holidays, workingDays, diffAmt,
+ prepayDate);
}
private LoanScheduleModel generate(final MathContext mc, final ApplicationCurrency applicationCurrency,
final LoanApplicationTerms loanApplicationTerms, final Set loanCharges, final boolean isHolidayEnabled,
- final List holidays, final WorkingDays workingDays, List diffAmt) {
+ final List holidays, final WorkingDays workingDays, List diffAmt, LocalDate prepayDate) {
// 1. generate list of proposed schedule due dates
final LocalDate loanEndDate = this.scheduledDateGenerator.getLastRepaymentDate(loanApplicationTerms, isHolidayEnabled, holidays,
@@ -191,8 +193,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
if (loanApplicationTerms.isMultiDisburseLoan()) {
loanApplicationTerms.setFixedEmiAmountForPeriod(scheduledDueDate);
final Collection disbursementDatas = new ArrayList<>();
- disburseAmt = disbursementForPeriod(loanApplicationTerms, periodStartDate, scheduledDueDate, disbursementDatas,
- diffAmt != null);
+ LocalDate tillDate = scheduledDueDate;
+ if (prepayDate != null && prepayDate.isBefore(tillDate)) {
+ tillDate = prepayDate;
+ }
+ disburseAmt = disbursementForPeriod(loanApplicationTerms, periodStartDate, tillDate, disbursementDatas, diffAmt != null);
principalDisbursed = principalDisbursed.plus(disburseAmt);
loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().plus(disburseAmt));
outstandingBalance = outstandingBalance.plus(disburseAmt);
@@ -207,11 +212,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final LoanScheduleModelDisbursementPeriod disbursementPeriod = LoanScheduleModelDisbursementPeriod.disbursement(
disbursementData.disbursementDate(), disbursedAmt, chargesDueAtTimeOfDisbursement);
periods.add(disbursementPeriod);
- if (disbursementData.disbursementDate().isAfter(periodStartDateApplicableForInterest)) {
+
+ if (disbursementData.disbursementDate().isAfter(periodStartDateApplicableForInterest)
+ && (prepayDate == null || prepayDate.isAfter(disbursementData.disbursementDate()) || disbursementData
+ .isDisbursed())) {
interestToBeAdded = interestToBeAdded.add(calculateInterestForSpecificDays(mc, loanApplicationTerms, periodNumber,
totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableInFullInstallment,
interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt, disbursementData.disbursementDate(),
- scheduledDueDate));
+ tillDate));
}
}
}
@@ -224,14 +232,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
case REDUCE_EMI_AMOUNT:
loanApplicationTerms.setFixedEmiAmount(null);
outstandingBalance = outstandingBalance.minus(reducePrincipal);
- balanceForcalculation = outstandingBalance;
+ balanceForcalculation = balanceForcalculation.minus(reducePrincipal);
totalCumulativePrincipal = totalCumulativePrincipal.plus(reducePrincipal);
reducePrincipal = reducePrincipal.zero();
break;
case REDUCE_NUMBER_OF_INSTALLMENTS:
loanApplicationTerms.setFixedEmiAmount(fixedEmiAmount.getAmount());
outstandingBalance = outstandingBalance.minus(reducePrincipal);
- balanceForcalculation = outstandingBalance;
+ balanceForcalculation = balanceForcalculation.minus(reducePrincipal);
totalCumulativePrincipal = totalCumulativePrincipal.plus(reducePrincipal);
reducePrincipal = reducePrincipal.zero();
break;
@@ -1022,11 +1030,15 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
List installments = previousSchedule;
List removeInstallments = new ArrayList<>();
MonetaryCurrency currency = loanApplicationTerms.getPrincipal().getCurrency();
- LoanTransaction preCloseTransaction = getPreclosureTransaction(transactions, installments, currency, loanApplicationTerms, mc);
+ LoanTransaction preCloseTransaction = getPreclosureTransaction(transactions, installments, currency, loanApplicationTerms, mc,
+ loanCharges);
+ Integer updatedInstallmentNumber = 1;
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.isRecalculatedInterestComponent() && recalculateFrom != null
&& !recalculateFrom.isAfter(installment.getDueDate())) {
removeInstallments.add(installment);
+ } else {
+ installment.updateInstallmentNumber(updatedInstallmentNumber++);
}
}
installments.removeAll(removeInstallments);
@@ -1097,12 +1109,15 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final List recalculationDetails, final Map retainRecalculationDetails,
boolean recalculate, int installmentNumber, List processTransactions, LoanTransaction preCloseTransaction) {
LoanTransaction loanTransaction = processTransactions.remove(processTransactions.size() - 1);
- if (loanTransaction == preCloseTransaction) {
+ if (!(loanTransaction.isRepayment() || loanTransaction.isInterestWaiver())) {
processTransactions.add(loanTransaction);
return loanScheduleModel;
}
- LocalDate processTransactionsForInterestCompound = getNextRestScheduleDate(loanTransaction.getTransactionDate().minusDays(1),
- loanApplicationTerms, isHolidayEnabled, holidays, workingDays);
+ LocalDate processTransactionsForInterestCompound = loanTransaction.getTransactionDate();
+ if (loanTransaction != preCloseTransaction) {
+ processTransactionsForInterestCompound = getNextRestScheduleDate(loanTransaction.getTransactionDate().minusDays(1),
+ loanApplicationTerms, isHolidayEnabled, holidays, workingDays);
+ }
List scheduleInstallments = getInstallmentsForInterestCompound(installments,
processTransactionsForInterestCompound, retainRecalculationDetails.keySet());
@@ -1214,7 +1229,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final List holidays, final WorkingDays workingDays, final List transactions,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final int installmentNumber,
final List installments, final List recalculationDetails,
- final int skipRecalculation, LoanTransaction preCloseTransaction) {
+ final int skipRecalculation, final LoanTransaction preCloseTransaction) {
boolean processRecalculate = false;
int processedInstallmentNumber = installmentNumber;
@@ -1324,8 +1339,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
LoanScheduleModel model = null;
recalculationDetails.addAll(diffAmt);
if (processRecalculate) {
+ LocalDate prepayDate = null;
+ if (preCloseTransaction != null) {
+ prepayDate = preCloseTransaction.getTransactionDate();
+ }
model = generate(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled, holidays, workingDays,
- recalculationDetails);
+ recalculationDetails, prepayDate);
}
return new RecalculatedSchedule(model, processedInstallmentNumber);
}
@@ -1392,7 +1411,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
@Override
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(final List installments,
MonetaryCurrency currency, final LocalDate onDate, LocalDate interestChargedFromLocalDate,
- LoanApplicationTerms loanApplicationTerms, MathContext mc) {
+ LoanApplicationTerms loanApplicationTerms, MathContext mc, Set charges) {
Money feeCharges = Money.zero(currency);
Money penaltyCharges = Money.zero(currency);
Money totalPrincipal = Money.zero(currency);
@@ -1400,12 +1419,21 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
LocalDate calculateInterestFrom = onDate;
LocalDate dueDate = onDate;
LocalDate repaymentDueDate = null;
+ LocalDate periodStartDate = onDate;
boolean isInterestRepayment = false;
Money inerestForCurrentInstallment = Money.zero(currency);
Money principalOutstanding = Money.zero(currency);
Integer periodNumber = 0;
LocalDate lastDueDate = loanApplicationTerms.getExpectedDisbursementDate();
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
+ if (!currentInstallment.getDueDate().isAfter(LocalDate.now())) {
+ calculateInterestFrom = currentInstallment.getFromDate();
+ if (currentInstallment.isRecalculatedInterestComponent()) {
+ isInterestRepayment = true;
+ } else {
+ isInterestRepayment = false;
+ }
+ }
if (currentInstallment.isNotFullyPaidOff()) {
if (!currentInstallment.getDueDate().isAfter(onDate)) {
totalPrincipal = totalPrincipal.plus(currentInstallment.getPrincipalOutstanding(currency));
@@ -1417,8 +1445,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
totalPrincipal = totalPrincipal.minus(currentInstallment.getPrincipalCompleted(currency));
totalInterest = totalInterest.minus(currentInstallment.getInterestPaid(currency)).minus(
currentInstallment.getInterestWaived(currency));
- if (currentInstallment.getFromDate().isBefore(calculateInterestFrom)) {
- calculateInterestFrom = currentInstallment.getFromDate();
+ if (currentInstallment.getFromDate().isBefore(periodStartDate)) {
+ if (!isInterestRepayment) {
+ calculateInterestFrom = currentInstallment.getFromDate();
+ }
+ periodStartDate = currentInstallment.getFromDate();
dueDate = currentInstallment.getDueDate();
inerestForCurrentInstallment = currentInstallment.getInterestCharged(currency);
if (currentInstallment.isRecalculatedInterestComponent()) {
@@ -1443,8 +1474,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
calculateInterestFrom = interestChargedFromLocalDate;
}
Money interest = Money.zero(currency);
-
- if (calculateInterestFrom.isBefore(onDate)) {
+ LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
+ loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, true);
+ final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
+ loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);
+ if (calculateInterestFrom.isBefore(onDate) && !periodStartDate.isBefore(idealDisbursementDate)) {
boolean useDailyInterest = false;
if (repaymentDueDate == null) {
if (isInterestRepayment) {
@@ -1453,7 +1487,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
repaymentDueDate = dueDate;
}
int daysInPeriodApplicableForInterest = Days.daysBetween(calculateInterestFrom, repaymentDueDate).getDays();
- int days = Days.daysBetween(calculateInterestFrom, onDate).getDays();
+ int days = Days.daysBetween(periodStartDate, onDate).getDays();
+ int actualPeriodDays = Days.daysBetween(periodStartDate, repaymentDueDate).getDays();
BigDecimal interestForInstallment = BigDecimal.ZERO;
if (useDailyInterest) {
interestForInstallment = loanApplicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc,
@@ -1462,11 +1497,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
interest = interest.plus(calculateInterestForDays(daysInPeriodApplicableForInterest, interestForInstallment, days));
} else {
- LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
- loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, true);
- final LocalDate idealDisbursementDate = this.scheduledDateGenerator
- .idealDisbursementDateBasedOnFirstRepaymentDate(loanApplicationTerms.getLoanTermPeriodFrequencyType(),
- loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);
+
LocalDate periodStartDateApplicableForInterest = calculateInterestFrom;
if (calculateInterestFrom.isBefore(idealDisbursementDate)) {
if (loanApplicationTerms.getInterestChargedFromLocalDate() != null) {
@@ -1481,58 +1512,48 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
.calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest, repaymentDueDate,
loanApplicationTerms.getInterestChargedFromLocalDate(),
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery());
-
+ Money calculateInterestOnPrincipal = principalOutstanding;
+ final Collection disbursementDatas = new ArrayList<>();
if (loanApplicationTerms.isMultiDisburseLoan()) {
BigDecimal reducePrincipal = disbursementAfterPeriod(loanApplicationTerms, repaymentDueDate, lastDueDate);
principalOutstanding = principalOutstanding.minus(reducePrincipal);
+ calculateInterestOnPrincipal = principalOutstanding;
+ BigDecimal currentPeriodDisbursal = disbursementForPeriod(loanApplicationTerms, periodStartDate, repaymentDueDate,
+ disbursementDatas, true);
+ calculateInterestOnPrincipal = calculateInterestOnPrincipal.minus(currentPeriodDisbursal);
}
PrincipalInterest principalInterest = loanApplicationTerms.calculateTotalInterestForPeriod(
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc,
- totalOutstandingInterestPaymentDueToGrace.zero(), daysInPeriodApplicableForInterest, principalOutstanding);
- interestForInstallment = principalInterest.interest().getAmount();
- Money alteredPrincipal = principalOutstanding;
- Money reducePricipal = principalOutstanding.zero();
+ totalOutstandingInterestPaymentDueToGrace.zero(), daysInPeriodApplicableForInterest, calculateInterestOnPrincipal);
+ interestForInstallment = BigDecimal.valueOf(calculateInterestForDays(daysInPeriodApplicableForInterest, principalInterest
+ .interest().getAmount(), actualPeriodDays));
+ BigDecimal interestToBeAdded = BigDecimal.ZERO;
BigDecimal interestToBeReduced = BigDecimal.ZERO;
- BigDecimal interestForExtraPrincipal = BigDecimal.ZERO;
if (loanApplicationTerms.isMultiDisburseLoan()) {
- final Collection disbursementDatas = new ArrayList<>();
- BigDecimal addedPrincipal = disbursementForPeriod(loanApplicationTerms, calculateInterestFrom, repaymentDueDate,
- disbursementDatas, true);
- alteredPrincipal = alteredPrincipal.minus(addedPrincipal);
for (DisbursementData disbursementData : disbursementDatas) {
Money disbursedAmt = Money.of(currency, disbursementData.amount());
- if (disbursementData.disbursementDate().isAfter(calculateInterestFrom)) {
- LocalDate calculateTill = disbursementData.disbursementDate();
+ LocalDate calculateTill = disbursementData.disbursementDate();
+ if (!onDate.isAfter(calculateTill)) {
+ principalOutstanding = principalOutstanding.minus(disbursedAmt);
+ } else {
+ interestToBeAdded = interestToBeAdded.add(calculateInterestForSpecificDays(mc, loanApplicationTerms,
+ periodNumber, totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableForInterest,
+ interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt, calculateTill, onDate));
+ }
+
+ if (disbursementData.disbursementDate().isAfter(periodStartDateApplicableForInterest)) {
interestToBeReduced = interestToBeReduced.add(calculateInterestForSpecificDays(mc, loanApplicationTerms,
periodNumber, totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableForInterest,
- interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt, calculateInterestFrom, calculateTill));
-
- if (onDate.isAfter(calculateTill)) {
- interestForExtraPrincipal = interestForExtraPrincipal.add(calculateInterestForSpecificDays(mc,
- loanApplicationTerms, periodNumber, totalOutstandingInterestPaymentDueToGrace,
- daysInPeriodApplicableForInterest, interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt,
- calculateTill, onDate));
- } else {
- reducePricipal = reducePricipal.plus(disbursedAmt);
- }
+ interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt, calculateTill, repaymentDueDate));
}
- }
- interest = interest.plus(inerestForCurrentInstallment.minus(interestForInstallment).plus(interestToBeReduced));
- BigDecimal interestForCloseDate = BigDecimal.ZERO;
- if (alteredPrincipal.isNotEqualTo(principalOutstanding)) {
- interestForCloseDate = interestForExtraPrincipal;
- interestForCloseDate = interestForCloseDate.add(calculateInterestForSpecificDays(mc, loanApplicationTerms,
- periodNumber, totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableForInterest,
- interestCalculationGraceOnRepaymentPeriodFraction, alteredPrincipal, calculateInterestFrom, onDate));
- } else {
- interestForCloseDate = interestForCloseDate.add(BigDecimal.valueOf(calculateInterestForDays(
- daysInPeriodApplicableForInterest, interestForInstallment, days)));
- }
- interest = interest.plus(interestForCloseDate);
- principalOutstanding = principalOutstanding.minus(reducePricipal);
- }
+ }
+ }
+ interest = interest.plus(inerestForCurrentInstallment.minus(interestForInstallment).minus(interestToBeReduced));
+ BigDecimal interestForCloseDate = BigDecimal.valueOf(calculateInterestForDays(actualPeriodDays, interestForInstallment,
+ days));
+ interest = interest.plus(interestForCloseDate).plus(interestToBeAdded);
}
}
@@ -1540,6 +1561,17 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
totalInterest = totalInterest.plus(interest);
totalPrincipal = totalPrincipal.plus(principalOutstanding);
+ for (LoanCharge loanCharge : charges) {
+ if (loanCharge.isActive() && loanCharge.isNotFullyPaid() && !loanCharge.isWaived()
+ && loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStartDate, onDate)) {
+ if (loanCharge.isFeeCharge()) {
+ feeCharges = feeCharges.plus(loanCharge.amountOutstanding());
+ } else {
+ penaltyCharges = penaltyCharges.plus(loanCharge.amountOutstanding());
+ }
+ }
+ }
+
return new LoanRepaymentScheduleInstallment(null, 0, onDate, onDate, totalPrincipal.getAmount(), totalInterest.getAmount(),
feeCharges.getAmount(), penaltyCharges.getAmount(), false);
}
@@ -1588,7 +1620,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
private LoanTransaction getPreclosureTransaction(List loanTransactions,
List installments, MonetaryCurrency currency, final LoanApplicationTerms applicationTerms,
- MathContext mc) {
+ MathContext mc, final Set loanCharges) {
LoanTransaction precloseTransaction = null;
for (LoanTransaction loanTransaction : loanTransactions) {
if (precloseTransaction == null || precloseTransaction.getTransactionDate().isBefore(loanTransaction.getTransactionDate())) {
@@ -1597,7 +1629,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
if (precloseTransaction != null) {
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = calculatePrepaymentAmount(installments, currency,
- precloseTransaction.getTransactionDate(), applicationTerms.getInterestChargedFromLocalDate(), applicationTerms, mc);
+ precloseTransaction.getTransactionDate(), applicationTerms.getInterestChargedFromLocalDate(), applicationTerms, mc,
+ loanCharges);
if (precloseTransaction.getAmount(currency).isLessThan(loanRepaymentScheduleInstallment.getTotalOutstanding(currency))) {
precloseTransaction = null;
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
index 4450461ee..214c04444 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
@@ -33,7 +33,7 @@ public interface LoanScheduleGenerator {
List previousSchedule, LocalDate recalculateFrom);
LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List installments, MonetaryCurrency currency,
- LocalDate onDate, LocalDate interestChargedFromLocalDate, LoanApplicationTerms loanApplicationTerms, MathContext mc);
+ LocalDate onDate, LocalDate interestChargedFromLocalDate, LoanApplicationTerms loanApplicationTerms, MathContext mc, Set charges);
LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
final ApplicationCurrency applicationCurrency, final boolean isHolidayEnabled,
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
index c58068442..73337ecdb 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
@@ -385,7 +385,8 @@ public class LoanScheduleAssembler {
}
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List installments,
- MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms,final Long officeId) {
+ MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms, final Long officeId,
+ final Set loanCharges) {
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final MathContext mc = new MathContext(8, roundingMode);
@@ -404,7 +405,7 @@ public class LoanScheduleAssembler {
}
return loanScheduleGenerator.calculatePrepaymentAmount(installments, currency, nextScheduleDate,
- loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms, mc);
+ loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms, mc, loanCharges);
}
private void validateDisbursementDateIsOnNonWorkingDay(final LocalDate disbursementDate, final WorkingDays workingDays) {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
index 3b85035e0..e7b803a91 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
@@ -5,6 +5,7 @@
*/
package org.mifosplatform.portfolio.loanaccount.loanschedule.service;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -127,6 +128,12 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
if (!loan.repaymentScheduleDetail().isInterestRecalculationEnabled() || loan.isNpa() || !loan.status().isActive()
|| !loanRepaymentScheduleTransactionProcessor.isInterestFirstRepaymentScheduleTransactionProcessor()) { return; }
+ if (loan.loanProduct().isMultiDisburseLoan()) {
+ BigDecimal disbursedAmount = loan.getDisbursedAmount();
+ BigDecimal principalRepaid = loan.getLoanSummary().getTotalPrincipalRepaid();
+ BigDecimal principalWrittenOff = loan.getLoanSummary().getTotalPrincipalWrittenOff();
+ if (disbursedAmount.subtract(principalWrittenOff).subtract(principalRepaid).compareTo(BigDecimal.ZERO) != 1) { return; }
+ }
MonetaryCurrency currency = loan.getCurrency();
Money totalPrincipal = Money.zero(currency);
final List futureInstallments = new ArrayList<>();
@@ -147,7 +154,8 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(applicationCurrency,
calculatedRepaymentsStartingFromDate, restCalendarInstance);
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(
- loan.fetchRepaymentScheduleInstallments(), currency, LocalDate.now(), loanApplicationTerms, loan.getOfficeId());
+ loan.fetchRepaymentScheduleInstallments(), currency, LocalDate.now(), loanApplicationTerms, loan.getOfficeId(),
+ loan.charges());
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
Money interestDue = Money.zero(currency);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
index 1b45df998..583094ae8 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
@@ -156,7 +156,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
}
int daysToBeAccrued = Days.daysBetween(startDate, tilldate).getDays();
// if (daysToBeAccrued < 1) { return; }
- int daysInSchedule = Days.daysBetween(interestStartDate, tilldate).getDays();
+// int daysInSchedule = Days.daysBetween(interestStartDate, tilldate).getDays();
/*
* switch (accrualData.getRepaymentFrequency()) { case MONTHS: int
* numberOfDaysInMonth =
@@ -175,7 +175,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
BigDecimal interestportion = null;
BigDecimal feeportion = accrualData.getDueDateFeeIncome();
BigDecimal penaltyportion = accrualData.getDueDatePenaltyIncome();
- if (daysInSchedule >= totalNumberOfDays) {
+ if (daysToBeAccrued >= totalNumberOfDays) {
interestportion = accrualData.getInterestIncome();
} else {
double iterest = interestPerDay * daysToBeAccrued;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index e28e38414..b9e3c610c 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -83,6 +83,7 @@ import org.mifosplatform.portfolio.collectionsheet.command.SingleRepaymentComman
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
+import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData;
@@ -280,7 +281,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
ChangedTransactionDetail changedTransactionDetail = null;
if (canDisburse) {
Money disburseAmount = loan.adjustDisburseAmount(command, actualDisbursementDate);
- boolean recalcualteSchedule = amountBeforeAdjust.isNotEqualTo(loan.getPrincpal());
+ boolean recalculateSchedule = amountBeforeAdjust.isNotEqualTo(loan.getPrincpal());
final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");
if (isAccountTransfer) {
disburseLoanToSavings(loan, command, disburseAmount, paymentDetail);
@@ -301,9 +302,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
}
+ regenerateScheduleOnDisbursement(command, loan, applicationCurrency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
+ workingDays, recalculateSchedule);
+ if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
+ this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(loan.fetchRepaymentScheduleInstallments(),
+ loan, null);
+ }
changedTransactionDetail = loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, changes,
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
- allowTransactionsOnNonWorkingDay, recalcualteSchedule, restCalendarInstance);
+ allowTransactionsOnNonWorkingDay, recalculateSchedule, restCalendarInstance);
}
if (!changes.isEmpty()) {
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
@@ -322,10 +329,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
}
- if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
- createLoanScheduleArchive(loan, applicationCurrency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
- workingDays);
- }
+
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
}
@@ -476,7 +480,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (canDisburse) {
Money amountBeforeAdjust = loan.getPrincpal();
Money disburseAmount = loan.adjustDisburseAmount(command, actualDisbursementDate);
- boolean recalcualteSchedule = amountBeforeAdjust.isNotEqualTo(loan.getPrincpal());
+ boolean recalculateSchedule = amountBeforeAdjust.isNotEqualTo(loan.getPrincpal());
final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");
if (isAccountTransfer) {
disburseLoanToSavings(loan, command, disburseAmount, paymentDetail);
@@ -496,10 +500,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
}
-
+ regenerateScheduleOnDisbursement(command, loan, applicationCurrency, firstRepaymentOnDate, isHolidayEnabled, holidays,
+ workingDays, recalculateSchedule);
+ if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
+ this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(loan.fetchRepaymentScheduleInstallments(),
+ loan, null);
+ }
changedTransactionDetail = loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, changes,
firstRepaymentOnDate, isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
- allowTransactionsOnNonWorkingDay, recalcualteSchedule, restCalendarInstance);
+ allowTransactionsOnNonWorkingDay, recalculateSchedule, restCalendarInstance);
}
if (!changes.isEmpty()) {
@@ -518,10 +527,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
}
-
- if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
- createLoanScheduleArchive(loan, applicationCurrency, firstRepaymentOnDate, isHolidayEnabled, holidays, workingDays);
- }
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
}
final Set loanCharges = loan.charges();
@@ -2315,6 +2320,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
+ private void regenerateScheduleOnDisbursement(final JsonCommand command, final Loan loan, final ApplicationCurrency applicationCurrency,
+ final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled, final List holidays,
+ final WorkingDays workingDays, final boolean recalculateSchedule) {
+ final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
+ BigDecimal emiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName);
+ loan.regenerateScheduleOnDisbursement(loanScheduleFactory, applicationCurrency, calculatedRepaymentsStartingFromDate,
+ isHolidayEnabled, holidays, workingDays, recalculateSchedule, actualDisbursementDate, emiAmount);
+ }
+
private List retrieveRepaymentScheduleFromModel(LoanScheduleModel model) {
final List installments = new ArrayList<>();
for (final LoanScheduleModelPeriod scheduledLoanInstallment : model.getPeriods()) {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java
index 97de3bd5c..dd8817c46 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java
@@ -78,12 +78,13 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
RecalculationFrequencyType frequencyType = RecalculationFrequencyType.fromInt(recurrenceFrequency);
Date recurrenceOnDate = null;
if (recurrenceOnLocalDate != null) {
- if (frequencyType.isSameAsRepayment()) {
- recurrenceInterval = 0;
- } else {
+ if (!frequencyType.isSameAsRepayment()) {
recurrenceOnDate = recurrenceOnLocalDate.toDate();
}
}
+ if (frequencyType.isSameAsRepayment()) {
+ recurrenceInterval = 0;
+ }
return new LoanProductInterestRecalculationDetails(interestRecalculationCompoundingMethod, loanRescheduleStrategyMethod,
recurrenceFrequency, recurrenceInterval, recurrenceOnDate);