# US-MGN-005-003-002: Validar Movimiento de Stock

**RF Asociado:** [RF-MGN-005-003](../../02-modelado/requerimientos-funcionales/mgn-005/RF-MGN-005-003-movimientos-de-stock.md)
**Módulo:** MGN-005 - Inventario Básico
**Epic:** Movimientos de Stock
**Prioridad:** P0
**Story Points:** 5
**Sprint:** Sprint 10
**Estado:** Ready for Development
**Fecha:** 2025-11-24

---

## User Story

**Como** usuario de inventario,
**Quiero** validar movimientos de stock en estado draft,
**Para** actualizar las cantidades de stock en las ubicaciones origen y destino (quants).

---

## Descripción Detallada

Validar un movimiento cambia su estado de draft → done y ejecuta la lógica de actualización de stock:
1. Resta cantidad de stock_quants en location_from
2. Suma cantidad de stock_quants en location_to
3. Actualiza state=done y fecha de validación
4. Registra trazabilidad del movimiento

Si no hay stock suficiente en origin, el sistema puede permitir stock negativo (configurable) o rechazar el movimiento.

---

## Criterios de Aceptación

### Escenario 1: Validar movimiento con stock suficiente (Camino Feliz)
**Dado que** tengo movimiento en draft: product=1, from=Zona A (stock=10), to=Zona B, qty=5,
**Cuando** valido el movimiento,
**Entonces** el sistema actualiza: Zona A stock=5, Zona B stock=5, state=done.

### Escenario 2: Validar movimiento sin stock (permitir negativo)
**Dado que** ubicación origen tiene stock=3 y movimiento requiere qty=5,
**Cuando** valido y allow_negative_stock=true,
**Entonces** el sistema actualiza: origen stock=-2, destino stock=5, state=done.

### Escenario 3: Error al validar sin stock (no permitir negativo)
**Dado que** ubicación origen tiene stock=3 y movimiento requiere qty=5,
**Cuando** valido y allow_negative_stock=false,
**Entonces** el sistema retorna error 400 "Stock insuficiente en ubicación origen".

### Escenario 4: Error al validar movimiento ya validado
**Dado que** movimiento está en state=done,
**Cuando** intento validar nuevamente,
**Entonces** el sistema retorna error 400 "Movimiento ya fue validado".

### Escenario 5: Error al validar movimiento cancelado
**Dado que** movimiento está en state=cancelled,
**Cuando** intento validar,
**Entonces** el sistema retorna error 400 "No se puede validar un movimiento cancelado".

---

## Reglas de Negocio

- **RN-1:** Solo movimientos en state=draft pueden validarse.
- **RN-2:** Validar actualiza stock_quants (resta origen, suma destino).
- **RN-3:** Stock negativo permitido según configuración de empresa.
- **RN-4:** Movimiento validado no puede modificarse.
- **RN-5:** Validación registra fecha y usuario que valida.
- **RN-6:** Si producto tiene tracking (lot/serial), se requiere especificar lote.

---

## Tareas Técnicas

### Backend
- [ ] Endpoint: POST /api/v1/inventory/stock-moves/:id/validate
- [ ] Service: StockMoveService.validate(moveId)
- [ ] Service: StockMoveService.updateQuants(move)
- [ ] Service: QuantService.updateQuantity(productId, locationId, quantityDelta)
- [ ] Validar movimiento en state=draft
- [ ] Verificar stock disponible
- [ ] Actualizar quants (origen y destino)
- [ ] Actualizar state y fecha
- [ ] Transaction para atomicidad
- [ ] Unit tests (>80% coverage)
- [ ] Integration tests
- [ ] Swagger docs

### Frontend
- [ ] Componente: ValidateStockMoveButton.tsx
- [ ] Modal de confirmación con resumen
- [ ] Mostrar stock actual antes/después
- [ ] API client: stockMoveApi.validate(id)
- [ ] Actualizar lista de movimientos tras validar
- [ ] Component tests
- [ ] E2E test: "should validate stock move and update stock"

### Database
- [ ] Tabla: inventory.stock_quants (actualización)
- [ ] Índices: idx_stock_quants_product_location
- [ ] Transaction isolation level: READ COMMITTED

---

## Mockups / Wireframes

**Modal Validar Movimiento:**
```
┌─────────────────────────────────────────────┐
│ Validar Movimiento de Stock                │
├─────────────────────────────────────────────┤
│ Producto: Laptop HP                        │
│ Cantidad: 5 unidades                       │
│                                             │
│ Ubicación Origen: Zona A                   │
│ Stock Actual: 10 → Nuevo: 5               │
│                                             │
│ Ubicación Destino: Zona B                 │
│ Stock Actual: 3 → Nuevo: 8                │
│                                             │
│ ⚠ Esta acción no puede deshacerse.        │
├─────────────────────────────────────────────┤
│ [Validar]  [Cancelar]                      │
└─────────────────────────────────────────────┘
```

---

## Casos de Prueba

### Funcionales
1. **TC-001:** Validar movimiento con stock suficiente
2. **TC-002:** Validar movimiento con stock negativo (permitido)
3. **TC-003:** Error por stock insuficiente (no permitido)
4. **TC-004:** Error por movimiento ya validado
5. **TC-005:** Error por movimiento cancelado
6. **TC-006:** Transaction rollback en caso de error
7. **TC-007:** RLS filtra por empresa

### No Funcionales
1. **Performance:** < 500ms para validar movimiento
2. **Seguridad:** JWT + permiso inventory_validate

---

## Dependencias

- **US bloqueantes:** US-MGN-005-003-001 (Crear Movimiento Stock)
- **Módulos requeridos:** MGN-001, MGN-002
- **Datos maestros:** Stock quants

---

## Notas de Implementación

- Usar transaction para garantizar atomicidad de actualización de quants
- Si quant no existe, crear con quantity (INSERT)
- Si quant existe, actualizar quantity (UPDATE)
- Considerar bloqueo pesimista (SELECT FOR UPDATE) en quants para evitar condiciones de carrera
- Frontend: Polling o WebSocket para refresh automático de stock

---

## Estimación Detallada

| Tarea | Horas |
|-------|-------|
| Backend | 3 |
| Frontend | 2 |
| Testing | 2 |
| Code Review | 1 |
| **TOTAL** | **8 horas = 5 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

---

## Referencias

- [RF-MGN-005-003](../../02-modelado/requerimientos-funcionales/mgn-005/RF-MGN-005-003-movimientos-de-stock.md)
- [ET Backend](../../02-modelado/especificaciones-tecnicas/backend/mgn-005/ET-BACKEND-MGN-005-003-movimientos-de-stock.md)
- [ET Frontend](../../02-modelado/especificaciones-tecnicas/frontend/mgn-005/ET-FRONTEND-MGN-005-003-movimientos-de-stock.md)
- [Traceability](../../02-modelado/trazabilidad/TRACEABILITY-MGN-005.yaml)
- [Schema](../../02-modelado/database-design/schemas/inventory-schema-ddl.sql)
