QAT Client
1. Descripción general
qat-client es una librería cliente reutilizable (JAR) que encapsula la comunicación con la API de gestión de pedidos QAT. El proyecto no expone ningún endpoint REST propio; se publica en el registro de artefactos Maven interno y es consumido por otros microservicios del ecosistema Hawkers que necesiten listar pedidos, aceptar sus líneas y descargar la documentación asociada (etiquetas/albaranes) en formato ZIP.
2. Información técnica
| Propiedad | Valor |
|---|---|
artifactId | qat-client |
groupId | com.hawkersco |
version | 1.0.25-SNAPSHOT |
| Java | 25 |
| Spring Boot | 4.0.6 |
| Tipo de artefacto | JAR (librería, no ejecutable) |
| Módulos | Proyecto único (no multi-módulo) |
3. Arquitectura y diseño
Estructura del proyecto:
com.hawkersco.qatclient
├── QatClientApplication.java # Clase @SpringBootApplication (residual, sin lógica)
├── client/
│ └── QatClient.java # Interfaz @HttpExchange con las 5 operaciones de negocio
├── config/
│ └── QatClientAutoConfiguration.java # @AutoConfiguration principal (cabecera apikey + Accept dinámico)
└── model/
├── AcceptOrderQtaRequest.java # Request de aceptación de líneas de pedido
└── OrdersQatResponse.java # Respuesta de listado de pedidos (jerarquía completa, ~490 líneas)
Flujo principal
sequenceDiagram
participant Consumidor as Microservicio consumidor
participant Client as QatClient
participant API as API QAT
Consumidor->>Client: getOrderList / acceptOrder / downloadDocumentsByOrderList / ...
Client->>API: GET/PUT + header apikey + Accept (dinámico según ruta)
API-->>Client: ResponseEntity<OrdersQatResponse | String | byte[]>
Client-->>Consumidor: ResponseEntity<T>
La autoconfiguración (QatClientAutoConfiguration) se activa condicionalmente con @ConditionalOnProperty(prefix = "qat.credentials", name = {"url", "key"}), registrando un único bean QatClient cuyo RestClient:
- Fija la cabecera
apikeypor defecto (defaultHeader) con el valor deqat.credentials.key. - Incorpora un
requestInterceptorque decide dinámicamente el valor de la cabeceraAcceptsegún la URL de la petición:*/*para las rutas que contienendocumentmanagement/documents/entities/ORDER/downloado/accept, yapplication/vnd.private.api.v1+jsonpara el resto.
El registro de la autoconfiguración se realiza mediante el fichero estándar de Spring Boot:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
4. Dependencias principales
| Dependencia | Versión | Propósito |
|---|---|---|
spring-boot-starter | (gestionada SB4) | Base de Spring Boot (contexto, autoconfiguración) |
spring-web | (gestionada SB4) | RestClient + @HttpExchange / HttpServiceProxyFactory |
com.google.code.gson:gson | (gestionada SB4) | Anotaciones @SerializedName en los modelos (soporte dual con Jackson) |
com.fasterxml.jackson.core:jackson-annotations | (gestionada SB4) | Anotaciones @JsonProperty en los modelos |
org.projectlombok:lombok | 1.18.42 (dependencia; annotationProcessorPath del compilador usa 1.18.46) | Generación de boilerplate en los modelos |
spring-boot-starter-test | (gestionada SB4) | Testing (scope test) |
5. API / Endpoints
No aplica a este proyecto. qat-client es una librería cliente JAR que no expone endpoints REST propios. Las operaciones que encapsula sobre la API de QAT se detallan en la sección 6.
6. Integraciones externas
API de gestión de pedidos QAT
| Método cliente | HTTP | Ruta remota | Descripción |
|---|---|---|---|
acceptOrder | PUT | /api/ordermanagement/orders/{orderId}/accept?shop_id= | Acepta/rechaza las líneas de un pedido (accepted por ítem) |
getOrderListByStateCode | GET | /api/ordermanagement/orders?order_state_codes&shop_id&start_date&max&offset | Lista pedidos paginados filtrados por código de estado |
getOrderList | GET | /api/ordermanagement/orders?shop_id&start_date&max&offset | Lista todos los pedidos de una tienda, paginados, sin filtro de estado |
downloadDocumentsByOrderList | GET | /api/documentmanagement/documents/entities/ORDER/download?order_ids&shop_id | Descarga un ZIP de documentos asociados a una lista de pedidos, devuelve byte[] |
getOrderListById | GET | /api/ordermanagement/orders?order_ids&shop_id | Consulta pedidos por una lista concreta de identificadores |
Ejemplo de payload acceptOrder (AcceptOrderQtaRequest):
{
"items": [
{ "id": "ORDLINE-001", "accepted": true },
{ "id": "ORDLINE-002", "accepted": false }
]
}
Ejemplo de respuesta getOrderList (OrdersQatResponse, resumida — misma forma general que otras integraciones de marketplace del ecosistema, con pedido, canal, cliente, líneas y direcciones anidadas):
{
"total_count": 12,
"orders": [
{
"commercial_id": "ORD-000123",
"created_date": "2026-07-01T10:00:00Z",
"currency_iso_code": "EUR",
"can_cancel": true,
"can_evaluate": false,
"channel": { "code": "MP", "label": "Marketplace" },
"customer": { "firstname": "Nombre", "lastname": "Apellido" }
}
]
}
Protocolo: HTTPS REST (JSON para las operaciones de pedido; binario byte[] para la descarga de documentos). Autenticación: cabecera estática apikey, inyectada como valor por defecto en el RestClient a partir de qat.credentials.key.
7. Configuración
No se incluye ningún application.properties/application.yml en la librería. Las propiedades deben ser inyectadas por la aplicación consumidora.
Propiedades requeridas (prefijo qat.credentials)
| Propiedad | Descripción | Ejemplo de valor |
|---|---|---|
qat.credentials.url | URL base de la API QAT (activa la autoconfiguración) | ${QAT_CLIENT_URL} |
qat.credentials.key | Valor de la cabecera apikey | ${QAT_CLIENT_API_KEY} |
Importante: Si falta
qat.credentials.urloqat.credentials.key, el beanQatClientno se registra (condición@ConditionalOnPropertycon ambas claves).
Variables de entorno recomendadas
| Variable | Propiedad mapeada |
|---|---|
QAT_CLIENT_URL | qat.credentials.url |
QAT_CLIENT_API_KEY | qat.credentials.key |
8. Persistencia
No aplica a este proyecto. La librería no accede a ninguna base de datos ni mantiene estado en memoria.
9. Procesos programados y mensajería
No aplica a este proyecto. No existen jobs @Scheduled, listeners de colas/topics ni runners batch.
10. Ejecución en local
qat-client es una librería JAR, no una aplicación ejecutable. No tiene servidor embebido ni endpoint de health.
Requisitos previos
- Java 25
- Maven 3.x
- Acceso al registro de artefactos Maven interno (
europe-west3-maven.pkg.dev/pi-saldum/pi-repo-maven) para resolver/publicar dependencias.
Compilar e instalar en repositorio local
# Compilar sin tests
./mvnw -B -DskipTests clean install
# Compilar con tests
./mvnw clean install
# Ejecutar tests
./mvnw test
Uso como dependencia en un microservicio consumidor
<dependency>
<groupId>com.hawkersco</groupId>
<artifactId>qat-client</artifactId>
<version>1.0.25-SNAPSHOT</version>
</dependency>
La autoconfiguración se activa automáticamente al declarar qat.credentials.url y qat.credentials.key en la aplicación consumidora.
11. Despliegue
El pipeline de Jenkins (Jenkinsfile) consta de dos etapas:
- Checkout — descarga el código del repositorio.
- Publish to Artifact Registry — ejecuta
mvn deploy -DskipTestspara publicar el JAR en Google Artifact Registry.
| Parámetro | Valor |
|---|---|
| JDK | JDK25 (tool Jenkins) |
| Maven | Maven3 (tool Jenkins) |
| Repositorio | europe-west3-maven.pkg.dev/pi-saldum/pi-repo-maven (Artifact Registry GCP) |
No existe Dockerfile ni despliegue como servicio independiente; el artefacto es un JAR publicado en el registro Maven.
Job de Jenkins:
https://jenkins-pi.hawkersco.net/job/qat-client/
12. Manejo de errores y logging
La librería no implementa ninguna estrategia propia de manejo de excepciones ni logging estructurado. Las excepciones de red o HTTP propagadas por RestClient (como RestClientResponseException) son responsabilidad del servicio consumidor, ya que ningún método de QatClient declara throws explícito. No hay configuración de logback ni de niveles de log específicos en la librería.
13. Notas y consideraciones
-
Cabecera
Acceptdinámica basada en substring de la URL: El interceptor deQatClientAutoConfigurationdecide el valor deAcceptcomprobando si la URL contiene las cadenasdocumentmanagement/documents/entities/ORDER/downloado/accept. Esta lógica basada en coincidencia de texto es frágil ante cambios futuros en las rutas (p. ej. si se añadiera un nuevo endpoint cuya ruta contuviera casualmente/accept), en lugar de una asociación explícita por método o por constante de ruta completa. -
getOrderListByStateCode,getOrderListygetOrderListByIdcomparten la misma ruta base: Los tres métodos apuntan aGET /api/ordermanagement/orders, diferenciándose únicamente en los parámetros de query enviados (order_state_codes+paginación, solo paginación, oorder_ids). Refleja un único endpoint remoto con múltiples modos de uso, modelados como métodos Java distintos por claridad de la API del cliente. -
AcceptOrderQtaRequest.Item.acceptedvs. nombre del métodoacceptOrder: El campo se llamaaccepted(noaccept), pese a que la clase se llamaAcceptOrderQtaRequest— nomenclatura menor a tener en cuenta al construir el payload. -
Estructura de
OrdersQatResponsemuy similar a otras integraciones del ecosistema: La jerarquía de campos (acceptance_decision_date,can_cancel,channel,commercial_id,currency_iso_code,customer...) coincide en gran medida con la deOrdersLiverpoolResponse(liverpool-client), sugiriendo que ambas integraciones comparten un formato de pedido subyacente similar (posible plataforma de marketplace común o plantilla de generación compartida entre clientes del ecosistema). -
Sin tests implementados: El directorio
src/test/java/com/hawkersco/existe pero está vacío, sin ninguna clase de test.CLAUDE.mdseñala que no hay etapa de test en CI. -
QatClientApplication.java: Clase principal de Spring Boot en el paquete raíz, sin funcionalidad operativa. Artefacto residual de la generación inicial del proyecto con Spring Initializr, mismo patrón observado en otros clientes del ecosistema.