You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by al...@apache.org on 2022/05/04 13:13:36 UTC
[fineract] branch develop updated: FINERACT-1596 New Merchant Issued and Payout Refunds and Goodwill Credit Transactions
This is an automated email from the ASF dual-hosted git repository.
aleks pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new c2be3d9b4 FINERACT-1596 New Merchant Issued and Payout Refunds and Goodwill Credit Transactions
c2be3d9b4 is described below
commit c2be3d9b4b0560f170deebe39605d4717ea80700
Author: John Woodlock <jo...@gmail.com>
AuthorDate: Wed May 4 13:07:20 2022 +0100
FINERACT-1596 New Merchant Issued and Payout Refunds and Goodwill Credit Transactions
---
.../accounting/common/AccountingConstants.java | 6 +--
.../AccrualBasedAccountingProcessorForLoan.java | 18 +++++--
.../commands/service/CommandWrapperBuilder.java | 27 ++++++++++
.../AccountTransfersWritePlatformServiceImpl.java | 18 +++----
.../common/BusinessEventNotificationConstants.java | 4 ++
.../api/LoanTransactionsApiResource.java | 59 ++++++++++++++------
.../loanaccount/data/LoanTransactionEnumData.java | 27 +++++++++-
.../portfolio/loanaccount/domain/Loan.java | 24 ++++-----
.../domain/LoanAccountDomainService.java | 13 ++---
.../domain/LoanAccountDomainServiceJpa.java | 47 +++++++++++-----
.../loanaccount/domain/LoanTransaction.java | 27 ++++++++--
.../loanaccount/domain/LoanTransactionType.java | 30 ++++++++++-
...tLoanRepaymentScheduleTransactionProcessor.java | 6 +--
...AndDeleteLoanDisburseDetailsCommandHandler.java | 8 +--
.../handler/AddLoanChargeCommandHandler.java | 16 ++----
.../BulkUpdateLoanOfficerCommandHandler.java | 8 +--
.../CloseLoanAsRescheduledCommandHandler.java | 8 +--
.../handler/CloseLoanCommandHandler.java | 8 +--
.../handler/CreditBalanceRefundCommandHandler.java | 4 +-
.../handler/DeleteLoanChargeCommandHandler.java | 8 +--
.../handler/DisburseLoanCommandHandler.java | 8 +--
.../DisburseLoanToSavingsCommandHandler.java | 8 +--
.../handler/ForeClosureCommandHandler.java | 8 +--
...r.java => LoanGoodwilCreditCommandHandler.java} | 16 +++---
...=> LoanMerchantIssuedRefundCommandHandler.java} | 16 +++---
...er.java => LoanPayoutRefundCommandHandler.java} | 18 +++----
.../handler/LoanRecoveryPaymentCommandHandler.java | 3 +-
.../handler/LoanRepaymentCommandHandler.java | 12 ++---
...ationWritePlatformServiceJpaRepositoryImpl.java | 11 ++--
.../service/LoanReadPlatformService.java | 3 +-
.../service/LoanReadPlatformServiceImpl.java | 6 ++-
.../loanaccount/service/LoanUtilService.java | 10 ++++
.../service/LoanWritePlatformService.java | 4 +-
.../LoanWritePlatformServiceJpaRepositoryImpl.java | 26 ++++-----
.../loanproduct/service/LoanEnumerations.java | 12 +++++
.../db/changelog/tenant/changelog-tenant.xml | 1 +
...und_payoutrefund_goodwillcredit_permissions.xml | 46 ++++++++++++++++
...anceRefundandRepaymentTypeIntegrationTest.java} | 63 +++++++++++++++++++---
.../common/loans/LoanTransactionHelper.java | 6 +++
39 files changed, 444 insertions(+), 199 deletions(-)
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java
index 9de490cc5..320ff34fc 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java
@@ -73,9 +73,9 @@ public final class AccountingConstants {
***/
public enum AccrualAccountsForLoan {
- FUND_SOURCE(1), LOAN_PORTFOLIO(2), INTEREST_ON_LOANS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), LOSSES_WRITTEN_OFF(
- 6), INTEREST_RECEIVABLE(
- 7), FEES_RECEIVABLE(8), PENALTIES_RECEIVABLE(9), TRANSFERS_SUSPENSE(10), OVERPAYMENT(11), INCOME_FROM_RECOVERY(12);
+ FUND_SOURCE(1), LOAN_PORTFOLIO(2), INTEREST_ON_LOANS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), //
+ LOSSES_WRITTEN_OFF(6), INTEREST_RECEIVABLE(7), FEES_RECEIVABLE(8), PENALTIES_RECEIVABLE(9), //
+ TRANSFERS_SUSPENSE(10), OVERPAYMENT(11), INCOME_FROM_RECOVERY(12);
private final Integer value;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
index 330651ac8..537d906ea 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
@@ -61,9 +61,10 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
}
/***
- * Handle repayments, repayments at disbursement and reversal of Repayments and Repayments at disbursement
+ * Handle repayments, loan refunds, repayments at disbursement and reversal of Repayments and Repayments at
+ * disbursement
***/
- else if (loanTransactionDTO.getTransactionType().isRepayment()
+ else if (loanTransactionDTO.getTransactionType().isRepaymentType()
|| loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement()
|| loanTransactionDTO.getTransactionType().isChargePayment()) {
createJournalEntriesForRepaymentsAndWriteOffs(loanDTO, loanTransactionDTO, office, false,
@@ -293,9 +294,16 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
FinancialActivity.LIABILITY_TRANSFER.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
transactionDate, totalDebitAmount, isReversal);
} else {
- this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
- AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
- transactionDate, totalDebitAmount, isReversal);
+ if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
+ this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
+ AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
+ transactionDate, totalDebitAmount, isReversal);
+
+ } else {
+ this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
+ AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
+ transactionDate, totalDebitAmount, isReversal);
+ }
}
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
index 775cd84e1..5a2b9239a 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
@@ -797,6 +797,33 @@ public class CommandWrapperBuilder {
return this;
}
+ public CommandWrapperBuilder loanMerchantIssuedRefundTransaction(final Long loanId) {
+ this.actionName = "MERCHANTISSUEDREFUND";
+ this.entityName = "LOAN";
+ this.entityId = null;
+ this.loanId = loanId;
+ this.href = "/loans/" + loanId + "/transactions/template?command=merchantissuedrefund";
+ return this;
+ }
+
+ public CommandWrapperBuilder loanPayoutRefundTransaction(final Long loanId) {
+ this.actionName = "PAYOUTREFUND";
+ this.entityName = "LOAN";
+ this.entityId = null;
+ this.loanId = loanId;
+ this.href = "/loans/" + loanId + "/transactions/template?command=payoutrefund";
+ return this;
+ }
+
+ public CommandWrapperBuilder loanGoodwillCreditTransaction(final Long loanId) {
+ this.actionName = "GOODWILLCREDIT";
+ this.entityName = "LOAN";
+ this.entityId = null;
+ this.loanId = loanId;
+ this.href = "/loans/" + loanId + "/transactions/template?command=goodwillcredit";
+ return this;
+ }
+
public CommandWrapperBuilder loanRecoveryPaymentTransaction(final Long loanId) {
this.actionName = "RECOVERYPAYMENT";
this.entityName = "LOAN";
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java
index 98b2162dd..4bfc81c18 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java
@@ -177,8 +177,8 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
final Boolean isHolidayValidationDone = false;
final HolidayDetailDTO holidayDetailDto = null;
final boolean isRecoveryRepayment = false;
- final LoanTransaction loanRepaymentTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccount,
- new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null,
+ final LoanTransaction loanRepaymentTransaction = this.loanAccountDomainService.makeRepayment(LoanTransactionType.REPAYMENT,
+ toLoanAccount, new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null,
isRecoveryRepayment, isAccountTransfer, holidayDetailDto, isHolidayValidationDone);
final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleSavingsToLoanTransfer(command,
@@ -340,10 +340,10 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
final boolean isRecoveryRepayment = false;
final Boolean isHolidayValidationDone = false;
final HolidayDetailDTO holidayDetailDto = null;
- loanTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccount, new CommandProcessingResultBuilder(),
- accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
- accountTransferDTO.getPaymentDetail(), null, null, isRecoveryRepayment, isAccountTransfer, holidayDetailDto,
- isHolidayValidationDone);
+ loanTransaction = this.loanAccountDomainService.makeRepayment(LoanTransactionType.REPAYMENT, toLoanAccount,
+ new CommandProcessingResultBuilder(), accountTransferDTO.getTransactionDate(),
+ accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(), null, null, isRecoveryRepayment,
+ isAccountTransfer, holidayDetailDto, isHolidayValidationDone);
}
accountTransferDetails = this.accountTransferAssembler.assembleSavingsToLoanTransfer(accountTransferDTO, fromSavingsAccount,
@@ -476,9 +476,9 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(),
accountTransferDTO.getNoteText(), accountTransferDTO.getTxnExternalId(), true);
- LoanTransaction repayTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccount, new CommandProcessingResultBuilder(),
- accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(),
- null, null, false, isAccountTransfer, null, false, true);
+ LoanTransaction repayTransaction = this.loanAccountDomainService.makeRepayment(LoanTransactionType.REPAYMENT, toLoanAccount,
+ new CommandProcessingResultBuilder(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
+ accountTransferDTO.getPaymentDetail(), null, null, false, isAccountTransfer, null, false, true);
AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleLoanToLoanTransfer(accountTransferDTO,
fromLoanAccount, toLoanAccount, disburseTransaction, repayTransaction);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java
index 4c4af1cf1..e7799abbd 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java
@@ -33,6 +33,10 @@ public class BusinessEventNotificationConstants {
LOAN_UNDO_TRANSACTION("loan_undo_transaction"), //
LOAN_ADJUST_TRANSACTION("loan_adjust_transaction"), //
LOAN_MAKE_REPAYMENT("loan_repayment_transaction"), //
+ LOAN_MERCHANT_ISSUED_REFUND("loan_merchant_issued_refund"), //
+ LOAN_PAYOUT_REFUND("loan_payout_refund"), //
+ LOAN_GOODWILL_CREDIT("loan_goodwill_credit"), //
+ LOAN_RECOVERY_PAYMENT("loan_recovery_payment"), //
LOAN_WRITTEN_OFF("loan_writtenoff"), //
LOAN_UNDO_WRITTEN_OFF("loan_undo_writtenoff"), //
LOAN_DISBURSAL("loan_disbursal"), //
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
index 646ff12de..985566905 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
@@ -57,6 +57,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData;
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.service.LoanChargePaidByReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
@@ -110,12 +111,14 @@ public class LoanTransactionsApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve Loan Transaction Template", description = "This is a convenience resource. It can be useful when building maintenance user interface screens for client applications. The template data returned consists of any or all of:\n"
+ "\n" + "Field Defaults\n" + "Allowed Value Lists\n\n" + "Example Requests:\n" + "\n"
- + "loans/1/transactions/template?command=repayment" + "\n" + "loans/1/transactions/template?command=waiveinterest" + "\n"
- + "loans/1/transactions/template?command=writeoff" + "\n" + "loans/1/transactions/template?command=close-rescheduled" + "\n"
- + "loans/1/transactions/template?command=close" + "\n" + "loans/1/transactions/template?command=disburse" + "\n"
- + "loans/1/transactions/template?command=disburseToSavings" + "\n" + "loans/1/transactions/template?command=recoverypayment"
- + "\n" + "loans/1/transactions/template?command=prepayLoan" + "\n" + "loans/1/transactions/template?command=refundbycash" + "\n"
- + "loans/1/transactions/template?command=refundbytransfer" + "\n" + "loans/1/transactions/template?command=foreclosure" + "\n"
+ + "loans/1/transactions/template?command=repayment" + "loans/1/transactions/template?command=merchantIssuedRefund"
+ + "loans/1/transactions/template?command=payoutRefund" + "loans/1/transactions/template?command=goodwillCredit" + "\n"
+ + "loans/1/transactions/template?command=waiveinterest" + "\n" + "loans/1/transactions/template?command=writeoff" + "\n"
+ + "loans/1/transactions/template?command=close-rescheduled" + "\n" + "loans/1/transactions/template?command=close" + "\n"
+ + "loans/1/transactions/template?command=disburse" + "\n" + "loans/1/transactions/template?command=disburseToSavings" + "\n"
+ + "loans/1/transactions/template?command=recoverypayment" + "\n" + "loans/1/transactions/template?command=prepayLoan" + "\n"
+ + "loans/1/transactions/template?command=refundbycash" + "\n" + "loans/1/transactions/template?command=refundbytransfer" + "\n"
+ + "loans/1/transactions/template?command=foreclosure" + "\n"
+ "loans/1/transactions/template?command=creditBalanceRefund (returned 'amount' field will have the overpaid value")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanTransactionsApiResourceSwagger.GetLoansLoanIdTransactionsTemplateResponse.class))) })
@@ -130,6 +133,18 @@ public class LoanTransactionsApiResource {
LoanTransactionData transactionData = null;
if (is(commandParam, "repayment")) {
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(loanId);
+ } else if (is(commandParam, "merchantIssuedRefund")) {
+ LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
+ transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.MERCHANT_ISSUED_REFUND,
+ loanId, transactionDate);
+ } else if (is(commandParam, "payoutRefund")) {
+ LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
+ transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.PAYOUT_REFUND, loanId,
+ transactionDate);
+ } else if (is(commandParam, "goodwillCredit")) {
+ LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
+ transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.GOODWILL_CREDIT, loanId,
+ transactionDate);
} else if (is(commandParam, "waiveinterest")) {
transactionData = this.loanReadPlatformService.retrieveWaiveInterestDetails(loanId);
} else if (is(commandParam, "writeoff")) {
@@ -156,7 +171,8 @@ public class LoanTransactionsApiResource {
transactionDate = LocalDate.ofInstant(transactionDateParam.getDate("transactionDate", dateFormat, locale).toInstant(),
DateUtils.getDateTimeZoneOfTenant());
}
- transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(loanId, transactionDate);
+ transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanId,
+ transactionDate);
} else if (is(commandParam, "refundbycash")) {
transactionData = this.loanReadPlatformService.retrieveRefundByCashTemplate(loanId);
} else if (is(commandParam, "refundbytransfer")) {
@@ -209,15 +225,17 @@ public class LoanTransactionsApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Significant Loan Transactions", description = "This API covers the major loan transaction functionality\n\n"
- + "Example Requests:\n" + "\n" + "loans/1/transactions/template?command=repayment" + " | Make a Repayment | \n"
- + "loans/1/transactions/template?command=waiveinterest" + " | Waive Interest | \n"
- + "loans/1/transactions/template?command=writeoff" + " | Write-off Loan | \n"
- + "loans/1/transactions/template?command=close-rescheduled" + " | Close Rescheduled Loan | \n"
- + "loans/1/transactions/template?command=close" + " | Close Loan | \n" + "loans/1/transactions/template?command=undowriteoff"
- + " | Undo Loan Write-off | \n" + "loans/1/transactions/template?command=recoverypayment" + " | Make Recovery Payment | \n"
- + "loans/1/transactions/template?command=refundByCash" + " | Make a Refund of an Active Loan by Cash | \n"
- + "loans/1/transactions/template?command=foreclosure" + " | Foreclosure of an Active Loan | \n"
- + "loans/1/transactions/template?command=creditBalanceRefund" + " | Credit Balance Refund" + " | \n")
+ + "Example Requests:\n" + "\n" + "loans/1/transactions?command=repayment" + " | Make a Repayment | \n"
+ + "loans/1/transactions?command=merchantIssuedRefund" + " | Merchant Issued Refund | \n"
+ + "loans/1/transactions?command=payoutRefund" + " | Payout Refund | \n" + "loans/1/transactions?command=goodwillCredit"
+ + " | Goodwil Credit | \n" + "loans/1/transactions?command=waiveinterest" + " | Waive Interest | \n"
+ + "loans/1/transactions?command=writeoff" + " | Write-off Loan | \n" + "loans/1/transactions?command=close-rescheduled"
+ + " | Close Rescheduled Loan | \n" + "loans/1/transactions?command=close" + " | Close Loan | \n"
+ + "loans/1/transactions?command=undowriteoff" + " | Undo Loan Write-off | \n" + "loans/1/transactions?command=recoverypayment"
+ + " | Make Recovery Payment | \n" + "loans/1/transactions?command=refundByCash"
+ + " | Make a Refund of an Active Loan by Cash | \n" + "loans/1/transactions?command=foreclosure"
+ + " | Foreclosure of an Active Loan | \n" + "loans/1/transactions?command=creditBalanceRefund" + " | Credit Balance Refund"
+ + " | \n")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = LoanTransactionsApiResourceSwagger.PostLoansLoanIdTransactionsRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanTransactionsApiResourceSwagger.PostLoansLoanIdTransactionsResponse.class))) })
@@ -231,6 +249,15 @@ public class LoanTransactionsApiResource {
if (is(commandParam, "repayment")) {
final CommandWrapper commandRequest = builder.loanRepaymentTransaction(loanId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+ } else if (is(commandParam, "merchantIssuedRefund")) {
+ final CommandWrapper commandRequest = builder.loanMerchantIssuedRefundTransaction(loanId).build();
+ result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+ } else if (is(commandParam, "payoutRefund")) {
+ final CommandWrapper commandRequest = builder.loanPayoutRefundTransaction(loanId).build();
+ result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+ } else if (is(commandParam, "goodwillCredit")) {
+ final CommandWrapper commandRequest = builder.loanGoodwillCreditTransaction(loanId).build();
+ result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "waiveinterest")) {
final CommandWrapper commandRequest = builder.waiveInterestPortionTransaction(loanId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
index 1cf00e9e3..5d8928a75 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
@@ -31,6 +31,9 @@ public class LoanTransactionEnumData {
private final boolean disbursement;
private final boolean repaymentAtDisbursement;
private final boolean repayment;
+ private final boolean merchantIssuedRefund;
+ private final boolean payoutRefund;
+ private final boolean goodwillCredit;
private final boolean contra;
private final boolean waiveInterest;
private final boolean waiveCharges;
@@ -53,6 +56,9 @@ public class LoanTransactionEnumData {
this.disbursement = Long.valueOf(1).equals(this.id);
this.repaymentAtDisbursement = Long.valueOf(5).equals(this.id);
this.repayment = Long.valueOf(2).equals(this.id);
+ this.merchantIssuedRefund = Long.valueOf(21).equals(this.id);
+ this.payoutRefund = Long.valueOf(22).equals(this.id);
+ this.goodwillCredit = Long.valueOf(23).equals(this.id);
this.contra = Long.valueOf(3).equals(this.id);
this.waiveInterest = Long.valueOf(4).equals(this.id);
this.waiveCharges = Long.valueOf(9).equals(this.id);
@@ -88,7 +94,14 @@ public class LoanTransactionEnumData {
* @return
*/
public boolean isPaymentOrReceipt() {
- if (isDisbursement() || isRepayment() || isRepaymentAtDisbursement() || isRecoveryRepayment()) {
+ if (isDisbursement() || isRepaymentType() || isRepaymentAtDisbursement() || isRecoveryRepayment()) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isRepaymentType() {
+ if (isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() || isGoodwillCredit()) {
return true;
}
return false;
@@ -106,6 +119,18 @@ public class LoanTransactionEnumData {
return this.repayment;
}
+ public boolean isMerchantIssuedRefund() {
+ return this.merchantIssuedRefund;
+ }
+
+ public boolean isPayoutRefund() {
+ return this.payoutRefund;
+ }
+
+ public boolean isGoodwillCredit() {
+ return this.goodwillCredit;
+ }
+
public boolean isWaiveInterest() {
return this.waiveInterest;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index dbf7680f2..12a804bd8 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -3179,7 +3179,7 @@ public class Loan extends AbstractPersistableCustom {
addLoanTransaction(loanTransaction);
}
- if (loanTransaction.isNotRepayment() && loanTransaction.isNotWaiver() && loanTransaction.isNotRecoveryRepayment()) {
+ if (loanTransaction.isNotRepaymentType() && 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);
@@ -3502,7 +3502,7 @@ public class Loan extends AbstractPersistableCustom {
final LocalDate currentTransactionDate = loanTransaction.getTransactionDate();
for (final LoanTransaction previousTransaction : loanTransactions) {
- if (previousTransaction.isRepayment() && previousTransaction.isNotReversed()) {
+ if (previousTransaction.isRepaymentType() && previousTransaction.isNotReversed()) {
if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
isAfterLatRepayment = false;
break;
@@ -3543,7 +3543,7 @@ public class Loan extends AbstractPersistableCustom {
LocalDate lastTransactionDate = null;
for (final LoanTransaction transaction : this.loanTransactions) {
- if (transaction.isRepayment() && transaction.isNonZero()) {
+ if (transaction.isRepaymentType() && transaction.isNonZero()) {
lastTransactionDate = transaction.getTransactionDate();
}
}
@@ -3615,7 +3615,7 @@ public class Loan extends AbstractPersistableCustom {
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
transactionForAdjustment.getTransactionDate());
- if (transactionForAdjustment.isNotRepayment() && transactionForAdjustment.isNotWaiver()
+ if (transactionForAdjustment.isNotRepaymentType() && transactionForAdjustment.isNotWaiver()
&& transactionForAdjustment.isNotCreditBalanceRefund()) {
final String errorMessage = "Only transactions of type repayment, waiver or credit balance refund can be adjusted.";
throw new InvalidLoanTransactionTypeException("transaction",
@@ -3635,7 +3635,7 @@ public class Loan extends AbstractPersistableCustom {
this.loanStatus = LoanStatus.ACTIVE.getValue();
}
- if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) {
+ if (newTransactionDetail.isRepaymentType() || newTransactionDetail.isInterestWaiver()) {
changedTransactionDetail = handleRepaymentOrRecoveryOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine,
transactionForAdjustment, scheduleGeneratorDTO, currentUser);
}
@@ -4139,7 +4139,7 @@ public class Loan extends AbstractPersistableCustom {
Money cumulativePaid = Money.zero(loanCurrency());
for (final LoanTransaction repayment : this.loanTransactions) {
- if (repayment.isRepayment() && !repayment.isReversed()) {
+ if (repayment.isRepaymentType() && !repayment.isReversed()) {
cumulativePaid = cumulativePaid.plus(repayment.getAmount(loanCurrency()));
}
}
@@ -4464,7 +4464,7 @@ public class Loan extends AbstractPersistableCustom {
&& !transaction.getTransactionDate().isAfter(tillDate)) {
if (transaction.isAccrual()) {
receivableInterest = receivableInterest.plus(transaction.getInterestPortion(getCurrency()));
- } else if (transaction.isRepayment() || transaction.isInterestWaiver()) {
+ } else if (transaction.isRepaymentType() || transaction.isInterestWaiver()) {
receivableInterest = receivableInterest.minus(transaction.getInterestPortion(getCurrency()));
}
}
@@ -4953,7 +4953,7 @@ public class Loan extends AbstractPersistableCustom {
public LocalDate getLastRepaymentDate() {
LocalDate currentTransactionDate = getDisbursementDate();
for (final LoanTransaction previousTransaction : this.loanTransactions) {
- if (previousTransaction.isRepayment()) {
+ if (previousTransaction.isRepaymentType()) {
if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
currentTransactionDate = previousTransaction.getTransactionDate();
}
@@ -5063,7 +5063,7 @@ public class Loan extends AbstractPersistableCustom {
break;
case LOAN_REPAYMENT_OR_WAIVER:
if (!isOpen()) {
- final String defaultUserMessage = "Loan Repayment or Waiver is not allowed. Loan Account is not active.";
+ final String defaultUserMessage = "Loan Repayment (or its types) or Waiver is not allowed. Loan Account is not active.";
final ApiParameterError error = ApiParameterError
.generalError("error.msg.loan.repayment.or.waiver.account.is.not.active", defaultUserMessage);
dataValidationErrors.add(error);
@@ -6223,7 +6223,7 @@ public class Loan extends AbstractPersistableCustom {
LocalDate lastTransactionDate = null;
for (final LoanTransaction transaction : this.loanTransactions) {
- if ((transaction.isRepayment() || transaction.isRefundForActiveLoan() || transaction.isCreditBalanceRefund())
+ if ((transaction.isRepaymentType() || transaction.isRefundForActiveLoan() || transaction.isCreditBalanceRefund())
&& transaction.isNonZero() && transaction.isNotReversed()) {
lastTransactionDate = transaction.getTransactionDate();
}
@@ -6268,7 +6268,7 @@ public class Loan extends AbstractPersistableCustom {
Collections.reverse(loanTransactions);
for (final LoanTransaction previousTransaction : loanTransactions) {
if (lastTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
- if (previousTransaction.isRepayment() || previousTransaction.isWaiver() || previousTransaction.isChargePayment()) {
+ if (previousTransaction.isRepaymentType() || previousTransaction.isWaiver() || previousTransaction.isChargePayment()) {
throw new UndoLastTrancheDisbursementException(previousTransaction.getId());
}
}
@@ -6602,7 +6602,7 @@ public class Loan extends AbstractPersistableCustom {
receivableInterest = receivableInterest.plus(transaction.getInterestPortion(currency));
receivableFee = receivableFee.plus(transaction.getFeeChargesPortion(currency));
receivablePenalty = receivablePenalty.plus(transaction.getPenaltyChargesPortion(currency));
- } else if (transaction.isRepayment() || transaction.isChargePayment()) {
+ } else if (transaction.isRepaymentType() || transaction.isChargePayment()) {
receivableInterest = receivableInterest.minus(transaction.getInterestPortion(currency));
receivableFee = receivableFee.minus(transaction.getFeeChargesPortion(currency));
receivablePenalty = receivablePenalty.minus(transaction.getPenaltyChargesPortion(currency));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
index 29819a3e2..35cef98b4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
@@ -28,9 +28,9 @@ import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
public interface LoanAccountDomainService {
- LoanTransaction makeRepayment(Loan loan, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
- BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId, boolean isRecoveryRepayment,
- boolean isAccountTransfer, HolidayDetailDTO holidatDetailDto, Boolean isHolidayValidationDone);
+ LoanTransaction makeRepayment(LoanTransactionType repaymentTransactionType, Loan loan, CommandProcessingResultBuilder builderResult,
+ LocalDate transactionDate, BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId,
+ boolean isRecoveryRepayment, boolean isAccountTransfer, HolidayDetailDTO holidatDetailDto, Boolean isHolidayValidationDone);
LoanTransaction makeRefund(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId);
@@ -61,9 +61,10 @@ public interface LoanAccountDomainService {
*/
void recalculateAccruals(Loan loan);
- LoanTransaction makeRepayment(Loan loan, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
- BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId, boolean isRecoveryRepayment,
- boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto, Boolean isHolidayValidationDone, boolean isLoanToLoanTransfer);
+ LoanTransaction makeRepayment(LoanTransactionType repaymentTransactionType, Loan loan, CommandProcessingResultBuilder builderResult,
+ LocalDate transactionDate, BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId,
+ boolean isRecoveryRepayment, boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto, Boolean isHolidayValidationDone,
+ boolean isLoanToLoanTransfer);
void saveLoanWithDataIntegrityViolationChecks(Loan loan);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
index cf6c62775..285b6f8d8 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
@@ -146,12 +146,12 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Transactional
@Override
- public LoanTransaction makeRepayment(final Loan loan, final CommandProcessingResultBuilder builderResult,
- final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText,
- final String txnExternalId, final boolean isRecoveryRepayment, boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto,
- Boolean isHolidayValidationDone) {
- return makeRepayment(loan, builderResult, transactionDate, transactionAmount, paymentDetail, noteText, txnExternalId,
- isRecoveryRepayment, isAccountTransfer, holidayDetailDto, isHolidayValidationDone, false);
+ public LoanTransaction makeRepayment(final LoanTransactionType repaymentTransactionType, final Loan loan,
+ final CommandProcessingResultBuilder builderResult, final LocalDate transactionDate, final BigDecimal transactionAmount,
+ final PaymentDetail paymentDetail, final String noteText, final String txnExternalId, final boolean isRecoveryRepayment,
+ boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto, Boolean isHolidayValidationDone) {
+ return makeRepayment(repaymentTransactionType, loan, builderResult, transactionDate, transactionAmount, paymentDetail, noteText,
+ txnExternalId, isRecoveryRepayment, isAccountTransfer, holidayDetailDto, isHolidayValidationDone, false);
}
@Transactional
@@ -171,13 +171,16 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Transactional
@Override
- public LoanTransaction makeRepayment(final Loan loan, final CommandProcessingResultBuilder builderResult,
- final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText,
- final String txnExternalId, final boolean isRecoveryRepayment, boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto,
- Boolean isHolidayValidationDone, final boolean isLoanToLoanTransfer) {
+ public LoanTransaction makeRepayment(final LoanTransactionType repaymentTransactionType, final Loan loan,
+ final CommandProcessingResultBuilder builderResult, final LocalDate transactionDate, final BigDecimal transactionAmount,
+ final PaymentDetail paymentDetail, final String noteText, final String txnExternalId, final boolean isRecoveryRepayment,
+ boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto, Boolean isHolidayValidationDone,
+ final boolean isLoanToLoanTransfer) {
AppUser currentUser = getAppUserIfPresent();
checkClientOrGroupActive(loan);
- this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BusinessEvents.LOAN_MAKE_REPAYMENT,
+
+ BusinessEvents repaymentTypeEvent = getRepaymentTypeBusinessEvent(repaymentTransactionType, isRecoveryRepayment);
+ this.businessEventNotifierService.notifyBusinessEventToBeExecuted(repaymentTypeEvent,
constructEntityMap(BusinessEntity.LOAN, loan));
// TODO: Is it required to validate transaction date with meeting dates
@@ -199,8 +202,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
newRepaymentTransaction = LoanTransaction.recoveryRepayment(loan.getOffice(), repaymentAmount, paymentDetail, transactionDate,
txnExternalId, currentDateTime, currentUser);
} else {
- newRepaymentTransaction = LoanTransaction.repayment(loan.getOffice(), repaymentAmount, paymentDetail, transactionDate,
- txnExternalId, currentDateTime, currentUser);
+ newRepaymentTransaction = LoanTransaction.repaymentType(repaymentTransactionType, loan.getOffice(), repaymentAmount,
+ paymentDetail, transactionDate, txnExternalId, currentDateTime, currentUser);
}
LocalDate recalculateFrom = null;
@@ -242,7 +245,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
recalculateAccruals(loan);
- this.businessEventNotifierService.notifyBusinessEventWasExecuted(BusinessEvents.LOAN_MAKE_REPAYMENT,
+ this.businessEventNotifierService.notifyBusinessEventWasExecuted(repaymentTypeEvent,
constructEntityMap(BusinessEntity.LOAN_TRANSACTION, newRepaymentTransaction));
// disable all active standing orders linked to this loan if status
@@ -284,6 +287,22 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
return newRepaymentTransaction;
}
+ private BusinessEvents getRepaymentTypeBusinessEvent(LoanTransactionType repaymentTransactionType, boolean isRecoveryRepayment) {
+ BusinessEvents repaymentTypeEvent = null;
+ if (repaymentTransactionType.isRepayment()) {
+ repaymentTypeEvent = BusinessEvents.LOAN_MAKE_REPAYMENT;
+ } else if (repaymentTransactionType.isMerchantIssuedRefund()) {
+ repaymentTypeEvent = BusinessEvents.LOAN_MERCHANT_ISSUED_REFUND;
+ } else if (repaymentTransactionType.isPayoutRefund()) {
+ repaymentTypeEvent = BusinessEvents.LOAN_PAYOUT_REFUND;
+ } else if (repaymentTransactionType.isGoodwillCredit()) {
+ repaymentTypeEvent = BusinessEvents.LOAN_GOODWILL_CREDIT;
+ } else if (isRecoveryRepayment) {
+ repaymentTypeEvent = BusinessEvents.LOAN_RECOVERY_PAYMENT;
+ }
+ return repaymentTypeEvent;
+ }
+
private void saveLoanTransactionWithDataIntegrityViolationChecks(LoanTransaction newRepaymentTransaction) {
try {
this.loanTransactionRepository.saveAndFlush(newRepaymentTransaction);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index 351566a2f..dd52ed73d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -169,6 +169,13 @@ public class LoanTransaction extends AbstractPersistableCustom {
createdDate, appUser);
}
+ public static LoanTransaction repaymentType(final LoanTransactionType repaymentType, final Office office, final Money amount,
+ final PaymentDetail paymentDetail, final LocalDate paymentDate, final String externalId, final LocalDateTime createdDate,
+ final AppUser appUser) {
+ return new LoanTransaction(null, office, repaymentType, paymentDetail, amount.getAmount(), paymentDate, externalId, createdDate,
+ appUser);
+ }
+
public void setLoanTransactionToRepaymentScheduleMappings(final Integer installmentId, final BigDecimal chargePerInstallment) {
for (LoanTransactionToRepaymentScheduleMapping loanTransactionToRepaymentScheduleMapping : this.loanTransactionToRepaymentScheduleMappings) {
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loanTransactionToRepaymentScheduleMapping
@@ -524,16 +531,28 @@ public class LoanTransaction extends AbstractPersistableCustom {
this.manuallyAdjustedOrReversed = true;
}
- public boolean isAnyTypeOfRepayment() {
- return isRepayment() || isRepaymentAtDisbursement() || isRecoveryRepayment();
+ public boolean isRepaymentType() {
+ return isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() || isGoodwillCredit();
}
public boolean isRepayment() {
return LoanTransactionType.REPAYMENT.equals(getTypeOf()) && isNotReversed();
}
- public boolean isNotRepayment() {
- return !isRepayment();
+ public boolean isMerchantIssuedRefund() {
+ return LoanTransactionType.MERCHANT_ISSUED_REFUND.equals(getTypeOf()) && isNotReversed();
+ }
+
+ public boolean isPayoutRefund() {
+ return LoanTransactionType.PAYOUT_REFUND.equals(getTypeOf()) && isNotReversed();
+ }
+
+ public boolean isGoodwillCredit() {
+ return LoanTransactionType.GOODWILL_CREDIT.equals(getTypeOf()) && isNotReversed();
+ }
+
+ public boolean isNotRepaymentType() {
+ return !isRepaymentType();
}
public boolean isIncomePosting() {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
index c38bda6be..e05d97262 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
@@ -52,7 +52,10 @@ public enum LoanTransactionType {
CHARGE_PAYMENT(17, "loanTransactionType.chargePayment"), //
REFUND_FOR_ACTIVE_LOAN(18, "loanTransactionType.refund"), //
INCOME_POSTING(19, "loanTransactionType.incomePosting"), //
- CREDIT_BALANCE_REFUND(20, "loanTransactionType.creditBalanceRefund");
+ CREDIT_BALANCE_REFUND(20, "loanTransactionType.creditBalanceRefund"), //
+ MERCHANT_ISSUED_REFUND(21, "loanTransactionType.merchantIssuedRefund"), //
+ PAYOUT_REFUND(22, "loanTransactionType.payoutRefund"), //
+ GOODWILL_CREDIT(23, "loanTransactionType.goodwillCredit");
private final Integer value;
private final String code;
@@ -135,6 +138,15 @@ public enum LoanTransactionType {
case 20:
loanTransactionType = LoanTransactionType.CREDIT_BALANCE_REFUND;
break;
+ case 21:
+ loanTransactionType = LoanTransactionType.MERCHANT_ISSUED_REFUND;
+ break;
+ case 22:
+ loanTransactionType = LoanTransactionType.PAYOUT_REFUND;
+ break;
+ case 23:
+ loanTransactionType = LoanTransactionType.GOODWILL_CREDIT;
+ break;
default:
loanTransactionType = LoanTransactionType.INVALID;
break;
@@ -154,6 +166,22 @@ public enum LoanTransactionType {
return this.value.equals(LoanTransactionType.REPAYMENT.getValue());
}
+ public boolean isMerchantIssuedRefund() {
+ return this.value.equals(LoanTransactionType.MERCHANT_ISSUED_REFUND.getValue());
+ }
+
+ public boolean isPayoutRefund() {
+ return this.value.equals(LoanTransactionType.PAYOUT_REFUND.getValue());
+ }
+
+ public boolean isGoodwillCredit() {
+ return this.value.equals(LoanTransactionType.GOODWILL_CREDIT.getValue());
+ }
+
+ public boolean isRepaymentType() {
+ return (isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() || isGoodwillCredit());
+ }
+
public boolean isRecoveryRepayment() {
return this.value.equals(LoanTransactionType.RECOVERY_REPAYMENT.getValue());
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
index 8c95c2b2a..224cc7ca9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
@@ -152,7 +152,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
Collections.sort(installments, byDate);
}
- if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
+ if (loanTransaction.isRepaymentType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
// pass through for new transactions
if (loanTransaction.getId() == null) {
handleTransaction(loanTransaction, currency, installments, charges);
@@ -230,7 +230,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges, final Money chargeAmountToProcess,
final boolean isFeeCharge) {
// to.
- if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
+ if (loanTransaction.isRepaymentType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
loanTransaction.resetDerivedComponents();
}
Money transactionAmountUnprocessed = processTransaction(loanTransaction, currency, installments, chargeAmountToProcess);
@@ -488,7 +488,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
Money unProcessed = Money.zero(currency);
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
Money amountToProcess = null;
- if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
+ if (loanTransaction.isRepaymentType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
loanTransaction.resetDerivedComponents();
}
if (loanTransaction.isInterestWaiver()) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/AddAndDeleteLoanDisburseDetailsCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/AddAndDeleteLoanDisburseDetailsCommandHandler.java
index 214827055..07c161bdb 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/AddAndDeleteLoanDisburseDetailsCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/AddAndDeleteLoanDisburseDetailsCommandHandler.java
@@ -18,24 +18,20 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
+@RequiredArgsConstructor
public class AddAndDeleteLoanDisburseDetailsCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public AddAndDeleteLoanDisburseDetailsCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/AddLoanChargeCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/AddLoanChargeCommandHandler.java
index b93d90c76..4c4987b4c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/AddLoanChargeCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/AddLoanChargeCommandHandler.java
@@ -18,33 +18,27 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
+@RequiredArgsConstructor
+@Slf4j
@CommandType(entity = "LOANCHARGE", action = "CREATE")
public class AddLoanChargeCommandHandler implements NewCommandSourceHandler {
- private static final Logger LOG = LoggerFactory.getLogger(AddLoanChargeCommandHandler.class);
-
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public AddLoanChargeCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
@@ -71,7 +65,7 @@ public class AddLoanChargeCommandHandler implements NewCommandSourceHandler {
}
private void logAsErrorUnexpectedDataIntegrityException(final Exception dve) {
- LOG.error("Error occured.", dve);
+ log.error("Error occured.", dve);
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/BulkUpdateLoanOfficerCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/BulkUpdateLoanOfficerCommandHandler.java
index 017b354d5..aac2d9dbc 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/BulkUpdateLoanOfficerCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/BulkUpdateLoanOfficerCommandHandler.java
@@ -18,26 +18,22 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
+@RequiredArgsConstructor
@CommandType(entity = "LOAN", action = "BULKREASSIGN")
public class BulkUpdateLoanOfficerCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public BulkUpdateLoanOfficerCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CloseLoanAsRescheduledCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CloseLoanAsRescheduledCommandHandler.java
index af1ed6c15..d45b62f25 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CloseLoanAsRescheduledCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CloseLoanAsRescheduledCommandHandler.java
@@ -18,26 +18,22 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
+@RequiredArgsConstructor
@CommandType(entity = "LOAN", action = "CLOSEASRESCHEDULED")
public class CloseLoanAsRescheduledCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public CloseLoanAsRescheduledCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CloseLoanCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CloseLoanCommandHandler.java
index 2460bde85..c95416c65 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CloseLoanCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CloseLoanCommandHandler.java
@@ -18,26 +18,22 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
+@RequiredArgsConstructor
@CommandType(entity = "LOAN", action = "CLOSE")
public class CloseLoanCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public CloseLoanCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CreditBalanceRefundCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CreditBalanceRefundCommandHandler.java
index 798290c51..4253ee231 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CreditBalanceRefundCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/CreditBalanceRefundCommandHandler.java
@@ -31,9 +31,9 @@ import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-@Slf4j
-@RequiredArgsConstructor
@Service
+@RequiredArgsConstructor
+@Slf4j
@CommandType(entity = "LOAN", action = "CREDITBALANCEREFUND")
public class CreditBalanceRefundCommandHandler implements NewCommandSourceHandler {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DeleteLoanChargeCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DeleteLoanChargeCommandHandler.java
index 98066bea5..b9b61e805 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DeleteLoanChargeCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DeleteLoanChargeCommandHandler.java
@@ -18,26 +18,22 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
+@RequiredArgsConstructor
@CommandType(entity = "LOANCHARGE", action = "DELETE")
public class DeleteLoanChargeCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public DeleteLoanChargeCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DisburseLoanCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DisburseLoanCommandHandler.java
index e6acaf692..a90183f79 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DisburseLoanCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DisburseLoanCommandHandler.java
@@ -18,26 +18,22 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
+@RequiredArgsConstructor
@CommandType(entity = "LOAN", action = "DISBURSE")
public class DisburseLoanCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public DisburseLoanCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DisburseLoanToSavingsCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DisburseLoanToSavingsCommandHandler.java
index 04fff7c9b..762b7c389 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DisburseLoanToSavingsCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DisburseLoanToSavingsCommandHandler.java
@@ -18,26 +18,22 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
+@RequiredArgsConstructor
@CommandType(entity = "LOAN", action = "DISBURSETOSAVINGS")
public class DisburseLoanToSavingsCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public DisburseLoanToSavingsCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/ForeClosureCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/ForeClosureCommandHandler.java
index e249dc978..caf039903 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/ForeClosureCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/ForeClosureCommandHandler.java
@@ -18,25 +18,21 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
+@RequiredArgsConstructor
@CommandType(entity = "LOAN", action = "FORECLOSURE")
public class ForeClosureCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public ForeClosureCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return writePlatformService.forecloseLoan(command.getLoanId(), command);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanGoodwilCreditCommandHandler.java
similarity index 76%
copy from fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentCommandHandler.java
copy to fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanGoodwilCreditCommandHandler.java
index 4061bf6e2..81a696edf 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanGoodwilCreditCommandHandler.java
@@ -18,30 +18,28 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
-@CommandType(entity = "LOAN", action = "REPAYMENT")
-public class LoanRepaymentCommandHandler implements NewCommandSourceHandler {
+@RequiredArgsConstructor
+@CommandType(entity = "LOAN", action = "GOODWILLCREDIT")
+public class LoanGoodwilCreditCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public LoanRepaymentCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
boolean isRecoveryRepayment = false;
- return this.writePlatformService.makeLoanRepayment(command.getLoanId(), command, isRecoveryRepayment);
+ return this.writePlatformService.makeLoanRepayment(LoanTransactionType.GOODWILL_CREDIT, command.getLoanId(), command,
+ isRecoveryRepayment);
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanMerchantIssuedRefundCommandHandler.java
similarity index 76%
copy from fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentCommandHandler.java
copy to fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanMerchantIssuedRefundCommandHandler.java
index 4061bf6e2..433c479a7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanMerchantIssuedRefundCommandHandler.java
@@ -18,30 +18,28 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
-@CommandType(entity = "LOAN", action = "REPAYMENT")
-public class LoanRepaymentCommandHandler implements NewCommandSourceHandler {
+@RequiredArgsConstructor
+@CommandType(entity = "LOAN", action = "MERCHANTISSUEDREFUND")
+public class LoanMerchantIssuedRefundCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public LoanRepaymentCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
boolean isRecoveryRepayment = false;
- return this.writePlatformService.makeLoanRepayment(command.getLoanId(), command, isRecoveryRepayment);
+ return this.writePlatformService.makeLoanRepayment(LoanTransactionType.MERCHANT_ISSUED_REFUND, command.getLoanId(), command,
+ isRecoveryRepayment);
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DeleteLoanChargeCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanPayoutRefundCommandHandler.java
similarity index 76%
copy from fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DeleteLoanChargeCommandHandler.java
copy to fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanPayoutRefundCommandHandler.java
index 98066bea5..0f48ad6d9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/DeleteLoanChargeCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanPayoutRefundCommandHandler.java
@@ -18,30 +18,28 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
-@CommandType(entity = "LOANCHARGE", action = "DELETE")
-public class DeleteLoanChargeCommandHandler implements NewCommandSourceHandler {
+@RequiredArgsConstructor
+@CommandType(entity = "LOAN", action = "PAYOUTREFUND")
+public class LoanPayoutRefundCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public DeleteLoanChargeCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
-
- return this.writePlatformService.deleteLoanCharge(command.getLoanId(), command.entityId(), command);
+ boolean isRecoveryRepayment = false;
+ return this.writePlatformService.makeLoanRepayment(LoanTransactionType.PAYOUT_REFUND, command.getLoanId(), command,
+ isRecoveryRepayment);
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRecoveryPaymentCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRecoveryPaymentCommandHandler.java
index 87aa86d73..18ada7cef 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRecoveryPaymentCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRecoveryPaymentCommandHandler.java
@@ -22,6 +22,7 @@ import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -40,6 +41,6 @@ public class LoanRecoveryPaymentCommandHandler implements NewCommandSourceHandle
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
final boolean isRecoveryRepayment = true;
- return writePlatformService.makeLoanRepayment(command.getLoanId(), command, isRecoveryRepayment);
+ return writePlatformService.makeLoanRepayment(LoanTransactionType.REPAYMENT, command.getLoanId(), command, isRecoveryRepayment);
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentCommandHandler.java
index 4061bf6e2..3bbd62bf7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentCommandHandler.java
@@ -18,30 +18,28 @@
*/
package org.apache.fineract.portfolio.loanaccount.handler;
+import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
+@RequiredArgsConstructor
@CommandType(entity = "LOAN", action = "REPAYMENT")
public class LoanRepaymentCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
- @Autowired
- public LoanRepaymentCommandHandler(final LoanWritePlatformService writePlatformService) {
- this.writePlatformService = writePlatformService;
- }
-
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
boolean isRecoveryRepayment = false;
- return this.writePlatformService.makeLoanRepayment(command.getLoanId(), command, isRecoveryRepayment);
+ return this.writePlatformService.makeLoanRepayment(LoanTransactionType.REPAYMENT, command.getLoanId(), command,
+ isRecoveryRepayment);
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
index fe9776087..45abfa493 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
@@ -112,6 +112,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTopupDetails;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationDateException;
import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified;
@@ -378,8 +379,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
+ " should be after last transaction date of loan to be closed "
+ lastUserTransactionOnLoanToClose);
}
- BigDecimal loanOutstanding = this.loanReadPlatformService
- .retrieveLoanPrePaymentTemplate(loanIdToClose, newLoanApplication.getDisbursementDate()).getAmount();
+ BigDecimal loanOutstanding = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT,
+ loanIdToClose, newLoanApplication.getDisbursementDate()).getAmount();
final BigDecimal firstDisbursalAmount = newLoanApplication.getFirstDisbursalAmount();
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
@@ -956,8 +957,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
+ " should be after last transaction date of loan to be closed "
+ lastUserTransactionOnLoanToClose);
}
- BigDecimal loanOutstanding = this.loanReadPlatformService
- .retrieveLoanPrePaymentTemplate(loanIdToClose, existingLoanApplication.getDisbursementDate()).getAmount();
+ BigDecimal loanOutstanding = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(
+ LoanTransactionType.REPAYMENT, loanIdToClose, existingLoanApplication.getDisbursementDate()).getAmount();
final BigDecimal firstDisbursalAmount = existingLoanApplication.getFirstDisbursalAmount();
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
@@ -1456,7 +1457,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
+ " should be after last transaction date of loan to be closed " + lastUserTransactionOnLoanToClose);
}
BigDecimal loanOutstanding = this.loanReadPlatformService
- .retrieveLoanPrePaymentTemplate(loanIdToClose, expectedDisbursementDate).getAmount();
+ .retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, expectedDisbursementDate).getAmount();
final BigDecimal firstDisbursalAmount = loan.getFirstDisbursalAmount();
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
index 8618c33f0..3d81a76a1 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
@@ -38,6 +38,7 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
import org.apache.fineract.portfolio.loanaccount.data.PaidInAdvanceData;
import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
@@ -114,7 +115,7 @@ public interface LoanReadPlatformService {
List<Long> fetchLoansForInterestRecalculation(Integer pageSize, Long maxLoanIdInList, String officeHierarchy);
- LoanTransactionData retrieveLoanPrePaymentTemplate(Long loanId, LocalDate onDate);
+ LoanTransactionData retrieveLoanPrePaymentTemplate(LoanTransactionType repaymentTransactionType, Long loanId, LocalDate onDate);
Collection<LoanTransactionData> retrieveWaiverLoanTransactions(Long loanId);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index cb3e177ca..bf126f58d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -445,9 +445,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
- public LoanTransactionData retrieveLoanPrePaymentTemplate(final Long loanId, LocalDate onDate) {
+ public LoanTransactionData retrieveLoanPrePaymentTemplate(final LoanTransactionType repaymentTransactionType, final Long loanId,
+ LocalDate onDate) {
this.context.authenticatedUser();
+ this.loanUtilService.validateRepaymentTransactionType(repaymentTransactionType);
final Loan loan = this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId, true);
loan.setHelpers(null, null, loanRepaymentScheduleTransactionProcessorFactory);
@@ -461,7 +463,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final LocalDate recalculateFrom = null;
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loan.fetchPrepaymentDetail(scheduleGeneratorDTO, onDate);
- final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
+ final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(repaymentTransactionType);
final Collection<PaymentTypeData> paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
final BigDecimal outstandingLoanBalance = loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency).getAmount();
final BigDecimal unrecognizedIncomePortion = null;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
index 0653a7218..8c810548f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
@@ -30,6 +30,7 @@ import java.util.Locale;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
+import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.organisation.holiday.domain.Holiday;
import org.apache.fineract.organisation.holiday.domain.HolidayRepository;
@@ -57,6 +58,7 @@ import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.springframework.beans.factory.annotation.Autowired;
@@ -351,4 +353,12 @@ public class LoanUtilService {
return disbursementDatas;
}
+ public void validateRepaymentTransactionType(LoanTransactionType repaymentTransactionType) {
+ if (!repaymentTransactionType.isRepaymentType()) {
+ throw new PlatformServiceUnavailableException("error.msg.repaymentTransactionType.provided.not.a.repayment.type",
+ "Loan :" + repaymentTransactionType.getCode() + " Repayment Transaction Type provided is not a Repayment Type",
+ repaymentTransactionType.getCode());
+ }
+ }
+
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformService.java
index 9c49ade84..83555bb24 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformService.java
@@ -32,6 +32,7 @@ import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulk
import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
public interface LoanWritePlatformService {
@@ -43,7 +44,8 @@ public interface LoanWritePlatformService {
CommandProcessingResult undoLoanDisbursal(Long loanId, JsonCommand command);
- CommandProcessingResult makeLoanRepayment(Long loanId, JsonCommand command, boolean isRecoveryRepayment);
+ CommandProcessingResult makeLoanRepayment(LoanTransactionType repaymentTransactionType, Long loanId, JsonCommand command,
+ boolean isRecoveryRepayment);
Map<String, Object> makeLoanBulkRepayment(CollectionSheetBulkRepaymentCommand bulkRepaymentCommand);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 512242dee..ee5772b7a 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -488,7 +488,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
BigDecimal loanOutstanding = this.loanReadPlatformService
- .retrieveLoanPrePaymentTemplate(loanIdToClose, actualDisbursementDate).getAmount();
+ .retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, actualDisbursementDate).getAmount();
final BigDecimal firstDisbursalAmount = loan.getFirstDisbursalAmount();
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
@@ -886,7 +886,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LocalDate expectedDisbursementDate = command
.localDateValueOfParameterNamed(LoanApiConstants.disbursementDateParameterName);
BigDecimal loanOutstanding = this.loanReadPlatformService
- .retrieveLoanPrePaymentTemplate(loanIdToClose, expectedDisbursementDate).getAmount();
+ .retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, expectedDisbursementDate).getAmount();
BigDecimal netDisbursalAmount = loan.getApprovedPrincipal().subtract(loanOutstanding);
loan.adjustNetDisbursalAmount(netDisbursalAmount);
}
@@ -941,15 +941,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
int j = 0;
for (JsonElement element : repayments) {
childCommand = JsonCommand.fromExistingCommand(command, element);
- result = makeLoanRepayment(childLoanId[j++], childCommand, false);
+ result = makeLoanRepayment(LoanTransactionType.REPAYMENT, childLoanId[j++], childCommand, false);
}
return result;
}
@Transactional
@Override
- public CommandProcessingResult makeLoanRepayment(final Long loanId, final JsonCommand command, final boolean isRecoveryRepayment) {
+ public CommandProcessingResult makeLoanRepayment(final LoanTransactionType repaymentTransactionType, final Long loanId,
+ final JsonCommand command, final boolean isRecoveryRepayment) {
+ this.loanUtilService.validateRepaymentTransactionType(repaymentTransactionType);
this.loanEventApiJsonValidator.validateNewRepaymentTransaction(command.json());
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
@@ -973,9 +975,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final HolidayDetailDTO holidayDetailDto = null;
boolean isAccountTransfer = false;
final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder();
- LoanTransaction loanTransaction = this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, transactionDate,
- transactionAmount, paymentDetail, noteText, txnExternalId, isRecoveryRepayment, isAccountTransfer, holidayDetailDto,
- isHolidayValidationDone);
+ LoanTransaction loanTransaction = this.loanAccountDomainService.makeRepayment(repaymentTransactionType, loan,
+ commandProcessingResultBuilder, transactionDate, transactionAmount, paymentDetail, noteText, txnExternalId,
+ isRecoveryRepayment, isAccountTransfer, holidayDetailDto, isHolidayValidationDone);
// Update loan transaction on repayment.
if (AccountType.fromInt(loan.getLoanType()).isIndividualAccount()) {
@@ -1044,10 +1046,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.paymentDetailWritePlatformService.persistPaymentDetail(paymentDetail);
}
final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder();
- LoanTransaction loanTransaction = this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder,
- bulkRepaymentCommand.getTransactionDate(), singleLoanRepaymentCommand.getTransactionAmount(), paymentDetail,
- bulkRepaymentCommand.getNote(), null, isRecoveryRepayment, isAccountTransfer, holidayDetailDTO,
- isHolidayValidationDone);
+ LoanTransaction loanTransaction = this.loanAccountDomainService.makeRepayment(LoanTransactionType.REPAYMENT, loan,
+ commandProcessingResultBuilder, bulkRepaymentCommand.getTransactionDate(),
+ singleLoanRepaymentCommand.getTransactionAmount(), paymentDetail, bulkRepaymentCommand.getNote(), null,
+ isRecoveryRepayment, isAccountTransfer, holidayDetailDTO, isHolidayValidationDone);
transactionIds.add(loanTransaction.getId());
}
}
@@ -1183,7 +1185,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanAccountDomainService.recalculateAccruals(loan);
Map<BusinessEntity, Object> entityMap = constructEntityMap(BusinessEntity.LOAN_ADJUSTED_TRANSACTION, transactionToAdjust);
- if (newTransactionDetail.isRepayment() && newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
+ if (newTransactionDetail.isRepaymentType() && newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
entityMap.put(BusinessEntity.LOAN_TRANSACTION, newTransactionDetail);
}
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BusinessEvents.LOAN_ADJUST_TRANSACTION, entityMap);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
index 56faedcba..0407304a2 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
@@ -415,6 +415,18 @@ public final class LoanEnumerations {
optionData = new LoanTransactionEnumData(LoanTransactionType.CREDIT_BALANCE_REFUND.getValue().longValue(),
LoanTransactionType.CREDIT_BALANCE_REFUND.getCode(), "Credit Balance Refund");
break;
+ case MERCHANT_ISSUED_REFUND:
+ optionData = new LoanTransactionEnumData(LoanTransactionType.MERCHANT_ISSUED_REFUND.getValue().longValue(),
+ LoanTransactionType.MERCHANT_ISSUED_REFUND.getCode(), "Merchant Issued Refund");
+ break;
+ case PAYOUT_REFUND:
+ optionData = new LoanTransactionEnumData(LoanTransactionType.PAYOUT_REFUND.getValue().longValue(),
+ LoanTransactionType.PAYOUT_REFUND.getCode(), "Payout Refund");
+ break;
+ case GOODWILL_CREDIT:
+ optionData = new LoanTransactionEnumData(LoanTransactionType.GOODWILL_CREDIT.getValue().longValue(),
+ LoanTransactionType.GOODWILL_CREDIT.getCode(), "Goodwill Credit");
+ break;
}
return optionData;
}
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index e871a7f94..0eed83638 100644
--- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -31,4 +31,5 @@
<include file="parts/0009_hold_reason_savings_account.xml" relativeToChangelogFile="true"/>
<include file="parts/0010_lien_allowed_on_savings_account_products.xml" relativeToChangelogFile="true"/>
<include file="parts/0011_add_credit_balance_refund_permission.xml" relativeToChangelogFile="true"/>
+ <include file="parts/0012_add_merchantissuedrefund_payoutrefund_goodwillcredit_permissions.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0012_add_merchantissuedrefund_payoutrefund_goodwillcredit_permissions.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0012_add_merchantissuedrefund_payoutrefund_goodwillcredit_permissions.xml
new file mode 100644
index 000000000..f8706a844
--- /dev/null
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0012_add_merchantissuedrefund_payoutrefund_goodwillcredit_permissions.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
+ <changeSet author="fineract" id="1">
+ <insert tableName="m_permission">
+ <column name="grouping" value="transaction_loan" />
+ <column name="code" value="MERCHANTISSUEDREFUND_LOAN" />
+ <column name="entity_name" value="LOAN" />
+ <column name="action_name" value="MERCHANTISSUEDREFUND" />
+ <column name="can_maker_checker" valueBoolean="false" />
+ </insert>
+ <insert tableName="m_permission">
+ <column name="grouping" value="transaction_loan" />
+ <column name="code" value="PAYOUTREFUND_LOAN" />
+ <column name="entity_name" value="LOAN" />
+ <column name="action_name" value="PAYOUTREFUND" />
+ <column name="can_maker_checker" valueBoolean="false" />
+ </insert>
+ <insert tableName="m_permission">
+ <column name="grouping" value="transaction_loan" />
+ <column name="code" value="GOODWILLCREDIT_LOAN" />
+ <column name="entity_name" value="LOAN" />
+ <column name="action_name" value="GOODWILLCREDIT" />
+ <column name="can_maker_checker" valueBoolean="false" />
+ </insert>
+ </changeSet>
+</databaseChangeLog>
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java
similarity index 84%
rename from integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundIntegrationTest.java
rename to integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java
index 91959773e..61508badb 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundIntegrationTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java
@@ -45,9 +45,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings({ "rawtypes", "unchecked" })
-public class ClientLoanCreditBalanceRefundIntegrationTest {
+public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
- private static final Logger LOG = LoggerFactory.getLogger(ClientLoanCreditBalanceRefundIntegrationTest.class);
+ private static final Logger LOG = LoggerFactory.getLogger(ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.class);
private ResponseSpecification responseSpec;
private RequestSpecification requestSpec;
@@ -56,11 +56,15 @@ public class ClientLoanCreditBalanceRefundIntegrationTest {
private JournalEntryHelper journalEntryHelper;
private AccountHelper accountHelper;
private Integer disbursedLoanID;
+ private static final String CASH_BASED = "2";
private static final String ACCRUAL_PERIODIC = "3";
private Account assetAccount;
private Account incomeAccount;
private Account expenseAccount;
private Account overpaymentAccount;
+ private static final String MERCHANT_ISSUED_REFUND = "merchantIssuedRefund";
+ private static final String PAYOUT_REFUND = "payoutRefund";
+ private static final String GOODWILL_CREDIT = "goodwillCredit";
@BeforeEach
public void setup() {
@@ -76,12 +80,13 @@ public class ClientLoanCreditBalanceRefundIntegrationTest {
this.expenseAccount = this.accountHelper.createExpenseAccount();
this.overpaymentAccount = this.accountHelper.createLiabilityAccount();
this.journalEntryHelper = new JournalEntryHelper(this.requestSpec, this.responseSpec);
+ }
+ private void disburseLoanOfAccountingRule(final String accountingType) {
final String principal = "12000.00";
final String submitApproveDisburseDate = "01 January 2022";
this.disbursedLoanID = fromStartToDisburseLoan(submitApproveDisburseDate, principal, ACCRUAL_PERIODIC, assetAccount, incomeAccount,
expenseAccount, overpaymentAccount);
-
}
private Integer createLoanProduct(final String principal, final boolean multiDisburseLoan, final String accountingRule,
@@ -162,6 +167,7 @@ public class ClientLoanCreditBalanceRefundIntegrationTest {
@Test
public void creditBalanceRefundCanOnlyBeAppliedWhereLoanStatusIsOverpaidTest() {
+ disburseLoanOfAccountingRule(ACCRUAL_PERIODIC);
HashMap loanStatusHashMap = makeRepayment("06 January 2022", 2000.00f); // not full payment
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
@@ -174,14 +180,11 @@ public class ClientLoanCreditBalanceRefundIntegrationTest {
assertEquals("error.msg.loan.credit.balance.refund.account.is.not.overpaid",
cbrErrors.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
- // ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec,
- // this.responseSpec, loanID);
- // final int loanScheduleLineCount = loanSchedule.size();
-
}
@Test
public void cantRefundMoreThanOverpaidTest() {
+ disburseLoanOfAccountingRule(ACCRUAL_PERIODIC);
HashMap loanStatusHashMap = makeRepayment("06 January 2022", 20000.00f); // overpayment
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
@@ -204,6 +207,7 @@ public class ClientLoanCreditBalanceRefundIntegrationTest {
@Test
public void fullRefundChangesStatusToClosedObligationMetTest() {
+ disburseLoanOfAccountingRule(ACCRUAL_PERIODIC);
HashMap loanStatusHashMap = makeRepayment("06 January 2022", 20000.00f); // overpayment
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
@@ -229,6 +233,7 @@ public class ClientLoanCreditBalanceRefundIntegrationTest {
@Test
public void partialRefundKeepsOverpaidStatusTest() {
+ disburseLoanOfAccountingRule(ACCRUAL_PERIODIC);
HashMap loanStatusHashMap = makeRepayment("06 January 2022", 20000.00f); // overpayment
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
@@ -246,6 +251,7 @@ public class ClientLoanCreditBalanceRefundIntegrationTest {
@Test
public void newCreditBalanceRefundSavesExternalIdTest() {
+ disburseLoanOfAccountingRule(ACCRUAL_PERIODIC);
HashMap loanStatusHashMap = makeRepayment("06 January 2022", 20000.00f); // overpayment
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
@@ -265,6 +271,7 @@ public class ClientLoanCreditBalanceRefundIntegrationTest {
@Test
public void newCreditBalanceRefundFindsDuplicateExternalIdTest() {
+ disburseLoanOfAccountingRule(ACCRUAL_PERIODIC);
HashMap loanStatusHashMap = makeRepayment("06 January 2022", 20000.00f); // overpayment
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
@@ -287,6 +294,7 @@ public class ClientLoanCreditBalanceRefundIntegrationTest {
@Test
public void newCreditBalanceRefundCreatesCorrectJournalEntriesForPeriodicAccrualsTest() {
+ disburseLoanOfAccountingRule(ACCRUAL_PERIODIC);
HashMap loanStatusHashMap = makeRepayment("06 January 2022", 20000.00f); // overpayment
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
@@ -304,4 +312,45 @@ public class ClientLoanCreditBalanceRefundIntegrationTest {
}
+ @Test
+ public void newCreditBalanceRefundCreatesCorrectJournalEntriesForCashAccrualsTest() {
+
+ disburseLoanOfAccountingRule(CASH_BASED);
+ HashMap loanStatusHashMap = makeRepayment("08 January 2022", 20000.00f); // overpayment
+ LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
+
+ final Float refund = 1000.00f; // partial refund
+ final String creditBalanceRefundDate = "09 January 2022";
+ final String externalId = null;
+ final Integer resourceId = (Integer) loanTransactionHelper.creditBalanceRefund(creditBalanceRefundDate, refund, externalId,
+ disbursedLoanID, "resourceId");
+ Assertions.assertNotNull(resourceId);
+
+ this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, creditBalanceRefundDate,
+ new JournalEntry(refund, JournalEntry.TransactionType.DEBIT));
+ this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, creditBalanceRefundDate,
+ new JournalEntry(refund, JournalEntry.TransactionType.CREDIT));
+
+ }
+
+ @Test
+ public void repaymentTransactionTypeMatchesTest() {
+ disburseLoanOfAccountingRule(ACCRUAL_PERIODIC);
+ verifyRepaymentTransactionTypeMatches(MERCHANT_ISSUED_REFUND);
+ verifyRepaymentTransactionTypeMatches(PAYOUT_REFUND);
+ verifyRepaymentTransactionTypeMatches(GOODWILL_CREDIT);
+
+ }
+
+ private void verifyRepaymentTransactionTypeMatches(final String repaymentTransactionType) {
+ HashMap loanStatusHashMap = this.loanTransactionHelper.makeRepaymentTypePayment(repaymentTransactionType, "06 January 2022",
+ 200.00f, this.disbursedLoanID);
+ Integer newTransactionId = (Integer) loanStatusHashMap.get("resourceId");
+ loanStatusHashMap = this.loanTransactionHelper.getLoanTransactionDetails(this.disbursedLoanID, newTransactionId);
+
+ HashMap typeMap = (HashMap) loanStatusHashMap.get("type");
+ Boolean isTypeCorrect = (Boolean) typeMap.get(repaymentTransactionType);
+ Assertions.assertTrue(Boolean.TRUE.equals(isTypeCorrect), "Not " + repaymentTransactionType);
+ }
+
}
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
index 50942ac27..85527944d 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
@@ -339,6 +339,12 @@ 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 HashMap makeRepayment(final String date, final Float amountToBePaid, final Integer loanID) {
return (HashMap) performLoanTransaction(createLoanTransactionURL(MAKE_REPAYMENT_COMMAND, loanID),
getRepaymentBodyAsJSON(date, amountToBePaid), "");