erp-core/docs/04-modelado/trazabilidad/TRACEABILITY-MGN-005.yaml

1011 lines
42 KiB
YAML

# 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