FINERACT-1760: Fix error handling

This commit is contained in:
Adam Saghy
2022-11-30 11:13:21 +01:00
parent 8c7e417c5d
commit e95eba3e8a
7 changed files with 188 additions and 12 deletions
@@ -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);
}
}
@@ -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;
}
@@ -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;
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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")
@@ -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));
}
}