Skip to main content

HK Times Logistics Client

1. Descripción general

hk-timeslogistics-client es una librería cliente reutilizable (JAR) que encapsula la comunicación con la API de Hong Kong Times Logistics (HKTL), proveedor de fulfillment logístico integrado en el ecosistema de microservicios de Hawkers. El proyecto no expone ningún endpoint REST propio; se publica en el registro de artefactos Maven interno y es consumido por otros microservicios que necesiten crear/cancelar pedidos, consultar inventario, SKUs o el estado de tracking en el almacén HKTL.

La librería gestiona de forma transparente la autenticación mediante token Bearer (con caché de 1 hora), de modo que los servicios consumidores no necesitan implementar ninguna lógica de autenticación. Expone operaciones para:

  • Crear o actualizar un pedido (order/create).
  • Cancelar un pedido (orders/cancel).
  • Consultar inventario paginado (inventory).
  • Consultar el listado paginado de SKUs (sku).
  • Consultar el estado/tracking de un pedido (order/status).

2. Información técnica

PropiedadValor
artifactIdhk-timeslogistics-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.hktimeslogistics
├── client/
│ ├── HkTimesLogisticsClient.java # Interfaz @HttpExchange con las 5 operaciones de negocio
│ └── HkTimesLogisticsTokenClient.java # Interfaz @HttpExchange para obtención de token (/auth/login)
├── config/
│ ├── HkTimesLogisticsConfig.java # @AutoConfiguration principal (registra ambos clientes + interceptor Bearer)
│ ├── CacheStore.java # Cache genérica en memoria (Guava)
│ └── HkTimesLogisticsConstants.java # Constante TXT_TOKEN = "token"
└── pojos/
├── HkTimesLogisticsOrderCU / HkTimesLogisticsOrderCUResponse
├── HkTimesLogisticsOrderStatus
├── HkTimesLogisticsInventory
├── HkTimesLogisticSkus
└── HkTimesLogisticsTokenRequest / HkTimesLogisticsTokenResponse

Flujo principal de autenticación y llamada

sequenceDiagram
participant Consumidor as Microservicio consumidor
participant Client as HkTimesLogisticsClient
participant Cache as CacheStore
participant TokenClient as HkTimesLogisticsTokenClient
participant API as API HKTL

Consumidor->>Client: createOrder / getInventory / ...
Client->>Cache: get("token")
alt Token en caché (< 1h)
Cache-->>Client: token válido
else Token ausente o expirado
Client->>TokenClient: getToken(username, password)
TokenClient->>API: POST /auth/login
API-->>TokenClient: { "token": "...", "expires_in": ... }
TokenClient-->>Client: token
Client->>Cache: add("token", token)
end
Client->>API: request + header Authorization: Bearer <token>
API-->>Client: respuesta JSON
Client-->>Consumidor: ResponseEntity<T>

La autoconfiguración (HkTimesLogisticsConfig) se activa condicionalmente con @ConditionalOnProperty(prefix = "hktl", name = {"url", "id", "pass"}), por lo que solo se inicializa si las tres propiedades están presentes. Registra dos beans:

  • hkTimesLogisticsTokenClientRestClient sin interceptor, usado únicamente para /auth/login.
  • hkTimesLogisticsClientRestClient con un requestInterceptor que resuelve el token (desde caché o pidiendo uno nuevo) e inyecta la cabecera Authorization: Bearer <token> en cada llamada.

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
org.json:json20251224Declarada en el pom.xml; no se usa en el código fuente actual
com.google.guava:guava33.6.0-jreImplementación de caché en CacheStore (CacheBuilder)
com.google.code.gson:gson(gestionada SB4)Anotaciones @SerializedName en los POJOs (soporte dual con Jackson)
com.fasterxml.jackson.core:jackson-databind(gestionada SB4)Serialización/deserialización Jackson en los POJOs
org.projectlombok:lombok1.18.46Generación de boilerplate en los POJOs (getters, setters, constructores)
spring-boot-starter-test(gestionada SB4)Testing (scope test)

5. API / Endpoints

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

6. Integraciones externas

API de HKTL (fulfillment logístico)

Método clienteHTTPRuta remotaDirecciónDescripción
createOrderPOST/api/foms/v2/order/createSalienteCrea o actualiza un pedido en el sistema de fulfillment HKTL
cancelOrderPOST/api/foms/v1/orders/cancelSalienteCancela un pedido existente por su orderName
getInventoryGET/api/foms/v2/inventorySalienteConsulta paginada del inventario del almacén (page, size)
getSkusGET/api/foms/v2/skuSalienteConsulta paginada del catálogo de SKUs (page, size)
getOrderStatusGET/api/foms/v2/order/statusSalienteConsulta el estado de fulfillment y tracking de un pedido (orderNumber)

El endpoint de autenticación es POST /auth/login (vía HkTimesLogisticsTokenClient), al que se llama con username/password en el body JSON.

Ejemplo de payload createOrder (HkTimesLogisticsOrderCU):

{
"warehouse_code": "HKG01",
"logistics_provider": { "code": "HKTL" },
"order_number": "ORD-000123",
"declared_value": 5000,
"currency": "USD",
"sender": {
"name": "Hawkers HK",
"company": "Hawkers",
"address": "...",
"city": "Hong Kong",
"country_code": "HK",
"phone": "...",
"email": "..."
},
"receiver": {
"name": "Cliente Final",
"address": "...",
"city": "...",
"province": "...",
"post_code": "...",
"country_code": "ES",
"phone": "..."
},
"items": [
{ "sku_code": "SKU-001", "unit_price": 2500, "qty": 2 }
]
}

Ejemplo de respuesta getOrderStatus (HkTimesLogisticsOrderStatus, resumida):

{
"code": 200,
"message": "OK",
"data": {
"order_number": "ORD-000123",
"packages": [
{
"master_tracking_number": "...",
"tracking_number": "...",
"courier_code": "...",
"courier_name": "...",
"package_status": {
"event_time": "2026-07-01T10:00:00",
"event_code": "DELIVERED",
"remark": ""
},
"items": [
{ "sku_code": "SKU-001", "qty": 2 }
]
}
]
}
}

Protocolo: HTTPS REST (JSON, contentType = application/json). Autenticación: Bearer token (obtenido dinámicamente vía /auth/login, cacheado 1 hora).

7. Configuración

No se incluye ningún application.properties/application.yml en la librería (no existe fichero de propiedades en src/main/resources, salvo el registro de autoconfiguración). Las propiedades deben ser inyectadas por la aplicación consumidora.

Propiedades requeridas (prefijo hktl)

PropiedadDescripciónEjemplo de valor
hktl.urlURL base de la API HKTL (activa la autoconfiguración)${HKTL_URL}
hktl.idUsuario para autenticación en HKTL${HKTL_ID}
hktl.passContraseña para autenticación en HKTL${HKTL_PASS}

Importante: Si falta cualquiera de las tres propiedades (hktl.url, hktl.id, hktl.pass), el bean HkTimesLogisticsConfig no se activa (condición @ConditionalOnProperty con las tres claves).

Variables de entorno recomendadas

VariablePropiedad mapeada
HKTL_URLhktl.url
HKTL_IDhktl.id
HKTL_PASShktl.pass

8. Persistencia

No aplica a este proyecto. La librería no accede a ninguna base de datos. El único estado que persiste en memoria es la caché del token Bearer (CacheStore, TTL 1 hora, backend Guava).

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

hk-timeslogistics-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 package

Uso como dependencia en un microservicio consumidor

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

La autoconfiguración se activa automáticamente al declarar hktl.url, hktl.id y hktl.pass 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.
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/hk-timeslogistics-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 RestClientException) son responsabilidad del servicio consumidor.

En resolveToken, si la respuesta de /auth/login no contiene body o el campo token viene nulo, el método devuelve una cadena vacía ("") en lugar de lanzar una excepción — esto provocaría que las llamadas posteriores se autentiquen con Authorization: Bearer (token vacío) y fallen con un error HTTP del lado de HKTL, en vez de fallar de forma explícita en el cliente.

No hay configuración de logback ni de niveles de log específicos en la librería.

13. Notas y consideraciones

  • Dependencia org.json sin uso: El pom.xml declara org.json:json (versión 20251224) pero no se encuentra ninguna referencia a esta librería en el código fuente (pojos/, client/, config/). Posible remanente de una versión anterior del cliente o de otro cliente similar (p. ej. auro-client) usado como plantilla. Pendiente de verificar si puede eliminarse.

  • Fallo silencioso en resolveToken: Si la autenticación falla o el body de respuesta no incluye token, HkTimesLogisticsConfig.resolveToken devuelve "" en lugar de propagar una excepción. Esto puede dificultar el diagnóstico de errores de autenticación, ya que el fallo real se manifestará como un 401/403 en la llamada de negocio posterior, no en el punto donde se obtiene el token.

  • expires_in no utilizado: HkTimesLogisticsTokenResponse incluye el campo expires_in devuelto por la API, pero la caché de token usa un TTL fijo de 1 hora (HkTimesLogisticsConfig) sin tener en cuenta este valor. Si HKTL emite tokens con una expiración distinta a 1 hora, podría producirse un desajuste entre el TTL de la caché local y la validez real del token.

  • Doble serialización (Jackson + Gson): Todos los POJOs del paquete pojos/ contienen anotaciones de Jackson (@JsonProperty) y Gson (@SerializedName) simultáneamente, permitiendo que los microservicios consumidores usen cualquiera de las dos librerías para (de)serializar. Mismo patrón que otros clientes del ecosistema (p. ej. auro-client).

  • Campos Object en POJOs de respuesta: Varios campos como expiry_date, manufacture_date, batch_no, udf_1/2/3 en HkTimesLogisticsOrderStatus.Data.Item y en HkTimesLogisticsInventory.Datum están tipados como Object en lugar de String/tipo concreto, probablemente porque la API HKTL devuelve estos campos con tipo variable (string, null, número). Reduce la seguridad de tipos para el consumidor.

  • Sin tests implementados: El directorio src/test/ no existe. La dependencia spring-boot-starter-test está declarada pero no hay ninguna prueba. Pendiente implementar cobertura.

  • HkTimesLogisticsClientApplication.java: Existe una clase principal de Spring Boot en el paquete raíz (HkTimeslogisticsClientApplication), lo que es inusual para una librería. No tiene funcionalidad operativa y probablemente sea un artefacto residual de la generación inicial del proyecto con Spring Initializr, mismo patrón observado en otros clientes del ecosistema.

  • Nombres de clase con inconsistencia de mayúsculas: El artifactId y el paquete usan hktimeslogistics (minúsculas), mientras que las clases usan HkTimesLogistics... (con "Times" y "Logistics" en PascalCase); la clase principal usa HkTimeslogisticsClientApplication (con "logistics" en minúscula), una inconsistencia menor de nomenclatura entre la clase principal y el resto de clases del proyecto.