Skip to content

Commit

Permalink
FINERACT-1981: pay-off transaction for progressive loans
Browse files Browse the repository at this point in the history
  • Loading branch information
kjozsa committed Aug 14, 2024
1 parent c70007e commit f871058
Show file tree
Hide file tree
Showing 9 changed files with 258 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
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);
}

}


Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
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;
Expand Down Expand Up @@ -4366,8 +4367,8 @@ private LoanScheduleDTO getRecalculatedSchedule(final ScheduleGeneratorDTO gener
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();
Expand All @@ -4379,12 +4380,12 @@ public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final ScheduleGene
.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) {
Expand Down Expand Up @@ -4458,11 +4459,11 @@ public BigDecimal constructLoanTermVariations(FloatingRateDTO floatingRateDTO, B
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) {
Expand All @@ -4471,9 +4472,11 @@ private LoanRepaymentScheduleInstallment getTotalOutstandingOnLoan() {
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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,20 +583,20 @@ public Money payInterestComponent(final LocalDate transactionDate, final Money t
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
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;
Expand Down Expand Up @@ -2775,9 +2776,9 @@ private LocalDate getNextCompoundScheduleDate(LocalDate startDate, LoanApplicati
* Method returns the amount payable to close the loan account as of today.
*/
@Override
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(final MonetaryCurrency currency, final LocalDate onDate,
final LoanApplicationTerms loanApplicationTerms, final MathContext mc, Loan loan, final HolidayDetailDTO holidayDetailDTO,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
public OutstandingAmountsDTO calculatePrepaymentAmount(final MonetaryCurrency currency, final LocalDate onDate,
final LoanApplicationTerms loanApplicationTerms, final MathContext mc, Loan loan, final HolidayDetailDTO holidayDetailDTO,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {

LocalDate calculateTill = onDate;
if (loanApplicationTerms.getPreClosureInterestCalculationStrategy().calculateTillRestFrequencyEnabled()) {
Expand All @@ -2790,10 +2791,10 @@ public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(final Monetary

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));
Expand All @@ -2802,8 +2803,10 @@ public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(final Monetary
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
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;
Expand All @@ -38,8 +39,8 @@ LoanScheduleDTO rescheduleNextInstallments(MathContext mc, LoanApplicationTerms
HolidayDetailDTO holidayDetailDTO, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
LocalDate rescheduleFrom);

LoanRepaymentScheduleInstallment calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate,
LoanApplicationTerms loanApplicationTerms, MathContext mc, Loan loan, HolidayDetailDTO holidayDetailDTO,
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor);
OutstandingAmountsDTO calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate,
LoanApplicationTerms loanApplicationTerms, MathContext mc, Loan loan, HolidayDetailDTO holidayDetailDTO,
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor);

}
Loading

0 comments on commit f871058

Please sign in to comment.