FINERACT-1661 Allow merchant_issued and payout refunds when fullyPaid/Overpaid

This commit is contained in:
John Woodlock
2022-07-08 14:44:45 +02:00
committed by Arnold Gálovics
parent 2bb92ae539
commit 0487bece0b
3 changed files with 60 additions and 11 deletions
@@ -3098,7 +3098,7 @@ public class Loan extends AbstractPersistableCustom {
if (!isHolidayValidationDone) {
holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO();
}
validateAccountStatus(event);
validateRepaymentTypeAccountStatus(repaymentTransaction, event);
validateActivityNotBeforeClientOrGroupTransferDate(event, repaymentTransaction.getTransactionDate());
validateActivityNotBeforeLastTransactionDate(event, repaymentTransaction.getTransactionDate());
if (!isHolidayValidationDone) {
@@ -3116,6 +3116,24 @@ public class Loan extends AbstractPersistableCustom {
return changedTransactionDetail;
}
private void validateRepaymentTypeAccountStatus(LoanTransaction repaymentTransaction, LoanEvent event) {
if (repaymentTransaction.isGoodwillCredit() || repaymentTransaction.isMerchantIssuedRefund()
|| repaymentTransaction.isPayoutRefund()) {
if (!(isOpen() || isClosedObligationsMet() || isOverPaid())) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final String defaultUserMessage = "Loan must be Active, Fully Paid or Overpaid";
final ApiParameterError error = ApiParameterError.generalError("error.msg.loan.must.be.active.fully.paid.or.overpaid",
defaultUserMessage);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException(dataValidationErrors);
}
} else {
validateAccountStatus(event);
}
}
public void makeChargePayment(final Long chargeId, final LoanLifecycleStateMachine loanLifecycleStateMachine,
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
final HolidayDetailDTO holidayDetailDTO, final LoanTransaction paymentTransaction, final Integer installmentNumber) {
@@ -62,6 +62,7 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
private Account incomeAccount;
private Account expenseAccount;
private Account overpaymentAccount;
private static final String REPAYMENT = "repayment";
private static final String MERCHANT_ISSUED_REFUND = "merchantIssuedRefund";
private static final String PAYOUT_REFUND = "payoutRefund";
private static final String GOODWILL_CREDIT = "goodwillCredit";
@@ -343,8 +344,8 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
}
private void verifyRepaymentTransactionTypeMatches(final String repaymentTransactionType) {
HashMap loanStatusHashMap = this.loanTransactionHelper.makeRepaymentTypePayment(repaymentTransactionType, "06 January 2022",
200.00f, this.disbursedLoanID);
HashMap loanStatusHashMap = (HashMap) this.loanTransactionHelper.makeRepaymentTypePayment(repaymentTransactionType,
"06 January 2022", 200.00f, this.disbursedLoanID, "");
Integer newTransactionId = (Integer) loanStatusHashMap.get("resourceId");
loanStatusHashMap = this.loanTransactionHelper.getLoanTransactionDetails(this.disbursedLoanID, newTransactionId);
@@ -353,6 +354,36 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
Assertions.assertTrue(Boolean.TRUE.equals(isTypeCorrect), "Not " + repaymentTransactionType);
}
@Test
public void repaymentTransactionTypeWhenPaidTest() {
verifyRepaymentTransactionTypeWhenPaid(MERCHANT_ISSUED_REFUND);
verifyRepaymentTransactionTypeWhenPaid(PAYOUT_REFUND);
verifyRepaymentTransactionTypeWhenPaid(GOODWILL_CREDIT);
verifyRepaymentTransactionTypeWhenPaid(REPAYMENT);
}
private void verifyRepaymentTransactionTypeWhenPaid(final String repaymentTransactionType) {
disburseLoanOfAccountingRule(ACCRUAL_PERIODIC);
// Overpay loan
Integer resourceId = (Integer) this.loanTransactionHelper.makeRepaymentTypePayment(REPAYMENT, "06 January 2022", 13000.00f,
this.disbursedLoanID, "resourceId");
Assertions.assertNotNull(resourceId);
if (repaymentTransactionType.equalsIgnoreCase(REPAYMENT)) {
ArrayList<HashMap> errors = (ArrayList<HashMap>) this.loanTransactionHelperValidationError.makeRepaymentTypePayment(
repaymentTransactionType, "06 January 2022", 1.00f, this.disbursedLoanID, CommonConstants.RESPONSE_ERROR);
assertEquals("error.msg.loan.repayment.or.waiver.account.is.not.active",
errors.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
} else {
resourceId = (Integer) this.loanTransactionHelper.makeRepaymentTypePayment(repaymentTransactionType, "06 January 2022", 1.00f,
this.disbursedLoanID, "resourceId");
Assertions.assertNotNull(resourceId);
}
}
@Test
public void newGoodwillCreditCreatesCorrectJournalEntriesForPeriodicAccrualsTest() {
@@ -366,8 +397,8 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
final Float overpaidAmount = 159.00f;
final Float goodwillAmount = totalOutstanding + overpaidAmount;
final String goodwillDate = "09 January 2022";
HashMap loanStatusHashMap = this.loanTransactionHelper.makeRepaymentTypePayment(GOODWILL_CREDIT, goodwillDate, goodwillAmount,
this.disbursedLoanID);
HashMap loanStatusHashMap = (HashMap) this.loanTransactionHelper.makeRepaymentTypePayment(GOODWILL_CREDIT, goodwillDate,
goodwillAmount, this.disbursedLoanID, "");
// only a single credit for principal and interest as test sets up same GL account for both (summed up)
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, goodwillDate,
@@ -392,8 +423,8 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
final Float overpaidAmount = 159.00f;
final Float goodwillAmount = totalOutstanding + overpaidAmount;
final String goodwillDate = "09 January 2022";
HashMap loanStatusHashMap = this.loanTransactionHelper.makeRepaymentTypePayment(GOODWILL_CREDIT, goodwillDate, goodwillAmount,
this.disbursedLoanID);
HashMap loanStatusHashMap = (HashMap) this.loanTransactionHelper.makeRepaymentTypePayment(GOODWILL_CREDIT, goodwillDate,
goodwillAmount, this.disbursedLoanID, "");
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, goodwillDate,
new JournalEntry(principalOutstanding, JournalEntry.TransactionType.CREDIT));
@@ -349,10 +349,10 @@ public class LoanTransactionHelper {
getCreditBalanceRefundBodyAsJSON(date, amountToBePaid, externalId), jsonAttributeToGetback);
}
public HashMap makeRepaymentTypePayment(final String repaymentTypeCommand, final String date, final Float amountToBePaid,
final Integer loanID) {
return (HashMap) performLoanTransaction(createLoanTransactionURL(repaymentTypeCommand, loanID),
getRepaymentBodyAsJSON(date, amountToBePaid), "");
public Object makeRepaymentTypePayment(final String repaymentTypeCommand, final String date, final Float amountToBePaid,
final Integer loanID, String jsonAttributeToGetback) {
return performLoanTransaction(createLoanTransactionURL(repaymentTypeCommand, loanID), getRepaymentBodyAsJSON(date, amountToBePaid),
jsonAttributeToGetback);
}
public HashMap makeRepayment(final String date, final Float amountToBePaid, final Integer loanID) {