# US-MGN-007-002-003: Cancelar Sales Order

**RF Asociado:** [RF-MGN-007-003](../../02-modelado/requerimientos-funcionales/mgn-007/RF-MGN-007-003-gestión-de-órdenes-de-venta.md)
**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
1. **TC-001:** Cancelar SO draft exitosamente
2. **TC-002:** Cancelar SO confirmed exitosamente
3. **TC-003:** Error al cancelar SO done
4. **TC-004:** Error al cancelar SO con entregas validadas
5. **TC-005:** Error al cancelar SO con facturas
6. **TC-006:** Error si reason está vacío
7. **TC-007:** Entregas pendientes se cancelan automáticamente
8. **TC-008:** date_cancelled y reason se registran correctamente
9. **TC-009:** Mensaje se crea en chatter con reason

### No Funcionales
1. **Performance:** < 500ms para cancelar orden
2. **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_id` para 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

---

## Referencias

- [RF-MGN-007-003](../../02-modelado/requerimientos-funcionales/mgn-007/RF-MGN-007-003-gestión-de-órdenes-de-venta.md)
- [ET Backend](../../02-modelado/especificaciones-tecnicas/backend/mgn-007/ET-BACKEND-MGN-007-003-ordenes-venta.md)
- [ET Frontend](../../02-modelado/especificaciones-tecnicas/frontend/mgn-007/ET-FRONTEND-MGN-007-003-ordenes-venta.md)
- [Traceability](../../02-modelado/trazabilidad/TRACEABILITY-MGN-007.yaml)
- [Schema](../../02-modelado/database-design/schemas/sales-schema-ddl.sql)
