# 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