# 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