# 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)