diff --git a/pom.xml b/pom.xml index 05d652b..cda5e19 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,7 @@ io.quarkus.platform 3.14.2 3.0.0-M7 + 3.9.1 @@ -104,6 +105,12 @@ 5.13.0 test + + org.wiremock + wiremock + test + ${wiremock.version} + io.quarkus quarkus-jacoco diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/ApiConfigCacheClient.java b/src/main/java/it/gov/pagopa/payment/options/clients/ApiConfigCacheClient.java index aadc946..0f87393 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/ApiConfigCacheClient.java +++ b/src/main/java/it/gov/pagopa/payment/options/clients/ApiConfigCacheClient.java @@ -1,6 +1,6 @@ package it.gov.pagopa.payment.options.clients; -import it.gov.pagopa.payment.options.clients.model.ConfigDataV1; +import it.gov.pagopa.payment.options.models.clients.cache.ConfigDataV1; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.QueryParam; diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/CreditorInstitutionRestClient.java b/src/main/java/it/gov/pagopa/payment/options/clients/CreditorInstitutionRestClient.java new file mode 100644 index 0000000..0c3ecb6 --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/clients/CreditorInstitutionRestClient.java @@ -0,0 +1,98 @@ +package it.gov.pagopa.payment.options.clients; + +import com.fasterxml.jackson.databind.ObjectMapper; +import it.gov.pagopa.payment.options.exception.CreditorInstitutionException; +import it.gov.pagopa.payment.options.exception.PaymentOptionsException; +import it.gov.pagopa.payment.options.models.ErrorResponse; +import it.gov.pagopa.payment.options.models.clients.creditorInstitution.PaymentOptionsResponse; +import it.gov.pagopa.payment.options.models.enums.AppErrorCodeEnum; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.rest.client.RestClientBuilder; +import org.jboss.resteasy.reactive.ClientWebApplicationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Rest Client for Creditor Institution services + */ +@ApplicationScoped +public class CreditorInstitutionRestClient { + + private final Logger logger = LoggerFactory.getLogger(CreditorInstitutionRestClient.class); + + @Inject + ObjectMapper objectMapper; + + /** + * + * @param endpoint endpoint to use for the call (should be equivalent to the forwader( + * @param proxyHost proxy host, optional + * @param proxyPort proxy port, optional + * @param targetHost verify service host + * @param targetPort verify service port + * @param targetPath verify service path + * @param fiscalCode fiscal code to be used as input for the call + * @param noticeNumber notice number to be used as input for the call + * @return PaymentOptionResponse + * @throws MalformedURLException + * @throws PaymentOptionsException + */ + public PaymentOptionsResponse callEcPaymentOptionsVerify( + String endpoint, String proxyHost, Long proxyPort, + String targetHost, Long targetPort, String targetPath, +// String idPA, String idBrokerPA, String idStazione, + String fiscalCode, String noticeNumber) + throws MalformedURLException { + + RestClientBuilder builder = + RestClientBuilder.newBuilder().baseUrl(new URL(endpoint)); + if (proxyHost != null && proxyPort != null) { + builder = builder.proxyAddress(proxyHost, proxyPort.intValue()); + } + CreditorInstitutionRestClientInterface ecRestClientInterface = builder.build( + CreditorInstitutionRestClientInterface.class); + + try (Response response = ecRestClientInterface.verifyPaymentOptions( + fiscalCode, noticeNumber, +// idPA, idBrokerPA, idStazione, + targetHost, targetPort.intValue(), + targetPath)) { + + return objectMapper.readValue( + response.readEntity(String.class), PaymentOptionsResponse.class); + + } catch (ClientWebApplicationException clientWebApplicationException) { + logger.error("[Payment Options] Encountered REST client exception: {}", + clientWebApplicationException.getMessage()); + manageErrorResponse(clientWebApplicationException.getResponse()); + return null; + } catch (Exception e) { + logger.error("[Payment Options] Unable to call the station due to error: {}", + e.getMessage()); + throw new PaymentOptionsException( + AppErrorCodeEnum.ODP_STAZIONE_INT_PA_IRRAGGIUNGIBILE, e.getMessage()); + } + + } + + private void manageErrorResponse(Response response) { + try { + ErrorResponse errorResponse = objectMapper.readValue( + response.readEntity(String.class), ErrorResponse.class); + throw new CreditorInstitutionException(errorResponse, + "[Payment Options] Encountered a managed error calling the station REST endpoint"); + } catch (CreditorInstitutionException creditorInstitutionException) { + throw creditorInstitutionException; + } catch (Exception e) { + logger.error("[Payment Options] Unable to call the station due to error: {}", + e.getMessage()); + throw new PaymentOptionsException( + AppErrorCodeEnum.ODP_STAZIONE_INT_PA_IRRAGGIUNGIBILE, e.getMessage()); + } + } + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/CreditorInstitutionRestClientInterface.java b/src/main/java/it/gov/pagopa/payment/options/clients/CreditorInstitutionRestClientInterface.java new file mode 100644 index 0000000..61708e2 --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/clients/CreditorInstitutionRestClientInterface.java @@ -0,0 +1,30 @@ +package it.gov.pagopa.payment.options.clients; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam; + +/** + * Template for the creditor institution REST client + */ +public interface CreditorInstitutionRestClientInterface { + + @GET + @Path("/payment-options/organizations/{fiscal-code}/notices/{notice-number}") + @ClientHeaderParam(name = "Ocp-Apim-Subscription-Key", value = "${CreditorInstitutionRestClient.ocpSubKey}") + Response verifyPaymentOptions( + @PathParam("fiscal-code") String fiscalCode, + @PathParam("notice-number") String noticeNumber, +// @QueryParam("idPA") String idPA, +// @QueryParam("idBrokerPA") String idBrokerPA, +// @QueryParam("idStation") String idStation, + @HeaderParam("X-Host-Url") String hostUrl, + @HeaderParam("X-Host-Port") Integer hostPort, + @HeaderParam("X-Host-Path") String hostPath + ); + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/consumers/ConfigCacheUpdatesConsumer.java b/src/main/java/it/gov/pagopa/payment/options/consumers/ConfigCacheUpdatesConsumer.java index 113ccb3..f421e5e 100644 --- a/src/main/java/it/gov/pagopa/payment/options/consumers/ConfigCacheUpdatesConsumer.java +++ b/src/main/java/it/gov/pagopa/payment/options/consumers/ConfigCacheUpdatesConsumer.java @@ -1,10 +1,9 @@ package it.gov.pagopa.payment.options.consumers; -import it.gov.pagopa.payment.options.models.CacheUpdateEvent; +import it.gov.pagopa.payment.options.models.events.CacheUpdateEvent; import it.gov.pagopa.payment.options.services.ConfigCacheService; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.transaction.Transactional; import org.eclipse.microprofile.reactive.messaging.Incoming; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/it/gov/pagopa/payment/options/exception/CreditorInstitutionException.java b/src/main/java/it/gov/pagopa/payment/options/exception/CreditorInstitutionException.java new file mode 100644 index 0000000..f1ac59a --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/exception/CreditorInstitutionException.java @@ -0,0 +1,38 @@ +package it.gov.pagopa.payment.options.exception; + +import it.gov.pagopa.payment.options.models.ErrorResponse; +import it.gov.pagopa.payment.options.models.enums.AppErrorCodeEnum; +import jakarta.ws.rs.core.Response; +import lombok.Getter; +import java.util.Objects; + +@Getter +public class CreditorInstitutionException extends RuntimeException { + + private ErrorResponse errorResponse; + + /** + * Constructs new exception with provided error code and message + * + * @param errorResponse Error Response + * @param message Detail message + */ + public CreditorInstitutionException(ErrorResponse errorResponse, String message) { + super(message); + this.errorResponse = Objects.requireNonNull(errorResponse); + } + + /** + * Constructs new exception with provided error response, message and cause + * + * @param errorResponse Error Response + * @param message Detail message + * @param cause Exception causing the constructed one + */ + public CreditorInstitutionException(ErrorResponse errorResponse, String message, Throwable cause) { + super(message, cause); + this.errorResponse = Objects.requireNonNull(errorResponse); + } + + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/exception/PaymentOptionsException.java b/src/main/java/it/gov/pagopa/payment/options/exception/PaymentOptionsException.java new file mode 100644 index 0000000..fec917e --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/exception/PaymentOptionsException.java @@ -0,0 +1,50 @@ +package it.gov.pagopa.payment.options.exception; + +import it.gov.pagopa.payment.options.models.enums.AppErrorCodeEnum; +import jakarta.ws.rs.core.Response; +import lombok.Getter; +import java.util.Objects; + +/** + * Base exception for PaymentOptions exceptions + */ +@Getter +public class PaymentOptionsException extends RuntimeException { + + /** + * Error code of this exception + * -- GETTER -- + * Returns error code + * + * @return Error code of this exception + */ + private final AppErrorCodeEnum errorCode; + + /** + * Constructs new exception with provided error code and message + * + * @param errorCode Error code + * @param message Detail message + */ + public PaymentOptionsException(AppErrorCodeEnum errorCode, String message) { + super(message); + this.errorCode = Objects.requireNonNull(errorCode); + } + + /** + * Constructs new exception with provided error code, message and cause + * + * @param errorCode Error code + * @param message Detail message + * @param cause Exception causing the constructed one + */ + public PaymentOptionsException(AppErrorCodeEnum errorCode, String message, Throwable cause) { + super(message, cause); + this.errorCode = Objects.requireNonNull(errorCode); + } + + public static Response.Status getHttpStatus(PaymentOptionsException e) { + return e.getErrorCode().getStatus(); + } + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/exception/mapper/ExceptionMapper.java b/src/main/java/it/gov/pagopa/payment/options/exception/mapper/ExceptionMapper.java new file mode 100644 index 0000000..7229cb3 --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/exception/mapper/ExceptionMapper.java @@ -0,0 +1,88 @@ +package it.gov.pagopa.payment.options.exception.mapper; + +import static it.gov.pagopa.payment.options.exception.PaymentOptionsException.getHttpStatus; +import static org.jboss.resteasy.reactive.RestResponse.Status.NOT_FOUND; +import static org.jboss.resteasy.reactive.RestResponse.StatusCode.INTERNAL_SERVER_ERROR; + +import io.smallrye.mutiny.CompositeException; +import it.gov.pagopa.payment.options.exception.CreditorInstitutionException; +import it.gov.pagopa.payment.options.exception.PaymentOptionsException; +import it.gov.pagopa.payment.options.models.ErrorResponse; +import it.gov.pagopa.payment.options.models.enums.AppErrorCodeEnum; +import jakarta.ws.rs.NotFoundException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +import java.time.Instant; +import java.util.List; +import org.jboss.resteasy.reactive.server.ServerExceptionMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExceptionMapper { + + Logger logger = LoggerFactory.getLogger(ExceptionMapper.class); + + private ErrorResponse buildErrorResponse(Response.Status status, AppErrorCodeEnum errorCode, String message) { + return ErrorResponse.builder() + .httpStatusCode(status.getStatusCode()) + .httpStatusDescription(status.getReasonPhrase()) + .appErrorCode(errorCode.getErrorCode()) + .errorMessage(errorCode.getErrorMessage()) + .timestamp(Instant.now().getEpochSecond()) + .build(); + } + + @ServerExceptionMapper + public Response mapCompositeException(CompositeException exception) { + logger.error(exception.getMessage(), exception); + Exception composedException; + List causes = exception.getCauses(); + composedException = (Exception) causes.get(causes.size() - 1); + + if(composedException instanceof NotFoundException ex) { + return mapNotFoundException(ex); + } else if(composedException instanceof PaymentOptionsException paymentNoticeException) { + return mapPaymentNoticeException(paymentNoticeException); + } else if(composedException instanceof CreditorInstitutionException creditorInstitutionException) { + return mapCreditorInstitutionException(creditorInstitutionException); + } else { + return mapGenericException(exception); + } + + } + + @ServerExceptionMapper + public Response mapCreditorInstitutionException(CreditorInstitutionException creditorInstitutionException) { + logger.error(creditorInstitutionException.getMessage(), creditorInstitutionException); + return Response.status(creditorInstitutionException.getErrorResponse().getHttpStatusCode()) + .entity(creditorInstitutionException.getErrorResponse()).build(); + } + + @ServerExceptionMapper + public Response mapNotFoundException(NotFoundException exception) { + logger.error(exception.getMessage(), exception); + return Response.status(NOT_FOUND).entity( + buildErrorResponse(Status.NOT_FOUND, AppErrorCodeEnum.ODP_SINTASSI, + "Invalid parameters on request")).build(); + } + + @ServerExceptionMapper + public Response mapPaymentNoticeException(PaymentOptionsException exception) { + logger.error(exception.getMessage(), exception); + Response.Status status = getHttpStatus(exception); + return Response.status(status).entity(buildErrorResponse(status, + exception.getErrorCode(), exception.getMessage())).build(); + } + + @ServerExceptionMapper + public Response mapGenericException(Exception exception) { + logger.error(exception.getMessage(), exception); + return Response.status(INTERNAL_SERVER_ERROR) + .entity(buildErrorResponse( + Response.Status.INTERNAL_SERVER_ERROR, + AppErrorCodeEnum.ODP_SYSTEM_ERROR, + "Unexpected Error")) + .build(); + } + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/models/ConfigCacheData.java b/src/main/java/it/gov/pagopa/payment/options/models/ConfigCacheData.java index 1f0e417..f60d3cb 100644 --- a/src/main/java/it/gov/pagopa/payment/options/models/ConfigCacheData.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/ConfigCacheData.java @@ -1,6 +1,6 @@ package it.gov.pagopa.payment.options.models; -import it.gov.pagopa.payment.options.clients.model.ConfigDataV1; +import it.gov.pagopa.payment.options.models.clients.cache.ConfigDataV1; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/it/gov/pagopa/payment/options/models/ErrorResponse.java b/src/main/java/it/gov/pagopa/payment/options/models/ErrorResponse.java new file mode 100644 index 0000000..48d16cf --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/models/ErrorResponse.java @@ -0,0 +1,36 @@ +package it.gov.pagopa.payment.options.models; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import lombok.Builder; +import lombok.Getter; +import lombok.extern.jackson.Jacksonized; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +/** + * Model class for the error response + */ +@Getter +@Builder +@Jacksonized +@RegisterForReflection +public class ErrorResponse { + + @Schema(example = "500") + private int httpStatusCode; + + @Schema(example = "Internal Server Error") + private String httpStatusDescription; + + @Schema(example = "An unexpected error has occurred. Please contact support.") + private String errorMessage; + + @Schema(example = "ODP-") + private String appErrorCode; + + @Schema(example = "1724425035") + private Long timestamp; + + @Schema(example = "2024-08-23T14:57:15.635528") + private String dateTime; + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/BrokerCreditorInstitution.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/BrokerCreditorInstitution.java similarity index 72% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/BrokerCreditorInstitution.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/BrokerCreditorInstitution.java index 81773d1..4fca621 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/BrokerCreditorInstitution.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/BrokerCreditorInstitution.java @@ -1,15 +1,11 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; -import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import java.util.Objects; /** * BrokerCreditorInstitution diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/ConfigDataV1.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/ConfigDataV1.java similarity index 98% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/ConfigDataV1.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/ConfigDataV1.java index 3bcf1a6..393ff6f 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/ConfigDataV1.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/ConfigDataV1.java @@ -1,4 +1,4 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/Connection.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Connection.java similarity index 94% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/Connection.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Connection.java index aa328aa..4b095e0 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/Connection.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Connection.java @@ -1,4 +1,4 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/CreditorInstitution.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/CreditorInstitution.java similarity index 93% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/CreditorInstitution.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/CreditorInstitution.java index 8150858..062d0c9 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/CreditorInstitution.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/CreditorInstitution.java @@ -1,4 +1,4 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/CreditorInstitutionAddress.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/CreditorInstitutionAddress.java similarity index 91% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/CreditorInstitutionAddress.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/CreditorInstitutionAddress.java index 5761204..04355b1 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/CreditorInstitutionAddress.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/CreditorInstitutionAddress.java @@ -1,4 +1,4 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/Proxy.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Proxy.java similarity index 73% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/Proxy.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Proxy.java index 1ae507a..c32bede 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/Proxy.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Proxy.java @@ -1,9 +1,6 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; -import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/Redirect.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Redirect.java similarity index 85% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/Redirect.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Redirect.java index 543aa29..bbfaf88 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/Redirect.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Redirect.java @@ -1,4 +1,4 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonCreator; @@ -8,9 +8,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; /** * Redirect diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/Service.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Service.java similarity index 73% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/Service.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Service.java index 7d3b03a..6a436e3 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/Service.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Service.java @@ -1,9 +1,6 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/Station.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Station.java similarity index 86% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/Station.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Station.java index a1de3ef..1b17687 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/Station.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Station.java @@ -1,9 +1,6 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; -import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -71,4 +68,10 @@ public class Station { @JsonProperty("flag_standin") private Boolean flagStandin = null; + @JsonProperty("verify_payment_option_enabled") + private Boolean verifyPaymentOptionEnabled = false; + + @JsonProperty("rest_endpoint") + private String restEndpoint; + } diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/StationCreditorInstitution.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/StationCreditorInstitution.java similarity index 94% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/StationCreditorInstitution.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/StationCreditorInstitution.java index 56e19fe..3af11c5 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/StationCreditorInstitution.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/StationCreditorInstitution.java @@ -1,4 +1,4 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/src/main/java/it/gov/pagopa/payment/options/clients/model/Timeouts.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Timeouts.java similarity index 89% rename from src/main/java/it/gov/pagopa/payment/options/clients/model/Timeouts.java rename to src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Timeouts.java index 796636e..c1fdf04 100644 --- a/src/main/java/it/gov/pagopa/payment/options/clients/model/Timeouts.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/cache/Timeouts.java @@ -1,4 +1,4 @@ -package it.gov.pagopa.payment.options.clients.model; +package it.gov.pagopa.payment.options.models.clients.cache; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/src/main/java/it/gov/pagopa/payment/options/models/clients/creditorInstitution/Installment.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/creditorInstitution/Installment.java new file mode 100644 index 0000000..3731d96 --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/creditorInstitution/Installment.java @@ -0,0 +1,26 @@ +package it.gov.pagopa.payment.options.models.clients.creditorInstitution; + +import it.gov.pagopa.payment.options.models.enums.EnumInstallment; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Installment { + + private String nav; + private String iuv; + private Long amount; + private String description; + private String dueDate; + private String validFrom; + private EnumInstallment status; + private String statusReason; + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/models/clients/creditorInstitution/PaymentOption.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/creditorInstitution/PaymentOption.java new file mode 100644 index 0000000..d3a1ccd --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/creditorInstitution/PaymentOption.java @@ -0,0 +1,28 @@ +package it.gov.pagopa.payment.options.models.clients.creditorInstitution; + +import it.gov.pagopa.payment.options.models.enums.EnumPo; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import java.util.List; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PaymentOption { + + private String description; + private Integer numberOfInstallments; + private String dueDate; + private String validFrom; + private Long amount; + private EnumPo status; + private String statusReason; + private Boolean allCCP; + private List installments; + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/models/clients/creditorInstitution/PaymentOptionsResponse.java b/src/main/java/it/gov/pagopa/payment/options/models/clients/creditorInstitution/PaymentOptionsResponse.java new file mode 100644 index 0000000..81a0880 --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/models/clients/creditorInstitution/PaymentOptionsResponse.java @@ -0,0 +1,23 @@ +package it.gov.pagopa.payment.options.models.clients.creditorInstitution; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import java.util.List; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PaymentOptionsResponse { + + private String paTaxCode; + private String paFullName; + private String paOfficeName; + private Boolean standin; + private List paymentOptions; + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/models/enums/AppErrorCodeEnum.java b/src/main/java/it/gov/pagopa/payment/options/models/enums/AppErrorCodeEnum.java new file mode 100644 index 0000000..e34974c --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/models/enums/AppErrorCodeEnum.java @@ -0,0 +1,30 @@ +package it.gov.pagopa.payment.options.models.enums; + +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +import lombok.Getter; + +/** + * Enumeration for application error codes and messages + */ +@Getter +public enum AppErrorCodeEnum { + + ODP_STAZIONE_INT_PA_IRRAGGIUNGIBILE(Status.SERVICE_UNAVAILABLE, "ODP_STAZIONE_INT_PA_IRRAGGIUNGIBILE", "Required station is currently unavailable through the provided config params"), + ODP_SEMANTICA(Response.Status.BAD_REQUEST, "ODP_SINTASSI", "Bad request error on input syntax"), + ODP_SINTASSI(Response.Status.BAD_REQUEST, "ODP_SEMANTICA", "Bad request error due to semantic error withing the verify flow"), + ODP_SYSTEM_ERROR(Response.Status.INTERNAL_SERVER_ERROR, "ODP_SYSTEM_ERROR", "Unexpected system Error"), + + PA_SYSTEM_ERROR(Response.Status.INTERNAL_SERVER_ERROR, "PA_SYSTEM_ERROR", "Unexpected error on EC system call"); + + + private final Response.Status status; + private final String errorCode; + private final String errorMessage; + + AppErrorCodeEnum(Response.Status status, String errorCode, String errorMessage) { + this.status = status; + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } +} diff --git a/src/main/java/it/gov/pagopa/payment/options/models/enums/EnumInstallment.java b/src/main/java/it/gov/pagopa/payment/options/models/enums/EnumInstallment.java new file mode 100644 index 0000000..f36a598 --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/models/enums/EnumInstallment.java @@ -0,0 +1,11 @@ +package it.gov.pagopa.payment.options.models.enums; + +public enum EnumInstallment { + + POI_UNPAID, + POI_PAID, + POI_EXPIRED_NOT_PAYABLE, + POI_EXPIRED_UNPAID, + POI_INVALID + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/models/enums/EnumPo.java b/src/main/java/it/gov/pagopa/payment/options/models/enums/EnumPo.java new file mode 100644 index 0000000..8c1da9d --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/models/enums/EnumPo.java @@ -0,0 +1,12 @@ +package it.gov.pagopa.payment.options.models.enums; + +public enum EnumPo { + + PO_UNPAID, + PO_PAID, + PO_PARTIALLY_PAID, + PO_EXPIRED_NOT_PAYABLE, + PO_EXPIRED_UNPAID, + PO_INVALID + +} diff --git a/src/main/java/it/gov/pagopa/payment/options/models/CacheUpdateEvent.java b/src/main/java/it/gov/pagopa/payment/options/models/events/CacheUpdateEvent.java similarity index 85% rename from src/main/java/it/gov/pagopa/payment/options/models/CacheUpdateEvent.java rename to src/main/java/it/gov/pagopa/payment/options/models/events/CacheUpdateEvent.java index 5eb2ff4..b884f63 100644 --- a/src/main/java/it/gov/pagopa/payment/options/models/CacheUpdateEvent.java +++ b/src/main/java/it/gov/pagopa/payment/options/models/events/CacheUpdateEvent.java @@ -1,4 +1,4 @@ -package it.gov.pagopa.payment.options.models; +package it.gov.pagopa.payment.options.models.events; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/src/main/java/it/gov/pagopa/payment/options/services/ConfigCacheService.java b/src/main/java/it/gov/pagopa/payment/options/services/ConfigCacheService.java index 7da79d6..a2870af 100644 --- a/src/main/java/it/gov/pagopa/payment/options/services/ConfigCacheService.java +++ b/src/main/java/it/gov/pagopa/payment/options/services/ConfigCacheService.java @@ -2,9 +2,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import it.gov.pagopa.payment.options.clients.ApiConfigCacheClient; -import it.gov.pagopa.payment.options.clients.model.ConfigDataV1; -import it.gov.pagopa.payment.options.consumers.ConfigCacheUpdatesConsumer; -import it.gov.pagopa.payment.options.models.CacheUpdateEvent; +import it.gov.pagopa.payment.options.models.clients.cache.ConfigDataV1; +import it.gov.pagopa.payment.options.models.events.CacheUpdateEvent; import it.gov.pagopa.payment.options.models.ConfigCacheData; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; diff --git a/src/main/java/it/gov/pagopa/payment/options/services/CreditorInstitutionService.java b/src/main/java/it/gov/pagopa/payment/options/services/CreditorInstitutionService.java new file mode 100644 index 0000000..2ac1a17 --- /dev/null +++ b/src/main/java/it/gov/pagopa/payment/options/services/CreditorInstitutionService.java @@ -0,0 +1,108 @@ +package it.gov.pagopa.payment.options.services; + +import it.gov.pagopa.payment.options.clients.CreditorInstitutionRestClient; +import it.gov.pagopa.payment.options.exception.PaymentOptionsException; +import it.gov.pagopa.payment.options.models.clients.cache.Connection.ProtocolEnum; +import it.gov.pagopa.payment.options.models.clients.cache.Station; +import it.gov.pagopa.payment.options.models.clients.creditorInstitution.PaymentOptionsResponse; +import it.gov.pagopa.payment.options.models.enums.AppErrorCodeEnum; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import java.net.MalformedURLException; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Service containing methods to manage call to the creditor institution REST service + */ +@ApplicationScoped +public class CreditorInstitutionService { + + private final Logger logger = LoggerFactory.getLogger(CreditorInstitutionService.class); + + @ConfigProperty(name = "CreditorInstitutionRestClient.apimEndpoint") + String APIM_FORWARDER_ENDPOINT; + + static String PAYMENT_OPTIONS_SERVICE_SUFFIX = "/payment-options/organizations/%s/notices/%s"; + + @Inject + CreditorInstitutionRestClient creditorInstitutionRestClient; + + /** + * Using the provided input attempts to call the creditor institution service + * to obtain the list paymentOptions related to the input + * + * The method contains checks regarding the endpoint to use, and attempts to + * extract the REST target params + * +// * @param idPA pa identifier +// * @param idBrokerPA broker pa identifier + * @param noticeNumber input notice number + * @param fiscalCode input fiscal code + * @param station station containing the connection config to use + * @return + */ + public PaymentOptionsResponse getPaymentOptions( + //String idPA, String idBrokerPA, + String noticeNumber, String fiscalCode, Station station) { + + if (station.getConnection().getIp() == null || + !APIM_FORWARDER_ENDPOINT.contains(station.getConnection().getIp())) { + throw new PaymentOptionsException(AppErrorCodeEnum.ODP_STAZIONE_INT_PA_IRRAGGIUNGIBILE, + "[Payment Options] Station not configured to pass through the APIM Forwarder"); + } + + String endpoint = getEndpoint(station); + + if (station.getRestEndpoint() == null) { + throw new PaymentOptionsException(AppErrorCodeEnum.ODP_SEMANTICA, + "[Payment Options] Station new verify endpoint not provided"); + } + + String targetHost; + long targetPort; + String targetPath; + try { + String[] verifyEndpointParts = + station.getRestEndpoint().split("/", 4); + targetHost = verifyEndpointParts[0] + verifyEndpointParts[2]; + String[] hostSplit = verifyEndpointParts[2].split(":"); + targetPort = hostSplit.length > 1 ? + Long.parseLong(hostSplit[1]) : + verifyEndpointParts[0].contains(ProtocolEnum.HTTPS.name().toLowerCase()) ? + 443L : 80L; + targetPath = verifyEndpointParts[3].concat( + String.format(PAYMENT_OPTIONS_SERVICE_SUFFIX, fiscalCode, noticeNumber)); + } catch (Exception e) { + logger.error("[Payment Options] Malformed Target URL: {}", e.getMessage()); + throw new PaymentOptionsException(AppErrorCodeEnum.ODP_SEMANTICA, e.getMessage()); + } + + try { + return creditorInstitutionRestClient.callEcPaymentOptionsVerify( + endpoint, + station.getProxy() != null ? station.getProxy().getProxyHost() : null, + station.getProxy() != null ? station.getProxy().getProxyPort() : null, + targetHost, targetPort, targetPath, + fiscalCode, noticeNumber + ); + } catch (MalformedURLException e) { + logger.error("[Payment Options] Malformed URL: {}", e.getMessage()); + throw new PaymentOptionsException(AppErrorCodeEnum.ODP_SEMANTICA, e.getMessage()); + } + + } + + private static String getEndpoint(Station station) { + return (station.getConnection().getProtocol() != null && + (station.getConnection().getProtocol().equals(ProtocolEnum.HTTPS)) ? + ProtocolEnum.HTTPS.name().toLowerCase() : + station.getConnection().getProtocol().name().toLowerCase()) + + "://" + station.getConnection().getIp() + ":" + + (station.getConnection().getPort() != null ? + String.valueOf(station.getConnection().getPort()) : "80") + + PAYMENT_OPTIONS_SERVICE_SUFFIX; + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 4117435..9a12840 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -14,8 +14,7 @@ quarkus.native.additional-build-args=-H:ResourceConfigurationFiles=resources-con ################### ## LOG ################### -quarkus.log.level=${LOG_LEVEL:INFO} - +quarkus.log.level=${LOG_LEVEL:DEBUG} quarkus.log.category."org.jboss".level=${JBOSS_LOG_LEVEL:DEBUG} quarkus.log.category."it.gov.pagopa.payment.options".level=${APP_LOG_LEVEL:DEBUG} %dev.quarkus.log.console.json=false @@ -56,6 +55,13 @@ mp.messaging.incoming.nodo-dei-pagamenti-cache.connections.max.request.size=${KA quarkus.rest-client."it.gov.pagopa.payment.options.clients.ApiConfigCacheClient".url=${APICONFIG_CACHE_URL:localhost:8082} ApiConfigCacheClient.ocpSubKey=${APICONFIG_SUBKEY:} +################### +## EC REST CLIENT +################### + +CreditorInstitutionRestClient.ocpSubKey=${EC_APIM_SUBKEY:} +CreditorInstitutionRestClient.apimEndpoint=${EC_APIM_FORWARDER_ENDPOINT:localhost:8083} + ################### ## OPENTELEMETRY ################### diff --git a/src/test/java/it/gov/pagopa/payment/options/WireMockExtensions.java b/src/test/java/it/gov/pagopa/payment/options/WireMockExtensions.java new file mode 100644 index 0000000..bb3d638 --- /dev/null +++ b/src/test/java/it/gov/pagopa/payment/options/WireMockExtensions.java @@ -0,0 +1,83 @@ +package it.gov.pagopa.payment.options; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.http.Body; +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import it.gov.pagopa.payment.options.models.ErrorResponse; +import it.gov.pagopa.payment.options.models.clients.creditorInstitution.PaymentOptionsResponse; +import java.util.Map; +import lombok.SneakyThrows; + + +public class WireMockExtensions implements QuarkusTestResourceLifecycleManager { + + private WireMockServer wireMockServer; + + @SneakyThrows + @Override + public Map start() { + ObjectMapper objectMapper = new ObjectMapper(); + wireMockServer = new WireMockServer(); + wireMockServer.start(); + + wireMockServer.stubFor( + get(urlEqualTo( + "/payment-options/organizations/77777777777/notices/311111111112222222")) + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withResponseBody( + new Body(objectMapper.writeValueAsString( + PaymentOptionsResponse.builder().standin(true).build() + )) + ) + ) + ); + + wireMockServer.stubFor( + get(urlEqualTo( + "/payment-options/organizations/97777777777/notices/311111111112222222")) + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withBody("AAAAAAAA") + ) + ); + + wireMockServer.stubFor( + get(urlEqualTo( + "/payment-options/organizations/87777777777/notices/311111111112222222")) + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withStatus(412) + .withResponseBody( + new Body(objectMapper.writeValueAsString( + ErrorResponse.builder() + .httpStatusCode(500) + .httpStatusDescription("Error") + .appErrorCode("ODB_ERRID") + .errorMessage("TEST") + .build() + )) + ) + ) + ); + + return Map.of( + "CreditorInstitutionRestClient.apimEndpoint", + wireMockServer.baseUrl(), + "CreditorInstitutionRestClient.ocpSubKey", "test", + "wiremock.port", String.valueOf(wireMockServer.port()) + ); + } + + @Override + public void stop() { + if (null != wireMockServer) { + wireMockServer.stop(); + } + } +} diff --git a/src/test/java/it/gov/pagopa/payment/options/clients/CreditorInstitutionRestClientTest.java b/src/test/java/it/gov/pagopa/payment/options/clients/CreditorInstitutionRestClientTest.java new file mode 100644 index 0000000..4da7e48 --- /dev/null +++ b/src/test/java/it/gov/pagopa/payment/options/clients/CreditorInstitutionRestClientTest.java @@ -0,0 +1,103 @@ +package it.gov.pagopa.payment.options.clients; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; +import it.gov.pagopa.payment.options.WireMockExtensions; +import it.gov.pagopa.payment.options.exception.CreditorInstitutionException; +import it.gov.pagopa.payment.options.exception.PaymentOptionsException; +import it.gov.pagopa.payment.options.models.clients.cache.Connection; +import it.gov.pagopa.payment.options.models.clients.cache.Connection.ProtocolEnum; +import it.gov.pagopa.payment.options.models.clients.cache.Station; +import it.gov.pagopa.payment.options.models.clients.creditorInstitution.PaymentOptionsResponse; +import it.gov.pagopa.payment.options.models.enums.AppErrorCodeEnum; +import jakarta.inject.Inject; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.net.MalformedURLException; + +import static org.junit.jupiter.api.Assertions.*; + +@QuarkusTest +@QuarkusTestResource(WireMockExtensions.class) +class CreditorInstitutionRestClientTest { + + @ConfigProperty(name = "CreditorInstitutionRestClient.apimEndpoint") + private String wiremockUrl; + + @ConfigProperty(name = "wiremock.port") + private String wiremockPort; + + + @Inject + CreditorInstitutionRestClient creditorInstitutionRestClient; + + @Test + void callEcPaymentOptionsVerifyShouldReturnData() { + PaymentOptionsResponse paymentOptionsResponse = + assertDoesNotThrow(() -> creditorInstitutionRestClient.callEcPaymentOptionsVerify( + wiremockUrl, null, null, + "http://externalService", 443L, "/externalPath", + "77777777777", "311111111112222222")); + assertNotNull(paymentOptionsResponse); + } + + @Test + void callEcPaymentOptionsVerifyShouldReturnErrorResponse() { + CreditorInstitutionException exception = + assertThrows(CreditorInstitutionException.class, + () -> creditorInstitutionRestClient.callEcPaymentOptionsVerify( + wiremockUrl, null, null, + "http://externalService", 443L, "/externalPath", + "87777777777", "311111111112222222")); + assertNotNull(exception); + assertEquals(exception.getErrorResponse().getHttpStatusCode(), 500); + } + + @Test + void callEcPaymentOptionsVerifyShouldReturnErrorOnUnexpectedContent() { + PaymentOptionsException exception = + assertThrows(PaymentOptionsException.class, + () -> creditorInstitutionRestClient.callEcPaymentOptionsVerify( + wiremockUrl, null, null, + "http://externalService", 443L, "/externalPath", + "97777777777", "311111111112222222")); + assertNotNull(exception); + } + + @Test + void callEcPaymentOptionsVerifyShouldReturnUnreachableKOWithoutErrorResponse() { + PaymentOptionsException exception = + assertThrows(PaymentOptionsException.class, + () -> creditorInstitutionRestClient.callEcPaymentOptionsVerify( + wiremockUrl, null, null, + "http://externalService", 443L, "/externalPath", + "08888888888", "88888888888")); + assertNotNull(exception); + assertEquals(exception.getErrorCode(), AppErrorCodeEnum.ODP_STAZIONE_INT_PA_IRRAGGIUNGIBILE); + } + + + @Test + void callEcPaymentOptionsVerifyShouldReturnExceptionOnMalformedUrl() { + assertThrows(MalformedURLException.class, + () -> creditorInstitutionRestClient.callEcPaymentOptionsVerify( + "AAAAAAA", null, null, + "http://externalService", 443L, "/externalPath", + "88888888888", "88888888888")); + } + + @Test + void callEcPaymentOptionsVerifyShouldReturnExceptionOnWrongProxy() { + assertThrows(Exception.class, + () -> creditorInstitutionRestClient.callEcPaymentOptionsVerify( + "AAAAAAA", "AAAAAAA%%%", 8081L, + "http://externalService", 443L, "/externalPath", + "88888888888", "88888888888")); + } + + + + +} diff --git a/src/test/java/it/gov/pagopa/payment/options/consumers/ConfigCacheUpdatesConsumerTest.java b/src/test/java/it/gov/pagopa/payment/options/consumers/ConfigCacheUpdatesConsumerTest.java index 13fca55..eb555fc 100644 --- a/src/test/java/it/gov/pagopa/payment/options/consumers/ConfigCacheUpdatesConsumerTest.java +++ b/src/test/java/it/gov/pagopa/payment/options/consumers/ConfigCacheUpdatesConsumerTest.java @@ -2,7 +2,7 @@ import io.quarkus.test.InjectMock; import io.quarkus.test.junit.QuarkusTest; -import it.gov.pagopa.payment.options.models.CacheUpdateEvent; +import it.gov.pagopa.payment.options.models.events.CacheUpdateEvent; import it.gov.pagopa.payment.options.models.ConfigCacheData; import it.gov.pagopa.payment.options.services.ConfigCacheService; import jakarta.inject.Inject; diff --git a/src/test/java/it/gov/pagopa/payment/options/services/ConfigCacheServiceTest.java b/src/test/java/it/gov/pagopa/payment/options/services/ConfigCacheServiceTest.java index 4649d1e..1338f7a 100644 --- a/src/test/java/it/gov/pagopa/payment/options/services/ConfigCacheServiceTest.java +++ b/src/test/java/it/gov/pagopa/payment/options/services/ConfigCacheServiceTest.java @@ -3,9 +3,8 @@ import io.quarkus.test.InjectMock; import io.quarkus.test.junit.QuarkusTest; import it.gov.pagopa.payment.options.clients.ApiConfigCacheClient; -import it.gov.pagopa.payment.options.clients.model.ConfigDataV1; -import it.gov.pagopa.payment.options.models.CacheUpdateEvent; -import it.gov.pagopa.payment.options.models.ConfigCacheData; +import it.gov.pagopa.payment.options.models.clients.cache.ConfigDataV1; +import it.gov.pagopa.payment.options.models.events.CacheUpdateEvent; import jakarta.inject.Inject; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/it/gov/pagopa/payment/options/services/CreditorInstitutionServiceTest.java b/src/test/java/it/gov/pagopa/payment/options/services/CreditorInstitutionServiceTest.java new file mode 100644 index 0000000..6b0ee6f --- /dev/null +++ b/src/test/java/it/gov/pagopa/payment/options/services/CreditorInstitutionServiceTest.java @@ -0,0 +1,180 @@ +package it.gov.pagopa.payment.options.services; + +import io.quarkus.test.InjectMock; +import io.quarkus.test.junit.QuarkusTest; +import it.gov.pagopa.payment.options.clients.CreditorInstitutionRestClient; +import it.gov.pagopa.payment.options.exception.PaymentOptionsException; +import it.gov.pagopa.payment.options.models.clients.cache.Connection; +import it.gov.pagopa.payment.options.models.clients.cache.Connection.ProtocolEnum; +import it.gov.pagopa.payment.options.models.clients.cache.Station; +import it.gov.pagopa.payment.options.models.clients.creditorInstitution.PaymentOptionsResponse; +import it.gov.pagopa.payment.options.models.enums.AppErrorCodeEnum; +import jakarta.inject.Inject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.net.MalformedURLException; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +@QuarkusTest +class CreditorInstitutionServiceTest { + + @InjectMock + CreditorInstitutionRestClient creditorInstitutionRestClient; + + @Inject + CreditorInstitutionService creditorInstitutionService; + + @BeforeEach + public void init() { + Mockito.reset(creditorInstitutionRestClient); + } + + @Test + void getPaymentOptionsShouldReturnData() throws MalformedURLException { + when(creditorInstitutionRestClient.callEcPaymentOptionsVerify( + any(), any(), any(), any(), any(), any(), any(), any()) + ).thenReturn(PaymentOptionsResponse.builder().build()); + PaymentOptionsResponse paymentOptionsResponse = + assertDoesNotThrow(() -> creditorInstitutionService.getPaymentOptions( + "000001","000001", + Station.builder().stationCode("000001_01") + .connection( + Connection.builder() + .ip("localhost") + .protocol(ProtocolEnum.HTTP) + .port(8082L) + .build() + ) + .restEndpoint("http://localhost:8080/test") + .verifyPaymentOptionEnabled(true) + .build() + )); + assertNotNull(paymentOptionsResponse); + verify(creditorInstitutionRestClient).callEcPaymentOptionsVerify( + any(), any(), any(), any(), any(), any(), any(), any()); + } + + @Test + void getPaymentOptionsShouldReturnDataWithDefaultPort() throws MalformedURLException { + when(creditorInstitutionRestClient.callEcPaymentOptionsVerify( + any(), any(), any(), any(), any(), any(), any(), any()) + ).thenReturn(PaymentOptionsResponse.builder().build()); + PaymentOptionsResponse paymentOptionsResponse = + assertDoesNotThrow(() -> creditorInstitutionService.getPaymentOptions( + "000001","000001", + Station.builder().stationCode("000001_01") + .connection( + Connection.builder() + .ip("localhost") + .protocol(ProtocolEnum.HTTP) + .port(8082L) + .build() + ) + .restEndpoint("http://localhost/test") + .verifyPaymentOptionEnabled(true) + .build() + )); + assertNotNull(paymentOptionsResponse); + verify(creditorInstitutionRestClient).callEcPaymentOptionsVerify( + any(), any(), any(), any(), any(), any(), any(), any()); + } + + @Test + void getPaymentOptionsShouldReturnExceptionOnMalformed() throws MalformedURLException { + when(creditorInstitutionRestClient.callEcPaymentOptionsVerify( + any(), any(), any(), any(), any(), any(), any(), any()) + ).thenThrow(new MalformedURLException()); + PaymentOptionsException paymentOptionsException = + assertThrows(PaymentOptionsException.class, () -> creditorInstitutionService.getPaymentOptions( + "000001","000001", + Station.builder().stationCode("000001_01") + .connection( + Connection.builder() + .ip("localhost") + .protocol(ProtocolEnum.HTTP) + .port(8082L) + .build() + ) + .restEndpoint("http://localhost:8080/test") + .verifyPaymentOptionEnabled(true) + .build() + )); + assertNotNull(paymentOptionsException); + assertEquals(paymentOptionsException.getErrorCode(), AppErrorCodeEnum.ODP_SEMANTICA); + verify(creditorInstitutionRestClient).callEcPaymentOptionsVerify( + any(), any(), any(), any(), any(), any(), any(), any() + ); + } + + @Test + void getPaymentOptionsShouldReturnExceptionOnMissingEndpoint() throws MalformedURLException { + PaymentOptionsException paymentOptionsException = + assertThrows(PaymentOptionsException.class, () -> creditorInstitutionService.getPaymentOptions( + "000001","000001", + Station.builder().stationCode("000001_01") + .connection( + Connection.builder() + .ip("localhost") + .protocol(ProtocolEnum.HTTP) + .port(8082L) + .build() + ) + .restEndpoint(null) + .verifyPaymentOptionEnabled(true) + .build() + )); + assertNotNull(paymentOptionsException); + assertEquals(paymentOptionsException.getErrorCode(), AppErrorCodeEnum.ODP_SEMANTICA); + verifyNoInteractions(creditorInstitutionRestClient); + } + + @Test + void getPaymentOptionsShouldReturnExceptionOnBrokerServiceUrl() throws MalformedURLException { + PaymentOptionsException paymentOptionsException = + assertThrows(PaymentOptionsException.class, () -> creditorInstitutionService.getPaymentOptions( + "000001","000001", + Station.builder().stationCode("000001_01") + .connection( + Connection.builder() + .ip("localhost") + .protocol(ProtocolEnum.HTTP) + .port(8082L) + .build() + ) + .restEndpoint(":8080") + .verifyPaymentOptionEnabled(true) + .build() + )); + assertNotNull(paymentOptionsException); + assertEquals(paymentOptionsException.getErrorCode(), AppErrorCodeEnum.ODP_SEMANTICA); + } + + @Test + void getPaymentOptionsShouldReturnExceptionOnMissingConnection() throws MalformedURLException { + PaymentOptionsException paymentOptionsException = + assertThrows(PaymentOptionsException.class, () -> creditorInstitutionService.getPaymentOptions( + "000001","000001", + Station.builder().stationCode("000001_01") + .connection( + Connection.builder() + .protocol(ProtocolEnum.HTTP) + .port(8082L) + .build() + ) + .restEndpoint(":8080") + .verifyPaymentOptionEnabled(true) + .build() + )); + assertNotNull(paymentOptionsException); + assertEquals(paymentOptionsException.getErrorCode(), AppErrorCodeEnum.ODP_STAZIONE_INT_PA_IRRAGGIUNGIBILE); + } + + +}