FINERACT-1883 - New loan repayment parameter
- [x] New loan repayment parameter - [x] Integration test
This commit is contained in:
committed by
Arnold Gálovics
parent
670e0d55a3
commit
764f3de203
@@ -66,6 +66,22 @@
|
||||
"null",
|
||||
"bigdecimal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "lastRepaymentDate",
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "lastRepaymentAmount",
|
||||
"type": [
|
||||
"null",
|
||||
"bigdecimal"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+10
-4
@@ -112,10 +112,16 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
|
||||
collectionData.setAvailableDisbursementAmount(loan.getApprovedPrincipal().subtract(loan.getDisbursedAmount()));
|
||||
collectionData.setNextPaymentDueDate(loan.possibleNextRepaymentDate());
|
||||
|
||||
final LoanTransaction lastRepaymenTransaction = loan.getLastRepaymentTransaction();
|
||||
if (lastRepaymenTransaction != null) {
|
||||
collectionData.setLastPaymentDate(lastRepaymenTransaction.getTransactionDate());
|
||||
collectionData.setLastPaymentAmount(lastRepaymenTransaction.getAmount());
|
||||
final LoanTransaction lastPayment = loan.getLastPaymentTransaction();
|
||||
if (lastPayment != null) {
|
||||
collectionData.setLastPaymentDate(lastPayment.getTransactionDate());
|
||||
collectionData.setLastPaymentAmount(lastPayment.getAmount());
|
||||
}
|
||||
|
||||
final LoanTransaction lastRepaymentTransaction = loan.getLastRepaymentTransaction();
|
||||
if (lastRepaymentTransaction != null) {
|
||||
collectionData.setLastRepaymentDate(lastRepaymentTransaction.getTransactionDate());
|
||||
collectionData.setLastRepaymentAmount(lastRepaymentTransaction.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -979,6 +979,11 @@ final class LoansApiResourceSwagger {
|
||||
public LocalDate lastPaymentDate;
|
||||
@Schema(example = "100.000000")
|
||||
public Double lastPaymentAmount;
|
||||
|
||||
@Schema(example = "[2022, 07, 01]")
|
||||
public LocalDate lastRepaymentDate;
|
||||
@Schema(example = "100.000000")
|
||||
public Double lastRepaymentAmount;
|
||||
}
|
||||
|
||||
@Schema(example = "1")
|
||||
|
||||
+4
-1
@@ -40,9 +40,12 @@ public final class CollectionData {
|
||||
private LocalDate lastPaymentDate;
|
||||
private BigDecimal lastPaymentAmount;
|
||||
|
||||
private LocalDate lastRepaymentDate;
|
||||
private BigDecimal lastRepaymentAmount;
|
||||
|
||||
public static CollectionData template() {
|
||||
final BigDecimal zero = BigDecimal.ZERO;
|
||||
return new CollectionData(zero, 0L, null, 0L, null, zero, null, zero);
|
||||
return new CollectionData(zero, 0L, null, 0L, null, zero, null, zero, null, zero);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+22
-14
@@ -3217,7 +3217,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
addLoanTransaction(loanTransaction);
|
||||
}
|
||||
|
||||
if (loanTransaction.isNotRepaymentType() && loanTransaction.isNotWaiver() && loanTransaction.isNotRecoveryRepayment()) {
|
||||
if (loanTransaction.isNotRepaymentLikeType() && loanTransaction.isNotWaiver() && loanTransaction.isNotRecoveryRepayment()) {
|
||||
final String errorMessage = "A transaction of type repayment or recovery repayment or waiver was expected but not received.";
|
||||
throw new InvalidLoanTransactionTypeException("transaction", "is.not.a.repayment.or.waiver.or.recovery.transaction",
|
||||
errorMessage);
|
||||
@@ -3604,7 +3604,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
final LocalDate currentTransactionDate = loanTransaction.getTransactionDate();
|
||||
for (final LoanTransaction previousTransaction : loanTransactions) {
|
||||
if (previousTransaction.isRepaymentType() && previousTransaction.isNotReversed()
|
||||
if (previousTransaction.isRepaymentLikeType() && previousTransaction.isNotReversed()
|
||||
&& currentTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
|
||||
isAfterLatRepayment = false;
|
||||
break;
|
||||
@@ -3642,7 +3642,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
LocalDate lastTransactionDate = null;
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
if (transaction.isRepaymentType() && transaction.isNonZero()) {
|
||||
if (transaction.isRepaymentLikeType() && transaction.isNonZero()) {
|
||||
lastTransactionDate = transaction.getTransactionDate();
|
||||
}
|
||||
}
|
||||
@@ -3714,7 +3714,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
|
||||
transactionForAdjustment.getTransactionDate());
|
||||
|
||||
if (transactionForAdjustment.isNotRepaymentType() && transactionForAdjustment.isNotWaiver()
|
||||
if (transactionForAdjustment.isNotRepaymentLikeType() && transactionForAdjustment.isNotWaiver()
|
||||
&& transactionForAdjustment.isNotCreditBalanceRefund()) {
|
||||
final String errorMessage = "Only (non-reversed) transactions of type repayment, waiver or credit balance refund can be adjusted.";
|
||||
throw new InvalidLoanTransactionTypeException("transaction",
|
||||
@@ -3734,7 +3734,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
loanLifecycleStateMachine.transition(LoanEvent.LOAN_ADJUST_TRANSACTION, this);
|
||||
}
|
||||
|
||||
if (newTransactionDetail.isRepaymentType() || newTransactionDetail.isInterestWaiver()) {
|
||||
if (newTransactionDetail.isRepaymentLikeType() || newTransactionDetail.isInterestWaiver()) {
|
||||
changedTransactionDetail = handleRepaymentOrRecoveryOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine,
|
||||
transactionForAdjustment, scheduleGeneratorDTO);
|
||||
}
|
||||
@@ -4227,7 +4227,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
Money cumulativePaid = Money.zero(loanCurrency());
|
||||
|
||||
for (final LoanTransaction repayment : this.loanTransactions) {
|
||||
if (repayment.isRepaymentType() && !repayment.isReversed()) {
|
||||
if (repayment.isRepaymentLikeType() && !repayment.isReversed()) {
|
||||
cumulativePaid = cumulativePaid.plus(repayment.getAmount(loanCurrency()));
|
||||
}
|
||||
}
|
||||
@@ -4550,7 +4550,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
&& !transaction.getTransactionDate().isAfter(tillDate)) {
|
||||
if (transaction.isAccrual()) {
|
||||
receivableInterest = receivableInterest.plus(transaction.getInterestPortion(getCurrency()));
|
||||
} else if (transaction.isRepaymentType() || transaction.isInterestWaiver()) {
|
||||
} else if (transaction.isRepaymentLikeType() || transaction.isInterestWaiver()) {
|
||||
receivableInterest = receivableInterest.minus(transaction.getInterestPortion(getCurrency()));
|
||||
}
|
||||
}
|
||||
@@ -4942,7 +4942,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
public void validateRepaymentTypeTransactionNotBeforeAChargeRefund(final LoanTransaction repaymentTransaction,
|
||||
final String reversedOrCreated) {
|
||||
if (repaymentTransaction.isRepaymentType() && !repaymentTransaction.isChargeRefund()) {
|
||||
if (repaymentTransaction.isRepaymentLikeType() && !repaymentTransaction.isChargeRefund()) {
|
||||
for (LoanTransaction txn : this.getLoanTransactions()) {
|
||||
if (txn.isChargeRefund() && repaymentTransaction.getTransactionDate().isBefore(txn.getTransactionDate())) {
|
||||
final String errorMessage = "loan.transaction.cant.be." + reversedOrCreated + ".because.later.charge.refund.exists";
|
||||
@@ -4968,17 +4968,25 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
public LocalDate getLastRepaymentDate() {
|
||||
LocalDate currentTransactionDate = getDisbursementDate();
|
||||
for (final LoanTransaction previousTransaction : this.loanTransactions) {
|
||||
if (previousTransaction.isRepaymentType() && currentTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
|
||||
if (previousTransaction.isRepaymentLikeType() && currentTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
|
||||
currentTransactionDate = previousTransaction.getTransactionDate();
|
||||
}
|
||||
}
|
||||
return currentTransactionDate;
|
||||
}
|
||||
|
||||
public LoanTransaction getLastPaymentTransaction() {
|
||||
return loanTransactions.stream() //
|
||||
.filter(loanTransaction -> !loanTransaction.isReversed()) //
|
||||
.filter(LoanTransaction::isRepaymentLikeType) //
|
||||
.reduce((first, second) -> second) //
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public LoanTransaction getLastRepaymentTransaction() {
|
||||
return loanTransactions.stream() //
|
||||
.filter(loanTransaction -> !loanTransaction.isReversed()) //
|
||||
.filter(LoanTransaction::isRepaymentType) //
|
||||
.filter(LoanTransaction::isRepayment) //
|
||||
.reduce((first, second) -> second) //
|
||||
.orElse(null);
|
||||
}
|
||||
@@ -6300,7 +6308,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
LocalDate lastTransactionDate = null;
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
if ((transaction.isRepaymentType() || transaction.isRefundForActiveLoan() || transaction.isCreditBalanceRefund())
|
||||
if ((transaction.isRepaymentLikeType() || transaction.isRefundForActiveLoan() || transaction.isCreditBalanceRefund())
|
||||
&& transaction.isNonZero() && transaction.isNotReversed()) {
|
||||
lastTransactionDate = transaction.getTransactionDate();
|
||||
}
|
||||
@@ -6349,8 +6357,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
loanTransactions = retrieveListOfTransactionsExcludeAccruals();
|
||||
Collections.reverse(loanTransactions);
|
||||
for (final LoanTransaction previousTransaction : loanTransactions) {
|
||||
if (lastTransactionDate.isBefore(previousTransaction.getTransactionDate())
|
||||
&& (previousTransaction.isRepaymentType() || previousTransaction.isWaiver() || previousTransaction.isChargePayment())) {
|
||||
if (lastTransactionDate.isBefore(previousTransaction.getTransactionDate()) && (previousTransaction.isRepaymentLikeType()
|
||||
|| previousTransaction.isWaiver() || previousTransaction.isChargePayment())) {
|
||||
throw new UndoLastTrancheDisbursementException(previousTransaction.getId());
|
||||
}
|
||||
if (previousTransaction.getId().compareTo(lastDisbursalTransaction.getId()) < 0) {
|
||||
@@ -6673,7 +6681,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
receivableInterest = receivableInterest.plus(transaction.getInterestPortion(currency));
|
||||
receivableFee = receivableFee.plus(transaction.getFeeChargesPortion(currency));
|
||||
receivablePenalty = receivablePenalty.plus(transaction.getPenaltyChargesPortion(currency));
|
||||
} else if (transaction.isRepaymentType() || transaction.isChargePayment()) {
|
||||
} else if (transaction.isRepaymentLikeType() || transaction.isChargePayment()) {
|
||||
receivableInterest = receivableInterest.minus(transaction.getInterestPortion(currency));
|
||||
receivableFee = receivableFee.minus(transaction.getFeeChargesPortion(currency));
|
||||
receivablePenalty = receivablePenalty.minus(transaction.getPenaltyChargesPortion(currency));
|
||||
|
||||
+3
-3
@@ -562,7 +562,7 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
this.manuallyAdjustedOrReversed = true;
|
||||
}
|
||||
|
||||
public boolean isRepaymentType() {
|
||||
public boolean isRepaymentLikeType() {
|
||||
return isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() || isGoodwillCredit() || isChargeRefund()
|
||||
|| isChargeAdjustment();
|
||||
}
|
||||
@@ -591,8 +591,8 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
return LoanTransactionType.CHARGE_ADJUSTMENT.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isNotRepaymentType() {
|
||||
return !isRepaymentType();
|
||||
public boolean isNotRepaymentLikeType() {
|
||||
return !isRepaymentLikeType();
|
||||
}
|
||||
|
||||
public boolean isIncomePosting() {
|
||||
|
||||
+4
-4
@@ -165,7 +165,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
Collections.sort(installments, byDate);
|
||||
}
|
||||
|
||||
if (loanTransaction.isRepaymentType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||
if (loanTransaction.isRepaymentLikeType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||
// pass through for new transactions
|
||||
if (loanTransaction.getId() == null) {
|
||||
handleTransaction(loanTransaction, currency, installments, charges);
|
||||
@@ -306,7 +306,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
totalPaidInRepayments = totalPaidInRepayments.minus(transaction.getAmount(currency));
|
||||
} else if (transaction.isCreditBalanceRefund() || transaction.isChargeback()) {
|
||||
totalPaidInRepayments = totalPaidInRepayments.minus(transaction.getOverPaymentPortion(currency));
|
||||
} else if (transaction.isRepaymentType()) {
|
||||
} else if (transaction.isRepaymentLikeType()) {
|
||||
totalPaidInRepayments = totalPaidInRepayments.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -428,7 +428,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges, final Money chargeAmountToProcess,
|
||||
final boolean isFeeCharge) {
|
||||
// to.
|
||||
if (loanTransaction.isRepaymentType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||
if (loanTransaction.isRepaymentLikeType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||
loanTransaction.resetDerivedComponents();
|
||||
}
|
||||
Money transactionAmountUnprocessed = processTransaction(loanTransaction, currency, installments, chargeAmountToProcess);
|
||||
@@ -686,7 +686,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
Money unProcessed = Money.zero(currency);
|
||||
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
||||
Money amountToProcess = null;
|
||||
if (loanTransaction.isRepaymentType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||
if (loanTransaction.isRepaymentLikeType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||
loanTransaction.resetDerivedComponents();
|
||||
}
|
||||
if (loanTransaction.isInterestWaiver()) {
|
||||
|
||||
+1
-1
@@ -1197,7 +1197,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
||||
|
||||
LoanAdjustTransactionBusinessEvent.Data eventData = new LoanAdjustTransactionBusinessEvent.Data(transactionToAdjust);
|
||||
if (newTransactionDetail.isRepaymentType() && thereIsNewTransaction) {
|
||||
if (newTransactionDetail.isRepaymentLikeType() && thereIsNewTransaction) {
|
||||
eventData.setNewTransactionDetail(newTransactionDetail);
|
||||
}
|
||||
Long entityId = transactionToAdjust.getId();
|
||||
|
||||
+2
-1
@@ -115,7 +115,8 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
||||
LocalDate overDueSinceDate = DateUtils.getBusinessLocalDate().minusDays(2);
|
||||
LoanScheduleDelinquencyData loanScheduleDelinquencyData = new LoanScheduleDelinquencyData(1L, overDueSinceDate, 1L,
|
||||
loanForProcessing);
|
||||
CollectionData collectionData = new CollectionData(BigDecimal.ZERO, 2L, null, 2L, overDueSinceDate, BigDecimal.ZERO, null, null);
|
||||
CollectionData collectionData = new CollectionData(BigDecimal.ZERO, 2L, null, 2L, overDueSinceDate, BigDecimal.ZERO, null, null,
|
||||
null, null);
|
||||
|
||||
when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct);
|
||||
when(loanProduct.getDelinquencyBucket()).thenReturn(delinquencyBucket);
|
||||
|
||||
+5
-2
@@ -224,7 +224,7 @@ public class LoanTransactionSummaryTest {
|
||||
.transactionAmount(20.0));
|
||||
|
||||
final PostLoansLoanIdTransactionsResponse repaymentTransaction_1 = loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
|
||||
new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("8 September 2022").locale("en")
|
||||
new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("7 September 2022").locale("en")
|
||||
.transactionAmount(100.0));
|
||||
|
||||
final PostLoansLoanIdTransactionsResponse repaymentTransaction_2 = loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
|
||||
@@ -234,8 +234,11 @@ public class LoanTransactionSummaryTest {
|
||||
// Retrieve Loan with loanId
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails((long) loanId);
|
||||
|
||||
assertEquals(100.0, loanDetails.getDelinquent().getLastPaymentAmount());
|
||||
assertEquals(20.0, loanDetails.getDelinquent().getLastPaymentAmount());
|
||||
assertEquals(LocalDate.of(2022, 9, 8), loanDetails.getDelinquent().getLastPaymentDate());
|
||||
|
||||
assertEquals(100.0, loanDetails.getDelinquent().getLastRepaymentAmount());
|
||||
assertEquals(LocalDate.of(2022, 9, 7), loanDetails.getDelinquent().getLastRepaymentDate());
|
||||
}
|
||||
|
||||
private GetLoanProductsProductIdResponse createLoanProduct(final LoanTransactionHelper loanTransactionHelper,
|
||||
|
||||
Reference in New Issue
Block a user