ECI Client
1. Descripción general
eci-client es una librería cliente (JAR) que actúa como fachada HTTP declarativa (@HttpExchange) sobre la API del marketplace ECI (El Corte Inglés), según la description de su pom.xml: "ECI client".
El proyecto no es un servicio desplegable ni contiene lógica de negocio propia: es una dependencia interna publicada en el registro de artefactos Maven de Hawkers, consumida por los microservicios del ecosistema que necesitan integrar pedidos y catálogo con el marketplace de ECI. Encapsula:
- Autenticación mediante un header
Authorizationestático configurado por el consumidor (sin flujo OAuth2 ni renovación de token). - Operaciones declarativas sobre pedidos (consulta filtrada por estado/fecha, aceptación de líneas, actualización de tracking, confirmación de envío, confirmación de entrega, descarga de documentos).
- Operaciones declarativas sobre ofertas (consulta paginada, actualización masiva, importación de stock vía fichero multipart).
- Modelos de datos (DTO) para los payloads de petición/respuesta de ECI, con doble anotación Gson/Jackson.
Dentro del ecosistema de microservicios de Hawkers, eci-client cumple el mismo rol que otros clientes de marketplace (p. ej. auro-client, dynamics-client): aislar a los microservicios de negocio de los detalles de transporte HTTP y serialización específicos de la API externa de ECI.
2. Información técnica
| Propiedad | Valor |
|---|---|
artifactId | eci-client |
groupId | com.hawkersco |
version | 1.0.25-SNAPSHOT |
| Java | 25 |
| Spring Boot | 4.0.6 (spring-boot-starter-parent) |
| Tipo de artefacto | JAR (librería, no ejecutable) |
| Módulos | Proyecto único (no multi-módulo) |
3. Arquitectura y diseño
Estructura de paquetes bajo com.hawkersco.eciclient:
com.hawkersco.eciclient
├── EciClientApplication.java # @SpringBootApplication (arranque para pruebas locales)
├── client/
│ └── EciClient.java # @HttpExchange — único punto de integración: pedidos y ofertas
├── config/
│ └── EciClientConfig.java # @AutoConfiguration — bean EciClient con header Authorization fijo
└── pojo/ # DTOs de request/response (Gson + Jackson)
├── EciAcceptOrder
├── EciOrderResponse # modelo más extenso: Order, Customer, Address, OrderLine, Cancelation, Refund...
├── OffersEciRequest
├── OffersEciResponse
├── OffersEciResponseAlt # variante alternativa del modelo de ofertas (más campos: fulfillment, logisticClass...)
├── UpdateTrackingRequest
└── ValidateDelivery
EciClientConfig se registra como auto-configuración Spring Boot en META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports, de modo que cualquier microservicio que añada eci-client como dependencia obtiene el bean EciClient automáticamente, condicionado (@ConditionalOnProperty) a que existan las propiedades eci.auth.client.url y eci.credentials.key.
A diferencia de dynamics-client o auro-client, no hay interceptor de autenticación dinámica: el header Authorization se fija una única vez al construir el RestClient, con el valor de eci.credentials.key tal cual (no se antepone prefijo Bearer/bearer en el código).
Flujo principal
sequenceDiagram
participant Consumidor as Microservicio consumidor
participant EciClient
participant ECI as API ECI
Consumidor->>EciClient: getOrdersWaiting() / acceptOrder() / updateOffers() ...
EciClient->>ECI: petición HTTP con header Authorization fijo
ECI-->>EciClient: respuesta (JSON tipado o String/byte[])
EciClient-->>Consumidor: ResponseEntity<T>
4. Dependencias principales
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot y auto-configuración. |
spring-web | RestClient, HttpServiceProxyFactory y anotaciones @HttpExchange. |
org.projectlombok:lombok | Generación de getters/setters/constructores en los DTO (@Data, @Getter/@Setter...). |
com.fasterxml.jackson.core:jackson-annotations | Anotaciones Jackson (@JsonProperty) en los DTO. |
com.google.code.gson:gson | Anotaciones/serialización Gson (@SerializedName) en los DTO. |
com.google.cloud.artifactregistry:artifactregistry-maven-wagon (extensión de build) | Publicación del JAR en Google Artifact Registry (distributionManagement). |
No se listan dependencias de test más allá de spring-boot-starter-test (scope test): el proyecto no contiene clases de test.
5. API / Endpoints
No aplica como API REST propia. eci-client no expone endpoints; es una librería consumida como dependencia. EciClientApplication (@SpringBootApplication) existe únicamente como contexto de arranque para desarrollo/pruebas locales.
En su lugar, la interfaz EciClient declara las operaciones disponibles contra la API externa de ECI:
| Método Java | HTTP | Ruta | Descripción |
|---|---|---|---|
getOrdersWaiting() | GET | /api/orders?order_state_codes=WAITING_ACCEPTANCE | Pedidos pendientes de aceptación. |
getOrderListByStateCode(...) | GET | /api/orders | Pedidos filtrados por order_state_codes, start_date, max, offset (paginado). |
getAllOrderList(...) | GET | /api/orders | Todos los pedidos desde start_date, paginado con max/offset. |
acceptOrder(orderId, EciAcceptOrder) | PUT | /api/orders/{order_id}/accept | Acepta/rechaza líneas de un pedido (order_lines[].accepted). |
updateTracking(orderId, UpdateTrackingRequest) | PUT | /api/orders/{order_id}/tracking | Actualiza transportista y número de seguimiento del pedido. |
validateShipment(orderId) | PUT | /api/orders/{order_id}/ship | Marca el pedido como enviado. |
confirmDelivery(orderId, ValidateDelivery) | PUT | /api/orders/{order_id}/additional_fields | Confirma la entrega mediante campos adicionales (p. ej. fecha de entrega). |
downloadDocumentsByOrderList(orderIdList) | GET | /api/orders/documents/download | Descarga documentos (etiquetas) de una lista de pedidos, devuelve byte[]. |
getOffers(max, offset) | GET | /api/offers | Ofertas paginadas, deserializadas a OffersEciResponse. |
getOffersString(max, offset) | GET | /api/offers | Ofertas paginadas como JSON crudo (String). |
updateOffers(json) | POST | /api/offers | Actualización masiva de ofertas mediante payload JSON en crudo. |
importStockFile(file) | POST | /api/offers/stock/imports | Importa niveles de stock desde un fichero (multipart/form-data). |
Ejemplo de payload de aceptación de pedido (EciAcceptOrder):
{
"order_lines": [
{ "id": "12345", "accepted": true },
{ "id": "12346", "accepted": false }
]
}
Ejemplo de payload de actualización de tracking (UpdateTrackingRequest):
{
"carrier_code": "SEUR",
"carrier_name": "SEUR",
"carrier_url": "https://www.seur.com/tracking",
"tracking_number": "1234567890"
}
6. Integraciones externas
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
| Marketplace ECI — API de pedidos y ofertas | HTTPS, JSON (y multipart/form-data para importación de stock) | Saliente | Único sistema externo integrado: consulta/gestión de pedidos (/api/orders/*) y ofertas (/api/offers/*). |
No hay otras integraciones (colas, SFTP, Dynamics 365, etc.) en este proyecto.
7. Configuración
El proyecto no incluye application.properties/application.yml propio (es una librería); las propiedades deben ser definidas por el microservicio consumidor:
| Clave | Descripción | Ejemplo de valor |
|---|---|---|
eci.auth.client.url | URL base de la API de ECI. | https://api.eci-marketplace.com |
eci.credentials.key | Valor completo enviado en el header Authorization (token/API key). | ******** |
Si falta alguna de las dos propiedades, el bean EciClient no se registra (@ConditionalOnProperty), sin error de arranque explícito.
8. Persistencia
No aplica. El proyecto no gestiona base de datos ni realiza persistencia propia; todos los DTO son objetos de transporte para las llamadas HTTP a la API de ECI.
9. Procesos programados y mensajería
No aplica. No existen @Scheduled, @KafkaListener ni @RabbitListener en el código. La ejecución de las operaciones (consulta/actualización de pedidos y ofertas) es responsabilidad del microservicio consumidor, que decide cuándo invocarlas.
10. Ejecución en local
Requisitos previos:
- JDK 25.
- Maven Wrapper (
./mvnw, incluido en el repositorio). - Credenciales válidas del marketplace ECI (proporcionadas por el consumidor vía las propiedades de la sección 7).
Comandos:
# Build e instalación en repositorio Maven local
./mvnw clean install
# Empaquetado sin instalar
./mvnw clean package
# Build sin tests (equivalente al comportamiento de CI)
./mvnw clean install -DskipTests
# Análisis SonarQube
./mvnw sonar:sonar
Al ser una librería, no se "levanta" como servicio independiente ni expone actuator/health. Para probarla en local es necesario:
- Instalarla en el repositorio Maven local (
./mvnw clean install) o consumir la versión publicada en Artifact Registry. - Añadirla como dependencia en un microservicio consumidor que defina
eci.auth.client.urlyeci.credentials.key. - Verificar el correcto arranque comprobando que el bean
EciClientse inyecta sin error en el microservicio consumidor.
11. Despliegue
El proyecto se publica como artefacto Maven en Google Artifact Registry (artifactregistry://europe-west3-maven.pkg.dev/pi-saldum/pi-repo-maven), no se despliega como contenedor ni servicio.
El Jenkinsfile define un pipeline de dos etapas:
- Checkout —
checkout scm. - Publish to Artifact Registry —
mvn deploy -DskipTests.
Job de Jenkins del proyecto: https://jenkins-pi.hawkersco.net/job/eci-client/
12. Manejo de errores y logging
- No hay manejo de excepciones propio: los métodos de
EciClientdevuelvenResponseEntity<T>directamente (conString,byte[]o DTOs tipados), por lo que los errores HTTP de ECI se propagan tal cual al consumidor a través del código de estado y el cuerpo de la respuesta. - No se implementa lógica de reintento ni circuit breaker: es responsabilidad del microservicio consumidor.
- No hay un
@ControllerAdviceni códigos de error propios, al no exponer API REST propia. - No hay configuración de logging específica en el proyecto (ni SLF4J ni
java.util.loggingconfigurados); hereda la configuración de logs del consumidor.
13. Notas y consideraciones
- El header
Authorizationse construye con el valor íntegro deeci.credentials.keysin prefijo (Bearer/bearer) añadido en código; el prefijo, si es necesario, debe incluirse ya en el valor de la propiedad configurada por el consumidor. - Existen dos modelos distintos para la respuesta de ofertas (
OffersEciResponseyOffersEciResponseAlt), con estructuras de campos diferentes (p. ej.OffersEciResponseAltañadefulfillment,logisticClass,allPrices,channels...). El métodogetOffersusaOffersEciResponse;OffersEciResponseAltno está referenciado desde ningún método deEciClienten este repositorio — su propósito exacto (¿versión de API distinta? ¿modelo legado?) queda pendiente de verificar. - Todos los DTO llevan simultáneamente anotaciones Gson (
@SerializedName) y Jackson (@JsonProperty); al añadir campos nuevos hay que mantener ambas anotaciones sincronizadas, como indica el propioCLAUDE.mddel proyecto. EciOrderResponsees el DTO más extenso del proyecto, con múltiples clases anidadas (Order,Customer,Address,OrderLine,Cancelation,Refund,Promotions...) que reflejan fielmente el modelo de datos de pedidos de ECI.ValidateDelivery.OrderAdditionalFields.valuees de tipojava.util.Date; a diferencia del resto de campos de fecha del proyecto, que se modelan comoString. Comportamiento a tener en cuenta si se depuran problemas de formato de fecha en la confirmación de entrega.- No existen tests unitarios en el repositorio (solo la dependencia
spring-boot-starter-test, sin uso); el flag-DskipTestsen Jenkins refleja esto directamente, no es una omisión de CI.