FINERACT-2326: Not implemented exception handling
This commit is contained in:
+10
@@ -25,6 +25,7 @@ import static org.apache.http.HttpStatus.SC_FORBIDDEN;
|
||||
import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
|
||||
import static org.apache.http.HttpStatus.SC_METHOD_NOT_ALLOWED;
|
||||
import static org.apache.http.HttpStatus.SC_NOT_FOUND;
|
||||
import static org.apache.http.HttpStatus.SC_NOT_IMPLEMENTED;
|
||||
import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE;
|
||||
import static org.apache.http.HttpStatus.SC_UNAUTHORIZED;
|
||||
|
||||
@@ -139,6 +140,15 @@ public class ApiGlobalErrorResponse {
|
||||
"Errors contain reason for domain rule violation.", errors);
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse notImplemented(final String globalisationMessageCode, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
final List<ApiParameterError> errors = new ArrayList<>();
|
||||
errors.add(ApiParameterError.generalError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs));
|
||||
|
||||
return create(SC_NOT_IMPLEMENTED, "validation.msg.not.implemented", "Request was understood but not implemented.",
|
||||
"Errors contain reason for not implemented violation.", errors);
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse dataIntegrityError(final String globalisationMessageCode, final String defaultUserMessage,
|
||||
final String parameterName, final Object... defaultUserMessageArgs) {
|
||||
final List<ApiParameterError> errors = new ArrayList<>();
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.core.exceptionmapper;
|
||||
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import jakarta.ws.rs.ext.ExceptionMapper;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse;
|
||||
import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An {@link ExceptionMapper} to map {@link UnsupportedOperationException} thrown by platform into a HTTP API friendly
|
||||
* format.
|
||||
*
|
||||
* The {@link UnsupportedOperationException} is thrown when an operation was not yet implemented.
|
||||
*/
|
||||
@Provider
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
@Slf4j
|
||||
public class UnsupporterOperationExceptionMapper implements FineractExceptionMapper, ExceptionMapper<UnsupportedOperationException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(final UnsupportedOperationException exception) {
|
||||
log.warn("Exception occurred", ErrorHandler.findMostSpecificException(exception));
|
||||
final ApiGlobalErrorResponse notFoundErrorResponse = ApiGlobalErrorResponse.notImplemented("not.implemented",
|
||||
exception.getMessage());
|
||||
return Response.status(Status.NOT_IMPLEMENTED).entity(notFoundErrorResponse).type(MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int errorCode() {
|
||||
return 5010;
|
||||
}
|
||||
}
|
||||
+17
@@ -538,4 +538,21 @@ public class LoanReAgingStepDef extends AbstractStepDef {
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
@When("Admin creates a Loan re-aging transaction by Loan external ID with the following data, but fails with {int} error code:")
|
||||
public void adminCreatesALoanReAgingTransactionByLoanExternalIDWithTheFollowingDataButFailsWithErrorCode(int errorCode,
|
||||
DataTable table) {
|
||||
PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
String loanExternalId = loanResponse.getResourceExternalId();
|
||||
|
||||
PostLoansLoanIdTransactionsRequest reAgingRequest = setReAgeingRequestProperties(//
|
||||
LoanRequestFactory.defaultReAgingRequest(), //
|
||||
table.row(0), //
|
||||
table.row(1) //
|
||||
);
|
||||
|
||||
CallFailedRuntimeException response = fail(() -> fineractClient.loanTransactions().executeLoanTransaction1(loanExternalId,
|
||||
reAgingRequest, Map.<String, Object>of("command", "reAge")));
|
||||
assertThat(response.getStatus()).isEqualTo(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12320,7 +12320,6 @@ Feature: LoanReAging
|
||||
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false |
|
||||
| 01 March 2024 | Repayment | 17.01 | 16.52 | 0.49 | 0.0 | 0.0 | 67.05 | true | false |
|
||||
| 15 March 2024 | Re-age | 85.08 | 83.57 | 1.51 | 0.0 | 0.0 | 0.0 | false | true |
|
||||
|
||||
When Loan Pay-off is made on "01 April 2024"
|
||||
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
|
||||
|
||||
@@ -14537,4 +14536,34 @@ Feature: LoanReAging
|
||||
When Loan Pay-off is made on "01 April 2024"
|
||||
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
|
||||
|
||||
@TestRailId:C4272 @AdvancedPaymentAllocation
|
||||
Scenario: Verify Re-aging on interest bearing, no interest recalculation loan is not allowed (not implemented)
|
||||
When Admin sets the business date to "01 January 2024"
|
||||
When Admin creates a client with random data
|
||||
When Admin set "LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_PRINCIPAL_INTEREST_FEE" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule
|
||||
When Admin creates a fully customized loan with the following data:
|
||||
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||
| LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_PRINCIPAL_INTEREST_FEE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024"
|
||||
When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount
|
||||
Then Loan Repayment schedule has 6 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024| | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||
| 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
Then Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 |
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
|
||||
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false |
|
||||
When Admin creates a Loan re-aging transaction by Loan external ID with the following data, but fails with 501 error code:
|
||||
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||
| 1 | MONTHS | 16 January 2025 | 5 |
|
||||
When Loan Pay-off is made on "01 January 2024"
|
||||
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
|
||||
|
||||
|
||||
+7
-8
@@ -62,7 +62,6 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
@@ -165,34 +164,34 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
protected Money handleTransactionThatIsALateRepaymentOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
||||
List<LoanRepaymentScheduleInstallment> installments, LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges) {
|
||||
throw new NotImplementedException();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
||||
List<LoanRepaymentScheduleInstallment> installments, LoanTransaction loanTransaction, Money paymentInAdvance,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges) {
|
||||
throw new NotImplementedException();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Money handleTransactionThatIsOnTimePaymentOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
||||
LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges) {
|
||||
throw new NotImplementedException();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Money handleRefundTransactionPaymentOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
||||
LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
throw new NotImplementedException();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Money handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> loanCharges) {
|
||||
throw new NotImplementedException();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// only for progressive loans
|
||||
@@ -2957,12 +2956,12 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
handleReAgeWithInterestRecalculationEnabled(loanTransaction, progressiveTransactionCtx);
|
||||
} else if (loanTransaction.getLoan().isInterestBearing() && !loanTransaction.getLoan().isInterestRecalculationEnabled()) {
|
||||
// TODO: implement interestRecalculation = false logic
|
||||
throw new NotImplementedException(
|
||||
throw new UnsupportedOperationException(
|
||||
"Logic for re-aging when interest bearing loan has interestRecalculation disabled is not implemented");
|
||||
}
|
||||
|
||||
} else if (LoanReAgeInterestHandlingType.WAIVE_INTEREST.equals(loanReAgeParameter.getInterestHandlingType())) {
|
||||
throw new NotImplementedException("WAIVE_INTEREST interest handling strategy for re-aging is not implemented");
|
||||
throw new UnsupportedOperationException("WAIVE_INTEREST interest handling strategy for re-aging is not implemented");
|
||||
} else {
|
||||
if (LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST.equals(loanReAgeParameter.getInterestHandlingType())) {
|
||||
CommonReAgeSettings settings = new CommonReAgeSettings(false, true, true, true);
|
||||
|
||||
Reference in New Issue
Block a user