Skip to main content

Sarmed Client

1. Descripción general

sarmed-client es una librería cliente reutilizable (JAR) que encapsula la comunicación con el backend ecommerce/WMS de Sarmed. 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 autenticarse, enviar pedidos y dar de alta productos en el sistema de Sarmed.

2. Información técnica

PropiedadValor
artifactIdsarmed-client
groupIdcom.hawkersco
version1.0.25-SNAPSHOT
Java25
Spring Boot4.0.6
Tipo de artefactoJAR (librería, no ejecutable)
MódulosProyecto único (no multi-módulo)

3. Arquitectura y diseño

Estructura del proyecto:

com.hawkersco.sarmedclient
├── SarmedClientApplication.java # Clase @SpringBootApplication (residual, sin lógica)
├── client/
│ └── SarmedClient.java # Interfaz @HttpExchange: getSession, placeOrder, product
├── config/
│ └── SarmedClientAutoConfiguration.java # @AutoConfiguration principal (soporte opcional de SSL "trust-all")
└── model/
├── CredentialSarmedRequest.java # Record de credenciales; no cableado a ningún método del cliente (ver sección 13)
├── SessionSarmedRequest.java / SessionSarmedResponse.java
├── OrderSarmedRequest.java / OrderSarmedResponse.java
└── ProductSarmedRequest.java / ProductSarmedResponse.java

Flujo principal

sequenceDiagram
participant Consumidor as Microservicio consumidor
participant Client as SarmedClient
participant API as Backend Sarmed

Consumidor->>Client: getSession(username, password)
Client->>API: POST /ecommerce/api/login
API-->>Client: { "success": true, "session": "<uuid>" }
Consumidor->>Client: placeOrder(session, ...) / product(session, ...)
Client->>API: POST /ecommerce/api/placeOrder | POST /ecommerce/api/product
API-->>Client: ResponseEntity<OrderSarmedResponse | ProductSarmedResponse>
Client-->>Consumidor: ResponseEntity<T>

La autoconfiguración (SarmedClientAutoConfiguration) se activa condicionalmente con @ConditionalOnProperty(prefix = "sarmed.api", name = "url"), registrando el bean SarmedClient con un RestClient construido a partir de sarmed.api.url. Además, admite una propiedad opcional sarmed.api.trust-all-ssl (por defecto false): si se activa, configura un SSLContext que acepta cualquier certificado (implementación de X509TrustManager sin validación) y lo aplica a un HttpClient del JDK usado como JdkClientHttpRequestFactory del RestClient — ver consideración de seguridad en la sección 13.

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

DependenciaVersiónPropó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 de clase (soporte dual con Jackson)
com.fasterxml.jackson.core:jackson-databind(gestionada SB4)Serialización/deserialización Jackson en los modelos
org.projectlombok:lombok1.18.46Generación de boilerplate en OrderSarmedRequest/ProductSarmedRequest (los DTOs simples son records)
spring-boot-starter-test(gestionada SB4)Testing (scope test)

5. API / Endpoints

No aplica a este proyecto. sarmed-client es una librería cliente JAR que no expone endpoints REST propios. Las operaciones que encapsula sobre el backend de Sarmed se detallan en la sección 6.

6. Integraciones externas

Backend ecommerce Sarmed

Método clienteHTTPRuta remotaDescripción
getSessionPOST/ecommerce/api/loginAutentica con usuario/contraseña y devuelve una sesión (UUID)
placeOrderPOST/ecommerce/api/placeOrderEnvía un pedido con líneas de producto al sistema Sarmed
productPOST/ecommerce/api/productDa de alta o actualiza un producto (con códigos de barras, unidades, dimensiones)

Ejemplo de payload getSession (SessionSarmedRequest, record):

{
"username": "usuario_hawkers",
"password": "********"
}

Ejemplo de respuesta getSession (SessionSarmedResponse, record):

{
"success": true,
"errorCode": 0,
"errorDescription": "",
"session": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

Ejemplo de payload placeOrder (OrderSarmedRequest, resumido):

{
"Session": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"OrderType": 1,
"OrderCode": "ORD-000123",
"DepositorCode": "HAWKERS",
"FinalCustomerName": "Cliente Final",
"FinalCustomerCountryCode": "ES",
"OrderItem": [
{ "LineID": 1, "ProductCode": "SKU-001", "ShipQuantity": "2", "ShipProductUnit": "UN" }
]
}

Ejemplo de payload product (ProductSarmedRequest, resumido):

{
"Session": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"ActionCode": 1,
"ProductInfo": {
"ProductCode": "SKU-001",
"SkuID": "SKU-001",
"Descr": "Camiseta básica",
"DepositorCode": "HAWKERS",
"UnitCode1": "UN",
"Barcodes": [ { "Barcode": "8412345678901" } ]
}
}

Protocolo: HTTPS/HTTP REST (JSON, contentType = application/json). Autenticación: sesión obtenida mediante getSession (usuario/contraseña) y reenviada como campo Session en el cuerpo de las llamadas posteriores; no se usa ninguna cabecera HTTP de autenticación.

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 y opcionales (prefijo sarmed.api)

PropiedadDescripciónEjemplo de valor
sarmed.api.urlURL base del backend Sarmed (activa la autoconfiguración)${SARMED_API_URL}
sarmed.api.trust-all-ssl(Opcional, por defecto false) Si es true, desactiva la validación de certificados TLSfalse

Importante: Si sarmed.api.url no está definida, el bean SarmedClient no se registra (condición @ConditionalOnProperty). Las credenciales (username/password) no se configuran como propiedades Spring: se pasan explícitamente en el body de getSession.

Variables de entorno recomendadas

VariablePropiedad mapeada
SARMED_API_URLsarmed.api.url

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

sarmed-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
mvn -B -DskipTests clean install

# Compilar con tests
mvn clean install

# Ejecutar un test concreto
mvn -Dtest=ClassName test
mvn -Dtest=ClassName#methodName test

Uso como dependencia en un microservicio consumidor

<dependency>
<groupId>com.hawkersco</groupId>
<artifactId>sarmed-client</artifactId>
<version>1.0.25-SNAPSHOT</version>
</dependency>

La autoconfiguración se activa automáticamente al declarar sarmed.api.url en la aplicación consumidora.

11. Despliegue

El pipeline de Jenkins (Jenkinsfile) consta de dos etapas:

  1. Checkout — descarga el código del repositorio.
  2. Publish to Artifact Registry — ejecuta mvn deploy -DskipTests para publicar el JAR en Google Artifact Registry.

CLAUDE.md menciona que el build se ejecuta vía jenkins/scripts/mvn.sh, script no presente en este repositorio ni referenciado directamente en el Jenkinsfile actual (que invoca mvn deploy -DskipTests directamente). Se documenta el Jenkinsfile realmente presente.

ParámetroValor
JDKJDK25 (tool Jenkins)
MavenMaven3 (tool Jenkins)
Repositorioeurope-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/sarmed-client/

12. Manejo de errores y logging

La librería no implementa ninguna estrategia propia de manejo de excepciones ni logging estructurado. Ningún método de SarmedClient declara throws explícito; las excepciones de red o HTTP propagadas por RestClient (como RestClientResponseException) son responsabilidad del servicio consumidor. Los modelos de respuesta (SessionSarmedResponse, OrderSarmedResponse, ProductSarmedResponse) incluyen campos success, errorCode y errorDescription propios del contrato de Sarmed, que el consumidor debe inspeccionar manualmente para detectar errores de negocio (la API puede responder 200 OK con success: false). No hay configuración de logback ni de niveles de log específicos en la librería.

13. Notas y consideraciones

  • Bypass de validación TLS configurable (sarmed.api.trust-all-ssl): Cuando esta propiedad se activa, SarmedClientAutoConfiguration instala un X509TrustManager que acepta cualquier certificado sin validación (checkClientTrusted/checkServerTrusted vacíos), desactivando efectivamente la verificación TLS del RestClient. Esto expone al consumidor a ataques de intermediario (man-in-the-middle) si se habilita en un entorno que no sea estrictamente de pruebas/desarrollo controlado. Debe evitarse en producción; su presencia sugiere que el endpoint de Sarmed en algún entorno (p. ej. staging) tiene un certificado autofirmado o mal configurado.

  • CredentialSarmedRequest no utilizado: Existe un record CredentialSarmedRequest(username, password) con los mismos campos que SessionSarmedRequest, pero SarmedClient.getSession recibe SessionSarmedRequest, no CredentialSarmedRequest — el primero es un modelo huérfano/duplicado, posiblemente un remanente de una refactorización o de una versión anterior de la API.

  • Inconsistencia de tipo en el campo session: SessionSarmedResponse.session es de tipo UUID, OrderSarmedRequest.session también es UUID, pero ProductSarmedRequest.session es String. El consumidor debe convertir manualmente el UUID de sesión a texto al construir el request de producto.

  • Mezcla de records y clases Lombok: Los DTOs simples de sesión y respuesta (SessionSarmedRequest, SessionSarmedResponse, OrderSarmedResponse, ProductSarmedResponse, CredentialSarmedRequest) están modelados como records de Java, mientras que los DTOs anidados más complejos (OrderSarmedRequest, ProductSarmedRequest) usan clases con Lombok y anotaciones Jackson/Gson — refleja una mezcla de estilos dentro del mismo proyecto, a diferencia de otros clientes del ecosistema que son consistentemente uno u otro.

  • Sin renovación ni caché de sesión: El cliente no gestiona el ciclo de vida de la sesión obtenida en getSession; corresponde al consumidor almacenarla, reutilizarla y volver a autenticar cuando expire (el contrato no documenta explícitamente un TTL de sesión en los modelos disponibles).

  • Sin tests implementados: No se ha encontrado directorio src/test/ en el proyecto.

  • SarmedClientApplication.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.