feat(F-125): completed feature
This commit is contained in:
79
work/artifacts/F-125/architect.md
Normal file
79
work/artifacts/F-125/architect.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# F-125 — Permitir transiciones hacia atrás en pedidos + reenviar email SHIPPED↔PROCESSING
|
||||
|
||||
## Diagnóstico
|
||||
|
||||
El operador reporta que al equivocarse marcando un pedido (p. ej., marcar PROCESSING cuando aún no está listo, o SHIPPED antes de tiempo) **no puede revertir**. El state machine actual solo permite avanzar o cancelar:
|
||||
|
||||
```ts
|
||||
// src/modules/orders/domain/order.ts
|
||||
export const ALLOWED_TRANSITIONS: Readonly<Record<OrderState, ReadonlyArray<OrderState>>> = {
|
||||
PENDING: ['AWAITING_PAYMENT', 'CANCELLED'],
|
||||
AWAITING_PAYMENT: ['PAID', 'CANCELLED'],
|
||||
PAID: ['PROCESSING', 'CANCELLED', 'REFUNDED'],
|
||||
PROCESSING: ['SHIPPED', 'CANCELLED', 'REFUNDED'],
|
||||
SHIPPED: ['DELIVERED', 'PARTIALLY_REFUNDED'],
|
||||
DELIVERED: ['PARTIALLY_REFUNDED'],
|
||||
CANCELLED: [],
|
||||
REFUNDED: [],
|
||||
PARTIALLY_REFUNDED: [],
|
||||
};
|
||||
```
|
||||
|
||||
El state machine está **duplicado** en el frontend (`apps/admin/src/app/(dashboard)/orders/[id]/page.tsx:32`) — ambos deben actualizarse para mantener consistencia.
|
||||
|
||||
El reenvío de email ya ocurre en cada transición admin (orders.routes.ts:271), así que añadir transiciones nuevas implica que el email se envía automáticamente con el estado y courier/tracking actuales del pedido.
|
||||
|
||||
## Diseño
|
||||
|
||||
### Transiciones hacia atrás (un paso)
|
||||
- `PROCESSING → PAID` (revertir procesado)
|
||||
- `SHIPPED → PROCESSING` (revertir envío)
|
||||
- `DELIVERED → SHIPPED` (revertir entrega)
|
||||
|
||||
Estados terminales (`CANCELLED`, `REFUNDED`, `PARTIALLY_REFUNDED`) **se mantienen terminales** — un reembolso no se puede deshacer.
|
||||
|
||||
```ts
|
||||
export const ALLOWED_TRANSITIONS = {
|
||||
PENDING: ['AWAITING_PAYMENT', 'CANCELLED'],
|
||||
AWAITING_PAYMENT: ['PAID', 'CANCELLED'],
|
||||
PAID: ['PROCESSING', 'CANCELLED', 'REFUNDED'],
|
||||
PROCESSING: ['PAID', 'SHIPPED', 'CANCELLED', 'REFUNDED'], // + PAID
|
||||
SHIPPED: ['PROCESSING', 'DELIVERED', 'PARTIALLY_REFUNDED'], // + PROCESSING
|
||||
DELIVERED: ['SHIPPED', 'PARTIALLY_REFUNDED'], // + SHIPPED
|
||||
CANCELLED: [],
|
||||
REFUNDED: [],
|
||||
PARTIALLY_REFUNDED: [],
|
||||
};
|
||||
```
|
||||
|
||||
### Frontend
|
||||
- Actualizar la copia local de `ALLOWED_TRANSITIONS` en `apps/admin/src/app/(dashboard)/orders/[id]/page.tsx:32` con las mismas nuevas transiciones.
|
||||
- Añadir `ACTION_LABELS` para los nuevos botones:
|
||||
- `PAID → PROCESSING`: ya existía como "Procesar pedido"
|
||||
- `PROCESSING → PAID`: "Revertir a Pagado" (nuevo)
|
||||
- `SHIPPED → PROCESSING`: "Revertir a En preparación" (nuevo)
|
||||
- `DELIVERED → SHIPPED`: "Revertir a Enviado" (nuevo)
|
||||
|
||||
### Email
|
||||
- El handler admin `/orders/:id/transitions/admin` ya envía email en cada transición (orders.routes.ts:271). No requiere cambios.
|
||||
- Cuando `SHIPPED → PROCESSING`: el email se reenvía con `state='PROCESSING'` pero conserva `courier` y `trackingNumber` actuales del pedido en el cuerpo (verificado en `buildOrderStatusEmail` — incluye las líneas solo si están presentes, independientemente del estado).
|
||||
- El cliente recibe el email con "Tu pedido #ABC ahora está: En preparación" más el bloque de courier/tracking si aún están guardados.
|
||||
|
||||
### Tests
|
||||
Actualizar `src/modules/orders/tests/order-state-machine.test.ts`:
|
||||
- Eliminar o invertir el test "rejects SHIPPED back to PENDING" (sigue válido: SHIPPED → PENDING sigue prohibido, pero SHIPPED → PROCESSING ahora permitido).
|
||||
- Añadir test explícito: `isTransitionAllowed('SHIPPED', 'PROCESSING') === true`, etc.
|
||||
|
||||
## Riesgos
|
||||
|
||||
- **Bajo**. El cambio es ampliar el grafo de transiciones. Los terminales siguen terminales.
|
||||
- **Riesgo operativo**: un operador puede hacer ping-pong entre PROCESSING y SHIPPED. Cada cambio envía email al cliente → spam si abusa. Mitigación: no se cambia el límite de frecuencia, es responsabilidad del operador.
|
||||
|
||||
## Plan
|
||||
|
||||
1. Editar `src/modules/orders/domain/order.ts` — añadir transiciones hacia atrás.
|
||||
2. Editar `src/modules/orders/tests/order-state-machine.test.ts` — actualizar tests.
|
||||
3. Editar `apps/admin/src/app/(dashboard)/orders/[id]/page.tsx` — añadir transiciones + nuevos labels.
|
||||
4. Backend: `npm test` (vitest) — verificar 100% tests OK.
|
||||
5. Admin: `npx tsc --noEmit && npm run build`.
|
||||
6. Cerrar gates.
|
||||
Reference in New Issue
Block a user