7.5 KiB
US-MGN-007-002-003: Cancelar Sales Order
RF Asociado: RF-MGN-007-003 Módulo: MGN-007 - Ventas Básico Epic: Órdenes de Venta Prioridad: P1 Story Points: 3 Sprint: Sprint 16 Estado: Ready for Development Fecha: 2025-11-24
User Story
Como vendedor o gerente de ventas, Quiero cancelar una orden de venta, Para anular ventas que no se completarán y liberar recursos reservados.
Descripción Detallada
Cancelar una SO significa:
- Cambiar estado a cancelled
- Registrar fecha de cancelación (date_cancelled)
- Registrar motivo de cancelación (cancellation_reason)
- Liberar reservas de stock si las hay
- Cancelar entregas pendientes asociadas
- Notificar a stakeholders
- Crear mensaje en chatter con motivo
SO canceladas no pueden reactivarse (son inmutables).
Criterios de Aceptación
Escenario 1: Cancelar SO draft o confirmed (Camino Feliz)
Dado que SO id=1 está en estado draft, Cuando ejecuto action "Cancel" con reason="Cliente canceló pedido", Entonces sistema cambia estado a cancelled, registra date_cancelled y reason.
Escenario 2: Validar que SO no está done
Dado que SO está en estado done (completamente facturada y entregada), Cuando intento cancelar, Entonces sistema retorna error 400 "No se puede cancelar orden completada".
Escenario 3: Validar que SO no tiene entregas validadas
Dado que SO tiene entregas en estado done, Cuando intento cancelar, Entonces sistema retorna error 400 "No se puede cancelar orden con entregas validadas".
Escenario 4: Validar que SO no tiene facturas
Dado que SO tiene facturas emitidas, Cuando intento cancelar, Entonces sistema retorna error 400 "No se puede cancelar orden facturada".
Escenario 5: Cancelar entregas pendientes automáticamente
Dado que SO tiene 2 entregas en estado draft, Cuando cancelo SO, Entonces sistema cancela automáticamente las 2 entregas pendientes.
Escenario 6: Motivo de cancelación obligatorio
Dado que intento cancelar SO sin proporcionar reason, Cuando envío request, Entonces sistema retorna error 400 "El motivo de cancelación es obligatorio".
Reglas de Negocio
- RN-1: Solo SO en draft o confirmed pueden cancelarse.
- RN-2: SO con entregas validadas (state=done) no pueden cancelarse.
- RN-3: SO con facturas no pueden cancelarse (deben hacerse notas de crédito).
- RN-4: Motivo de cancelación es obligatorio.
- RN-5: Entregas pendientes (draft) se cancelan automáticamente.
- RN-6: Reservas de stock se liberan automáticamente.
- RN-7: SO canceladas no pueden reactivarse.
- RN-8: Permisos: sales_user puede cancelar sus órdenes draft, sales_manager puede cancelar cualquiera.
Tareas Técnicas
Backend
- Endpoint:
POST /api/v1/sales/orders/:id/cancel - Service:
SalesOrderService.cancel(id, cancelDto) - DTO:
CancelSalesOrderDto(reason: string) - Validar estado (draft o confirmed)
- Validar que no tiene entregas validadas
- Validar que no tiene facturas
- Validar reason no vacío
- Actualizar state=cancelled, date_cancelled=now()
- Cancelar entregas pendientes asociadas
- Liberar reservas de stock (si aplica)
- Crear mensaje en chatter con reason
- Unit tests (>80%)
- Integration tests
- Swagger docs
Frontend
- Botón: "Cancel" en vista de SO
- Modal: Solicitar motivo de cancelación (textarea)
- Validación: Motivo mínimo 10 caracteres
- Mostrar warnings si hay entregas pendientes
- API client:
salesOrderApi.cancel(id, {reason}) - Notificación toast de éxito
- Component tests
- E2E test: "should cancel sales order"
Database
- Columna:
sales.orders.date_cancelled(timestamp) - Columna:
sales.orders.cancellation_reason(text) - Índice:
idx_orders_date_cancelled
Mockups / Wireframes
Modal Cancelar SO:
┌─────────────────────────────────────────────┐
│ Cancelar Orden SO/2024/0001 │
├─────────────────────────────────────────────┤
│ ⚠ Esta acción no puede deshacerse │
│ │
│ Motivo de cancelación: * │
│ ┌─────────────────────────────────────────┐ │
│ │ Cliente canceló pedido por... │ │
│ │ │ │
│ └─────────────────────────────────────────┘ │
│ │
│ Impactos: │
│ • 2 entregas pendientes serán canceladas │
│ • Reservas de stock serán liberadas │
│ │
│ [Confirmar Cancelación] [Cerrar] │
└─────────────────────────────────────────────┘
Casos de Prueba
Funcionales
- TC-001: Cancelar SO draft exitosamente
- TC-002: Cancelar SO confirmed exitosamente
- TC-003: Error al cancelar SO done
- TC-004: Error al cancelar SO con entregas validadas
- TC-005: Error al cancelar SO con facturas
- TC-006: Error si reason está vacío
- TC-007: Entregas pendientes se cancelan automáticamente
- TC-008: date_cancelled y reason se registran correctamente
- TC-009: Mensaje se crea en chatter con reason
No Funcionales
- Performance: < 500ms para cancelar orden
- Seguridad: JWT + permiso sales_user (own) o sales_manager (all)
Dependencias
- US bloqueantes:
- US-MGN-007-002-002 (Confirmar SO)
- Módulos requeridos: MGN-007 (Entregas)
Notas de Implementación
- Usar transacción para cancelar SO + entregas pendientes atómicamente
- Validar permisos: sales_user solo puede cancelar sus propias órdenes draft
- Considerar agregar campo
cancelled_by_user_idpara auditoría - Frontend: Deshabilitar botón de cancelación si hay entregas validadas
Estimación Detallada
| Tarea | Horas |
|---|---|
| Backend | 1.5 |
| Frontend | 1 |
| Testing | 1 |
| Code Review | 0.5 |
| TOTAL | 4 horas = 3 SP |
Definition of Done
- Código implementado según ET
- Tests pasando (>80%)
- Code review aprobado
- Cancelación funciona correctamente
- Validaciones aplicadas
- Entregas pendientes canceladas
- date_cancelled y reason registrados
- Mensaje en chatter creado
- Swagger docs actualizado
- QA validado
- PO aprobado