Skip to main content

update-stock

1. Descripción general

Según el pom.xml, el proyecto se describe como "Update stock from dynamics" (descripción heredada, ver hallazgo en la sección 13: el proyecto no interactúa con Dynamics en absoluto). Es un microservicio batch (runner) que lee stock por marketplace desde una hoja de Google Sheets (dos pestañas, una por marca: Hawkers y Northweek) y sincroniza (upsert) los valores en la base de datos marketplaces, para los canales Decathlon, Miravia, Showroom y ECI.

2. Información técnica

CampoValor
artifactIdupdate-stock
groupIdcom.hawkersco
version1.0.25
Java25
Spring Boot4.0.6
Tipo de artefactojar (ejecutable, Spring Boot batch/CLI)
MódulosNo aplica (proyecto de módulo único)

3. Arquitectura y diseño

No es una API REST: es una aplicación Spring Boot CLI con un único CommandLineRunner (MarketplacesRunner).

  • .configUpdateStockConfig (bean MarketplaceStockService + PersistenceManagedTypes vía PersistenceManagedTypesScanner sobre com.hawkersco.marketplacescommons.dao).
flowchart TD
A[MarketplacesRunner] -->|lee stock!A2:F| B[Google Sheets · pestaña HAWKERS]
A -->|lee NW - Decathlon!A2:F| C[Google Sheets · pestaña NORTHWEEK]
B --> D{existe MarketplaceStock<br/>por SKU+empresa?}
C --> D
D -->|sí| E[updateMarketplaceStock]
D -->|no| F[save nuevo MarketplaceStock]
E --> G[(marketplaces · MarketplaceStock)]
F --> G

Flujo: por cada una de las 2 pestañas (stock para Hawkers, NW - Decathlon para Northweek), lee el rango A2:F de la hoja de cálculo, y para cada fila con SKU no vacío comprueba si ya existe un MarketplaceStock para ese SKU y esa empresa (findByCdSkuAndDsCompany); si existe, actualiza los 4 campos de stock por marketplace (nmDecathlon, nmMiravia, nmShowroom, nmEci); si no existe, crea un nuevo registro. Un fallo de la API de Google Sheets al leer una pestaña se registra como warning y esa pestaña se omite, sin interrumpir el procesamiento de la otra.

4. Dependencias principales

DependenciaPropósito
spring-boot-starterNúcleo de Spring Boot (sin web, es un runner CLI)
com.google.api-client:google-api-clientCliente base de APIs de Google
com.google.oauth-client:google-oauth-client-jettyAutenticación OAuth de Google
com.google.apis:google-api-services-sheetsCliente de la API de Google Sheets v4
com.hawkersco:marketplaces-commonsEntidad MarketplaceStock y MarketplaceStockService
com.hawkersco:pi-function-commonsSheetsServiceUtils (autenticación/acceso a Google Sheets)

5. API / Endpoints

No aplica a este proyecto. Es un batch/runner sin capa REST.

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
Google Sheets (hoja 1AFIE3V_eE58on_zyO4cpAhgItPUSuKBQVU4e1M2-vzQ)API de Google v4EntranteLectura de stock por SKU y marketplace, 2 pestañas (Hawkers/Northweek)
PostgreSQL (marketplaces)JDBCSalienteUpsert de MarketplaceStock por SKU y empresa

7. Configuración

En producción (application-pro.properties) las credenciales llegan por variables de entorno inyectadas como Secret de Kubernetes; en local (application.properties) el repositorio contiene actualmente valores reales hardcodeados (ver alerta de seguridad), pese a que el CLAUDE.md afirma que este fichero está en .gitignore.

ClaveDescripción
spring.datasource.*Credenciales de la BD marketplaces
GOOGLE_APPLICATION_CREDENTIALS (variable de entorno, no propiedad Spring)Ruta al JSON de la cuenta de servicio de GCP para autenticar contra Google Sheets

⚠️ Alerta de seguridad

El fichero src/main/resources/application.properties (perfil local) contiene actualmente la contraseña real en texto plano de la base de datos PostgreSQL marketplaces (la misma ya señalada como expuesta en otros proyectos de este ecosistema que comparten la instancia noctua-instance.hawkersco.net). No se ha reproducido en este documento. Se recomienda:

  1. Rotar la contraseña de BD.
  2. Sustituir el valor hardcodeado de application.properties por credenciales de un entorno de desarrollo aislado.
  3. Revisar el historial de control de versiones, ya que esta credencial puede seguir expuesta en commits anteriores.

8. Persistencia

Base de datos PostgreSQL marketplaces (spring.jpa.hibernate.ddl-auto=none). Entidad relevante: MarketplaceStock (paquete com.hawkersco.marketplacescommons.dao, escaneada vía PersistenceManagedTypesScanner). No hay Flyway/Liquibase en este repositorio.

9. Procesos programados y mensajería

No hay @Scheduled ni listeners de colas: la periodicidad la impone el CronJob de Kubernetes (k8s/cronjob.yaml), que ejecuta el contenedor cada hora (schedule: "0 * * * *", zona horaria Europe/Madrid, concurrencyPolicy: Forbid). Único runner, descrito en la sección 3.

10. Ejecución en local

Requisitos previos: JDK 25, Maven, acceso a la BD marketplaces y credenciales de aplicación por defecto de Google (Sheets).

# Compilar sin tests
./mvnw clean install -DskipTests

# Ejecutar la aplicación localmente
./mvnw spring-boot:run

No existen tests implementados (jenkins/scripts/test.sh es un placeholder vacío). Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o los valores reflejados en la tabla MarketplaceStock.

11. Despliegue

  • Imagen: construida con jib-maven-plugin (base eclipse-temurin:25-jre, containerizingMode=packaged), publicada en europe-west3-docker.pkg.dev/pi-saldum/pi-repo/update-stock:<tag>.
  • Orquestación: Kubernetes CronJob en el clúster GKE pi-cluster-hw, namespace pi, con credenciales de cuenta de servicio de GCP montadas por volumen (GOOGLE_APPLICATION_CREDENTIALS, necesarias en este caso para la autenticación real contra Google Sheets, a diferencia de otros proyectos de este lote donde el mismo montaje aparece sin uso aparente), ejecutándose cada hora.
  • CI/CD (Jenkins): pipeline real de 3 etapas — CheckoutBuild & PushDeploy to GKE. El CLAUDE.md describe un pipeline con KICS security scan y SonarQube que no existen en el Jenkinsfile actual (mismo patrón detectado en varios proyectos hermanos de este lote).

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/update-stock/

12. Manejo de errores y logging

No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). processCompanySheet captura IOException por pestaña de hoja de cálculo, registrando Level.WARNING y continuando con la siguiente pestaña sin interrumpir el proceso. Logging mediante java.util.logging.Logger estándar (consola).

13. Notas y consideraciones

  • description del pom.xml desactualizada: indica "Update stock from dynamics", pero el proyecto no lee ni escribe en Dynamics 365 en ningún punto del código — la única fuente de datos es Google Sheets. Es probable que la descripción sea un resto de una versión anterior del proyecto o de haberlo clonado de otro con un propósito distinto.
  • Fichero de recurso aliexpress-sku.json sin ninguna referencia en el código: el CLAUDE.md lo lista como parte de la arquitectura ("Static SKU mapping data"), pero no se ha encontrado ninguna referencia a aliexpress en MarketplacesRunner ni en UpdateStockConfig — el fichero está presente en src/main/resources/ pero no se carga ni se usa en ningún punto del código actual. Probablemente un resto de una integración con AliExpress ya retirada o nunca completada.
  • CLAUDE.md afirma que application.properties está en .gitignore, pero el fichero está presente y con la contraseña de BD real legible directamente en el repositorio de trabajo (mismo patrón detectado en showroom-flash-create-db y theiconic-create-db).
  • Pipeline de Jenkins más simple de lo documentado: ver hallazgo en la sección 11.
  • El resto de la arquitectura descrita en CLAUDE.md (flujo único de sincronización, las 2 pestañas de la hoja, los 4 campos de stock por marketplace) coincide con el código real, verificado directamente en MarketplacesRunner.
  • Ver alerta de seguridad en la sección 7 sobre la contraseña de BD expuesta en application.properties.