Capa de interoperabilidad · Prueba técnica de arquitectura

ADR-020: precios con vigencia, el evento lleva el calendario y el precio se elige al leer

Aceptado el 11/11/2026 por Andrés. Complementa ADR-015 (vigencias del precio).

Contexto

Price trae validFrom y validTo, pero el diseño no dice qué hace la capa con un precio de vigencia futura. Es el caso normal de una promoción: el área comercial carga el viernes negro con días de anticipación.

El tópico andes.pricing.prices.v1 es compactado con clave sku|channel|priceList. Si el erp-adapter publica el precio futuro con esa clave, la compactación termina borrando el precio vigente: el consumidor que reconstruye su modelo desde el tópico ve solo el futuro. Y si el servicio aplica cada evento al llegar, la promoción se vende antes de tiempo; si lo guarda para aplicarlo en validFrom, ningún evento llega en ese momento que dispare el cambio.

Así lo resuelven los sistemas de referencia:

Opciones

Opción A favor En contra
A. Mantener la clave y agregar al evento el calendario del alcance: todas las ventanas no vencidas. El consumidor elige al leer Compatible con la compactación: el último valor de la clave tiene todo; cambio aditivo en v1 (ADR-011); el orden por clave se conserva y la corrección de ADR-015 sigue igual El adaptador debe conocer todas las ventanas del alcance; el evento crece
B. Una clave por ventana: sku|channel|priceList|validFrom Una fila del ERP es un mensaje, como los precios independientes de commercetools Cambia la clave del tópico: ruptura que pide .v2; las ventanas de un mismo alcance caen en particiones distintas y la corrección de ADR-015 pierde el orden
C. Guardar vigente y siguiente, y cambiar en validFrom Simple de explicar No cubre el fin de una promoción que vuelve al precio base ni dos cambios programados; sigue perdiendo el vigente con la compactación
D. Un proceso programado aplica el precio a la hora de validFrom El modelo de lectura guarda un solo precio Una pieza más; si está caído en ese instante, el precio no cambia; con miles de SKU en la misma hora es un pico de escrituras

Decisión

Opción A.

  1. Contrato: Price agrega schedule, opcional: la lista de ventanas no vencidas del alcance sku|channel|priceList, cada una con listPrice, salePrice, currency, taxIncluded, priceVersion, validFrom y validTo (ausente es sin fin). Los campos de primer nivel siguen siendo la ventana vigente al publicar, así un consumidor que ignora schedule se comporta como hoy.
  2. Regla de selección, en el contrato: entre las ventanas con validFrom <= ahora y sin validTo o con ahora < validTo, gana la de validFrom más reciente. Así una promoción con fin gana sobre el precio base mientras dura, y al vencer vuelve el base sin que nadie publique nada. Si ninguna está vigente, el SKU va a notFound. La hora es UTC.
  3. erp-adapter: mantiene en su propia base las ventanas de cada alcance, alimentadas por la foto inicial y por el feed (no consulta al ERP por cada cambio). Ante el cambio de cualquier ventana, publica el calendario completo del alcance y omite las vencidas. Máximo 10 ventanas no vencidas por alcance (supuesto S22); si el ERP trae más, publica las 10 más próximas y alerta.
  4. pricing-service: guarda el calendario en price:{sku}:{channel}:{priceList} y aplica la regla al leer. La respuesta de GET /v1/prices no cambia: lleva la ventana elegida, con su validFrom, validTo y priceVersion.
  5. order-service (F4): su vista de precios guarda el calendario y aplica la misma regla al momento en que el canal vio el precio. La ventana de tolerancia y la corrección de ADR-015 no cambian: una corrección invalida las versiones anteriores del alcance.
  6. Mock del ERP: modela cada precio como fila con vigencia, varias por alcance. Un precio programado se inyecta como fila nueva con validFrom futuro.

Verificación

Qué se sacrifica