Skip to content

Commit

Permalink
FBR-737 Manage Early payment accrual interest and income interest jou…
Browse files Browse the repository at this point in the history
  • Loading branch information
Deepika1095 authored Dec 20, 2024
1 parent c693d3d commit 277448a
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public class LoanTransactionDTO {
/*** Breakup of amounts in case of repayments **/
private final BigDecimal principal;
private final BigDecimal interest;
private final BigDecimal incomeInterest;
private final BigDecimal receivableInterest;
private final BigDecimal fees;
private final BigDecimal penalties;
private final BigDecimal overPayment;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ public LoanDTO populateLoanDtoFromMap(final Map<String, Object> accountingBridge
final BigDecimal amount = (BigDecimal) map.get("amount");
final BigDecimal principal = (BigDecimal) map.get("principalPortion");
final BigDecimal interest = (BigDecimal) map.get("interestPortion");
final BigDecimal incomeInterest = (BigDecimal) map.get("incomeInterestPortion");
final BigDecimal receivableInterest = (BigDecimal) map.get("receivableInterestPortion");
final BigDecimal fees = (BigDecimal) map.get("feeChargesPortion");
final BigDecimal penalties = (BigDecimal) map.get("penaltyChargesPortion");
final BigDecimal overPayments = (BigDecimal) map.get("overPaymentPortion");
Expand Down Expand Up @@ -154,7 +156,7 @@ public LoanDTO populateLoanDtoFromMap(final Map<String, Object> accountingBridge
PortfolioAccountType.LOAN);
}
final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionOfficeId, paymentTypeId, transactionId,
transactionDate, transactionType, amount, principal, interest, fees, penalties, overPayments, reversed,
transactionDate, transactionType, amount, principal, interest, incomeInterest, receivableInterest , fees, penalties, overPayments, reversed,
penaltyPaymentDetails, feePaymentDetails, isAccountTransfer);
transaction.setGlAccountId(transactionGlAccountId != null ? transactionGlAccountId : glAccountId);
Boolean isLoanToLoanTransfer = (Boolean) accountingBridgeData.get("isLoanToLoanTransfer");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ private void createJournalEntriesForRepaymentsAndWriteOffs(final LoanDTO loanDTO
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
final BigDecimal incomeInterestAmount = loanTransactionDTO.getIncomeInterest();
final BigDecimal receivableInterest = loanTransactionDTO.getReceivableInterest();
final BigDecimal feesAmount = loanTransactionDTO.getFees();
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
Expand All @@ -205,16 +207,39 @@ private void createJournalEntriesForRepaymentsAndWriteOffs(final LoanDTO loanDTO
// handle interest payment of writeOff (and reversals)
if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(interestAmount);
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), paymentTypeId);
if (accountMap.containsKey(account)) {
BigDecimal amount = accountMap.get(account).add(interestAmount);
accountMap.put(account, amount);

if ((incomeInterestAmount !=null && incomeInterestAmount.compareTo(BigDecimal.ZERO) > 0)
&& (receivableInterest != null && receivableInterest.compareTo(BigDecimal.ZERO) > 0)) {
GLAccount incomeAccount = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), paymentTypeId);
if (accountMap.containsKey(incomeAccount)) {
BigDecimal amount = accountMap.get(incomeAccount).add(incomeInterestAmount);
accountMap.put(incomeAccount, amount);
} else {
accountMap.put(incomeAccount, incomeInterestAmount);
}
GLAccount receivableAccount = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), paymentTypeId);
if (accountMap.containsKey(receivableAccount)) {
BigDecimal amount = accountMap.get(receivableAccount).add(receivableInterest);
accountMap.put(receivableAccount, amount);
} else {
accountMap.put(receivableAccount, receivableInterest);
}

} else {
accountMap.put(account, interestAmount);
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), paymentTypeId);
if (accountMap.containsKey(account)) {
BigDecimal amount = accountMap.get(account).add(interestAmount);
accountMap.put(account, amount);
} else {
accountMap.put(account, interestAmount);
}
}
}


// handle fees payment of writeOff (and reversals)
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
Expand Down Expand Up @@ -76,6 +78,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
private BigDecimal interestWrittenOff;

@Column(name = "accrual_interest_derived", scale = 6, precision = 19, nullable = true)
@Setter
private BigDecimal interestAccrued;

@Column(name = "reschedule_interest_portion", scale = 6, precision = 19, nullable = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.persistence.Transient;

import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
Expand Down Expand Up @@ -121,6 +124,14 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "loanTransaction")
private Set<LoanTransactionToRepaymentScheduleMapping> loanTransactionToRepaymentScheduleMappings = new HashSet<>();

@Transient
@Setter
private BigDecimal incomeInterestPortion;

@Transient
@Setter
private BigDecimal receivableInterestPortion;

protected LoanTransaction() {}

public static LoanTransaction incomePosting(final Loan loan, final Office office, final LocalDate dateOf, final BigDecimal amount,
Expand Down Expand Up @@ -641,6 +652,8 @@ public Map<String, Object> toMapData(final CurrencyData currencyData) {
thisTransactionData.put("netDisbursalAmount", this.loan.getNetDisbursalAmount());
thisTransactionData.put("principalPortion", this.principalPortion);
thisTransactionData.put("interestPortion", this.interestPortion);
thisTransactionData.put("incomeInterestPortion", this.incomeInterestPortion);
thisTransactionData.put("receivableInterestPortion", this.receivableInterestPortion);
thisTransactionData.put("feeChargesPortion", this.feeChargesPortion);
thisTransactionData.put("penaltyChargesPortion", this.penaltyChargesPortion);
thisTransactionData.put("overPaymentPortion", this.overPaymentPortion);
Expand Down Expand Up @@ -819,4 +832,12 @@ public LocalDate getSubmittedOnDate() {

// TODO missing hashCode(), equals(Object obj), but probably OK as long as
// this is never stored in a Collection.

public Money getIncomeInterestPortion(final MonetaryCurrency currency) {
return Money.of(currency, this.incomeInterestPortion);
}

public Money getReceivableInterestPortion(final MonetaryCurrency currency) {
return Money.of(currency, this.receivableInterestPortion);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ protected Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepa
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);

interestPortion = currentInstallment.payInterestComponent(transactionDate, transactionAmountRemaining);
if (!currentInstallment.getDueDate().isBefore(transactionDate)
&& currentInstallment.getInterestAccrued(transactionAmountRemaining.getCurrency()).isGreaterThanZero()) {
loanTransaction.setIncomeInterestPortion(loanTransaction.getIncomeInterestPortion(transactionAmountRemaining.getCurrency())
.plus(interestPortion
.minus(currentInstallment.getInterestAccrued(transactionAmountRemaining.getCurrency())).getAmount())
.getAmount());
loanTransaction.setReceivableInterestPortion(loanTransaction.getReceivableInterestPortion(transactionAmountRemaining.getCurrency())
.plus(currentInstallment.getInterestAccrued(transactionAmountRemaining.getCurrency()).getAmount()).getAmount());
}
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);

principalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
Expand Down Expand Up @@ -158,6 +167,15 @@ protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentS

if (transactionAmountRemaining.isGreaterThanZero()) {
interestPortion = currentInstallment.unpayInterestComponent(transactionDate, transactionAmountRemaining);
if (!currentInstallment.getDueDate().isBefore(transactionDate)
&& currentInstallment.getInterestAccrued(transactionAmountRemaining.getCurrency()).isGreaterThanZero()) {
loanTransaction.setIncomeInterestPortion(loanTransaction.getIncomeInterestPortion(transactionAmountRemaining.getCurrency())
.plus(interestPortion
.minus(currentInstallment.getInterestAccrued(transactionAmountRemaining.getCurrency())).getAmount())
.getAmount());
loanTransaction.setReceivableInterestPortion(loanTransaction.getReceivableInterestPortion(transactionAmountRemaining.getCurrency())
.plus(currentInstallment.getInterestAccrued(transactionAmountRemaining.getCurrency()).getAmount()).getAmount());
}
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
}

Expand Down

0 comments on commit 277448a

Please sign in to comment.