# US-MGN-007-005-001: Crear Devolución de Cliente

**RF Asociado:** [RF-MGN-007-004](../../02-modelado/requerimientos-funcionales/mgn-007/RF-MGN-007-004-entregas-de-ventas.md)
**Módulo:** MGN-007 - Ventas Básico
**Epic:** Devoluciones de Ventas
**Prioridad:** P1
**Story Points:** 3
**Sprint:** Sprint 17
**Estado:** Ready for Development
**Fecha:** 2025-11-24

---

## User Story

**Como** usuario de ventas,
**Quiero** registrar devoluciones de productos por clientes,
**Para** gestionar productos defectuosos o cambios solicitados por el cliente.

---

## Descripción Detallada

Una Devolución (Return) es el proceso inverso a una delivery: productos regresan del cliente al almacén.

Se puede crear desde:
1. Una delivery existente (reversa parcial o total)
2. Manualmente (sin delivery origen)

Flujo:
- Cliente solicita devolución
- Se crea return order en draft
- Especifica productos y cantidades a devolver
- Motivo de devolución (defectuoso, cambio, error de envío)
- Al validar: crea movimientos de stock (cliente → almacén)

Estados: draft, confirmed, done, cancelled.

---

## Criterios de Aceptación

### Escenario 1: Crear devolución desde delivery (Camino Feliz)
**Dado que** delivery DO/2024/0001 está done con product_id=1, qty=50,
**Cuando** creo return desde delivery especificando qty_return=10, reason="Defectuoso",
**Entonces** sistema crea return RET/2024/0001 en draft con línea: product_id=1, qty=10, vinculado a delivery.

### Escenario 2: Validar cantidades a devolver <= cantidades entregadas
**Dado que** delivery tiene qty_delivered=50,
**Cuando** intento crear return con qty_return=100,
**Entonces** sistema retorna error 400 "No se pueden devolver más unidades de las entregadas".

### Escenario 3: Crear devolución manual (sin delivery origen)
**Dado que** cliente devuelve producto sin referencia a delivery,
**Cuando** creo return manual con customer_id=1, product_id=5, qty=3,
**Entonces** sistema crea return sin delivery_id vinculado.

### Escenario 4: Motivo de devolución obligatorio
**Dado que** intento crear return sin especificar reason,
**Cuando** envío request,
**Entonces** sistema retorna error 400 "El motivo de devolución es obligatorio".

### Escenario 5: Generar número secuencial
**Dado que** última return fue RET/2024/0005,
**Cuando** creo nueva return,
**Entonces** sistema genera número RET/2024/0006.

### Escenario 6: Vincular return a SO si proviene de delivery
**Dado que** return se crea desde delivery vinculada a SO id=1,
**Cuando** se crea return,
**Entonces** return.order_id=1.

---

## Reglas de Negocio

- **RN-1:** Return se crea en estado draft.
- **RN-2:** qty_return <= qty_delivered por producto.
- **RN-3:** Motivo de devolución es obligatorio (enum: defective, wrong_item, customer_request, other).
- **RN-4:** Número secuencial: RET/{year}/{seq:04d}.
- **RN-5:** Ubicación origen: cliente, destino: almacén.
- **RN-6:** Si proviene de delivery, se vincula delivery_id.
- **RN-7:** Permisos: sales_user.

---

## Tareas Técnicas

### Backend
- [ ] Endpoint: `POST /api/v1/sales/returns`
- [ ] Endpoint: `POST /api/v1/inventory/deliveries/:id/create-return`
- [ ] Service: `ReturnService.create(createReturnDto)`
- [ ] Service: `DeliveryService.createReturn(deliveryId, returnDto)`
- [ ] DTO: `CreateReturnDto` (customer_id, lines, reason, delivery_id?)
- [ ] DTO: `ReturnLineDto` (product_id, quantity, reason)
- [ ] Validar qty_return <= qty_delivered
- [ ] Validar reason no vacío
- [ ] Generar número secuencial RET
- [ ] Vincular delivery_id y order_id si aplica
- [ ] Crear mensaje en chatter
- [ ] Unit tests (>80%)
- [ ] Integration tests
- [ ] Swagger docs

### Frontend
- [ ] Botón: "Create Return" en vista de delivery done
- [ ] Formulario: CreateReturnForm.tsx
- [ ] Selector de productos/cantidades a devolver
- [ ] Dropdown: Motivo de devolución
- [ ] Validación: qty <= qty_delivered
- [ ] API client: `returnApi.create(data)`
- [ ] Notificación toast de éxito
- [ ] Component tests
- [ ] E2E test: "should create return from delivery"

### Database
- [ ] Tabla: `sales.returns` (id, customer_id, delivery_id, order_id, number, state, reason, date)
- [ ] Tabla: `sales.return_lines` (id, return_id, product_id, quantity)
- [ ] FK: `sales.returns.delivery_id → inventory.deliveries.id`
- [ ] Enum: return_reason (defective, wrong_item, customer_request, other)
- [ ] Índices: idx_returns_delivery_id, idx_returns_customer_id
- [ ] RLS policy: company_isolation_returns

---

## Mockups / Wireframes

**Formulario Crear Devolución:**
```
┌─────────────────────────────────────────────┐
│ Crear Devolución desde DO/2024/0001         │
├─────────────────────────────────────────────┤
│ Cliente: ABC Corp                           │
│ Referencia: SO/2024/0001                    │
│                                             │
│ Productos a devolver:                       │
│ ┌───────────────────────────────────────┐   │
│ │Producto  │Entregado│A devolver│Motivo │  │
│ ├──────────┼─────────┼──────────┼───────┤  │
│ │Laptop HP │  50     │[10]      │[▼]    │  │
│ └───────────────────────────────────────┘   │
│                                             │
│ Motivo general: [▼ Producto defectuoso]     │
│                                             │
│ Notas: [Opcional]                           │
│                                             │
│ [Crear Devolución] [Cancelar]               │
└─────────────────────────────────────────────┘
```

---

## Casos de Prueba

### Funcionales
1. **TC-001:** Crear return desde delivery exitosamente
2. **TC-002:** Crear return manual exitosamente
3. **TC-003:** Error si qty_return > qty_delivered
4. **TC-004:** Error si reason vacío
5. **TC-005:** Número secuencial generado correctamente
6. **TC-006:** delivery_id y order_id vinculados correctamente
7. **TC-007:** Mensaje creado en chatter

### No Funcionales
1. **Performance:** < 300ms para crear return
2. **Seguridad:** JWT + permiso sales_user

---

## Dependencias

- **US bloqueantes:**
  - US-MGN-007-003-002 (Validar Entrega)
- **Módulos requeridos:** MGN-005 (Inventario)

---

## Notas de Implementación

- Frontend: Mostrar lista de deliveries done del cliente para facilitar selección
- Validar que productos de la devolución coincidan con productos entregados
- Considerar campo `expected_date` para cuando se espera la devolución
- Stock se actualiza al validar return, no al crear

---

## Estimación Detallada

| Tarea | Horas |
|-------|-------|
| Backend | 1.5 |
| Frontend | 1.5 |
| Testing | 1 |
| Code Review | 0.5 |
| **TOTAL** | **4.5 horas = 3 SP** |

---

## Definition of Done

- [ ] Código implementado según ET
- [ ] Tests pasando (>80%)
- [ ] Code review aprobado
- [ ] Return se crea correctamente
- [ ] Validaciones aplicadas
- [ ] Número secuencial generado
- [ ] Vinculación a delivery/SO correcta
- [ ] Mensaje en chatter creado
- [ ] Swagger docs actualizado
- [ ] QA validado
- [ ] PO aprobado

---

## Referencias

- [RF-MGN-007-004](../../02-modelado/requerimientos-funcionales/mgn-007/RF-MGN-007-004-entregas-de-ventas.md)
- [ET Backend](../../02-modelado/especificaciones-tecnicas/backend/mgn-007/ET-BACKEND-MGN-007-004-entregas.md)
- [ET Frontend](../../02-modelado/especificaciones-tecnicas/frontend/mgn-007/ET-FRONTEND-MGN-007-004-entregas.md)
- [Traceability](../../02-modelado/trazabilidad/TRACEABILITY-MGN-007.yaml)
- [Schema](../../02-modelado/database-design/schemas/sales-schema-ddl.sql)
