FINERACT-1760: Fix error handling
This commit is contained in:
+7
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.charge.exception;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
@@ -38,4 +40,9 @@ public class LoanChargeNotFoundException extends AbstractPlatformResourceNotFoun
|
||||
super("error.msg.loanCharge.id.invalid.for.given.loan", "Loan charge with identifier " + id + " does not exist for loan " + loanId,
|
||||
id, loanId);
|
||||
}
|
||||
|
||||
public LoanChargeNotFoundException(ExternalId externalId) {
|
||||
super("error.msg.loanCharge.external.id.invalid", "Loan Charge with external identifier "
|
||||
+ ObjectUtils.defaultIfNull(externalId, ExternalId.empty()).getValue() + " does not exist", externalId);
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -58,9 +58,11 @@ import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeNotFoundException;
|
||||
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
@@ -549,6 +551,9 @@ public class LoanChargesApiResource {
|
||||
if (resolvedLoanChargeId == null) {
|
||||
loanChargeExternalId.throwExceptionIfEmpty();
|
||||
resolvedLoanChargeId = this.loanChargeReadPlatformService.retrieveLoanChargeIdByExternalId(loanChargeExternalId);
|
||||
if (resolvedLoanChargeId == null) {
|
||||
throw new LoanChargeNotFoundException(loanChargeExternalId);
|
||||
}
|
||||
}
|
||||
return resolvedLoanChargeId;
|
||||
}
|
||||
@@ -558,6 +563,9 @@ public class LoanChargesApiResource {
|
||||
if (resolvedLoanId == null) {
|
||||
loanExternalId.throwExceptionIfEmpty();
|
||||
resolvedLoanId = this.loanReadPlatformService.retrieveLoanIdByExternalId(loanExternalId.getValue());
|
||||
if (resolvedLoanId == null) {
|
||||
throw new LoanNotFoundException(loanExternalId);
|
||||
}
|
||||
}
|
||||
return resolvedLoanId;
|
||||
}
|
||||
|
||||
+8
@@ -62,6 +62,8 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityConte
|
||||
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.exception.LoanNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanChargePaidByReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
@@ -576,6 +578,9 @@ public class LoanTransactionsApiResource {
|
||||
if (resolvedLoanTransactionId == null) {
|
||||
externalTransactionId.throwExceptionIfEmpty();
|
||||
resolvedLoanTransactionId = this.loanReadPlatformService.retrieveLoanTransactionIdByExternalId(externalTransactionId);
|
||||
if (resolvedLoanTransactionId == null) {
|
||||
throw new LoanTransactionNotFoundException(externalTransactionId);
|
||||
}
|
||||
}
|
||||
return resolvedLoanTransactionId;
|
||||
}
|
||||
@@ -585,6 +590,9 @@ public class LoanTransactionsApiResource {
|
||||
if (resolvedLoanId == null) {
|
||||
loanExternalId.throwExceptionIfEmpty();
|
||||
resolvedLoanId = this.loanReadPlatformService.retrieveLoanIdByExternalId(loanExternalId.getValue());
|
||||
if (resolvedLoanId == null) {
|
||||
throw new LoanNotFoundException(loanExternalId);
|
||||
}
|
||||
}
|
||||
return resolvedLoanId;
|
||||
}
|
||||
|
||||
+7
-2
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.exception;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
@@ -39,10 +40,14 @@ public class LoanNotFoundException extends AbstractPlatformResourceNotFoundExcep
|
||||
}
|
||||
|
||||
public LoanNotFoundException(ExternalId externalId) {
|
||||
super("error.msg.loan.external.id.invalid", "Loan with external identifier " + externalId + " does not exist", externalId);
|
||||
super("error.msg.loan.external.id.invalid",
|
||||
"Loan with external identifier " + ObjectUtils.defaultIfNull(externalId, ExternalId.empty()).getValue() + " does not exist",
|
||||
externalId);
|
||||
}
|
||||
|
||||
public LoanNotFoundException(ExternalId externalId, Exception e) {
|
||||
super("error.msg.loan.external.id.invalid", "Loan with external identifier " + externalId + " does not exist", externalId, e);
|
||||
super("error.msg.loan.external.id.invalid",
|
||||
"Loan with external identifier " + ObjectUtils.defaultIfNull(externalId, ExternalId.empty()).getValue() + " does not exist",
|
||||
externalId, e);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.exception;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
@@ -40,8 +41,15 @@ public class LoanTransactionNotFoundException extends AbstractPlatformResourceNo
|
||||
super("error.msg.loan.transaction.id.invalid", "Transaction with identifier " + id + " does not exist", id, e);
|
||||
}
|
||||
|
||||
public LoanTransactionNotFoundException(ExternalId transactionExternalId) {
|
||||
super("error.msg.loan.transaction.external.id.invalid", "Transaction with external identifier "
|
||||
+ ObjectUtils.defaultIfNull(transactionExternalId, ExternalId.empty()).getValue() + " does not exist",
|
||||
transactionExternalId);
|
||||
}
|
||||
|
||||
public LoanTransactionNotFoundException(ExternalId transactionExternalId, EmptyResultDataAccessException e) {
|
||||
super("error.msg.loan.transaction.id.invalid", "Transaction with external identifier " + transactionExternalId + " does not exist",
|
||||
super("error.msg.loan.transaction.external.id.invalid", "Transaction with external identifier "
|
||||
+ ObjectUtils.defaultIfNull(transactionExternalId, ExternalId.empty()).getValue() + " does not exist",
|
||||
transactionExternalId, e);
|
||||
}
|
||||
}
|
||||
|
||||
+142
-9
@@ -20,6 +20,8 @@ package org.apache.fineract.integrationtests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
@@ -48,6 +50,7 @@ import org.apache.fineract.client.models.PutChargeTransactionChangesRequest;
|
||||
import org.apache.fineract.client.models.PutChargeTransactionChangesResponse;
|
||||
import org.apache.fineract.client.models.PutLoansLoanIdChargesChargeIdRequest;
|
||||
import org.apache.fineract.client.models.PutLoansLoanIdChargesChargeIdResponse;
|
||||
import org.apache.fineract.client.util.CallFailedRuntimeException;
|
||||
import org.apache.fineract.integrationtests.client.IntegrationTest;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
|
||||
@@ -157,15 +160,15 @@ public class ExternalIdSupportIntegrationTest extends IntegrationTest {
|
||||
assertNotNull(penalty2Result.getResourceExternalId());
|
||||
|
||||
// Check whether we can fetch transaction templates with proper result http code (HTTP 200..300)
|
||||
ok(fineract().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr, "repayment", null, null, null));
|
||||
ok(fineract().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr, "payoutRefund", null, null, null));
|
||||
ok(fineract().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr, "waiveinterest", null, null, null));
|
||||
ok(fineract().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr, "close-rescheduled", null, null, null));
|
||||
ok(fineract().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr, "disburse", null, null, null));
|
||||
ok(fineract().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr, "recoverypayment", null, null, null));
|
||||
ok(fineract().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr, "refundbycash", null, null, null));
|
||||
ok(fineract().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr, "foreclosure", null, null, null));
|
||||
ok(fineract().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr, "creditBalanceRefund", null, null, null));
|
||||
loanTransactionHelper.retrieveTransactionTemplate(loanExternalIdStr, "repayment", null, null, null);
|
||||
loanTransactionHelper.retrieveTransactionTemplate(loanExternalIdStr, "payoutRefund", null, null, null);
|
||||
loanTransactionHelper.retrieveTransactionTemplate(loanExternalIdStr, "waiveinterest", null, null, null);
|
||||
loanTransactionHelper.retrieveTransactionTemplate(loanExternalIdStr, "close-rescheduled", null, null, null);
|
||||
loanTransactionHelper.retrieveTransactionTemplate(loanExternalIdStr, "disburse", null, null, null);
|
||||
loanTransactionHelper.retrieveTransactionTemplate(loanExternalIdStr, "recoverypayment", null, null, null);
|
||||
loanTransactionHelper.retrieveTransactionTemplate(loanExternalIdStr, "refundbycash", null, null, null);
|
||||
loanTransactionHelper.retrieveTransactionTemplate(loanExternalIdStr, "foreclosure", null, null, null);
|
||||
loanTransactionHelper.retrieveTransactionTemplate(loanExternalIdStr, "creditBalanceRefund", null, null, null);
|
||||
|
||||
// Check whether an external id was generated
|
||||
String waiveChargeExternalIdStr = UUID.randomUUID().toString();
|
||||
@@ -667,6 +670,136 @@ public class ExternalIdSupportIntegrationTest extends IntegrationTest {
|
||||
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, 50, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void negativeTest() {
|
||||
// INIT
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
final Account assetFeeAndPenaltyAccount = this.accountHelper.createAssetAccount();
|
||||
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
|
||||
|
||||
final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
|
||||
.withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
|
||||
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat()
|
||||
.withAccountingRulePeriodicAccrual(new Account[] { assetAccount, incomeAccount, expenseAccount, overpaymentAccount })
|
||||
.withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0")
|
||||
.withFeeAndPenaltyAssetAccount(assetFeeAndPenaltyAccount).build(null);
|
||||
final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJSON);
|
||||
|
||||
final PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
|
||||
|
||||
String loanExternalIdStr = UUID.randomUUID().toString();
|
||||
final HashMap loan = applyForLoanApplication(client.getClientId().intValue(), loanProductID, loanExternalIdStr);
|
||||
Integer loanId = (Integer) loan.get("resourceId");
|
||||
|
||||
this.loanTransactionHelper.approveLoan("02 September 2022", loanId);
|
||||
String txnExternalIdStr = UUID.randomUUID().toString();
|
||||
final HashMap disbursedLoanResult = this.loanTransactionHelper.disburseLoan("03 September 2022", loanId, "1000", txnExternalIdStr);
|
||||
|
||||
// Check whether the provided external id was retrieved
|
||||
assertEquals(txnExternalIdStr, disbursedLoanResult.get("resourceExternalId"));
|
||||
|
||||
// NEGATIVE SCENARIOS
|
||||
|
||||
// GET
|
||||
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, () -> this.loanTransactionHelper
|
||||
.retrieveTransactionTemplate("randomNonExistingLoanExternalId", "disburse", null, null, null));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> this.loanTransactionHelper
|
||||
.getLoanTransactionDetails("randomNonExistingLoanExternalId", "randomNonExistingLoanTransactionExternalId"));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> this.loanTransactionHelper
|
||||
.getLoanTransactionDetails(loanExternalIdStr, "randomNonExistingLoanTransactionExternalId"));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.transaction.external.id.invalid"));
|
||||
|
||||
// POST
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> this.loanTransactionHelper
|
||||
.makeChargeRefund("randomNonExistingLoanExternalId", new PostLoansLoanIdTransactionsRequest()));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> this.loanTransactionHelper.adjustLoanTransaction("randomNonExistingLoanExternalId",
|
||||
"randomNonExistingLoanTransactionExternalId", new PostLoansLoanIdTransactionsTransactionIdRequest()));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> this.loanTransactionHelper.adjustLoanTransaction(loanExternalIdStr,
|
||||
"randomNonExistingLoanTransactionExternalId", new PostLoansLoanIdTransactionsTransactionIdRequest()));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.transaction.external.id.invalid"));
|
||||
|
||||
// PUT
|
||||
exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> this.loanTransactionHelper.undoWaiveLoanCharge("randomNonExistingLoanExternalId",
|
||||
"randomNonExistingLoanTransactionExternalId", new PutChargeTransactionChangesRequest()));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> this.loanTransactionHelper.undoWaiveLoanCharge(loanExternalIdStr,
|
||||
"randomNonExistingLoanTransactionExternalId", new PutChargeTransactionChangesRequest()));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.transaction.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> this.loanTransactionHelper.getLoanCharges("randomNonExistingLoanExternalId"));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> this.loanTransactionHelper.getLoanChargeTemplate("randomNonExistingLoanExternalId"));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> this.loanTransactionHelper.getLoanCharge("randomNonExistingLoanExternalId", "randomNonExistingLoanChargeExternalId"));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> this.loanTransactionHelper.getLoanCharge(loanExternalIdStr, "randomNonExistingLoanChargeExternalId"));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loanCharge.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> this.loanTransactionHelper.payLoanCharge("randomNonExistingLoanExternalId", "randomNonExistingLoanChargeExternalId",
|
||||
new PostLoansLoanIdChargesChargeIdRequest()));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> this.loanTransactionHelper.payLoanCharge(loanExternalIdStr,
|
||||
"randomNonExistingLoanChargeExternalId", new PostLoansLoanIdChargesChargeIdRequest()));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loanCharge.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> this.loanTransactionHelper.updateLoanCharge("randomNonExistingLoanExternalId",
|
||||
"randomNonExistingLoanChargeExternalId", new PutLoansLoanIdChargesChargeIdRequest()));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> this.loanTransactionHelper.updateLoanCharge(loanExternalIdStr,
|
||||
"randomNonExistingLoanChargeExternalId", new PutLoansLoanIdChargesChargeIdRequest()));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loanCharge.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class, () -> this.loanTransactionHelper
|
||||
.deleteLoanCharge("randomNonExistingLoanExternalId", "randomNonExistingLoanChargeExternalId"));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loan.external.id.invalid"));
|
||||
|
||||
exception = assertThrows(CallFailedRuntimeException.class,
|
||||
() -> this.loanTransactionHelper.deleteLoanCharge(loanExternalIdStr, "randomNonExistingLoanChargeExternalId"));
|
||||
assertEquals(404, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage().contains("error.msg.loanCharge.external.id.invalid"));
|
||||
}
|
||||
|
||||
private HashMap applyForLoanApplication(final Integer clientID, final Integer loanProductID, final String externalId) {
|
||||
final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1")
|
||||
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1")
|
||||
|
||||
+7
@@ -52,6 +52,7 @@ import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentSchedule;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdSummary;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTemplateResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse;
|
||||
import org.apache.fineract.client.models.GetPaymentTypesResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdRequest;
|
||||
@@ -1612,4 +1613,10 @@ public class LoanTransactionHelper extends IntegrationTest {
|
||||
return chargebackPayload;
|
||||
}
|
||||
|
||||
public GetLoansLoanIdTransactionsTemplateResponse retrieveTransactionTemplate(String loanExternalIdStr, String command,
|
||||
String dateFormat, String transactionDate, String locale) {
|
||||
return ok(
|
||||
fineract().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr, command, dateFormat, transactionDate, locale));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user