6.2 KiB
US-MGN-005-003-003: Cancelar Movimiento de Stock
RF Asociado: RF-MGN-005-003 Módulo: MGN-005 - Inventario Básico Epic: Movimientos de Stock Prioridad: P0 Story Points: 3 Sprint: Sprint 10 Estado: Ready for Development Fecha: 2025-11-24
User Story
Como usuario de inventario, Quiero cancelar movimientos de stock en estado draft o done, Para revertir movimientos erróneos y mantener la integridad del stock.
Descripción Detallada
Cancelar un movimiento cambia su estado a cancelled. El comportamiento depende del estado actual:
- draft: Solo cambia estado a cancelled (no hay reversión de stock)
- done: Revierte el stock (suma a origen, resta a destino) y cambia estado
Los movimientos cancelados no pueden volver a validarse ni editarse.
Criterios de Aceptación
Escenario 1: Cancelar movimiento draft (Camino Feliz)
Dado que tengo movimiento en state=draft, Cuando cancelo el movimiento, Entonces el sistema cambia state=cancelled sin afectar stock.
Escenario 2: Cancelar movimiento done (revertir stock)
Dado que tengo movimiento done: product=1, from=Zona A (stock=5), to=Zona B (stock=8), qty=5, Cuando cancelo el movimiento, Entonces el sistema revierte: Zona A stock=10, Zona B stock=3, state=cancelled.
Escenario 3: Error al cancelar movimiento ya cancelado
Dado que movimiento está en state=cancelled, Cuando intento cancelar nuevamente, Entonces el sistema retorna error 400 "Movimiento ya fue cancelado".
Escenario 4: Registrar motivo de cancelación
Dado que cancelo movimiento con reason="Error en cantidad", Cuando envío el request, Entonces el sistema guarda el motivo y fecha de cancelación.
Reglas de Negocio
- RN-1: Movimientos draft y done pueden cancelarse.
- RN-2: Movimientos cancelled no pueden cancelarse nuevamente.
- RN-3: Cancelar movimiento done revierte stock (operación inversa).
- RN-4: Cancelar movimiento draft no afecta stock.
- RN-5: Cancelación registra fecha, usuario y motivo.
- RN-6: Movimientos cancelados no pueden reactivarse.
Tareas Técnicas
Backend
- Endpoint: POST /api/v1/inventory/stock-moves/:id/cancel
- Service: StockMoveService.cancel(moveId, reason)
- Service: StockMoveService.reverseQuants(move)
- Validar movimiento no está cancelado
- Si done: revertir quants (suma origen, resta destino)
- Si draft: solo cambiar estado
- Registrar fecha, usuario, motivo
- Transaction para atomicidad
- Unit tests (>80% coverage)
- Integration tests
- Swagger docs
Frontend
- Componente: CancelStockMoveButton.tsx
- Modal de confirmación con campo motivo
- Mostrar impacto en stock (si done)
- API client: stockMoveApi.cancel(id, reason)
- Component tests
- E2E test: "should cancel stock move"
Database
- Tabla: inventory.stock_moves (campos: cancelled_date, cancelled_by, cancel_reason)
- Transaction isolation level: READ COMMITTED
Mockups / Wireframes
Modal Cancelar Movimiento:
┌─────────────────────────────────────────────┐
│ Cancelar Movimiento de Stock │
├─────────────────────────────────────────────┤
│ Movimiento: #SM-00123 │
│ Estado Actual: Done │
│ │
│ ⚠ Cancelar revertirá los cambios de stock:│
│ Zona A: 5 → 10 (+5) │
│ Zona B: 8 → 3 (-5) │
│ │
│ Motivo de Cancelación: * │
│ [TextArea: Error en cantidad registrada] │
│ │
│ ⚠ Esta acción no puede deshacerse. │
├─────────────────────────────────────────────┤
│ [Cancelar Movimiento] [Volver] │
└─────────────────────────────────────────────┘
Casos de Prueba
Funcionales
- TC-001: Cancelar movimiento draft exitosamente
- TC-002: Cancelar movimiento done y revertir stock
- TC-003: Error por movimiento ya cancelado
- TC-004: Registrar motivo de cancelación
- TC-005: Transaction rollback en caso de error
- TC-006: RLS filtra por empresa
No Funcionales
- Performance: < 500ms para cancelar movimiento
- Seguridad: JWT + permiso inventory_validate
Dependencias
- US bloqueantes: US-MGN-005-003-002 (Validar Movimiento Stock)
- Módulos requeridos: MGN-001, MGN-002
- Datos maestros: Ninguno
Notas de Implementación
- Usar transaction para garantizar atomicidad
- Reversión = operación inversa de validación
- Considerar agregar audit trail de cancelaciones
- Frontend: Deshabilitar botón cancelar si ya está cancelado
Estimación Detallada
| Tarea | Horas |
|---|---|
| Backend | 2 |
| Frontend | 1.5 |
| Testing | 1 |
| Code Review | 0.5 |
| TOTAL | 5 horas = 3 SP |
Definition of Done
- Código implementado según ET
- Tests pasando (>80%)
- Code review aprobado
- Documentación actualizada
- Swagger docs completo
- Transaction correctamente implementada
- RLS aplicado
- QA validado
- PO aprobado