338 lines
10 KiB
Markdown
338 lines
10 KiB
Markdown
# MODELO DE DOMINIO: Contabilidad Analítica
|
|
|
|
**Módulos:** MGN-008 (Contabilidad Analítica)
|
|
**Fecha:** 2025-11-24
|
|
**Referencia Odoo:** analytic
|
|
**Referencia Gamilit:** No implementado
|
|
|
|
---
|
|
|
|
## Diagrama de Entidades (Texto UML)
|
|
|
|
```
|
|
[AnalyticAccount]
|
|
- id: UUID (PK)
|
|
- tenant_id: UUID (FK)
|
|
- company_id: UUID (FK)
|
|
- name: String
|
|
- code: String
|
|
- account_type: ENUM (project, department, cost_center, customer)
|
|
- parent_id: UUID (FK self)
|
|
- partner_id: UUID (FK)
|
|
- budget: Decimal
|
|
- status: ENUM (active, inactive, closed)
|
|
|
|
1 <----> * [AnalyticLine]
|
|
1 <----> * [AnalyticDistribution]
|
|
|
|
[AnalyticLine]
|
|
- id: UUID (PK)
|
|
- tenant_id: UUID (FK)
|
|
- company_id: UUID (FK)
|
|
- analytic_account_id: UUID (FK)
|
|
- date: Date
|
|
- amount: Decimal
|
|
- unit_amount: Decimal (horas, cantidad)
|
|
- product_id: UUID (FK)
|
|
- employee_id: UUID (FK)
|
|
- description: String
|
|
- line_type: ENUM (expense, income, timesheet)
|
|
- source_document: String (ej: "invoice/123")
|
|
- source_model: String (ej: "Invoice")
|
|
- source_id: UUID
|
|
|
|
* <----> * [AnalyticTag]
|
|
|
|
[AnalyticDistribution]
|
|
- id: UUID (PK)
|
|
- source_line_id: UUID (FK)
|
|
- source_model: String (ej: "PurchaseOrderLine")
|
|
- analytic_account_id: UUID (FK)
|
|
- percentage: Decimal
|
|
- amount: Decimal
|
|
|
|
[AnalyticTag]
|
|
- id: UUID (PK)
|
|
- tenant_id: UUID (FK)
|
|
- name: String
|
|
- color: String
|
|
- tag_type: ENUM (phase, location, category)
|
|
|
|
* <----> * [AnalyticLine]
|
|
|
|
[AnalyticPlan]
|
|
- id: UUID (PK)
|
|
- tenant_id: UUID (FK)
|
|
- company_id: UUID (FK)
|
|
- name: String
|
|
- description: Text
|
|
|
|
1 <----> * [AnalyticAccount]
|
|
```
|
|
|
|
## Entidades Principales
|
|
|
|
### 1. AnalyticAccount (Cuenta Analítica)
|
|
**Descripción:** Cuenta para tracking de costos/ingresos por proyecto, departamento, centro de costo.
|
|
|
|
**Atributos:**
|
|
- `id`: UUID
|
|
- `name`: Nombre (ej: "Proyecto Torre A")
|
|
- `code`: Código (ej: "PRJ-001")
|
|
- `account_type`: project, department, cost_center, customer
|
|
- `parent_id`: Cuenta padre (jerarquía)
|
|
- `partner_id`: Cliente/Partner asociado
|
|
- `budget`: Presupuesto asignado
|
|
- `status`: active, inactive, closed
|
|
|
|
**Relaciones:**
|
|
- 1 AnalyticAccount → N AnalyticLines
|
|
- 1 AnalyticAccount → N Subdepartments
|
|
- 1 AnalyticAccount → 1 Project (MGN-011)
|
|
|
|
**Patrón Odoo:** account.analytic.account
|
|
**Tipos:**
|
|
- project: Proyectos (vinculado a MGN-011)
|
|
- department: Departamentos
|
|
- cost_center: Centros de costo
|
|
- customer: Por cliente
|
|
|
|
### 2. AnalyticLine (Línea Analítica)
|
|
**Descripción:** Registro individual de costo o ingreso en cuenta analítica.
|
|
|
|
**Atributos:**
|
|
- `id`: UUID
|
|
- `analytic_account_id`: Cuenta analítica
|
|
- `date`: Fecha del registro
|
|
- `amount`: Monto (negativo=costo, positivo=ingreso)
|
|
- `unit_amount`: Cantidad (horas para timesheet, unidades para productos)
|
|
- `product_id`: Producto asociado (opcional)
|
|
- `employee_id`: Empleado asociado (para timesheet)
|
|
- `description`: Descripción
|
|
- `line_type`: expense, income, timesheet
|
|
- `source_document`: Documento origen (ej: "invoice/123")
|
|
- `source_model`: Modelo origen (ej: "Invoice")
|
|
- `source_id`: ID del registro origen
|
|
|
|
**Relaciones:**
|
|
- N AnalyticLines → 1 AnalyticAccount
|
|
- N AnalyticLines ←→ N AnalyticTags
|
|
|
|
**Patrón Odoo:** account.analytic.line
|
|
**Creación:**
|
|
- Manual: Usuario crea línea directamente
|
|
- Automática: Generada desde transacciones (facturas, PO, SO, timesheet)
|
|
|
|
### 3. AnalyticDistribution (Distribución Analítica)
|
|
**Descripción:** Distribución de un monto a múltiples cuentas analíticas.
|
|
|
|
**Atributos:**
|
|
- `id`: UUID
|
|
- `source_line_id`: Línea origen (ej: PurchaseOrderLine)
|
|
- `source_model`: Modelo origen
|
|
- `analytic_account_id`: Cuenta analítica destino
|
|
- `percentage`: Porcentaje (ej: 60%)
|
|
- `amount`: Monto calculado
|
|
|
|
**Relaciones:**
|
|
- N AnalyticDistributions → 1 AnalyticAccount
|
|
|
|
**Patrón Odoo:** account.analytic.distribution (Odoo 16+)
|
|
**Validación:** SUM(percentage) = 100% por source_line_id
|
|
|
|
**Ejemplo:**
|
|
```
|
|
Compra de $10,000
|
|
- 60% → Proyecto A ($6,000)
|
|
- 40% → Proyecto B ($4,000)
|
|
```
|
|
|
|
### 4. AnalyticTag (Etiqueta Analítica)
|
|
**Descripción:** Etiqueta adicional para clasificación analítica.
|
|
|
|
**Atributos:**
|
|
- `id`: UUID
|
|
- `name`: Nombre (ej: "Fase 1", "Torre Norte")
|
|
- `color`: Color para UI
|
|
- `tag_type`: phase, location, category
|
|
|
|
**Relaciones:**
|
|
- N AnalyticTags ←→ N AnalyticLines
|
|
|
|
**Patrón Odoo:** account.analytic.tag
|
|
**Uso:** Clasificación adicional cross-cutting (no jerárquica)
|
|
|
|
**Ejemplos:**
|
|
- Tags de fase: "Planeación", "Ejecución", "Cierre"
|
|
- Tags de ubicación: "Torre A", "Torre B", "Área Común"
|
|
- Tags de categoría: "CAPEX", "OPEX"
|
|
|
|
### 5. AnalyticPlan (Plan Analítico)
|
|
**Descripción:** Agrupación de cuentas analíticas (opcional, para multi-dimensión).
|
|
|
|
**Atributos:**
|
|
- `id`: UUID
|
|
- `name`: Nombre del plan
|
|
- `description`: Descripción
|
|
|
|
**Relaciones:**
|
|
- 1 AnalyticPlan → N AnalyticAccounts
|
|
|
|
**Patrón Odoo:** account.analytic.plan (Odoo 16+)
|
|
**Uso:** Análisis multi-dimensional (por proyecto, por departamento, etc.)
|
|
|
|
## Reglas de Negocio
|
|
|
|
### RN-ANA-001: Generación Automática de Líneas
|
|
- Al validar factura: generar líneas analíticas desde invoice_lines con analytic_account_id
|
|
- Al validar PO: generar líneas desde purchase_order_lines
|
|
- Al validar SO: generar líneas desde sale_order_lines
|
|
- Al validar timesheet: generar líneas desde timesheet
|
|
|
|
### RN-ANA-002: Tipo de Línea
|
|
- expense: Monto negativo (costos)
|
|
- Compras, gastos, timesheet
|
|
- income: Monto positivo (ingresos)
|
|
- Ventas, facturación
|
|
- timesheet: Tipo especial (puede ser expense si se valora)
|
|
|
|
### RN-ANA-003: Distribución 100%
|
|
- Si línea tiene distribución analítica, SUM(percentage) = 100%
|
|
- Validación antes de guardar
|
|
|
|
### RN-ANA-004: Balance Analítico
|
|
- Balance = SUM(amount WHERE analytic_account_id = X)
|
|
- Balance positivo: más ingresos que costos
|
|
- Balance negativo: más costos que ingresos
|
|
|
|
### RN-ANA-005: Jerarquía de Cuentas
|
|
- Cuentas pueden tener parent_id (jerarquía)
|
|
- Balance se puede calcular recursivamente (cuenta + subcuentas)
|
|
|
|
### RN-ANA-006: Presupuesto vs Real
|
|
- budget: Presupuesto asignado
|
|
- real: SUM(amount WHERE line_type='expense')
|
|
- variance: budget - real
|
|
- Alertas si variance < 0 (sobre presupuesto)
|
|
|
|
### RN-ANA-007: Tags Multi-Dimensionales
|
|
- Una línea puede tener múltiples tags
|
|
- Filtros combinados: Proyecto X + Fase 1 + CAPEX
|
|
|
|
### RN-ANA-008: Inmutabilidad
|
|
- Líneas analíticas generadas automáticamente no se editan manualmente
|
|
- Si se corrige documento origen, se regeneran líneas
|
|
|
|
## Casos de Uso Principales
|
|
|
|
1. **UC-ANA-001:** Administrador crea cuenta analítica para proyecto
|
|
2. **UC-ANA-002:** Usuario asigna cuenta analítica a línea de PO
|
|
3. **UC-ANA-003:** Usuario distribuye costo a múltiples cuentas (60%-40%)
|
|
4. **UC-ANA-004:** Sistema genera líneas analíticas al validar factura
|
|
5. **UC-ANA-005:** Empleado registra timesheet → genera línea analítica
|
|
6. **UC-ANA-006:** Usuario consulta balance por cuenta analítica (P&L por proyecto)
|
|
7. **UC-ANA-007:** Usuario compara presupuesto vs real
|
|
8. **UC-ANA-008:** Usuario filtra líneas analíticas por tags
|
|
9. **UC-ANA-009:** Gerente consulta reporte de rentabilidad por proyecto
|
|
|
|
## Validaciones y Constraints
|
|
|
|
```sql
|
|
-- Code único por company
|
|
UNIQUE (tenant_id, company_id, code)
|
|
|
|
-- Cuenta no puede ser su propia padre
|
|
CHECK (parent_id != id)
|
|
|
|
-- Presupuesto >= 0
|
|
CHECK (budget >= 0)
|
|
|
|
-- Distribución: percentage entre 0 y 100
|
|
CHECK (percentage >= 0 AND percentage <= 100)
|
|
|
|
-- SUM(percentage) = 100 por source_line_id
|
|
-- (trigger custom)
|
|
|
|
-- unit_amount >= 0 (para timesheet)
|
|
CHECK (unit_amount >= 0)
|
|
```
|
|
|
|
## Índices Requeridos
|
|
|
|
```sql
|
|
CREATE INDEX idx_analytic_accounts_company_id ON analytics.analytic_accounts(company_id);
|
|
CREATE INDEX idx_analytic_accounts_parent_id ON analytics.analytic_accounts(parent_id);
|
|
CREATE INDEX idx_analytic_accounts_status ON analytics.analytic_accounts(status);
|
|
CREATE INDEX idx_analytic_lines_analytic_account_id ON analytics.analytic_lines(analytic_account_id);
|
|
CREATE INDEX idx_analytic_lines_date ON analytics.analytic_lines(date);
|
|
CREATE INDEX idx_analytic_lines_employee_id ON analytics.analytic_lines(employee_id);
|
|
CREATE INDEX idx_analytic_lines_line_type ON analytics.analytic_lines(line_type);
|
|
CREATE INDEX idx_analytic_distributions_source_line_id ON analytics.analytic_distributions(source_line_id);
|
|
CREATE INDEX idx_analytic_distributions_analytic_account_id ON analytics.analytic_distributions(analytic_account_id);
|
|
```
|
|
|
|
## Integración con Otros Módulos
|
|
|
|
### Con MGN-004 (Financiero)
|
|
- Invoice lines tienen analytic_account_id
|
|
- Al validar invoice, genera analytic lines
|
|
|
|
### Con MGN-006 (Compras)
|
|
- Purchase order lines tienen analytic_account_id
|
|
- Al validar PO, genera analytic lines (expense)
|
|
|
|
### Con MGN-007 (Ventas)
|
|
- Sale order lines tienen analytic_account_id
|
|
- Al validar SO, genera analytic lines (income)
|
|
|
|
### Con MGN-010 (RRHH)
|
|
- Timesheet tiene analytic_account_id
|
|
- Al validar timesheet, genera analytic lines (expense o neutral)
|
|
|
|
### Con MGN-011 (Proyectos)
|
|
- Project tiene analytic_account_id (1-1)
|
|
- Todos los costos/ingresos del proyecto se registran en su cuenta analítica
|
|
|
|
### Con MGN-012 (Reportes)
|
|
- Reportes analíticos:
|
|
- P&L por cuenta analítica
|
|
- Balance por proyecto
|
|
- Presupuesto vs Real
|
|
- Análisis por tags
|
|
|
|
## Vistas y Reportes Estándar
|
|
|
|
### 1. Balance Analítico
|
|
```sql
|
|
SELECT
|
|
analytic_account_id,
|
|
SUM(CASE WHEN line_type = 'expense' THEN amount ELSE 0 END) as total_costs,
|
|
SUM(CASE WHEN line_type = 'income' THEN amount ELSE 0 END) as total_income,
|
|
SUM(amount) as balance
|
|
FROM analytics.analytic_lines
|
|
WHERE tenant_id = :tenant_id
|
|
GROUP BY analytic_account_id
|
|
```
|
|
|
|
### 2. Presupuesto vs Real
|
|
```sql
|
|
SELECT
|
|
aa.name,
|
|
aa.budget,
|
|
SUM(al.amount) as real_cost,
|
|
aa.budget - SUM(al.amount) as variance
|
|
FROM analytics.analytic_accounts aa
|
|
LEFT JOIN analytics.analytic_lines al ON aa.id = al.analytic_account_id
|
|
WHERE al.line_type = 'expense'
|
|
GROUP BY aa.id
|
|
```
|
|
|
|
## Referencias
|
|
- [ALCANCE-POR-MODULO.md - MGN-008](../../01-definicion-modulos/ALCANCE-POR-MODULO.md#mgn-008)
|
|
- [ADR-007: Database Design](../../adr/ADR-007-database-design.md)
|
|
- [odoo-analytic-analysis.md](../../00-analisis-referencias/odoo/odoo-analytic-analysis.md)
|
|
|
|
---
|
|
|
|
**Importancia:** ⭐⭐⭐⭐⭐ CRÍTICO para ERPs de proyectos
|