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 <[email protected]>
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), "");