986 lines
40 KiB
YAML
986 lines
40 KiB
YAML
# TRACEABILITY-MGN-008.yaml
|
|
# Matriz de Trazabilidad - MGN-008: Contabilidad Analítica
|
|
# Fecha: 2025-11-24
|
|
# Versión: 1.0
|
|
|
|
module:
|
|
id: MGN-008
|
|
name: "Contabilidad Analítica"
|
|
description: "Sistema de cuentas analíticas para seguimiento de costos e ingresos por proyectos, departamentos y centros de costo"
|
|
priority: P0
|
|
story_points: 35
|
|
status: Diseñado
|
|
|
|
metadata:
|
|
total_rf: 5
|
|
total_et_backend: 5
|
|
total_et_frontend: 5
|
|
total_tables: 6
|
|
total_tests: 100
|
|
coverage: 100%
|
|
|
|
requirements:
|
|
- rf_id: RF-MGN-008-001
|
|
rf_title: "Gestión de Cuentas Analíticas"
|
|
rf_file: "requerimientos-funcionales/mgn-008/RF-MGN-008-001-gestión-de-cuentas-analíticas.md"
|
|
priority: P0
|
|
story_points: 8
|
|
|
|
et_backend:
|
|
file: "especificaciones-tecnicas/backend/mgn-008/ET-BACKEND-MGN-008-001-gestión-de-cuentas-analíticas.md"
|
|
endpoints:
|
|
- method: POST
|
|
path: /api/v1/analytics/accounts
|
|
description: "Crear nueva cuenta analítica"
|
|
- method: GET
|
|
path: /api/v1/analytics/accounts
|
|
description: "Listar todas las cuentas analíticas"
|
|
- method: GET
|
|
path: /api/v1/analytics/accounts/:id
|
|
description: "Obtener cuenta analítica por ID"
|
|
- method: PUT
|
|
path: /api/v1/analytics/accounts/:id
|
|
description: "Actualizar cuenta analítica"
|
|
- method: DELETE
|
|
path: /api/v1/analytics/accounts/:id
|
|
description: "Eliminar cuenta analítica (soft delete)"
|
|
services:
|
|
- name: "AnalyticAccountService"
|
|
file: "src/modules/analytics/services/analytic-account.service.ts"
|
|
methods:
|
|
- create
|
|
- findAll
|
|
- findOne
|
|
- update
|
|
- remove
|
|
- validateBusinessRules
|
|
controllers:
|
|
- name: "AnalyticAccountController"
|
|
file: "src/modules/analytics/controllers/analytic-account.controller.ts"
|
|
dtos:
|
|
- name: "CreateAnalyticAccountDto"
|
|
file: "src/modules/analytics/dto/create-analytic-account.dto.ts"
|
|
- name: "UpdateAnalyticAccountDto"
|
|
file: "src/modules/analytics/dto/update-analytic-account.dto.ts"
|
|
- name: "AnalyticAccountResponseDto"
|
|
file: "src/modules/analytics/dto/analytic-account-response.dto.ts"
|
|
- name: "FilterAnalyticAccountDto"
|
|
file: "src/modules/analytics/dto/filter-analytic-account.dto.ts"
|
|
|
|
et_frontend:
|
|
file: "especificaciones-tecnicas/frontend/mgn-008/ET-FRONTEND-MGN-008-001-gestión-de-cuentas-analíticas.md"
|
|
routes:
|
|
- path: "/analytics/accounts"
|
|
component: "AnalyticAccountsPage"
|
|
- path: "/analytics/accounts/create"
|
|
component: "CreateAnalyticAccountPage"
|
|
- path: "/analytics/accounts/:id/edit"
|
|
component: "EditAnalyticAccountPage"
|
|
- path: "/analytics/accounts/:id"
|
|
component: "ViewAnalyticAccountPage"
|
|
components:
|
|
- name: "AnalyticAccountsTable"
|
|
file: "src/widgets/analytic-accounts-table/ui/AnalyticAccountsTable.tsx"
|
|
type: widget
|
|
- name: "CreateAnalyticAccountForm"
|
|
file: "src/features/create-analytic-account/ui/CreateAnalyticAccountForm.tsx"
|
|
type: feature
|
|
- name: "AnalyticAccountCard"
|
|
file: "src/entities/analytic-account/ui/AnalyticAccountCard.tsx"
|
|
type: entity
|
|
- name: "AnalyticAccountPage"
|
|
file: "src/pages/analytics/AnalyticAccountPage.tsx"
|
|
type: page
|
|
api_client:
|
|
- name: "analyticAccountApi"
|
|
file: "src/entities/analytic-account/api/analytic-account.api.ts"
|
|
methods:
|
|
- getAll
|
|
- getById
|
|
- create
|
|
- update
|
|
- delete
|
|
state_management:
|
|
- name: "useAnalyticAccountStore"
|
|
file: "src/entities/analytic-account/model/analytic-account.store.ts"
|
|
type: zustand
|
|
- name: "useAnalyticAccounts"
|
|
file: "src/entities/analytic-account/api/analytic-account.queries.ts"
|
|
type: react-query
|
|
|
|
database_tables:
|
|
- schema: analytics
|
|
table: analytic_accounts
|
|
file: "database-design/schemas/analytics-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- UPDATE
|
|
- DELETE (soft)
|
|
indices:
|
|
- idx_analytic_accounts_tenant_id
|
|
- idx_analytic_accounts_code
|
|
- idx_analytic_accounts_plan_id
|
|
rls_policy: tenant_isolation_analytic_accounts
|
|
- schema: analytics
|
|
table: analytic_plans
|
|
file: "database-design/schemas/analytics-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
indices:
|
|
- idx_analytic_plans_tenant_id
|
|
rls_policy: tenant_isolation_analytic_plans
|
|
|
|
tests:
|
|
backend:
|
|
unit_tests:
|
|
- file: "src/modules/analytics/services/analytic-account.service.spec.ts"
|
|
test_cases:
|
|
- "should create analytic account with valid data"
|
|
- "should throw error when code already exists"
|
|
- "should support hierarchical accounts"
|
|
- "should find all accounts for tenant"
|
|
- "should update account successfully"
|
|
integration_tests:
|
|
- file: "test/analytics/analytic-account.controller.e2e-spec.ts"
|
|
test_cases:
|
|
- "POST /api/v1/analytics/accounts should create account"
|
|
- "GET /api/v1/analytics/accounts should return all accounts"
|
|
- "GET /api/v1/analytics/accounts/:id should return account"
|
|
- "PUT /api/v1/analytics/accounts/:id should update account"
|
|
- "DELETE /api/v1/analytics/accounts/:id should soft delete account"
|
|
- "should enforce tenant isolation"
|
|
- "should require authentication"
|
|
- "should check permissions"
|
|
frontend:
|
|
component_tests:
|
|
- file: "src/widgets/analytic-accounts-table/ui/AnalyticAccountsTable.test.tsx"
|
|
test_cases:
|
|
- "should render table with accounts"
|
|
- "should handle pagination"
|
|
- "should call delete on button click"
|
|
- file: "src/features/create-analytic-account/ui/CreateAnalyticAccountForm.test.tsx"
|
|
test_cases:
|
|
- "should validate required fields"
|
|
- "should submit valid form"
|
|
- "should show error messages"
|
|
e2e_tests:
|
|
- file: "e2e/analytics/analytic-accounts.spec.ts"
|
|
test_cases:
|
|
- "should create analytic account successfully"
|
|
- "should edit analytic account successfully"
|
|
- "should delete analytic account with confirmation"
|
|
- "should enforce permissions"
|
|
|
|
acceptance_criteria:
|
|
- id: AC-001
|
|
description: "Usuario puede crear cuentas analíticas con código único"
|
|
status: Pending
|
|
test_reference: "test/analytics/analytic-account.controller.e2e-spec.ts:32"
|
|
- id: AC-002
|
|
description: "Cuentas analíticas soportan estructura jerárquica"
|
|
status: Pending
|
|
test_reference: "src/modules/analytics/services/analytic-account.service.spec.ts:65"
|
|
- id: AC-003
|
|
description: "Cuentas pueden asociarse a diferentes planes analíticos"
|
|
status: Pending
|
|
test_reference: "test/analytics/analytic-account.controller.e2e-spec.ts:98"
|
|
|
|
business_rules:
|
|
- id: RN-001
|
|
description: "Código de cuenta analítica debe ser único por tenant"
|
|
implementation: "database-design/schemas/analytics-schema-ddl.sql:CONSTRAINT uq_analytic_accounts_code_tenant"
|
|
test_reference: "src/modules/analytics/services/analytic-account.service.spec.ts:88"
|
|
- id: RN-002
|
|
description: "Cuenta analítica debe estar asociada a un plan analítico"
|
|
implementation: "src/modules/analytics/services/analytic-account.service.ts:validatePlan()"
|
|
test_reference: "src/modules/analytics/services/analytic-account.service.spec.ts:112"
|
|
- id: RN-003
|
|
description: "Cuenta con movimientos no puede ser eliminada"
|
|
implementation: "src/modules/analytics/services/analytic-account.service.ts:remove()"
|
|
test_reference: "src/modules/analytics/services/analytic-account.service.spec.ts:138"
|
|
|
|
dependencies:
|
|
rf_dependencies: []
|
|
module_dependencies:
|
|
- MGN-001
|
|
external_dependencies:
|
|
- name: "@nestjs/common"
|
|
version: "^10.0.0"
|
|
- name: "ant-design"
|
|
version: "^5.0.0"
|
|
|
|
- rf_id: RF-MGN-008-002
|
|
rf_title: "Registro de Líneas Analíticas"
|
|
rf_file: "requerimientos-funcionales/mgn-008/RF-MGN-008-002-registro-de-líneas-analíticas.md"
|
|
priority: P0
|
|
story_points: 8
|
|
|
|
et_backend:
|
|
file: "especificaciones-tecnicas/backend/mgn-008/ET-BACKEND-MGN-008-002-registro-de-líneas-analíticas.md"
|
|
endpoints:
|
|
- method: POST
|
|
path: /api/v1/analytics/lines
|
|
description: "Crear nueva línea analítica"
|
|
- method: GET
|
|
path: /api/v1/analytics/lines
|
|
description: "Listar todas las líneas analíticas"
|
|
- method: GET
|
|
path: /api/v1/analytics/lines/:id
|
|
description: "Obtener línea analítica por ID"
|
|
- method: PUT
|
|
path: /api/v1/analytics/lines/:id
|
|
description: "Actualizar línea analítica"
|
|
- method: DELETE
|
|
path: /api/v1/analytics/lines/:id
|
|
description: "Eliminar línea analítica (soft delete)"
|
|
services:
|
|
- name: "AnalyticLineService"
|
|
file: "src/modules/analytics/services/analytic-line.service.ts"
|
|
methods:
|
|
- create
|
|
- findAll
|
|
- findOne
|
|
- update
|
|
- remove
|
|
- validateBusinessRules
|
|
controllers:
|
|
- name: "AnalyticLineController"
|
|
file: "src/modules/analytics/controllers/analytic-line.controller.ts"
|
|
dtos:
|
|
- name: "CreateAnalyticLineDto"
|
|
file: "src/modules/analytics/dto/create-analytic-line.dto.ts"
|
|
- name: "UpdateAnalyticLineDto"
|
|
file: "src/modules/analytics/dto/update-analytic-line.dto.ts"
|
|
- name: "AnalyticLineResponseDto"
|
|
file: "src/modules/analytics/dto/analytic-line-response.dto.ts"
|
|
- name: "FilterAnalyticLineDto"
|
|
file: "src/modules/analytics/dto/filter-analytic-line.dto.ts"
|
|
|
|
et_frontend:
|
|
file: "especificaciones-tecnicas/frontend/mgn-008/ET-FRONTEND-MGN-008-002-registro-de-líneas-analíticas.md"
|
|
routes:
|
|
- path: "/analytics/lines"
|
|
component: "AnalyticLinesPage"
|
|
- path: "/analytics/lines/create"
|
|
component: "CreateAnalyticLinePage"
|
|
- path: "/analytics/lines/:id/edit"
|
|
component: "EditAnalyticLinePage"
|
|
- path: "/analytics/lines/:id"
|
|
component: "ViewAnalyticLinePage"
|
|
components:
|
|
- name: "AnalyticLinesTable"
|
|
file: "src/widgets/analytic-lines-table/ui/AnalyticLinesTable.tsx"
|
|
type: widget
|
|
- name: "CreateAnalyticLineForm"
|
|
file: "src/features/create-analytic-line/ui/CreateAnalyticLineForm.tsx"
|
|
type: feature
|
|
- name: "AnalyticLineCard"
|
|
file: "src/entities/analytic-line/ui/AnalyticLineCard.tsx"
|
|
type: entity
|
|
- name: "AnalyticLinePage"
|
|
file: "src/pages/analytics/AnalyticLinePage.tsx"
|
|
type: page
|
|
api_client:
|
|
- name: "analyticLineApi"
|
|
file: "src/entities/analytic-line/api/analytic-line.api.ts"
|
|
methods:
|
|
- getAll
|
|
- getById
|
|
- create
|
|
- update
|
|
- delete
|
|
state_management:
|
|
- name: "useAnalyticLineStore"
|
|
file: "src/entities/analytic-line/model/analytic-line.store.ts"
|
|
type: zustand
|
|
- name: "useAnalyticLines"
|
|
file: "src/entities/analytic-line/api/analytic-line.queries.ts"
|
|
type: react-query
|
|
|
|
database_tables:
|
|
- schema: analytics
|
|
table: analytic_lines
|
|
file: "database-design/schemas/analytics-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- UPDATE
|
|
- DELETE (soft)
|
|
indices:
|
|
- idx_analytic_lines_tenant_id
|
|
- idx_analytic_lines_account_id
|
|
- idx_analytic_lines_date
|
|
- idx_analytic_lines_journal_entry_id
|
|
rls_policy: tenant_isolation_analytic_lines
|
|
- schema: financial
|
|
table: journal_entries
|
|
file: "database-design/schemas/financial-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
indices:
|
|
- idx_journal_entries_tenant_id
|
|
rls_policy: tenant_isolation_journal_entries
|
|
|
|
tests:
|
|
backend:
|
|
unit_tests:
|
|
- file: "src/modules/analytics/services/analytic-line.service.spec.ts"
|
|
test_cases:
|
|
- "should create analytic line with valid data"
|
|
- "should link to journal entry automatically"
|
|
- "should validate account existence"
|
|
- "should find all lines for tenant"
|
|
- "should update line successfully"
|
|
integration_tests:
|
|
- file: "test/analytics/analytic-line.controller.e2e-spec.ts"
|
|
test_cases:
|
|
- "POST /api/v1/analytics/lines should create line"
|
|
- "GET /api/v1/analytics/lines should return all lines"
|
|
- "GET /api/v1/analytics/lines/:id should return line"
|
|
- "PUT /api/v1/analytics/lines/:id should update line"
|
|
- "DELETE /api/v1/analytics/lines/:id should soft delete line"
|
|
- "should enforce tenant isolation"
|
|
- "should require authentication"
|
|
- "should check permissions"
|
|
frontend:
|
|
component_tests:
|
|
- file: "src/widgets/analytic-lines-table/ui/AnalyticLinesTable.test.tsx"
|
|
test_cases:
|
|
- "should render table with lines"
|
|
- "should handle pagination"
|
|
- "should filter by account"
|
|
- file: "src/features/create-analytic-line/ui/CreateAnalyticLineForm.test.tsx"
|
|
test_cases:
|
|
- "should validate required fields"
|
|
- "should submit valid form"
|
|
- "should show error messages"
|
|
e2e_tests:
|
|
- file: "e2e/analytics/analytic-lines.spec.ts"
|
|
test_cases:
|
|
- "should create analytic line successfully"
|
|
- "should edit analytic line successfully"
|
|
- "should delete analytic line with confirmation"
|
|
- "should enforce permissions"
|
|
|
|
acceptance_criteria:
|
|
- id: AC-001
|
|
description: "Usuario puede registrar líneas analíticas manualmente"
|
|
status: Pending
|
|
test_reference: "test/analytics/analytic-line.controller.e2e-spec.ts:35"
|
|
- id: AC-002
|
|
description: "Líneas analíticas se crean automáticamente desde asientos contables"
|
|
status: Pending
|
|
test_reference: "src/modules/analytics/services/analytic-line.service.spec.ts:72"
|
|
- id: AC-003
|
|
description: "Líneas soportan montos positivos (ingresos) y negativos (costos)"
|
|
status: Pending
|
|
test_reference: "test/analytics/analytic-line.controller.e2e-spec.ts:108"
|
|
|
|
business_rules:
|
|
- id: RN-001
|
|
description: "Línea analítica debe tener cuenta analítica válida"
|
|
implementation: "src/modules/analytics/services/analytic-line.service.ts:validateAccount()"
|
|
test_reference: "src/modules/analytics/services/analytic-line.service.spec.ts:95"
|
|
- id: RN-002
|
|
description: "Monto puede ser positivo (ingreso) o negativo (costo)"
|
|
implementation: "src/modules/analytics/services/analytic-line.service.ts:create()"
|
|
test_reference: "src/modules/analytics/services/analytic-line.service.spec.ts:122"
|
|
- id: RN-003
|
|
description: "Líneas vinculadas a journal_entry no pueden ser editadas"
|
|
implementation: "src/modules/analytics/services/analytic-line.service.ts:update()"
|
|
test_reference: "src/modules/analytics/services/analytic-line.service.spec.ts:148"
|
|
|
|
dependencies:
|
|
rf_dependencies:
|
|
- RF-MGN-008-001
|
|
- RF-MGN-004-003
|
|
module_dependencies:
|
|
- MGN-001
|
|
- MGN-004
|
|
external_dependencies:
|
|
- name: "@nestjs/common"
|
|
version: "^10.0.0"
|
|
|
|
- rf_id: RF-MGN-008-003
|
|
rf_title: "Distribución Analítica Multi-Cuenta"
|
|
rf_file: "requerimientos-funcionales/mgn-008/RF-MGN-008-003-distribución-analítica-multi-cuenta.md"
|
|
priority: P1
|
|
story_points: 8
|
|
|
|
et_backend:
|
|
file: "especificaciones-tecnicas/backend/mgn-008/ET-BACKEND-MGN-008-003-distribución-analítica-multi-cuenta.md"
|
|
endpoints:
|
|
- method: POST
|
|
path: /api/v1/analytics/distributions
|
|
description: "Crear nueva distribución analítica"
|
|
- method: GET
|
|
path: /api/v1/analytics/distributions
|
|
description: "Listar todas las distribuciones"
|
|
- method: GET
|
|
path: /api/v1/analytics/distributions/:id
|
|
description: "Obtener distribución por ID"
|
|
- method: PUT
|
|
path: /api/v1/analytics/distributions/:id
|
|
description: "Actualizar distribución"
|
|
- method: DELETE
|
|
path: /api/v1/analytics/distributions/:id
|
|
description: "Eliminar distribución (soft delete)"
|
|
services:
|
|
- name: "AnalyticDistributionService"
|
|
file: "src/modules/analytics/services/analytic-distribution.service.ts"
|
|
methods:
|
|
- create
|
|
- findAll
|
|
- findOne
|
|
- update
|
|
- remove
|
|
- validateBusinessRules
|
|
controllers:
|
|
- name: "AnalyticDistributionController"
|
|
file: "src/modules/analytics/controllers/analytic-distribution.controller.ts"
|
|
dtos:
|
|
- name: "CreateAnalyticDistributionDto"
|
|
file: "src/modules/analytics/dto/create-analytic-distribution.dto.ts"
|
|
- name: "UpdateAnalyticDistributionDto"
|
|
file: "src/modules/analytics/dto/update-analytic-distribution.dto.ts"
|
|
- name: "AnalyticDistributionResponseDto"
|
|
file: "src/modules/analytics/dto/analytic-distribution-response.dto.ts"
|
|
- name: "FilterAnalyticDistributionDto"
|
|
file: "src/modules/analytics/dto/filter-analytic-distribution.dto.ts"
|
|
|
|
et_frontend:
|
|
file: "especificaciones-tecnicas/frontend/mgn-008/ET-FRONTEND-MGN-008-003-distribución-analítica-multi-cuenta.md"
|
|
routes:
|
|
- path: "/analytics/distributions"
|
|
component: "AnalyticDistributionsPage"
|
|
- path: "/analytics/distributions/create"
|
|
component: "CreateAnalyticDistributionPage"
|
|
- path: "/analytics/distributions/:id/edit"
|
|
component: "EditAnalyticDistributionPage"
|
|
- path: "/analytics/distributions/:id"
|
|
component: "ViewAnalyticDistributionPage"
|
|
components:
|
|
- name: "AnalyticDistributionsTable"
|
|
file: "src/widgets/analytic-distributions-table/ui/AnalyticDistributionsTable.tsx"
|
|
type: widget
|
|
- name: "CreateAnalyticDistributionForm"
|
|
file: "src/features/create-analytic-distribution/ui/CreateAnalyticDistributionForm.tsx"
|
|
type: feature
|
|
- name: "AnalyticDistributionCard"
|
|
file: "src/entities/analytic-distribution/ui/AnalyticDistributionCard.tsx"
|
|
type: entity
|
|
- name: "AnalyticDistributionPage"
|
|
file: "src/pages/analytics/AnalyticDistributionPage.tsx"
|
|
type: page
|
|
api_client:
|
|
- name: "analyticDistributionApi"
|
|
file: "src/entities/analytic-distribution/api/analytic-distribution.api.ts"
|
|
methods:
|
|
- getAll
|
|
- getById
|
|
- create
|
|
- update
|
|
- delete
|
|
state_management:
|
|
- name: "useAnalyticDistributionStore"
|
|
file: "src/entities/analytic-distribution/model/analytic-distribution.store.ts"
|
|
type: zustand
|
|
- name: "useAnalyticDistributions"
|
|
file: "src/entities/analytic-distribution/api/analytic-distribution.queries.ts"
|
|
type: react-query
|
|
|
|
database_tables:
|
|
- schema: analytics
|
|
table: analytic_distributions
|
|
file: "database-design/schemas/analytics-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- UPDATE
|
|
- DELETE (soft)
|
|
indices:
|
|
- idx_analytic_distributions_tenant_id
|
|
- idx_analytic_distributions_name
|
|
rls_policy: tenant_isolation_analytic_distributions
|
|
- schema: analytics
|
|
table: distribution_lines
|
|
file: "database-design/schemas/analytics-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- UPDATE
|
|
- DELETE
|
|
indices:
|
|
- idx_distribution_lines_distribution_id
|
|
- idx_distribution_lines_account_id
|
|
rls_policy: tenant_isolation_distribution_lines
|
|
|
|
tests:
|
|
backend:
|
|
unit_tests:
|
|
- file: "src/modules/analytics/services/analytic-distribution.service.spec.ts"
|
|
test_cases:
|
|
- "should create distribution with multiple accounts"
|
|
- "should validate percentages sum to 100%"
|
|
- "should apply distribution to journal entry"
|
|
- "should find all distributions for tenant"
|
|
- "should update distribution successfully"
|
|
integration_tests:
|
|
- file: "test/analytics/analytic-distribution.controller.e2e-spec.ts"
|
|
test_cases:
|
|
- "POST /api/v1/analytics/distributions should create distribution"
|
|
- "GET /api/v1/analytics/distributions should return all distributions"
|
|
- "GET /api/v1/analytics/distributions/:id should return distribution"
|
|
- "PUT /api/v1/analytics/distributions/:id should update distribution"
|
|
- "DELETE /api/v1/analytics/distributions/:id should soft delete distribution"
|
|
- "should enforce tenant isolation"
|
|
- "should require authentication"
|
|
- "should check permissions"
|
|
frontend:
|
|
component_tests:
|
|
- file: "src/widgets/analytic-distributions-table/ui/AnalyticDistributionsTable.test.tsx"
|
|
test_cases:
|
|
- "should render table with distributions"
|
|
- "should handle pagination"
|
|
- "should call delete on button click"
|
|
- file: "src/features/create-analytic-distribution/ui/CreateAnalyticDistributionForm.test.tsx"
|
|
test_cases:
|
|
- "should validate percentages sum to 100%"
|
|
- "should submit valid form"
|
|
- "should show error messages"
|
|
e2e_tests:
|
|
- file: "e2e/analytics/analytic-distributions.spec.ts"
|
|
test_cases:
|
|
- "should create distribution successfully"
|
|
- "should edit distribution successfully"
|
|
- "should delete distribution with confirmation"
|
|
- "should enforce permissions"
|
|
|
|
acceptance_criteria:
|
|
- id: AC-001
|
|
description: "Usuario puede crear distribuciones con múltiples cuentas"
|
|
status: Pending
|
|
test_reference: "test/analytics/analytic-distribution.controller.e2e-spec.ts:38"
|
|
- id: AC-002
|
|
description: "Suma de porcentajes debe ser exactamente 100%"
|
|
status: Pending
|
|
test_reference: "src/modules/analytics/services/analytic-distribution.service.spec.ts:75"
|
|
- id: AC-003
|
|
description: "Distribuciones se aplican automáticamente a asientos contables"
|
|
status: Pending
|
|
test_reference: "test/analytics/analytic-distribution.controller.e2e-spec.ts:112"
|
|
|
|
business_rules:
|
|
- id: RN-001
|
|
description: "Suma de porcentajes de distribución debe ser 100%"
|
|
implementation: "src/modules/analytics/services/analytic-distribution.service.ts:validatePercentages()"
|
|
test_reference: "src/modules/analytics/services/analytic-distribution.service.spec.ts:98"
|
|
- id: RN-002
|
|
description: "Distribución debe tener al menos 2 cuentas analíticas"
|
|
implementation: "src/modules/analytics/services/analytic-distribution.service.ts:validateAccounts()"
|
|
test_reference: "src/modules/analytics/services/analytic-distribution.service.spec.ts:125"
|
|
- id: RN-003
|
|
description: "Al aplicar distribución, se crean múltiples líneas analíticas"
|
|
implementation: "src/modules/analytics/services/analytic-distribution.service.ts:apply()"
|
|
test_reference: "src/modules/analytics/services/analytic-distribution.service.spec.ts:152"
|
|
|
|
dependencies:
|
|
rf_dependencies:
|
|
- RF-MGN-008-001
|
|
- RF-MGN-008-002
|
|
module_dependencies:
|
|
- MGN-001
|
|
- MGN-004
|
|
external_dependencies:
|
|
- name: "@nestjs/common"
|
|
version: "^10.0.0"
|
|
|
|
- rf_id: RF-MGN-008-004
|
|
rf_title: "Tags Analíticos"
|
|
rf_file: "requerimientos-funcionales/mgn-008/RF-MGN-008-004-tags-analíticos.md"
|
|
priority: P1
|
|
story_points: 3
|
|
|
|
et_backend:
|
|
file: "especificaciones-tecnicas/backend/mgn-008/ET-BACKEND-MGN-008-004-tags-analíticos.md"
|
|
endpoints:
|
|
- method: POST
|
|
path: /api/v1/analytics/tags
|
|
description: "Crear nuevo tag analítico"
|
|
- method: GET
|
|
path: /api/v1/analytics/tags
|
|
description: "Listar todos los tags"
|
|
- method: GET
|
|
path: /api/v1/analytics/tags/:id
|
|
description: "Obtener tag por ID"
|
|
- method: PUT
|
|
path: /api/v1/analytics/tags/:id
|
|
description: "Actualizar tag"
|
|
- method: DELETE
|
|
path: /api/v1/analytics/tags/:id
|
|
description: "Eliminar tag (soft delete)"
|
|
services:
|
|
- name: "AnalyticTagService"
|
|
file: "src/modules/analytics/services/analytic-tag.service.ts"
|
|
methods:
|
|
- create
|
|
- findAll
|
|
- findOne
|
|
- update
|
|
- remove
|
|
- validateBusinessRules
|
|
controllers:
|
|
- name: "AnalyticTagController"
|
|
file: "src/modules/analytics/controllers/analytic-tag.controller.ts"
|
|
dtos:
|
|
- name: "CreateAnalyticTagDto"
|
|
file: "src/modules/analytics/dto/create-analytic-tag.dto.ts"
|
|
- name: "UpdateAnalyticTagDto"
|
|
file: "src/modules/analytics/dto/update-analytic-tag.dto.ts"
|
|
- name: "AnalyticTagResponseDto"
|
|
file: "src/modules/analytics/dto/analytic-tag-response.dto.ts"
|
|
- name: "FilterAnalyticTagDto"
|
|
file: "src/modules/analytics/dto/filter-analytic-tag.dto.ts"
|
|
|
|
et_frontend:
|
|
file: "especificaciones-tecnicas/frontend/mgn-008/ET-FRONTEND-MGN-008-004-tags-analíticos.md"
|
|
routes:
|
|
- path: "/analytics/tags"
|
|
component: "AnalyticTagsPage"
|
|
- path: "/analytics/tags/create"
|
|
component: "CreateAnalyticTagPage"
|
|
- path: "/analytics/tags/:id/edit"
|
|
component: "EditAnalyticTagPage"
|
|
- path: "/analytics/tags/:id"
|
|
component: "ViewAnalyticTagPage"
|
|
components:
|
|
- name: "AnalyticTagsTable"
|
|
file: "src/widgets/analytic-tags-table/ui/AnalyticTagsTable.tsx"
|
|
type: widget
|
|
- name: "CreateAnalyticTagForm"
|
|
file: "src/features/create-analytic-tag/ui/CreateAnalyticTagForm.tsx"
|
|
type: feature
|
|
- name: "AnalyticTagCard"
|
|
file: "src/entities/analytic-tag/ui/AnalyticTagCard.tsx"
|
|
type: entity
|
|
- name: "AnalyticTagPage"
|
|
file: "src/pages/analytics/AnalyticTagPage.tsx"
|
|
type: page
|
|
api_client:
|
|
- name: "analyticTagApi"
|
|
file: "src/entities/analytic-tag/api/analytic-tag.api.ts"
|
|
methods:
|
|
- getAll
|
|
- getById
|
|
- create
|
|
- update
|
|
- delete
|
|
state_management:
|
|
- name: "useAnalyticTagStore"
|
|
file: "src/entities/analytic-tag/model/analytic-tag.store.ts"
|
|
type: zustand
|
|
- name: "useAnalyticTags"
|
|
file: "src/entities/analytic-tag/api/analytic-tag.queries.ts"
|
|
type: react-query
|
|
|
|
database_tables:
|
|
- schema: analytics
|
|
table: analytic_tags
|
|
file: "database-design/schemas/analytics-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- UPDATE
|
|
- DELETE (soft)
|
|
indices:
|
|
- idx_analytic_tags_tenant_id
|
|
- idx_analytic_tags_name
|
|
rls_policy: tenant_isolation_analytic_tags
|
|
- schema: analytics
|
|
table: analytic_line_tags
|
|
file: "database-design/schemas/analytics-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- DELETE
|
|
indices:
|
|
- idx_analytic_line_tags_line_id
|
|
- idx_analytic_line_tags_tag_id
|
|
rls_policy: tenant_isolation_analytic_line_tags
|
|
|
|
tests:
|
|
backend:
|
|
unit_tests:
|
|
- file: "src/modules/analytics/services/analytic-tag.service.spec.ts"
|
|
test_cases:
|
|
- "should create analytic tag with valid data"
|
|
- "should assign tags to analytic lines"
|
|
- "should find all tags for tenant"
|
|
- "should update tag successfully"
|
|
- "should delete tag if no lines associated"
|
|
integration_tests:
|
|
- file: "test/analytics/analytic-tag.controller.e2e-spec.ts"
|
|
test_cases:
|
|
- "POST /api/v1/analytics/tags should create tag"
|
|
- "GET /api/v1/analytics/tags should return all tags"
|
|
- "GET /api/v1/analytics/tags/:id should return tag"
|
|
- "PUT /api/v1/analytics/tags/:id should update tag"
|
|
- "DELETE /api/v1/analytics/tags/:id should soft delete tag"
|
|
- "should enforce tenant isolation"
|
|
- "should require authentication"
|
|
- "should check permissions"
|
|
frontend:
|
|
component_tests:
|
|
- file: "src/widgets/analytic-tags-table/ui/AnalyticTagsTable.test.tsx"
|
|
test_cases:
|
|
- "should render table with tags"
|
|
- "should handle pagination"
|
|
- "should call delete on button click"
|
|
- file: "src/features/create-analytic-tag/ui/CreateAnalyticTagForm.test.tsx"
|
|
test_cases:
|
|
- "should validate required fields"
|
|
- "should submit valid form"
|
|
- "should show error messages"
|
|
e2e_tests:
|
|
- file: "e2e/analytics/analytic-tags.spec.ts"
|
|
test_cases:
|
|
- "should create analytic tag successfully"
|
|
- "should edit analytic tag successfully"
|
|
- "should delete analytic tag with confirmation"
|
|
- "should enforce permissions"
|
|
|
|
acceptance_criteria:
|
|
- id: AC-001
|
|
description: "Usuario puede crear tags para clasificación adicional"
|
|
status: Pending
|
|
test_reference: "test/analytics/analytic-tag.controller.e2e-spec.ts:32"
|
|
- id: AC-002
|
|
description: "Tags se asignan a líneas analíticas (relación many-to-many)"
|
|
status: Pending
|
|
test_reference: "src/modules/analytics/services/analytic-tag.service.spec.ts:68"
|
|
- id: AC-003
|
|
description: "Reportes pueden filtrarse por tags"
|
|
status: Pending
|
|
test_reference: "test/analytics/analytic-tag.controller.e2e-spec.ts:95"
|
|
|
|
business_rules:
|
|
- id: RN-001
|
|
description: "Nombre de tag debe ser único por tenant"
|
|
implementation: "database-design/schemas/analytics-schema-ddl.sql:CONSTRAINT uq_analytic_tags_name_tenant"
|
|
test_reference: "src/modules/analytics/services/analytic-tag.service.spec.ts:88"
|
|
- id: RN-002
|
|
description: "Una línea analítica puede tener múltiples tags"
|
|
implementation: "database-design/schemas/analytics-schema-ddl.sql:analytic_line_tags table"
|
|
test_reference: "src/modules/analytics/services/analytic-tag.service.spec.ts:112"
|
|
- id: RN-003
|
|
description: "Tag con líneas asociadas no puede ser eliminado permanentemente"
|
|
implementation: "src/modules/analytics/services/analytic-tag.service.ts:remove()"
|
|
test_reference: "src/modules/analytics/services/analytic-tag.service.spec.ts:138"
|
|
|
|
dependencies:
|
|
rf_dependencies:
|
|
- RF-MGN-008-002
|
|
module_dependencies:
|
|
- MGN-001
|
|
external_dependencies:
|
|
- name: "@nestjs/common"
|
|
version: "^10.0.0"
|
|
|
|
- rf_id: RF-MGN-008-005
|
|
rf_title: "Reportes Analíticos (P&L por Proyecto)"
|
|
rf_file: "requerimientos-funcionales/mgn-008/RF-MGN-008-005-reportes-analíticos-p&l-por-proyecto.md"
|
|
priority: P0
|
|
story_points: 8
|
|
|
|
et_backend:
|
|
file: "especificaciones-tecnicas/backend/mgn-008/ET-BACKEND-MGN-008-005-reportes-analíticos-p&l-por-proyecto.md"
|
|
endpoints:
|
|
- method: GET
|
|
path: /api/v1/analytics/reports/pl
|
|
description: "Obtener reporte P&L por cuenta analítica"
|
|
- method: GET
|
|
path: /api/v1/analytics/reports/balance
|
|
description: "Obtener balance analítico"
|
|
- method: GET
|
|
path: /api/v1/analytics/reports/summary
|
|
description: "Resumen analítico por período"
|
|
- method: GET
|
|
path: /api/v1/analytics/reports/comparison
|
|
description: "Comparación de cuentas analíticas"
|
|
- method: GET
|
|
path: /api/v1/analytics/reports/trends
|
|
description: "Tendencias analíticas"
|
|
services:
|
|
- name: "AnalyticReportService"
|
|
file: "src/modules/analytics/services/analytic-report.service.ts"
|
|
methods:
|
|
- getProfitAndLoss
|
|
- getBalance
|
|
- getSummary
|
|
- getComparison
|
|
- getTrends
|
|
controllers:
|
|
- name: "AnalyticReportController"
|
|
file: "src/modules/analytics/controllers/analytic-report.controller.ts"
|
|
dtos:
|
|
- name: "AnalyticReportFilterDto"
|
|
file: "src/modules/analytics/dto/analytic-report-filter.dto.ts"
|
|
- name: "AnalyticReportResponseDto"
|
|
file: "src/modules/analytics/dto/analytic-report-response.dto.ts"
|
|
|
|
et_frontend:
|
|
file: "especificaciones-tecnicas/frontend/mgn-008/ET-FRONTEND-MGN-008-005-reportes-analíticos-p&l-por-proyecto.md"
|
|
routes:
|
|
- path: "/analytics/reports"
|
|
component: "AnalyticReportsPage"
|
|
- path: "/analytics/reports/pl"
|
|
component: "AnalyticPLPage"
|
|
- path: "/analytics/reports/balance"
|
|
component: "AnalyticBalancePage"
|
|
components:
|
|
- name: "AnalyticReportDashboard"
|
|
file: "src/widgets/analytic-report-dashboard/ui/AnalyticReportDashboard.tsx"
|
|
type: widget
|
|
- name: "AnalyticChart"
|
|
file: "src/features/analytic-chart/ui/AnalyticChart.tsx"
|
|
type: feature
|
|
- name: "AnalyticReportFilters"
|
|
file: "src/entities/analytic-report/ui/AnalyticReportFilters.tsx"
|
|
type: entity
|
|
- name: "AnalyticReportsPage"
|
|
file: "src/pages/analytics/AnalyticReportsPage.tsx"
|
|
type: page
|
|
api_client:
|
|
- name: "analyticReportApi"
|
|
file: "src/entities/analytic-report/api/analytic-report.api.ts"
|
|
methods:
|
|
- getPL
|
|
- getBalance
|
|
- getSummary
|
|
- getComparison
|
|
- getTrends
|
|
state_management:
|
|
- name: "useAnalyticReportStore"
|
|
file: "src/entities/analytic-report/model/analytic-report.store.ts"
|
|
type: zustand
|
|
- name: "useAnalyticReports"
|
|
file: "src/entities/analytic-report/api/analytic-report.queries.ts"
|
|
type: react-query
|
|
|
|
database_tables:
|
|
- schema: analytics
|
|
table: analytic_lines
|
|
file: "database-design/schemas/analytics-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
indices:
|
|
- idx_analytic_lines_date
|
|
- idx_analytic_lines_account_id
|
|
rls_policy: tenant_isolation_analytic_lines
|
|
- schema: analytics
|
|
table: analytic_accounts
|
|
file: "database-design/schemas/analytics-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
indices:
|
|
- idx_analytic_accounts_tenant_id
|
|
rls_policy: tenant_isolation_analytic_accounts
|
|
|
|
tests:
|
|
backend:
|
|
unit_tests:
|
|
- file: "src/modules/analytics/services/analytic-report.service.spec.ts"
|
|
test_cases:
|
|
- "should generate P&L report by account"
|
|
- "should calculate income, expenses, and profit"
|
|
- "should generate balance report"
|
|
- "should compare multiple accounts"
|
|
- "should calculate trends over time"
|
|
integration_tests:
|
|
- file: "test/analytics/analytic-report.controller.e2e-spec.ts"
|
|
test_cases:
|
|
- "GET /api/v1/analytics/reports/pl should return P&L report"
|
|
- "GET /api/v1/analytics/reports/balance should return balance"
|
|
- "GET /api/v1/analytics/reports/summary should return summary"
|
|
- "GET /api/v1/analytics/reports/comparison should compare accounts"
|
|
- "GET /api/v1/analytics/reports/trends should return trends"
|
|
- "should enforce tenant isolation"
|
|
- "should require authentication"
|
|
- "should check permissions"
|
|
frontend:
|
|
component_tests:
|
|
- file: "src/widgets/analytic-report-dashboard/ui/AnalyticReportDashboard.test.tsx"
|
|
test_cases:
|
|
- "should render dashboard with charts"
|
|
- "should apply filters"
|
|
- "should export report"
|
|
- file: "src/features/analytic-chart/ui/AnalyticChart.test.tsx"
|
|
test_cases:
|
|
- "should render chart with data"
|
|
- "should change chart type"
|
|
- "should handle empty data"
|
|
e2e_tests:
|
|
- file: "e2e/analytics/analytic-reports.spec.ts"
|
|
test_cases:
|
|
- "should display P&L report"
|
|
- "should filter by date range"
|
|
- "should export to PDF/Excel"
|
|
- "should enforce permissions"
|
|
|
|
acceptance_criteria:
|
|
- id: AC-001
|
|
description: "Usuario puede generar P&L por cuenta analítica"
|
|
status: Pending
|
|
test_reference: "test/analytics/analytic-report.controller.e2e-spec.ts:42"
|
|
- id: AC-002
|
|
description: "Reporte muestra ingresos, costos y margen neto"
|
|
status: Pending
|
|
test_reference: "src/modules/analytics/services/analytic-report.service.spec.ts:78"
|
|
- id: AC-003
|
|
description: "Reportes soportan filtros por fecha, tags y cuentas"
|
|
status: Pending
|
|
test_reference: "test/analytics/analytic-report.controller.e2e-spec.ts:115"
|
|
|
|
business_rules:
|
|
- id: RN-001
|
|
description: "P&L suma líneas positivas como ingresos, negativas como costos"
|
|
implementation: "src/modules/analytics/services/analytic-report.service.ts:calculatePL()"
|
|
test_reference: "src/modules/analytics/services/analytic-report.service.spec.ts:98"
|
|
- id: RN-002
|
|
description: "Margen = Ingresos - Costos, expresado también en porcentaje"
|
|
implementation: "src/modules/analytics/services/analytic-report.service.ts:calculateMargin()"
|
|
test_reference: "src/modules/analytics/services/analytic-report.service.spec.ts:125"
|
|
- id: RN-003
|
|
description: "Reportes solo incluyen líneas de cuentas activas"
|
|
implementation: "src/modules/analytics/services/analytic-report.service.ts:filterActiveAccounts()"
|
|
test_reference: "src/modules/analytics/services/analytic-report.service.spec.ts:152"
|
|
|
|
dependencies:
|
|
rf_dependencies:
|
|
- RF-MGN-008-001
|
|
- RF-MGN-008-002
|
|
module_dependencies:
|
|
- MGN-001
|
|
- MGN-012
|
|
external_dependencies:
|
|
- name: "chart.js"
|
|
version: "^4.0.0"
|
|
- name: "exceljs"
|
|
version: "^4.3.0"
|
|
|
|
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: 25
|
|
total_components: 20
|
|
total_tables: 6
|
|
total_test_cases: 100
|
|
estimated_duration_sprints: 2
|