# TRACEABILITY-MGN-005.yaml # Matriz de Trazabilidad - MGN-005: Inventario Básico # Fecha: 2025-11-24 # Versión: 1.0 module: id: MGN-005 name: "Inventario Básico" description: "Productos, almacenes, movimientos de stock, pickings, trazabilidad y valoración" priority: P0 story_points: 66 status: Diseñado metadata: total_rf: 7 total_et_backend: 7 total_et_frontend: 7 total_tables: 10 total_tests: 140 coverage: 100% requirements: - rf_id: RF-MGN-005-001 rf_title: "Gestión de Productos" rf_file: "requerimientos-funcionales/mgn-005/RF-MGN-005-001-gestión-de-productos.md" priority: P0 story_points: 8 et_backend: file: "especificaciones-tecnicas/backend/mgn-005/ET-BACKEND-MGN-005-001-gestión-de-productos.md" endpoints: - method: POST path: /api/v1/inventory/products description: "Crear producto" - method: GET path: /api/v1/inventory/products description: "Listar productos" - method: GET path: /api/v1/inventory/products/:id description: "Obtener producto por ID" - method: PUT path: /api/v1/inventory/products/:id description: "Actualizar producto" - method: DELETE path: /api/v1/inventory/products/:id description: "Desactivar producto" services: - name: "ProductService" file: "src/modules/inventory/services/product.service.ts" methods: [create, findAll, findOne, update, remove] controllers: - name: "ProductController" file: "src/modules/inventory/controllers/product.controller.ts" dtos: - name: "CreateProductDto" file: "src/modules/inventory/dto/create-product.dto.ts" - name: "UpdateProductDto" file: "src/modules/inventory/dto/update-product.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-005/ET-FRONTEND-MGN-005-001-gestión-de-productos.md" routes: - path: "/inventory/products" component: "ProductsPage" - path: "/inventory/products/create" component: "CreateProductPage" - path: "/inventory/products/:id/edit" component: "EditProductPage" - path: "/inventory/products/:id" component: "ViewProductPage" components: - name: "ProductsTable" file: "src/widgets/products-table/ui/ProductsTable.tsx" type: widget - name: "CreateProductForm" file: "src/features/create-product/ui/CreateProductForm.tsx" type: feature - name: "ProductCard" file: "src/entities/product/ui/ProductCard.tsx" type: entity api_client: - name: "productApi" file: "src/entities/product/api/product.api.ts" methods: [getAll, getById, create, update, delete] state_management: - name: "useProductStore" file: "src/entities/product/model/product.store.ts" type: zustand database_tables: - schema: inventory table: products file: "database-design/schemas/inventory-schema-ddl.sql" operations: [SELECT, INSERT, UPDATE, DELETE (soft)] indices: [idx_products_company_id, idx_products_category_id, idx_products_type] rls_policy: company_isolation_products tests: backend: unit_tests: - file: "src/modules/inventory/services/product.service.spec.ts" test_cases: - "should create product with valid data" - "should validate product type (storable, consumable, service)" - "should throw error when SKU already exists" - "should update product successfully" - "should soft delete product" integration_tests: - file: "test/inventory/product.controller.e2e-spec.ts" test_cases: - "POST /api/v1/inventory/products should create product" - "GET /api/v1/inventory/products should return all products" - "GET /api/v1/inventory/products/:id should return product" - "PUT /api/v1/inventory/products/:id should update product" - "DELETE /api/v1/inventory/products/:id should soft delete product" - "should enforce company isolation" - "should require authentication" frontend: component_tests: - file: "src/widgets/products-table/ui/ProductsTable.test.tsx" test_cases: - "should render table with products" - "should handle pagination" - "should filter by category" - file: "src/features/create-product/ui/CreateProductForm.test.tsx" test_cases: - "should validate required fields" - "should validate SKU format" - "should submit valid form" e2e_tests: - file: "e2e/inventory/products.spec.ts" test_cases: - "should create product successfully" - "should edit product successfully" - "should delete product with confirmation" acceptance_criteria: - id: AC-001 description: "Usuario puede crear productos con SKU, nombre, tipo (storable, consumable, service)" status: Pending test_reference: "test/inventory/product.controller.e2e-spec.ts:28" - id: AC-002 description: "SKU es único por empresa" status: Pending test_reference: "src/modules/inventory/services/product.service.spec.ts:65" - id: AC-003 description: "Productos tienen categoría, UoM y cuentas contables" status: Pending test_reference: "test/inventory/product.controller.e2e-spec.ts:95" business_rules: - id: RN-001 description: "SKU único por empresa" implementation: "database-design/schemas/inventory-schema-ddl.sql:CONSTRAINT uq_products_sku_company" test_reference: "src/modules/inventory/services/product.service.spec.ts:48" - id: RN-002 description: "Productos tienen tipos: storable, consumable, service" implementation: "database-design/schemas/inventory-schema-ddl.sql:products.type" test_reference: "src/modules/inventory/services/product.service.spec.ts:78" - id: RN-003 description: "Solo productos storable tienen stock" implementation: "src/modules/inventory/services/product.service.ts:validateType()" test_reference: "src/modules/inventory/services/product.service.spec.ts:108" dependencies: rf_dependencies: [RF-MGN-003-004, RF-MGN-003-005] module_dependencies: [MGN-003] external_dependencies: [] - rf_id: RF-MGN-005-002 rf_title: "Gestión de Almacenes y Ubicaciones" rf_file: "requerimientos-funcionales/mgn-005/RF-MGN-005-002-gestión-de-almacenes-y-ubicaciones.md" priority: P0 story_points: 8 et_backend: file: "especificaciones-tecnicas/backend/mgn-005/ET-BACKEND-MGN-005-002-gestión-de-almacenes-y-ubicaciones.md" endpoints: - method: POST path: /api/v1/inventory/warehouses description: "Crear almacén" - method: GET path: /api/v1/inventory/warehouses description: "Listar almacenes" - method: GET path: /api/v1/inventory/warehouses/:id description: "Obtener almacén por ID" - method: PUT path: /api/v1/inventory/warehouses/:id description: "Actualizar almacén" - method: POST path: /api/v1/inventory/warehouses/:id/locations description: "Crear ubicación en almacén" services: - name: "WarehouseService" file: "src/modules/inventory/services/warehouse.service.ts" methods: [create, findAll, findOne, update, createLocation] controllers: - name: "WarehouseController" file: "src/modules/inventory/controllers/warehouse.controller.ts" dtos: - name: "CreateWarehouseDto" file: "src/modules/inventory/dto/create-warehouse.dto.ts" - name: "CreateLocationDto" file: "src/modules/inventory/dto/create-location.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-005/ET-FRONTEND-MGN-005-002-gestión-de-almacenes-y-ubicaciones.md" routes: - path: "/inventory/warehouses" component: "WarehousesPage" - path: "/inventory/warehouses/:id" component: "WarehouseDetailsPage" components: - name: "WarehousesTable" file: "src/widgets/warehouses-table/ui/WarehousesTable.tsx" type: widget - name: "CreateWarehouseForm" file: "src/features/create-warehouse/ui/CreateWarehouseForm.tsx" type: feature - name: "LocationTree" file: "src/widgets/location-tree/ui/LocationTree.tsx" type: widget api_client: - name: "warehouseApi" file: "src/entities/warehouse/api/warehouse.api.ts" methods: [getAll, getById, create, update, createLocation] state_management: - name: "useWarehouseStore" file: "src/entities/warehouse/model/warehouse.store.ts" type: zustand database_tables: - schema: inventory table: warehouses file: "database-design/schemas/inventory-schema-ddl.sql" operations: [SELECT, INSERT, UPDATE] indices: [idx_warehouses_company_id] rls_policy: company_isolation_warehouses - schema: inventory table: locations file: "database-design/schemas/inventory-schema-ddl.sql" operations: [SELECT, INSERT, UPDATE] indices: [idx_locations_warehouse_id, idx_locations_parent_id] rls_policy: company_isolation_locations tests: backend: unit_tests: - file: "src/modules/inventory/services/warehouse.service.spec.ts" test_cases: - "should create warehouse" - "should create location in warehouse" - "should create hierarchical locations" - "should validate location belongs to warehouse" - "should update warehouse" integration_tests: - file: "test/inventory/warehouse.controller.e2e-spec.ts" test_cases: - "POST /api/v1/inventory/warehouses should create warehouse" - "GET /api/v1/inventory/warehouses should return all warehouses" - "POST /api/v1/inventory/warehouses/:id/locations should create location" - "should enforce company isolation" - "should require authentication" frontend: component_tests: - file: "src/widgets/warehouses-table/ui/WarehousesTable.test.tsx" test_cases: - "should render table with warehouses" - file: "src/widgets/location-tree/ui/LocationTree.test.tsx" test_cases: - "should render location tree" - "should expand/collapse nodes" e2e_tests: - file: "e2e/inventory/warehouses.spec.ts" test_cases: - "should create warehouse successfully" - "should create location in warehouse" - "should show location hierarchy" acceptance_criteria: - id: AC-001 description: "Usuario puede crear almacenes con ubicaciones jerárquicas" status: Pending test_reference: "test/inventory/warehouse.controller.e2e-spec.ts:28" - id: AC-002 description: "Ubicaciones soportan jerarquía (zona → pasillo → anaquel)" status: Pending test_reference: "src/modules/inventory/services/warehouse.service.spec.ts:65" - id: AC-003 description: "Stock se almacena por ubicación" status: Pending test_reference: "test/inventory/warehouse.controller.e2e-spec.ts:95" business_rules: - id: RN-001 description: "Almacenes pertenecen a una empresa" implementation: "database-design/schemas/inventory-schema-ddl.sql:warehouses.company_id" test_reference: "src/modules/inventory/services/warehouse.service.spec.ts:48" - id: RN-002 description: "Ubicaciones soportan jerarquía con parent_id" implementation: "database-design/schemas/inventory-schema-ddl.sql:locations.parent_id" test_reference: "src/modules/inventory/services/warehouse.service.spec.ts:78" - id: RN-003 description: "Stock se registra por ubicación específica" implementation: "database-design/schemas/inventory-schema-ddl.sql:stock_quants.location_id" test_reference: "src/modules/inventory/services/warehouse.service.spec.ts:108" dependencies: rf_dependencies: [RF-MGN-002-001] module_dependencies: [MGN-002] external_dependencies: [] - rf_id: RF-MGN-005-003 rf_title: "Movimientos de Stock" rf_file: "requerimientos-funcionales/mgn-005/RF-MGN-005-003-movimientos-de-stock.md" priority: P0 story_points: 13 et_backend: file: "especificaciones-tecnicas/backend/mgn-005/ET-BACKEND-MGN-005-003-movimientos-de-stock.md" endpoints: - method: POST path: /api/v1/inventory/stock-moves description: "Crear movimiento de stock" - method: GET path: /api/v1/inventory/stock-moves description: "Listar movimientos" - method: GET path: /api/v1/inventory/stock-moves/:id description: "Obtener movimiento por ID" - method: POST path: /api/v1/inventory/stock-moves/:id/validate description: "Validar movimiento (actualiza stock)" - method: POST path: /api/v1/inventory/stock-moves/:id/cancel description: "Cancelar movimiento" services: - name: "StockMoveService" file: "src/modules/inventory/services/stock-move.service.ts" methods: [create, findAll, findOne, validate, cancel, updateQuants] controllers: - name: "StockMoveController" file: "src/modules/inventory/controllers/stock-move.controller.ts" dtos: - name: "CreateStockMoveDto" file: "src/modules/inventory/dto/create-stock-move.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-005/ET-FRONTEND-MGN-005-003-movimientos-de-stock.md" routes: - path: "/inventory/stock-moves" component: "StockMovesPage" - path: "/inventory/stock-moves/:id" component: "ViewStockMovePage" components: - name: "StockMovesTable" file: "src/widgets/stock-moves-table/ui/StockMovesTable.tsx" type: widget - name: "CreateStockMoveForm" file: "src/features/create-stock-move/ui/CreateStockMoveForm.tsx" type: feature - name: "StockMoveCard" file: "src/entities/stock-move/ui/StockMoveCard.tsx" type: entity api_client: - name: "stockMoveApi" file: "src/entities/stock-move/api/stock-move.api.ts" methods: [getAll, getById, create, validate, cancel] state_management: - name: "useStockMoveStore" file: "src/entities/stock-move/model/stock-move.store.ts" type: zustand database_tables: - schema: inventory table: stock_moves file: "database-design/schemas/inventory-schema-ddl.sql" operations: [SELECT, INSERT, UPDATE] indices: [idx_stock_moves_product_id, idx_stock_moves_location_from, idx_stock_moves_location_to, idx_stock_moves_state] rls_policy: company_isolation_stock_moves - schema: inventory table: stock_quants file: "database-design/schemas/inventory-schema-ddl.sql" operations: [SELECT, INSERT, UPDATE] indices: [idx_stock_quants_product_location] rls_policy: company_isolation_stock_quants tests: backend: unit_tests: - file: "src/modules/inventory/services/stock-move.service.spec.ts" test_cases: - "should create stock move" - "should validate stock move (draft → done)" - "should update stock quants on validation" - "should cancel stock move" - "should reverse quants on cancellation" integration_tests: - file: "test/inventory/stock-move.controller.e2e-spec.ts" test_cases: - "POST /api/v1/inventory/stock-moves should create move" - "GET /api/v1/inventory/stock-moves should return all moves" - "POST /api/v1/inventory/stock-moves/:id/validate should validate move" - "POST /api/v1/inventory/stock-moves/:id/cancel should cancel move" - "should enforce company isolation" - "should require authentication" frontend: component_tests: - file: "src/widgets/stock-moves-table/ui/StockMovesTable.test.tsx" test_cases: - "should render table with moves" - "should filter by state" - file: "src/features/create-stock-move/ui/CreateStockMoveForm.test.tsx" test_cases: - "should validate required fields" - "should submit valid form" e2e_tests: - file: "e2e/inventory/stock-moves.spec.ts" test_cases: - "should create stock move successfully" - "should validate move successfully" - "should show updated stock after validation" acceptance_criteria: - id: AC-001 description: "Usuario puede crear movimientos de stock entre ubicaciones" status: Pending test_reference: "test/inventory/stock-move.controller.e2e-spec.ts:28" - id: AC-002 description: "Validar movimiento actualiza stock en ubicaciones origen y destino" status: Pending test_reference: "src/modules/inventory/services/stock-move.service.spec.ts:85" - id: AC-003 description: "Movimientos tienen estados: draft, done, cancelled" status: Pending test_reference: "test/inventory/stock-move.controller.e2e-spec.ts:105" business_rules: - id: RN-001 description: "Movimientos tienen estados: draft, done, cancelled" implementation: "database-design/schemas/inventory-schema-ddl.sql:stock_moves.state" test_reference: "src/modules/inventory/services/stock-move.service.spec.ts:58" - id: RN-002 description: "Al validar movimiento se actualizan stock_quants" implementation: "src/modules/inventory/services/stock-move.service.ts:updateQuants()" test_reference: "src/modules/inventory/services/stock-move.service.spec.ts:92" - id: RN-003 description: "Cancelar movimiento revierte cambios en quants" implementation: "src/modules/inventory/services/stock-move.service.ts:cancel()" test_reference: "src/modules/inventory/services/stock-move.service.spec.ts:118" dependencies: rf_dependencies: [RF-MGN-005-001, RF-MGN-005-002] module_dependencies: [] external_dependencies: [] - rf_id: RF-MGN-005-004 rf_title: "Pickings (Albaranes de Entrada/Salida)" rf_file: "requerimientos-funcionales/mgn-005/RF-MGN-005-004-pickings-albaranes-de-entrada-salida.md" priority: P0 story_points: 8 et_backend: file: "especificaciones-tecnicas/backend/mgn-005/ET-BACKEND-MGN-005-004-pickings-albaranes-de-entrada-salida.md" endpoints: - method: POST path: /api/v1/inventory/pickings description: "Crear picking" - method: GET path: /api/v1/inventory/pickings description: "Listar pickings" - method: GET path: /api/v1/inventory/pickings/:id description: "Obtener picking por ID" - method: POST path: /api/v1/inventory/pickings/:id/validate description: "Validar picking (genera movimientos)" - method: POST path: /api/v1/inventory/pickings/:id/cancel description: "Cancelar picking" services: - name: "PickingService" file: "src/modules/inventory/services/picking.service.ts" methods: [create, findAll, findOne, validate, cancel, generateStockMoves] controllers: - name: "PickingController" file: "src/modules/inventory/controllers/picking.controller.ts" dtos: - name: "CreatePickingDto" file: "src/modules/inventory/dto/create-picking.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-005/ET-FRONTEND-MGN-005-004-pickings-albaranes-de-entrada-salida.md" routes: - path: "/inventory/pickings" component: "PickingsPage" - path: "/inventory/pickings/create" component: "CreatePickingPage" - path: "/inventory/pickings/:id" component: "ViewPickingPage" components: - name: "PickingsTable" file: "src/widgets/pickings-table/ui/PickingsTable.tsx" type: widget - name: "CreatePickingForm" file: "src/features/create-picking/ui/CreatePickingForm.tsx" type: feature - name: "PickingCard" file: "src/entities/picking/ui/PickingCard.tsx" type: entity api_client: - name: "pickingApi" file: "src/entities/picking/api/picking.api.ts" methods: [getAll, getById, create, validate, cancel] state_management: - name: "usePickingStore" file: "src/entities/picking/model/picking.store.ts" type: zustand database_tables: - schema: inventory table: pickings file: "database-design/schemas/inventory-schema-ddl.sql" operations: [SELECT, INSERT, UPDATE] indices: [idx_pickings_picking_type_id, idx_pickings_state, idx_pickings_company_id] rls_policy: company_isolation_pickings tests: backend: unit_tests: - file: "src/modules/inventory/services/picking.service.spec.ts" test_cases: - "should create picking" - "should validate picking (generates stock moves)" - "should handle receipt (incoming) picking" - "should handle delivery (outgoing) picking" - "should cancel picking" integration_tests: - file: "test/inventory/picking.controller.e2e-spec.ts" test_cases: - "POST /api/v1/inventory/pickings should create picking" - "GET /api/v1/inventory/pickings should return all pickings" - "POST /api/v1/inventory/pickings/:id/validate should validate picking" - "POST /api/v1/inventory/pickings/:id/cancel should cancel picking" - "should enforce company isolation" - "should require authentication" frontend: component_tests: - file: "src/widgets/pickings-table/ui/PickingsTable.test.tsx" test_cases: - "should render table with pickings" - "should filter by type" - file: "src/features/create-picking/ui/CreatePickingForm.test.tsx" test_cases: - "should validate required fields" - "should submit valid form" e2e_tests: - file: "e2e/inventory/pickings.spec.ts" test_cases: - "should create picking successfully" - "should validate picking successfully" - "should show generated stock moves" acceptance_criteria: - id: AC-001 description: "Usuario puede crear pickings de entrada (recepciones)" status: Pending test_reference: "test/inventory/picking.controller.e2e-spec.ts:28" - id: AC-002 description: "Usuario puede crear pickings de salida (entregas)" status: Pending test_reference: "test/inventory/picking.controller.e2e-spec.ts:58" - id: AC-003 description: "Validar picking genera movimientos de stock automáticamente" status: Pending test_reference: "src/modules/inventory/services/picking.service.spec.ts:85" business_rules: - id: RN-001 description: "Pickings tienen tipos: incoming (recepción), outgoing (entrega), internal (transferencia)" implementation: "database-design/schemas/inventory-schema-ddl.sql:picking_types" test_reference: "src/modules/inventory/services/picking.service.spec.ts:58" - id: RN-002 description: "Validar picking genera stock_moves automáticamente" implementation: "src/modules/inventory/services/picking.service.ts:generateStockMoves()" test_reference: "src/modules/inventory/services/picking.service.spec.ts:92" - id: RN-003 description: "Pickings tienen estados: draft, confirmed, done, cancelled" implementation: "database-design/schemas/inventory-schema-ddl.sql:pickings.state" test_reference: "src/modules/inventory/services/picking.service.spec.ts:118" dependencies: rf_dependencies: [RF-MGN-005-002, RF-MGN-005-003] module_dependencies: [] external_dependencies: [] - rf_id: RF-MGN-005-005 rf_title: "Trazabilidad (Lotes y Números de Serie)" rf_file: "requerimientos-funcionales/mgn-005/RF-MGN-005-005-trazabilidad-lotes-y-números-de-serie.md" priority: P1 story_points: 8 et_backend: file: "especificaciones-tecnicas/backend/mgn-005/ET-BACKEND-MGN-005-005-trazabilidad-lotes-y-números-de-serie.md" endpoints: - method: POST path: /api/v1/inventory/lots description: "Crear lote" - method: GET path: /api/v1/inventory/lots description: "Listar lotes" - method: GET path: /api/v1/inventory/lots/:id description: "Obtener lote por ID" - method: GET path: /api/v1/inventory/lots/:id/trace description: "Trazabilidad de lote" services: - name: "LotService" file: "src/modules/inventory/services/lot.service.ts" methods: [create, findAll, findOne, trace] controllers: - name: "LotController" file: "src/modules/inventory/controllers/lot.controller.ts" dtos: - name: "CreateLotDto" file: "src/modules/inventory/dto/create-lot.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-005/ET-FRONTEND-MGN-005-005-trazabilidad-lotes-y-números-de-serie.md" routes: - path: "/inventory/lots" component: "LotsPage" - path: "/inventory/lots/:id" component: "LotDetailsPage" components: - name: "LotsTable" file: "src/widgets/lots-table/ui/LotsTable.tsx" type: widget - name: "CreateLotForm" file: "src/features/create-lot/ui/CreateLotForm.tsx" type: feature - name: "LotTraceability" file: "src/widgets/lot-traceability/ui/LotTraceability.tsx" type: widget api_client: - name: "lotApi" file: "src/entities/lot/api/lot.api.ts" methods: [getAll, getById, create, trace] state_management: - name: "useLotStore" file: "src/entities/lot/model/lot.store.ts" type: zustand database_tables: - schema: inventory table: lots file: "database-design/schemas/inventory-schema-ddl.sql" operations: [SELECT, INSERT, UPDATE] indices: [idx_lots_product_id, idx_lots_name, idx_lots_company_id] rls_policy: company_isolation_lots tests: backend: unit_tests: - file: "src/modules/inventory/services/lot.service.spec.ts" test_cases: - "should create lot" - "should trace lot movements" - "should validate lot uniqueness per product" - "should handle expiration dates" integration_tests: - file: "test/inventory/lot.controller.e2e-spec.ts" test_cases: - "POST /api/v1/inventory/lots should create lot" - "GET /api/v1/inventory/lots should return all lots" - "GET /api/v1/inventory/lots/:id/trace should return traceability" - "should enforce company isolation" - "should require authentication" frontend: component_tests: - file: "src/widgets/lots-table/ui/LotsTable.test.tsx" test_cases: - "should render table with lots" - "should show expiration status" - file: "src/widgets/lot-traceability/ui/LotTraceability.test.tsx" test_cases: - "should render traceability timeline" e2e_tests: - file: "e2e/inventory/lots.spec.ts" test_cases: - "should create lot successfully" - "should view lot traceability" - "should show expired lots" acceptance_criteria: - id: AC-001 description: "Usuario puede crear lotes para productos" status: Pending test_reference: "test/inventory/lot.controller.e2e-spec.ts:28" - id: AC-002 description: "Sistema registra trazabilidad completa de lotes" status: Pending test_reference: "src/modules/inventory/services/lot.service.spec.ts:65" - id: AC-003 description: "Lotes tienen fecha de expiración" status: Pending test_reference: "test/inventory/lot.controller.e2e-spec.ts:95" business_rules: - id: RN-001 description: "Lote/Serial único por producto y empresa" implementation: "database-design/schemas/inventory-schema-ddl.sql:CONSTRAINT uq_lots_name_product_company" test_reference: "src/modules/inventory/services/lot.service.spec.ts:58" - id: RN-002 description: "Productos pueden requerir trazabilidad por lote o número de serie" implementation: "database-design/schemas/inventory-schema-ddl.sql:products.tracking" test_reference: "src/modules/inventory/services/lot.service.spec.ts:85" - id: RN-003 description: "Lotes tienen fecha de expiración opcional" implementation: "database-design/schemas/inventory-schema-ddl.sql:lots.expiration_date" test_reference: "src/modules/inventory/services/lot.service.spec.ts:108" dependencies: rf_dependencies: [RF-MGN-005-001, RF-MGN-005-003] module_dependencies: [] external_dependencies: [] - rf_id: RF-MGN-005-006 rf_title: "Valoración de Inventario (FIFO, Promedio)" rf_file: "requerimientos-funcionales/mgn-005/RF-MGN-005-006-valoración-de-inventario-fifo,-promedio.md" priority: P0 story_points: 13 et_backend: file: "especificaciones-tecnicas/backend/mgn-005/ET-BACKEND-MGN-005-006-valoración-de-inventario-fifo-promedio.md" endpoints: - method: GET path: /api/v1/inventory/valuation/:productId description: "Obtener valoración de producto" - method: GET path: /api/v1/inventory/valuation/report description: "Reporte de valoración de inventario" - method: POST path: /api/v1/inventory/valuation/recalculate description: "Recalcular valoración" services: - name: "ValuationService" file: "src/modules/inventory/services/valuation.service.ts" methods: [calculateValuation, generateReport, recalculate] controllers: - name: "ValuationController" file: "src/modules/inventory/controllers/valuation.controller.ts" dtos: - name: "ValuationReportDto" file: "src/modules/inventory/dto/valuation-report.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-005/ET-FRONTEND-MGN-005-006-valoración-de-inventario-fifo-promedio.md" routes: - path: "/inventory/valuation" component: "ValuationPage" - path: "/inventory/valuation/:productId" component: "ProductValuationPage" components: - name: "ValuationTable" file: "src/widgets/valuation-table/ui/ValuationTable.tsx" type: widget - name: "ValuationChart" file: "src/widgets/valuation-chart/ui/ValuationChart.tsx" type: widget api_client: - name: "valuationApi" file: "src/entities/valuation/api/valuation.api.ts" methods: [getByProduct, getReport, recalculate] state_management: - name: "useValuationStore" file: "src/entities/valuation/model/valuation.store.ts" type: zustand database_tables: - schema: inventory table: stock_valuation_layers file: "database-design/schemas/inventory-schema-ddl.sql" operations: [SELECT, INSERT, UPDATE] indices: [idx_valuation_layers_product_id, idx_valuation_layers_company_id] rls_policy: company_isolation_valuation_layers tests: backend: unit_tests: - file: "src/modules/inventory/services/valuation.service.spec.ts" test_cases: - "should calculate FIFO valuation" - "should calculate average cost valuation" - "should update valuation on stock move" - "should generate valuation report" - "should recalculate valuation" integration_tests: - file: "test/inventory/valuation.controller.e2e-spec.ts" test_cases: - "GET /api/v1/inventory/valuation/:productId should return valuation" - "GET /api/v1/inventory/valuation/report should return report" - "POST /api/v1/inventory/valuation/recalculate should recalculate" - "should enforce company isolation" - "should require authentication" frontend: component_tests: - file: "src/widgets/valuation-table/ui/ValuationTable.test.tsx" test_cases: - "should render table with valuations" - "should show total valuation" - file: "src/widgets/valuation-chart/ui/ValuationChart.test.tsx" test_cases: - "should render valuation chart" e2e_tests: - file: "e2e/inventory/valuation.spec.ts" test_cases: - "should view product valuation" - "should generate valuation report" - "should recalculate valuation" acceptance_criteria: - id: AC-001 description: "Sistema calcula valoración de inventario con método FIFO" status: Pending test_reference: "src/modules/inventory/services/valuation.service.spec.ts:58" - id: AC-002 description: "Sistema calcula valoración de inventario con método Promedio" status: Pending test_reference: "src/modules/inventory/services/valuation.service.spec.ts:85" - id: AC-003 description: "Valoración se actualiza automáticamente con movimientos de stock" status: Pending test_reference: "test/inventory/valuation.controller.e2e-spec.ts:68" business_rules: - id: RN-001 description: "Métodos de valoración: FIFO (First In First Out), Average Cost" implementation: "database-design/schemas/inventory-schema-ddl.sql:products.cost_method" test_reference: "src/modules/inventory/services/valuation.service.spec.ts:48" - id: RN-002 description: "Valoración se actualiza automáticamente en cada movimiento" implementation: "src/modules/inventory/services/valuation.service.ts:updateValuation()" test_reference: "src/modules/inventory/services/valuation.service.spec.ts:92" - id: RN-003 description: "Stock valuation layers registran historia de costos" implementation: "database-design/schemas/inventory-schema-ddl.sql:stock_valuation_layers" test_reference: "src/modules/inventory/services/valuation.service.spec.ts:118" dependencies: rf_dependencies: [RF-MGN-005-001, RF-MGN-005-003] module_dependencies: [] external_dependencies: [] - rf_id: RF-MGN-005-007 rf_title: "Inventario Físico y Ajustes" rf_file: "requerimientos-funcionales/mgn-005/RF-MGN-005-007-inventario-físico-y-ajustes.md" priority: P0 story_points: 8 et_backend: file: "especificaciones-tecnicas/backend/mgn-005/ET-BACKEND-MGN-005-007-inventario-físico-y-ajustes.md" endpoints: - method: POST path: /api/v1/inventory/adjustments description: "Crear ajuste de inventario" - method: GET path: /api/v1/inventory/adjustments description: "Listar ajustes" - method: GET path: /api/v1/inventory/adjustments/:id description: "Obtener ajuste por ID" - method: POST path: /api/v1/inventory/adjustments/:id/validate description: "Validar ajuste (actualiza stock)" - method: POST path: /api/v1/inventory/adjustments/:id/cancel description: "Cancelar ajuste" services: - name: "InventoryAdjustmentService" file: "src/modules/inventory/services/inventory-adjustment.service.ts" methods: [create, findAll, findOne, validate, cancel] controllers: - name: "InventoryAdjustmentController" file: "src/modules/inventory/controllers/inventory-adjustment.controller.ts" dtos: - name: "CreateInventoryAdjustmentDto" file: "src/modules/inventory/dto/create-inventory-adjustment.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-005/ET-FRONTEND-MGN-005-007-inventario-físico-y-ajustes.md" routes: - path: "/inventory/adjustments" component: "AdjustmentsPage" - path: "/inventory/adjustments/create" component: "CreateAdjustmentPage" - path: "/inventory/adjustments/:id" component: "ViewAdjustmentPage" components: - name: "AdjustmentsTable" file: "src/widgets/adjustments-table/ui/AdjustmentsTable.tsx" type: widget - name: "CreateAdjustmentForm" file: "src/features/create-adjustment/ui/CreateAdjustmentForm.tsx" type: feature - name: "AdjustmentCard" file: "src/entities/adjustment/ui/AdjustmentCard.tsx" type: entity api_client: - name: "inventoryAdjustmentApi" file: "src/entities/adjustment/api/adjustment.api.ts" methods: [getAll, getById, create, validate, cancel] state_management: - name: "useAdjustmentStore" file: "src/entities/adjustment/model/adjustment.store.ts" type: zustand database_tables: - schema: inventory table: inventory_adjustments file: "database-design/schemas/inventory-schema-ddl.sql" operations: [SELECT, INSERT, UPDATE] indices: [idx_adjustments_company_id, idx_adjustments_state] rls_policy: company_isolation_adjustments tests: backend: unit_tests: - file: "src/modules/inventory/services/inventory-adjustment.service.spec.ts" test_cases: - "should create inventory adjustment" - "should validate adjustment (generates stock moves)" - "should handle positive adjustments (increases stock)" - "should handle negative adjustments (decreases stock)" - "should cancel adjustment" integration_tests: - file: "test/inventory/inventory-adjustment.controller.e2e-spec.ts" test_cases: - "POST /api/v1/inventory/adjustments should create adjustment" - "GET /api/v1/inventory/adjustments should return all adjustments" - "POST /api/v1/inventory/adjustments/:id/validate should validate adjustment" - "POST /api/v1/inventory/adjustments/:id/cancel should cancel adjustment" - "should enforce company isolation" - "should require authentication" frontend: component_tests: - file: "src/widgets/adjustments-table/ui/AdjustmentsTable.test.tsx" test_cases: - "should render table with adjustments" - "should filter by state" - file: "src/features/create-adjustment/ui/CreateAdjustmentForm.test.tsx" test_cases: - "should validate required fields" - "should submit valid form" e2e_tests: - file: "e2e/inventory/adjustments.spec.ts" test_cases: - "should create adjustment successfully" - "should validate adjustment successfully" - "should show updated stock" acceptance_criteria: - id: AC-001 description: "Usuario puede crear ajustes de inventario por diferencias en conteo físico" status: Pending test_reference: "test/inventory/inventory-adjustment.controller.e2e-spec.ts:28" - id: AC-002 description: "Validar ajuste genera movimientos de stock automáticamente" status: Pending test_reference: "src/modules/inventory/services/inventory-adjustment.service.spec.ts:68" - id: AC-003 description: "Ajustes pueden ser positivos (incremento) o negativos (decremento)" status: Pending test_reference: "test/inventory/inventory-adjustment.controller.e2e-spec.ts:95" business_rules: - id: RN-001 description: "Ajustes generan movimientos de stock automáticamente" implementation: "src/modules/inventory/services/inventory-adjustment.service.ts:validate()" test_reference: "src/modules/inventory/services/inventory-adjustment.service.spec.ts:58" - id: RN-002 description: "Ajustes positivos incrementan stock, negativos decrementan" implementation: "src/modules/inventory/services/inventory-adjustment.service.ts:generateStockMoves()" test_reference: "src/modules/inventory/services/inventory-adjustment.service.spec.ts:85" - id: RN-003 description: "Ajustes validados generan asientos contables de valoración" implementation: "src/modules/inventory/services/inventory-adjustment.service.ts:generateJournalEntry()" test_reference: "src/modules/inventory/services/inventory-adjustment.service.spec.ts:108" dependencies: rf_dependencies: [RF-MGN-005-001, RF-MGN-005-002, RF-MGN-005-003] module_dependencies: [] external_dependencies: [] coverage: rf_to_et_backend: 100% rf_to_et_frontend: 100% rf_to_database: 100% rf_to_tests: 100% backend_tests: 100% frontend_tests: 100% statistics: total_endpoints: 35 total_components: 28 total_tables: 10 total_test_cases: 140 estimated_duration_sprints: 4