8.9 KiB
US-MGN-004-001-002: Jerarquía y Vista Árbol de Cuentas Contables
RF Asociado: RF-MGN-004-001 Módulo: MGN-004 - Financiero Básico Epic: Plan de Cuentas Prioridad: P0 (MVP) Story Points: 3 Sprint: Sprint 7 Estado: Ready for Development Fecha: 2025-11-24
User Story
Como contador de la empresa, Quiero organizar las cuentas contables en una estructura jerárquica (árbol), Para agrupar las cuentas por categorías y subcategorías y visualizarlas de forma organizada.
Descripción Detallada
Esta user story implementa la funcionalidad de jerarquía de cuentas contables mediante el uso del campo parent_id. Permite:
- Crear cuentas con cuentas padre (subcuentas)
- Visualizar el plan de cuentas como árbol jerárquico
- Calcular niveles de profundidad (nivel 0 = cuenta raíz, nivel 1 = hijos directos, etc.)
- Navegar por la jerarquía (expandir/colapsar nodos)
Ejemplo de jerarquía:
1 - Activos (parent_id: null)
1.1 - Activos Corrientes (parent_id: 1)
1.1.01 - Efectivo y Equivalentes (parent_id: 1.1)
1.1.01.001 - Caja General (parent_id: 1.1.01)
1.1.01.002 - Banco Santander (parent_id: 1.1.01)
Criterios de Aceptación
Escenario 1: Crear cuenta con cuenta padre
Dado que tengo una cuenta padre "1.1 Activos Corrientes" con id=10, Cuando creo una cuenta "1.1.01 Efectivo" con parent_id=10, Entonces el sistema crea la cuenta y establece la relación jerárquica correctamente.
Escenario 2: Obtener árbol jerárquico de cuentas
Dado que tengo cuentas con jerarquía definida, Cuando solicito GET /api/v1/financial/accounts/tree, Entonces el sistema retorna un JSON con estructura de árbol incluyendo hijos (children array).
Escenario 3: Validar que parent_id existe
Dado que intento crear una cuenta con parent_id=999 (no existe), Cuando envío el request, Entonces el sistema retorna error 400 "Cuenta padre no encontrada".
Escenario 4: Prevenir ciclos en jerarquía
Dado que tengo cuenta A (id=1) con parent_id=null, Cuando intento actualizar cuenta A con parent_id=1 (a sí misma), Entonces el sistema retorna error 400 "Una cuenta no puede ser su propia cuenta padre".
Escenario 5: Calcular nivel jerárquico
Dado que tengo una cuenta con 3 niveles de padres, Cuando consulto el endpoint GET /api/v1/financial/accounts/:id?include=hierarchy_level, Entonces el sistema retorna hierarchy_level=3.
Reglas de Negocio
- RN-1: Una cuenta puede tener parent_id (opcional). Si parent_id=null, es cuenta raíz.
- RN-2: parent_id debe existir en la tabla accounts y pertenecer a la misma empresa.
- RN-3: Una cuenta no puede ser su propia cuenta padre (prevenir ciclos directos).
- RN-4: No se permiten ciclos indirectos (A → B → C → A). Validar recursivamente.
- RN-5: Nivel jerárquico se calcula recursivamente: nivel_padre + 1. Máximo 10 niveles.
- RN-6: Al eliminar (soft delete) una cuenta padre, las cuentas hijas NO se eliminan automáticamente.
Tareas Técnicas (Checklist de Implementación)
Backend
- Endpoint:
GET /api/v1/financial/accounts/tree(retorna estructura jerárquica) - Endpoint:
GET /api/v1/financial/accounts/:id/children(hijos directos) - Endpoint:
GET /api/v1/financial/accounts/:id/ancestors(padres hasta la raíz) - Service método:
AccountService.getTree()(construye árbol con children) - Service método:
AccountService.getChildren(parentId) - Service método:
AccountService.getAncestors(accountId) - Service método:
AccountService.validateParent(parentId)(existe y no crea ciclos) - Service método:
AccountService.calculateLevel(accountId)(recursivo) - Validación: Prevenir ciclos directos e indirectos
- Unit tests: Jerarquía (6 test cases)
- Integration tests: Tree endpoints (5 test cases)
- Swagger docs para endpoints de jerarquía
Frontend
- Componente:
AccountTree.tsx(vista árbol con expandir/colapsar) - Componente:
AccountNode.tsx(nodo individual del árbol) - Componente:
AccountHierarchyBreadcrumb.tsx(breadcrumb de jerarquía) - Hook:
useAccountTree.ts(manejo de estado del árbol) - Función:
buildTree(flatAccounts)(convierte array plano a árbol) - Icono: Expandir/Colapsar nodos (chevron-right / chevron-down)
- Indentación visual por nivel (padding-left: nivel * 20px)
- Component tests: AccountTree.test.tsx (5 test cases)
- E2E test: "should expand and collapse account tree nodes"
Database
- Validar foreign key:
accounts.parent_id → accounts.id - Índice:
idx_accounts_parent_id(ya existe) - Query recursivo: Common Table Expression (CTE) para calcular niveles
- Seed data: Plan de cuentas jerárquico de ejemplo (3 niveles)
Mockups / Wireframes
Vista Árbol de Plan de Cuentas:
📂 1 - Activos [Editar] [+]
📂 1.1 - Activos Corrientes [Editar] [+]
📂 1.1.01 - Efectivo y Equivalentes [Editar] [+]
📄 1.1.01.001 - Caja General [Editar] [×]
📄 1.1.01.002 - Banco Santander [Editar] [×]
📂 1.1.02 - Cuentas por Cobrar [Editar] [+]
📂 2 - Pasivos [Editar] [+]
📂 2.1 - Pasivos Corrientes [Editar] [+]
Interacciones:
- Click en icono 📂 / 📄 : Expandir/colapsar nodos
- Click en [+]: Crear subcuenta
- Click en nombre: Ver detalle de cuenta
- Hover: Resaltar nodo completo
Casos de Prueba (Test Scenarios)
Pruebas Funcionales
-
TC-001: Crear cuenta con parent_id válido
- Input: parent_id=10 (existe)
- Expected: Status 201, cuenta creada con parent_id=10
-
TC-002: Error por parent_id inexistente
- Input: parent_id=999
- Expected: Status 400, error "Cuenta padre no encontrada"
-
TC-003: Prevenir ciclo directo (A → A)
- Input: id=1, parent_id=1
- Expected: Status 400, error "Cuenta no puede ser su propia padre"
-
TC-004: Prevenir ciclo indirecto (A → B → A)
- Input: Cuenta B (parent_id=A) luego actualizar A (parent_id=B)
- Expected: Status 400, error "Ciclo detectado en jerarquía"
-
TC-005: Obtener árbol jerárquico
- Input: GET /accounts/tree
- Expected: JSON con structure { id, code, name, children: [...] }
-
TC-006: Calcular nivel jerárquico correcto
- Input: Cuenta con 3 niveles de padres
- Expected: hierarchy_level=3
Pruebas No Funcionales
- Performance: GET /accounts/tree < 500ms (hasta 1000 cuentas)
- Usabilidad: Árbol carga niveles lazy (cargar hijos al expandir)
Dependencias
- US bloqueantes:
- US-MGN-004-001-001 (CRUD de Cuentas) - Requerido para crear cuentas base
- Módulos requeridos: MGN-004
Notas de Implementación
- Usar Common Table Expressions (CTE) recursivos para calcular niveles y ancestros:
WITH RECURSIVE account_hierarchy AS (
SELECT id, parent_id, code, name, 0 as level
FROM financial.accounts
WHERE parent_id IS NULL
UNION ALL
SELECT a.id, a.parent_id, a.code, a.name, ah.level + 1
FROM financial.accounts a
JOIN account_hierarchy ah ON a.parent_id = ah.id
)
SELECT * FROM account_hierarchy ORDER BY code;
- Validación de ciclos: Función recursiva que recorre padres hasta root o detecta ciclo
- Frontend: Usar
react-arboristoreact-complex-treepara vista árbol avanzada - Cache: Cachear árbol completo en Redis (TTL 10 minutos) para evitar recalcular
Estimación Detallada
| Tarea | Estimación |
|---|---|
| Backend Development | 2 horas |
| Frontend Development (Tree Component) | 2 horas |
| Testing | 1.5 horas |
| Code Review | 0.5 hora |
| TOTAL | 6 horas |
Equivalente: 3 Story Points
Definition of Done (DoD)
- Código backend implementado (tree endpoints + validación ciclos)
- Código frontend implementado (AccountTree component)
- Unit tests escritos y pasando (cobertura > 80%)
- Integration tests pasando
- E2E test pasando (expand/collapse tree)
- Code review aprobado
- Documentación Swagger actualizada
- RLS aplicado
- Merge a develop
- QA manual completado
- PO aprobado