feat(ADM-018): completed feature

This commit is contained in:
chattie
2026-08-17 22:23:10 +02:00
parent cf1c69fc8b
commit d595b4871f
871 changed files with 47411 additions and 281 deletions

View File

@@ -0,0 +1,295 @@
# 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