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);
+ }
+
+
+}