FINERACT-1981: pay-off transaction for progressive loans
This commit is contained in:
committed by
Adam Saghy
parent
721ceaa32c
commit
7304af57bc
+1
-1
@@ -250,7 +250,7 @@ public class LoanSummaryData {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
private static BigDecimal computeAccruedInterestTillDay(final LoanSchedulePeriodData period, final long untilDay,
|
||||
public static BigDecimal computeAccruedInterestTillDay(final LoanSchedulePeriodData period, final long untilDay,
|
||||
final CurrencyData currency) {
|
||||
Integer remainingDays = period.getDaysInPeriod();
|
||||
BigDecimal totalAccruedInterest = BigDecimal.ZERO;
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.data;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true, fluent = true)
|
||||
public class OutstandingAmountsDTO {
|
||||
|
||||
private Money principal;
|
||||
private Money interest;
|
||||
private Money feeCharges;
|
||||
private Money penaltyCharges;
|
||||
|
||||
public OutstandingAmountsDTO(MonetaryCurrency currency) {
|
||||
this.principal = Money.zero(currency);
|
||||
this.interest = Money.zero(currency);
|
||||
this.feeCharges = Money.zero(currency);
|
||||
this.penaltyCharges = Money.zero(currency);
|
||||
}
|
||||
|
||||
public Money getTotalOutstanding() {
|
||||
return principal() //
|
||||
.plus(interest()) //
|
||||
.plus(feeCharges()) //
|
||||
.plus(penaltyCharges());
|
||||
}
|
||||
|
||||
public void plusPrincipal(Money principal) {
|
||||
this.principal = this.principal.plus(principal);
|
||||
}
|
||||
|
||||
public void plusInterest(Money interest) {
|
||||
this.interest = this.interest.plus(interest);
|
||||
}
|
||||
|
||||
public void plusFeeCharges(Money feeCharges) {
|
||||
this.feeCharges = this.feeCharges.plus(feeCharges);
|
||||
}
|
||||
|
||||
public void plusPenaltyCharges(Money penaltyCharges) {
|
||||
this.penaltyCharges = this.penaltyCharges.plus(penaltyCharges);
|
||||
}
|
||||
|
||||
}
|
||||
+11
-11
@@ -109,6 +109,7 @@ import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.OutstandingAmountsDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
|
||||
@@ -4368,8 +4369,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
loanRepaymentScheduleTransactionProcessor, generatorDTO.getRecalculateFrom());
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final ScheduleGeneratorDTO scheduleGeneratorDTO, final LocalDate onDate) {
|
||||
LoanRepaymentScheduleInstallment installment;
|
||||
public OutstandingAmountsDTO fetchPrepaymentDetail(final ScheduleGeneratorDTO scheduleGeneratorDTO, final LocalDate onDate) {
|
||||
OutstandingAmountsDTO outstandingAmounts;
|
||||
|
||||
if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled()) {
|
||||
final MathContext mc = MoneyHelper.getMathContext();
|
||||
@@ -4381,12 +4382,12 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
.create(loanApplicationTerms.getLoanScheduleType(), interestMethod);
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||
installment = loanScheduleGenerator.calculatePrepaymentAmount(getCurrency(), onDate, loanApplicationTerms, mc, this,
|
||||
outstandingAmounts = loanScheduleGenerator.calculatePrepaymentAmount(getCurrency(), onDate, loanApplicationTerms, mc, this,
|
||||
scheduleGeneratorDTO.getHolidayDetailDTO(), loanRepaymentScheduleTransactionProcessor);
|
||||
} else {
|
||||
installment = this.getTotalOutstandingOnLoan();
|
||||
outstandingAmounts = this.getTotalOutstandingOnLoan();
|
||||
}
|
||||
return installment;
|
||||
return outstandingAmounts;
|
||||
}
|
||||
|
||||
public LoanApplicationTerms constructLoanApplicationTerms(final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||
@@ -4460,11 +4461,11 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
return annualNominalInterestRate;
|
||||
}
|
||||
|
||||
private LoanRepaymentScheduleInstallment getTotalOutstandingOnLoan() {
|
||||
Money feeCharges = Money.zero(loanCurrency());
|
||||
Money penaltyCharges = Money.zero(loanCurrency());
|
||||
private OutstandingAmountsDTO getTotalOutstandingOnLoan() {
|
||||
Money totalPrincipal = Money.zero(loanCurrency());
|
||||
Money totalInterest = Money.zero(loanCurrency());
|
||||
Money feeCharges = Money.zero(loanCurrency());
|
||||
Money penaltyCharges = Money.zero(loanCurrency());
|
||||
final Set<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
|
||||
List<LoanRepaymentScheduleInstallment> repaymentSchedule = getRepaymentScheduleInstallments();
|
||||
for (final LoanRepaymentScheduleInstallment scheduledRepayment : repaymentSchedule) {
|
||||
@@ -4473,9 +4474,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
feeCharges = feeCharges.plus(scheduledRepayment.getFeeChargesOutstanding(loanCurrency()));
|
||||
penaltyCharges = penaltyCharges.plus(scheduledRepayment.getPenaltyChargesOutstanding(loanCurrency()));
|
||||
}
|
||||
LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||
return new LoanRepaymentScheduleInstallment(null, 0, businessDate, businessDate, totalPrincipal.getAmount(),
|
||||
totalInterest.getAmount(), feeCharges.getAmount(), penaltyCharges.getAmount(), false, compoundingDetails);
|
||||
return new OutstandingAmountsDTO(totalPrincipal.getCurrency()).principal(totalPrincipal).interest(totalInterest)
|
||||
.feeCharges(feeCharges).penaltyCharges(penaltyCharges);
|
||||
}
|
||||
|
||||
public LocalDate fetchInterestRecalculateFromDate() {
|
||||
|
||||
+6
-6
@@ -583,20 +583,20 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
||||
return interestPortionOfTransaction;
|
||||
}
|
||||
|
||||
public Money payPrincipalComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
public Money payPrincipalComponent(final LocalDate transactionDate, final Money transactionAmount) {
|
||||
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
final MonetaryCurrency currency = transactionAmount.getCurrency();
|
||||
Money principalPortionOfTransaction = Money.zero(currency);
|
||||
if (transactionAmountRemaining.isZero()) {
|
||||
if (transactionAmount.isZero()) {
|
||||
return principalPortionOfTransaction;
|
||||
}
|
||||
final Money principalDue = getPrincipalOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(principalDue)) {
|
||||
if (transactionAmount.isGreaterThanOrEqualTo(principalDue)) {
|
||||
this.principalCompleted = getPrincipalCompleted(currency).plus(principalDue).getAmount();
|
||||
principalPortionOfTransaction = principalPortionOfTransaction.plus(principalDue);
|
||||
} else {
|
||||
this.principalCompleted = getPrincipalCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
||||
principalPortionOfTransaction = principalPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
this.principalCompleted = getPrincipalCompleted(currency).plus(transactionAmount).getAmount();
|
||||
principalPortionOfTransaction = principalPortionOfTransaction.plus(transactionAmount);
|
||||
}
|
||||
|
||||
this.principalCompleted = defaultToNullIfZero(this.principalCompleted);
|
||||
|
||||
+9
-6
@@ -45,6 +45,7 @@ import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.OutstandingAmountsDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
@@ -2775,7 +2776,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
* Method returns the amount payable to close the loan account as of today.
|
||||
*/
|
||||
@Override
|
||||
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(final MonetaryCurrency currency, final LocalDate onDate,
|
||||
public OutstandingAmountsDTO calculatePrepaymentAmount(final MonetaryCurrency currency, final LocalDate onDate,
|
||||
final LoanApplicationTerms loanApplicationTerms, final MathContext mc, Loan loan, final HolidayDetailDTO holidayDetailDTO,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
|
||||
|
||||
@@ -2790,10 +2791,10 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
|
||||
loanRepaymentScheduleTransactionProcessor.reprocessLoanTransactions(loanApplicationTerms.getExpectedDisbursementDate(),
|
||||
loanTransactions, currency, loanScheduleDTO.getInstallments(), loan.getActiveCharges());
|
||||
Money feeCharges = Money.zero(currency);
|
||||
Money penaltyCharges = Money.zero(currency);
|
||||
Money totalPrincipal = Money.zero(currency);
|
||||
Money totalInterest = Money.zero(currency);
|
||||
Money feeCharges = Money.zero(currency);
|
||||
Money penaltyCharges = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment currentInstallment : loanScheduleDTO.getInstallments()) {
|
||||
if (currentInstallment.isNotFullyPaidOff()) {
|
||||
totalPrincipal = totalPrincipal.plus(currentInstallment.getPrincipalOutstanding(currency));
|
||||
@@ -2802,8 +2803,10 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
penaltyCharges = penaltyCharges.plus(currentInstallment.getPenaltyChargesOutstanding(currency));
|
||||
}
|
||||
}
|
||||
final Set<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
|
||||
return new LoanRepaymentScheduleInstallment(null, 0, onDate, onDate, totalPrincipal.getAmount(), totalInterest.getAmount(),
|
||||
feeCharges.getAmount(), penaltyCharges.getAmount(), false, compoundingDetails);
|
||||
return new OutstandingAmountsDTO(currency) //
|
||||
.principal(totalPrincipal) //
|
||||
.interest(totalInterest) //
|
||||
.feeCharges(feeCharges) //
|
||||
.penaltyCharges(penaltyCharges);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -23,9 +23,9 @@ import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.OutstandingAmountsDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
|
||||
|
||||
@@ -38,8 +38,8 @@ public interface LoanScheduleGenerator {
|
||||
HolidayDetailDTO holidayDetailDTO, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||
LocalDate rescheduleFrom);
|
||||
|
||||
LoanRepaymentScheduleInstallment calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate,
|
||||
LoanApplicationTerms loanApplicationTerms, MathContext mc, Loan loan, HolidayDetailDTO holidayDetailDTO,
|
||||
OutstandingAmountsDTO calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms,
|
||||
MathContext mc, Loan loan, HolidayDetailDTO holidayDetailDTO,
|
||||
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user