296 lines
13 KiB
Markdown
296 lines
13 KiB
Markdown
# ADM-013 / ADM-014 / ADM-015 — Orders Spec
|
||
|
||
## Goal
|
||
|
||
Gestión completa de pedidos: listado, detalle, y transiciones de estado.
|
||
|
||
---
|
||
|
||
## 1. Order List (`/admin/orders`)
|
||
|
||
### API Contract
|
||
|
||
```
|
||
GET /orders
|
||
Authorization: session_token (admin role)
|
||
|
||
Query params:
|
||
?offset=0&limit=20
|
||
?state=PENDING
|
||
?q=maria@ejemplo.com (búsqueda por email de cliente)
|
||
|
||
Response: OrderSummary[]
|
||
```
|
||
|
||
```typescript
|
||
interface OrderSummary {
|
||
id: string;
|
||
userId: string;
|
||
state: OrderState;
|
||
totalCents: number;
|
||
currency: 'EUR';
|
||
itemCount: number;
|
||
createdAt: string; // ISO
|
||
}
|
||
```
|
||
|
||
### Desktop UX
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ Pedidos [Estado ▼] [Búsqueda: ________] [🔍] │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ #ID Cliente Total Estado Fecha │
|
||
│ ──────────────────────────────────────────────────────────────── │
|
||
│ abc-123 maria@email.com €45.83 ● Paid 15 ago 2026 │
|
||
│ def-456 juan@email.com €23.10 ● Pending 14 ago 2026 │
|
||
│ ghi-789 ana@email.com €89.00 ● Shipped 10 ago 2026 │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ [← Anterior] Página 1 de 5 [Siguiente →] │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Filters
|
||
|
||
- **Estado**: PENDING, AWAITING_PAYMENT, PAID, PROCESSING, SHIPPED, DELIVERED, CANCELLED, REFUNDED, PARTIALLY_REFUNDED
|
||
- **Búsqueda**: por email de cliente (o ID)
|
||
- Estado por defecto: todos
|
||
|
||
### Responsive
|
||
|
||
Mobile: Cards en lugar de tabla
|
||
```
|
||
┌─────────────────────────┐
|
||
│ #abc-123 │
|
||
│ maria@email.com │
|
||
│ €45.83 · ● Paid │
|
||
│ 15 ago 2026 │
|
||
│ [Ver detalle →] │
|
||
└─────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Order Detail (`/admin/orders/[id]`)
|
||
|
||
### API Contract
|
||
|
||
```
|
||
GET /orders/:id/admin
|
||
Authorization: session_token (admin role)
|
||
|
||
Response: Order (full)
|
||
```
|
||
|
||
```typescript
|
||
interface Order {
|
||
id: string;
|
||
userId: string;
|
||
state: OrderState;
|
||
subtotalCents: number;
|
||
discountCents: number;
|
||
taxCents: number;
|
||
totalCents: number;
|
||
currency: 'EUR';
|
||
idempotencyKey: string | null;
|
||
items: OrderItem[];
|
||
createdAt: string;
|
||
updatedAt: string;
|
||
}
|
||
|
||
interface OrderItem {
|
||
id: string;
|
||
productId: string;
|
||
variantId: string;
|
||
sku: string;
|
||
ean: string | null;
|
||
name: string;
|
||
unitPriceCents: number;
|
||
discountCents: number;
|
||
taxCents: number;
|
||
quantity: number;
|
||
}
|
||
```
|
||
|
||
### Desktop UX — Layout
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ ← Volver a pedidos │
|
||
├───────────────────────────────────┬─────────────────────────────┤
|
||
│ HEADER │ ACCIONES │
|
||
│ #abc-123-def │ [Cambiar estado ▼] │
|
||
│ ● Paid · 15 ago 2026 │ │
|
||
├───────────────────────────────────┴─────────────────────────────┤
|
||
│ │
|
||
│ ┌─────────────────────────┐ ┌─────────────────────────────┐ │
|
||
│ │ RESUMEN DEL PEDIDO │ │ CLIENTE │ │
|
||
│ │ │ │ maria@email.com │ │
|
||
│ │ Subtotal €37.88 │ │ │ │
|
||
│ │ Descuentos €0.00 │ │ ENVÍO │ │
|
||
│ │ IVA €7.95 │ │ Calle Gran Vía 42 │ │
|
||
│ │ ─────────────────── │ │ Madrid, 28013 │ │
|
||
│ │ TOTAL €45.83 │ │ │ │
|
||
│ └─────────────────────────┘ └─────────────────────────────┘ │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ PRODUCTOS PEDIDOS │ │
|
||
│ │ ───────────────────────────────────────────────────── │ │
|
||
│ │ Almendras Crudas 2 × €8.95 = €17.90 │ │
|
||
│ │ Vitamina D3 + K2 2 × €9.99 = €19.98 │ │
|
||
│ │ ───────────────────────────────────────────────────── │ │
|
||
│ │ Envío estándar + €4.99 │ │
|
||
│ └─────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ HISTORIAL │ │
|
||
│ │ ───────────────────────────────────────────────────── │ │
|
||
│ │ ● 15 ago 2026 14:32 Creado │ │
|
||
│ │ ● 15 ago 2026 14:35 Pagado │ │
|
||
│ └─────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Payment Transactions
|
||
|
||
```
|
||
GET /payments/orders/:orderId/transactions
|
||
Response: { transactions: PaymentTransaction[] }
|
||
```
|
||
|
||
Mostrar en sección separada: fecha, método, monto, estado.
|
||
|
||
---
|
||
|
||
## 3. Order State Transitions
|
||
|
||
### API Contract
|
||
|
||
```
|
||
POST /orders/:id/transitions/admin
|
||
Authorization: session_token (admin role)
|
||
|
||
Body: { state: OrderState }
|
||
|
||
Response: Order (updated)
|
||
```
|
||
|
||
### State Machine
|
||
|
||
```
|
||
PENDING ──────────→ AWAITING_PAYMENT (customer paid)
|
||
│ │
|
||
├─→ CANCELLED └─→ PAID ──→ PROCESSING ──→ SHIPPED ──→ DELIVERED
|
||
│ │ │
|
||
│ ├─→ CANCELLED│
|
||
│ │ ├─→ CANCELLED
|
||
│ │ │
|
||
│ ├─→ REFUNDED (full)
|
||
│ └─→ PARTIALLY_REFUNDED
|
||
│ │
|
||
└─→ CANCELLED ←──────────────────────────────┘
|
||
```
|
||
|
||
### Allowed transitions visible in UI
|
||
|
||
| Current State | Actions Available |
|
||
|-------------------|------------------------------------------------------------|
|
||
| PENDING | Marcar como Pagado · Cancelar pedido |
|
||
| AWAITING_PAYMENT | Marcar como Pagado · Cancelar pedido |
|
||
| PAID | Procesar pedido · Cancelar pedido · Reembolsar |
|
||
| PROCESSING | Marcar como enviado · Cancelar pedido · Reembolsar |
|
||
| SHIPPED | Marcar como entregado · Reembolso parcial |
|
||
| DELIVERED | Reembolso parcial |
|
||
| CANCELLED | (ninguna) |
|
||
| REFUNDED | (ninguna) |
|
||
| PARTIALLY_REFUNDED| (ninguna) |
|
||
|
||
### UX para transición
|
||
|
||
1. Dropdown o botones con las acciones válidas
|
||
2. Al hacer click en acción → Dialog de confirmación:
|
||
```
|
||
┌────────────────────────────────────────┐
|
||
│ Cambiar estado del pedido │
|
||
│ │
|
||
│ ¿Marcar este pedido como PAGADO? │
|
||
│ │
|
||
│ Estado actual: ● Pendiente │
|
||
│ Nuevo estado: ● Pagado │
|
||
│ │
|
||
│ [Cancelar] [Confirmar] │
|
||
└────────────────────────────────────────┘
|
||
```
|
||
3. Para Cancelar y Refund: campo obligatorio de "Motivo"
|
||
4. Submit → esperar respuesta → refresh del detalle
|
||
|
||
### Cancellation UX
|
||
|
||
```
|
||
┌────────────────────────────────────────┐
|
||
│ ⚠️ Cancelar pedido │
|
||
│ │
|
||
│ ¿Estás seguro de cancelar el pedido │
|
||
│ #abc-123-def? │
|
||
│ │
|
||
│ Motivo * │
|
||
│ ┌────────────────────────────────────┐│
|
||
│ │ Cliente solicitó cancelación ││
|
||
│ └────────────────────────────────────┘│
|
||
│ │
|
||
│ [Volver] [Cancelar pedido] │
|
||
└────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Acceptance Criteria
|
||
|
||
### ADM-013 — Order List
|
||
- [ ] Órdenes listadas con paginación (20 por página)
|
||
- [ ] Filtro por estado funcional
|
||
- [ ] Búsqueda por email/ID funcional
|
||
- [ ] Link a detalle
|
||
- [ ] Empty state si no hay pedidos
|
||
- [ ] Loading skeleton
|
||
|
||
### ADM-014 — Order Detail
|
||
- [ ] Resumen con todos los totales
|
||
- [ ] Lista de productos con precios
|
||
- [ ] Información de cliente
|
||
- [ ] Línea de tiempo con historial de estados
|
||
- [ ] Transacciones de pago visibles
|
||
- [ ] Estado actual con badge de color + texto
|
||
|
||
### ADM-015 — State Transitions
|
||
- [ ] Solo acciones válidas visibles según estado actual
|
||
- [ ] Confirmación antes de ejecutar
|
||
- [ ] Campo "Motivo" obligatorio para Cancelar y Refund
|
||
- [ ] Refresh del detalle post-transición
|
||
- [ ] Timeline actualizada
|
||
- [ ] Toast de éxito/error
|
||
|
||
---
|
||
|
||
## 5. Tests
|
||
|
||
### Unit
|
||
- State machine: verify only valid transitions shown
|
||
- Transition formatter: state → label + color
|
||
|
||
### Component
|
||
- OrderStatusBadge renders correct color for each state
|
||
- TransitionDialog shows only valid actions
|
||
- OrderTimeline renders in correct order
|
||
|
||
### Integration
|
||
- Transition PENDING → PAID → PROCESSING → SHIPPED → DELIVERED
|
||
- Attempt invalid transition → backend error shown
|
||
|
||
### E2E
|
||
- Filter orders by status
|
||
- View order detail
|
||
- Transition order through valid states
|
||
- Cancel order with reason
|
||
- Error when backend rejects transition
|