Files
mercadodevida/work/artifacts/F-125/implementer.md
2026-08-21 17:58:15 +02:00

3.3 KiB

F-125 — Transiciones hacia atrás en pedidos + reenviar email

Cambios

src/modules/orders/domain/order.ts

State machine ampliado con transiciones hacia atrás (un paso):

 export const ALLOWED_TRANSITIONS = {
   PENDING: ['AWAITING_PAYMENT', 'CANCELLED'],
   AWAITING_PAYMENT: ['PAID', 'CANCELLED'],
-  PAID: ['PROCESSING', 'SHIPPED', 'CANCELLED', 'REFUNDED'],
+  PAID: ['PROCESSING', 'SHIPPED', 'CANCELLED', 'REFUNDED'],  // unchanged
-  PROCESSING: ['SHIPPED', 'CANCELLED', 'REFUNDED'],
+  PROCESSING: ['PAID', 'SHIPPED', 'CANCELLED', 'REFUNDED'],  // + PAID (backward)
-  SHIPPED: ['DELIVERED', 'PARTIALLY_REFUNDED'],
+  SHIPPED: ['PROCESSING', 'DELIVERED', 'PARTIALLY_REFUNDED'], // + PROCESSING (backward)
-  DELIVERED: ['PARTIALLY_REFUNDED'],
+  DELIVERED: ['SHIPPED', 'PARTIALLY_REFUNDED'],                // + SHIPPED (backward)
   CANCELLED: [],
   REFUNDED: [],
   PARTIALLY_REFUNDED: [],
 };

Terminales (CANCELLED, REFUNDED, PARTIALLY_REFUNDED) siguen terminales — un reembolso no se puede deshacer.

src/modules/orders/tests/order-state-machine.test.ts

  • Test renombrado: "rejects SHIPPED back to PENDING (too far)" — el comportamiento de rechazo sigue siendo correcto (PENDING está demasiado lejos).
  • Test nuevo: "allows one-step backward transitions (F-125)" — verifica PROCESSING→PAID, SHIPPED→PROCESSING, DELIVERED→SHIPPED.

apps/admin/src/app/(dashboard)/orders/[id]/page.tsx

  • Mismo ALLOWED_TRANSITIONS duplicado (frontend) actualizado con las nuevas transiciones.
  • ACTION_LABELS reemplazado por ACTION_LABELS_BY_TRANSITION keyed por "<from>><to>". Esto permite que el mismo target (p. ej. PROCESSING) tenga label distinto según origen:
    • PAID > PROCESSING: "Procesar pedido"
    • SHIPPED > PROCESSING: "Revertir a En preparación"
  • Función helper actionLabel(from, to) que devuelve el label del par o fallback "Pasar a {to}".
  • Dos usos actualizados: {actionLabel(currentState, next)} (botón) y {actionLabel(currentState, showConfirm)} (modal de confirmación).

Email

Sin cambios en backend de email. El handler POST /orders/:id/transitions/admin ya envía email en cada transición con courier y trackingNumber actuales del pedido (ver orders.routes.ts:271 y buildOrderStatusEmail en order-status-mailer.ts).

Cuando SHIPPED → PROCESSING:

  • El email se reenvía con state='PROCESSING'
  • El bloque "Transportista: X / Número de seguimiento: Y" sigue apareciendo porque courier y trackingNumber siguen guardados en DB y se incluyen en el body si están presentes (independiente del estado).

Verificación

Tests

  • npx vitest run src/modules/orders/tests/order-state-machine.test.ts5/5 pass (incluye el nuevo test de transiciones hacia atrás).

Build

  • cd apps/admin && npx tsc --noEmit → exit 0.
  • cd apps/admin && npm run build → exit 0.

Evidencia manual

Con pedidos existentes:

  • PROCESSING → botón "Marcar como Enviado" + botón nuevo "Revertir a Pagado"
  • SHIPPED → botón "Marcar como Entregado" + botón nuevo "Revertir a En preparación"
  • DELIVERED → botón "Reembolso parcial" + botón nuevo "Revertir a Enviado"

Notas

  • El reenvío de email ya estaba implementado (F-113) — solo había que permitir las transiciones.
  • El operador debe reiniciar admin (./scripts/monolith.sh prod restart) para desplegar la nueva UI.