7.9 KiB
US-MGN-007-005-001: Crear Devolución de Cliente
RF Asociado: RF-MGN-007-004 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:
- Una delivery existente (reversa parcial o total)
- 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
- TC-001: Crear return desde delivery exitosamente
- TC-002: Crear return manual exitosamente
- TC-003: Error si qty_return > qty_delivered
- TC-004: Error si reason vacío
- TC-005: Número secuencial generado correctamente
- TC-006: delivery_id y order_id vinculados correctamente
- TC-007: Mensaje creado en chatter
No Funcionales
- Performance: < 300ms para crear return
- 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_datepara 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