Skip to content

Commit

Permalink
SU-533 fixed interest portion issue for replayed transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
faheem205 committed Dec 24, 2024
1 parent 2a4dc4b commit 0ef9012
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1046,47 +1046,52 @@ public Money payInterestComponent(final LocalDate transactionDate, final Money t

Money interestDue = Money.zero(currency);

if (this.isMigratedInstallment) {
interestDue = getInterestOutstanding(currency);
} else if (isOn(transactionDate, this.getDueDate())) {
interestDue = getInterestOutstanding(currency);
} else if (isOnOrBetween(transactionDate) && getInterestOutstanding(currency).isGreaterThanZero()) {
final RoundingMode roundingMode = RoundingMode.HALF_UP;

BigDecimal numberOfDaysForInterestCalculation = BigDecimal.ZERO;
if (this.interestRecalculatedOnDate != null) {
if (this.interestRecalculatedOnDate.isAfter(transactionDate)) { // This should only be true if the
// repayment is reversed
if (loanTransaction.interestPaidByOriginalTransaction().compareTo(BigDecimal.ZERO) > 0) {
// SU-533 Avoid reprocessing of transaction paying different amount than originally paid.
interestDue = interestDue.plus(loanTransaction.interestPaidByOriginalTransaction());
} else {
if (this.isMigratedInstallment) {
interestDue = getInterestOutstanding(currency);
} else if (isOn(transactionDate, this.getDueDate())) {
interestDue = getInterestOutstanding(currency);
} else if (isOnOrBetween(transactionDate) && getInterestOutstanding(currency).isGreaterThanZero()) {
final RoundingMode roundingMode = RoundingMode.HALF_UP;

BigDecimal numberOfDaysForInterestCalculation = BigDecimal.ZERO;
if (this.interestRecalculatedOnDate != null) {
if (this.interestRecalculatedOnDate.isAfter(transactionDate)) { // This should only be true if the
// repayment is reversed
numberOfDaysForInterestCalculation = BigDecimal.valueOf(ChronoUnit.DAYS.between(this.fromDate, transactionDate));
} else {
numberOfDaysForInterestCalculation = BigDecimal
.valueOf(ChronoUnit.DAYS.between(this.interestRecalculatedOnDate, transactionDate));
}
} else {
numberOfDaysForInterestCalculation = BigDecimal.valueOf(ChronoUnit.DAYS.between(this.fromDate, transactionDate));
}
BigDecimal numberOfDaysInPeriod = BigDecimal.valueOf(ChronoUnit.DAYS.between(this.fromDate, this.dueDate));
BigDecimal oneDayOfInterest = this.interestCharged.divide(numberOfDaysInPeriod, RoundingMode.HALF_UP);
oneDayOfInterest = oneDayOfInterest.setScale(5, roundingMode);
interestDue = Money.of(currency, oneDayOfInterest.multiply(numberOfDaysForInterestCalculation));
if (interestDue.isGreaterThan(getInterestOutstanding(currency))) {
interestDue = getInterestOutstanding(currency);
}

//// Update installment interest charged if principal is fully paid during the accrual period
// Keep the original interest charged in case the transaction is rollbacked and interest charged needs
//// to be moved to original amount.
this.interestRecalculatedOnDate = transactionDate;
if (this.getPrincipalOutstanding(currency).isZero()) {
this.originalInterestChargedAmount = this.interestCharged;
this.interestCharged = getInterestPaid(currency).plus(getInterestWaived(currency)).plus(getInterestWrittenOff(currency))
.plus(interestDue).getAmount();
} else {
numberOfDaysForInterestCalculation = BigDecimal
.valueOf(ChronoUnit.DAYS.between(this.interestRecalculatedOnDate, transactionDate));
this.originalInterestChargedAmount = BigDecimal.ZERO;
}
} else {
numberOfDaysForInterestCalculation = BigDecimal.valueOf(ChronoUnit.DAYS.between(this.fromDate, transactionDate));
}
BigDecimal numberOfDaysInPeriod = BigDecimal.valueOf(ChronoUnit.DAYS.between(this.fromDate, this.dueDate));
BigDecimal oneDayOfInterest = this.interestCharged.divide(numberOfDaysInPeriod, RoundingMode.HALF_UP);
oneDayOfInterest = oneDayOfInterest.setScale(5, roundingMode);
interestDue = Money.of(currency, oneDayOfInterest.multiply(numberOfDaysForInterestCalculation));
if (interestDue.isGreaterThan(getInterestOutstanding(currency))) {
interestDue = getInterestOutstanding(currency);
}

//// Update installment interest charged if principal is fully paid during the accrual period
// Keep the original interest charged in case the transaction is rollbacked and interest charged needs
//// to be moved to original amount.
this.interestRecalculatedOnDate = transactionDate;
if (this.getPrincipalOutstanding(currency).isZero()) {
this.originalInterestChargedAmount = this.interestCharged;
this.interestCharged = getInterestPaid(currency).plus(getInterestWaived(currency)).plus(getInterestWrittenOff(currency))
.plus(interestDue).getAmount();
} else {
this.originalInterestChargedAmount = BigDecimal.ZERO;
interestDue = getInterestOutstanding(currency);
}

} else {
interestDue = getInterestOutstanding(currency);
}

if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ protected LoanTransaction() {}
@Transient
List<LoanChargePaidByData> chargesPaidByOriginalTransaction;

@Transient
private BigDecimal interestPaidByOriginalTransaction;

public static LoanTransaction incomePosting(final Loan loan, final Office office, final LocalDate dateOf, final BigDecimal amount,
final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion,
final ExternalId externalId) {
Expand Down Expand Up @@ -329,6 +332,7 @@ public static LoanTransaction copyTransactionProperties(final LoanTransaction lo
// SU-533 set amounts paid by original transaction so that copied transaction also pays the same amounts
// to avoid rollbacks
newTransaction.setChargesPaidByOriginalTransaction(getLoanChargePaidByDataList(loanTransaction.getLoanChargesPaid()));
newTransaction.setInterestPaidByOriginalTransaction(loanTransaction.getInterestPortion());
return newTransaction;
}

Expand Down Expand Up @@ -1160,6 +1164,14 @@ public void setChargesPaidByOriginalTransaction(List<LoanChargePaidByData> charg
this.chargesPaidByOriginalTransaction = chargesPaidByOriginalTransaction;
}

public BigDecimal interestPaidByOriginalTransaction() {
return Objects.requireNonNullElse(interestPaidByOriginalTransaction, BigDecimal.ZERO);
}

public void setInterestPaidByOriginalTransaction(BigDecimal interestPaidByOriginalTransaction) {
this.interestPaidByOriginalTransaction = interestPaidByOriginalTransaction;
}

private static List<LoanChargePaidByData> getLoanChargePaidByDataList(Set<LoanChargePaidBy> originalList) {
List<LoanChargePaidByData> list = new ArrayList<>();
if (originalList != null && !originalList.isEmpty()) {
Expand Down

0 comments on commit 0ef9012

Please sign in to comment.