Skip to main content

return-pi-dynamics

1. Descripción general

Según el pom.xml, el proyecto se describe como "Return PI Dynamics". Es un microservicio batch (runner) que sincroniza las devoluciones (Return) registradas en la base de datos de logística con Dynamics 365 (creación, recepción y pago de la devolución), gestiona el caso de devoluciones con origen cancelado, y finalmente dispara el email transaccional de reembolso al cliente vía Salesforce Marketing Cloud.

2. Información técnica

CampoValor
artifactIdreturn-pi-dynamics
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 4 CommandLineRunner, todos activos, ejecutados en orden.

OrdenRunnerEstado de entradaAcción
1ReturnApprovedPiDynamicsRunnerAPPROVEDCrea y recibe la devolución en Dynamics; omite (y notifica por Slack) las que tienen origen cancelado (idReturnOrigin == 8)
2ReturnPaymentPiDynamicsRunnerREFUNDED pendiente de pagoCrea → recibe → paga la devolución en Dynamics
3ReturnCancelledPiDynamicsRunnerREFUNDED con origen canceladoEnvía la cancelación a Dynamics
4ReturnSendEmailPiDynamicsRunnerPost-DynamicsEnvía el email de reembolso vía SFCC Marketing Cloud, y cierra la JVM
  • .utilReturnPiDynamicsUtil (mapeo SKU→dimensiones de inventario de Dynamics, con caché local en BD), ReturnPiSendDynamicsUtil (lógica central de envío: sendCreateReturn, sendReceiveReturn, sendPaymentReturn, sendCancelledReturn).
  • .configLogisticsDbConfig (datasource primario logistics), DynamicsDbConfig (datasource secundario dynamics-pro).
flowchart TD
A["1. ReturnApprovedPiDynamicsRunner"] -->|crea + recibe| B[Dynamics 365]
C["2. ReturnPaymentPiDynamicsRunner"] -->|crea + recibe + paga| B
D["3. ReturnCancelledPiDynamicsRunner"] -->|cancela| B
E["4. ReturnSendEmailPiDynamicsRunner"] -->|email reembolso| F[SFCC Marketing Cloud]
E -->|System.exit| G[Fin del proceso]

A -.->|origen cancelado| H[Slack]

Doble datasource

LogisticsDbConfig (primario, BD logistics: Order, Return, ReturnLine, ReturnStatus) y DynamicsDbConfig (secundario, BD dynamics-pro: InventDimensionsCombinations, PiCustomerSetup).

4. Dependencias principales

DependenciaPropósito
spring-boot-starterNúcleo de Spring Boot (sin web, es un runner CLI)
com.hawkersco:logistics-commonsEntidades/servicios de devoluciones y pedidos
com.hawkersco:dynamics-commonsEntidades de dimensiones de inventario y configuración de cliente PI en Dynamics
com.hawkersco:dynamics-clientCliente @HttpExchange (DynamicsDataClient) para crear/cancelar/recibir devoluciones y consultar dimensiones de inventario
com.hawkersco:slack-clientNotificaciones de error/escalado a Slack
com.hawkersco:sfcc-marketing-clientCliente para Salesforce Marketing Cloud (envío del email de reembolso)
com.hawkersco:sfcc-commonsUtilidades SFCC compartidas
spring-boot-starter-test (test)JUnit 5 + Spring Test

5. API / Endpoints

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

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
Dynamics 365 (scul072xsfj99233501-rs.su.retail.dynamics.com)HTTP OAuth client_credentials (DynamicsDataClient)SalienteCrear/recibir/pagar/cancelar devoluciones, consultar dimensiones de inventario
PI Customer Setup (hawkers.operations.dynamics.com)HTTP OAuth client_credentialsSalienteConfiguración de cliente PI en Dynamics F&O
Salesforce Marketing CloudHTTP OAuth client_credentialsSalienteEnvío del email transaccional de reembolso
SlackHTTP (SlackClient)SalienteEscalado de errores y aviso de devoluciones con origen cancelado
PostgreSQL (logistics, dynamics-pro)JDBCEntrante/SalienteLectura de devoluciones pendientes y persistencia de contadores de reintento

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).

ClaveDescripción
spring.datasource.*Credenciales de la BD logistics (datasource primario)
dynamics.datasource.*Credenciales de la BD dynamics-pro (datasource secundario)
dynamics.login.*OAuth client_credentials para Dynamics 365 Commerce — mismas credenciales ya señaladas como expuestas en otros proyectos del ecosistema
dynamics.picustomersetup.*OAuth client_credentials para Dynamics F&O (PI Customer Setup)
slack.client.url / .auth.token / .channel.idConfiguración de Slack
sfccmarketing.credentials.*Credenciales OAuth y configuración de Salesforce Marketing Cloud (incluye eventdefinitionkey, account-id)

⚠️ Alerta de seguridad (severidad alta)

El fichero src/main/resources/application.properties (perfil local) contiene actualmente credenciales OAuth reales de Dynamics 365 (las mismas ya señaladas como expuestas en gio-pos-sync-service, infranete-api, products-dynamics-pi), las contraseñas de ambas bases de datos PostgreSQL, un token de bot de Slack, y credenciales OAuth reales de Salesforce Marketing Cloud (client-id/client-secret, no señaladas hasta ahora en el resto del ecosistema documentado). Ninguno de estos valores se ha reproducido en este documento. Se recomienda:

  1. Rotar el client-secret de las aplicaciones Azure AD de Dynamics (coordinando con los demás proyectos que las comparten).
  2. Rotar las credenciales de Salesforce Marketing Cloud y el token de Slack.
  3. Rotar las contraseñas de ambas bases de datos.
  4. Sustituir los valores hardcodeados de application.properties por credenciales de un entorno de desarrollo aislado.
  5. Revisar el historial de control de versiones, ya que estas credenciales pueden seguir expuestas en commits anteriores.

8. Persistencia

Dos bases de datos PostgreSQL: logistics (Order, Return, ReturnLine, ReturnStatus) y dynamics-pro (InventDimensionsCombinations, PiCustomerSetup), ambas con ddl-auto=none. El progreso de sincronización se rastrea mediante columnas contador (nmReturnCreateDynamics, nmReturnReceiveDynamics, etc.) en la entidad Return, con un máximo de 5 reintentos antes de escalar por Slack. ReturnPiDynamicsUtil cachea en BD el mapeo SKU→dimensiones de inventario de Dynamics para reducir llamadas a la API. 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 15 minutos (schedule: "*/15 * * * *"). Cada uno de los 4 runners verifica el resultado del paso anterior antes de continuar (p. ej. ReturnApprovedPiDynamicsRunner solo llama a sendReceiveReturn si la devolución ya estaba creada o si sendCreateReturn tuvo éxito en esta misma ejecución). Las devoluciones con origen cancelado se omiten explícitamente en el flujo de aprobadas y se notifican por Slack como posible anomalía (una devolución con origen cancelado no debería llegar a estado APPROVED).

10. Ejecución en local

Requisitos previos: JDK 25, Maven, acceso a ambas BD y credenciales OAuth válidas de Dynamics 365 y Salesforce Marketing Cloud.

# Compilar
mvn clean package

# Ejecutar (perfil dev)
mvn spring-boot:run

# Ejecutar (perfil pro)
mvn spring-boot:run -Dspring.profiles.active=pro

# Ejecutar tests
mvn test
mvn test -Dtest=ClassName

# Build de imagen OCI
mvn spring-boot:build-image

Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o el estado de las devoluciones (ReturnStatus) tras la ejecución.

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/return-pi-dynamics:<tag>.
  • Orquestación: Kubernetes CronJob en el clúster GKE pi-cluster-hw, namespace pi, ejecutándose cada 15 minutos.
  • CI/CD (Jenkins): pipeline que sustituye application-pro.properties por application.properties antes de construir.

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/return-pi-dynamics/

12. Manejo de errores y logging

No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). Cada paso del flujo comprueba el éxito del anterior antes de continuar (patrón de "cortocircuito" por devolución individual, no a nivel de todo el runner). Notificación a Slack específica cuando una devolución con origen cancelado llega al flujo de aprobadas, y escalado tras superar el máximo de reintentos por operación. Logging mediante SLF4J (consola).

13. Notas y consideraciones

  • CLAUDE.md verificado y consistente con el código: la secuencia de 4 runners, sus órdenes de ejecución, el doble datasource y las integraciones externas descritas coinciden con lo observado directamente en el código (ReturnApprovedPiDynamicsRunner, órdenes 1–4 confirmados por grep). No se han encontrado discrepancias relevantes en este proyecto, a diferencia de la mayoría de los documentados en este lote.
  • Ver alerta de seguridad en la sección 7 sobre credenciales OAuth reales de Dynamics 365 y de Salesforce Marketing Cloud expuestas en application.properties.