-- ============================================================================ -- 08-finance-schema-ddl.sql -- Schema: finance -- ERP Construccion - Modulo Finanzas y Controlling (MAE-014) -- ============================================================================ -- Descripcion: Gestion financiera completa incluyendo: -- - Catalogo de cuentas contables (Chart of Accounts) -- - Polizas contables (Journal Entries) -- - Cuentas por pagar (Accounts Payable) -- - Cuentas por cobrar (Accounts Receivable) -- - Cuentas bancarias y movimientos -- - Conciliacion bancaria -- - Proyecciones de flujo de efectivo -- ============================================================================ -- Autor: Claude-Arquitecto-Orquestador -- Fecha: 2026-01-25 -- Version: 1.0.0 -- ============================================================================ -- Crear schema si no existe CREATE SCHEMA IF NOT EXISTS finance; -- ============================================================================ -- ENUMS -- ============================================================================ -- Tipo de cuenta contable CREATE TYPE finance.account_type AS ENUM ( 'asset', -- Activo 'liability', -- Pasivo 'equity', -- Capital 'income', -- Ingreso 'expense' -- Gasto ); -- Naturaleza de cuenta (deudora/acreedora) CREATE TYPE finance.account_nature AS ENUM ( 'debit', -- Deudora 'credit' -- Acreedora ); -- Estado de cuenta contable CREATE TYPE finance.account_status AS ENUM ( 'active', -- Activa 'inactive', -- Inactiva 'blocked' -- Bloqueada ); -- Tipo de poliza contable CREATE TYPE finance.entry_type AS ENUM ( 'purchase', -- Compra 'sale', -- Venta 'payment', -- Pago 'collection', -- Cobro 'payroll', -- Nomina 'adjustment', -- Ajuste 'depreciation', -- Depreciacion 'transfer', -- Traspaso 'opening', -- Apertura 'closing' -- Cierre ); -- Estado de poliza contable CREATE TYPE finance.entry_status AS ENUM ( 'draft', -- Borrador 'pending_approval', -- Pendiente de aprobacion 'approved', -- Aprobada 'posted', -- Contabilizada 'cancelled', -- Cancelada 'reversed' -- Reversada ); -- Tipo de documento CxP CREATE TYPE finance.ap_document_type AS ENUM ( 'invoice', -- Factura 'credit_note', -- Nota de credito 'debit_note', -- Nota de debito 'advance', -- Anticipo 'retention' -- Retencion ); -- Estado de CxP CREATE TYPE finance.ap_status AS ENUM ( 'pending', -- Pendiente 'partial', -- Parcialmente pagado 'paid', -- Pagado 'overdue', -- Vencido 'cancelled', -- Cancelado 'disputed' -- En disputa ); -- Tipo de documento CxC CREATE TYPE finance.ar_document_type AS ENUM ( 'invoice', -- Factura 'credit_note', -- Nota de credito 'debit_note', -- Nota de debito 'advance', -- Anticipo 'estimation' -- Estimacion ); -- Estado de CxC CREATE TYPE finance.ar_status AS ENUM ( 'pending', -- Pendiente 'partial', -- Parcialmente cobrado 'collected', -- Cobrado 'overdue', -- Vencido 'cancelled', -- Cancelado 'written_off' -- Incobrable ); -- Tipo de cuenta bancaria CREATE TYPE finance.bank_account_type AS ENUM ( 'checking', -- Cuenta de cheques 'savings', -- Cuenta de ahorro 'investment', -- Inversion 'credit_line', -- Linea de credito 'other' -- Otro ); -- Estado de cuenta bancaria CREATE TYPE finance.bank_account_status AS ENUM ( 'active', -- Activa 'inactive', -- Inactiva 'blocked', -- Bloqueada 'closed' -- Cerrada ); -- Tipo de movimiento bancario CREATE TYPE finance.bank_movement_type AS ENUM ( 'debit', -- Cargo 'credit' -- Abono ); -- Estado de movimiento bancario CREATE TYPE finance.bank_movement_status AS ENUM ( 'pending', -- Pendiente 'matched', -- Coincidente 'reconciled', -- Conciliado 'unreconciled', -- No conciliado 'ignored' -- Ignorado ); -- Origen de movimiento bancario CREATE TYPE finance.bank_movement_source AS ENUM ( 'manual', -- Manual 'import_file', -- Importacion de archivo 'api', -- API bancaria 'system' -- Sistema ); -- Metodo de pago CREATE TYPE finance.payment_method AS ENUM ( 'cash', -- Efectivo 'check', -- Cheque 'transfer', -- Transferencia 'card', -- Tarjeta 'compensation', -- Compensacion 'other' -- Otro ); -- Estado de pago (CxP) CREATE TYPE finance.payment_status AS ENUM ( 'pending', -- Pendiente 'processed', -- Procesado 'reconciled', -- Conciliado 'cancelled', -- Cancelado 'returned' -- Devuelto ); -- Metodo de cobro CREATE TYPE finance.collection_method AS ENUM ( 'cash', -- Efectivo 'check', -- Cheque 'transfer', -- Transferencia 'card', -- Tarjeta 'compensation', -- Compensacion 'other' -- Otro ); -- Estado de cobro (CxC) CREATE TYPE finance.collection_status AS ENUM ( 'pending', -- Pendiente 'deposited', -- Depositado 'reconciled', -- Conciliado 'cancelled', -- Cancelado 'returned' -- Devuelto ); -- Estado de conciliacion CREATE TYPE finance.reconciliation_status AS ENUM ( 'draft', -- Borrador 'in_progress', -- En proceso 'completed', -- Completada 'approved', -- Aprobada 'cancelled' -- Cancelada ); -- Tipo de flujo de efectivo CREATE TYPE finance.cash_flow_type AS ENUM ( 'projected', -- Proyectado 'actual', -- Real 'comparison' -- Comparativo ); -- Tipo de periodo de flujo CREATE TYPE finance.cash_flow_period_type AS ENUM ( 'daily', -- Diario 'weekly', -- Semanal 'monthly', -- Mensual 'quarterly' -- Trimestral ); -- ============================================================================ -- TABLAS -- ============================================================================ -- ---------------------------------------------------------------------------- -- 1. Catalogo de Cuentas Contables (Chart of Accounts) -- ---------------------------------------------------------------------------- CREATE TABLE finance.chart_of_accounts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Codigo jerarquico de cuenta code VARCHAR(50) NOT NULL, name VARCHAR(255) NOT NULL, description TEXT, -- Tipo y naturaleza account_type finance.account_type NOT NULL, nature finance.account_nature NOT NULL, status finance.account_status NOT NULL DEFAULT 'active', -- Jerarquia level INTEGER NOT NULL DEFAULT 1, parent_id UUID REFERENCES finance.chart_of_accounts(id), -- Configuracion de imputacion cost_center_required BOOLEAN NOT NULL DEFAULT FALSE, project_required BOOLEAN NOT NULL DEFAULT FALSE, allows_direct_posting BOOLEAN NOT NULL DEFAULT TRUE, -- Codigos de integracion con ERPs externos sap_code VARCHAR(50), contpaqi_code VARCHAR(50), aspel_code VARCHAR(50), -- Saldos (actualizados periodicamente) initial_balance DECIMAL(18,2) NOT NULL DEFAULT 0, current_balance DECIMAL(18,2) NOT NULL DEFAULT 0, balance_updated_at TIMESTAMPTZ, -- Notas y metadatos notes TEXT, metadata JSONB, -- Auditoria created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ, -- Constraints CONSTRAINT uq_chart_of_accounts_tenant_code UNIQUE (tenant_id, code) ); -- Tabla de closure para jerarquia (TypeORM Tree closure-table) CREATE TABLE finance.chart_of_accounts_closure ( id_ancestor UUID NOT NULL REFERENCES finance.chart_of_accounts(id) ON DELETE CASCADE, id_descendant UUID NOT NULL REFERENCES finance.chart_of_accounts(id) ON DELETE CASCADE, PRIMARY KEY (id_ancestor, id_descendant) ); -- ---------------------------------------------------------------------------- -- 2. Polizas Contables (Accounting Entries) -- ---------------------------------------------------------------------------- CREATE TABLE finance.accounting_entries ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Numero de poliza entry_number VARCHAR(50) NOT NULL, -- Tipo y fecha entry_type finance.entry_type NOT NULL, entry_date DATE NOT NULL, status finance.entry_status NOT NULL DEFAULT 'draft', -- Descripcion description TEXT NOT NULL, reference VARCHAR(255), -- Origen (modulo que genero la poliza) source_module VARCHAR(50), source_id UUID, -- Proyecto asociado project_id UUID, -- Periodo contable fiscal_year INTEGER NOT NULL, fiscal_period INTEGER NOT NULL, -- Totales (calculados) total_debit DECIMAL(18,2) NOT NULL DEFAULT 0, total_credit DECIMAL(18,2) NOT NULL DEFAULT 0, is_balanced BOOLEAN NOT NULL DEFAULT FALSE, -- Moneda currency VARCHAR(3) NOT NULL DEFAULT 'MXN', exchange_rate DECIMAL(12,6) NOT NULL DEFAULT 1, -- Aprobacion approved_by_id UUID, approved_at TIMESTAMPTZ, -- Contabilizacion posted_at TIMESTAMPTZ, posted_by_id UUID, -- Reversion reversed_entry_id UUID REFERENCES finance.accounting_entries(id), reversal_reason TEXT, -- Notas y metadatos notes TEXT, metadata JSONB, -- Auditoria created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ, -- Constraints CONSTRAINT uq_accounting_entries_tenant_number UNIQUE (tenant_id, entry_number) ); -- ---------------------------------------------------------------------------- -- 3. Lineas de Poliza Contable (Accounting Entry Lines) -- ---------------------------------------------------------------------------- CREATE TABLE finance.accounting_entry_lines ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Referencia a la poliza entry_id UUID NOT NULL REFERENCES finance.accounting_entries(id) ON DELETE CASCADE, -- Numero de linea line_number INTEGER NOT NULL, -- Cuenta contable account_id UUID NOT NULL REFERENCES finance.chart_of_accounts(id), account_code VARCHAR(50) NOT NULL, -- Descripcion de la linea description TEXT NOT NULL, -- Montos debit DECIMAL(18,2) NOT NULL DEFAULT 0, credit DECIMAL(18,2) NOT NULL DEFAULT 0, -- Centro de costo (opcional) cost_center_id UUID, cost_center_code VARCHAR(50), -- Proyecto (opcional) project_id UUID, project_code VARCHAR(50), -- Tercero (proveedor/cliente) partner_id UUID, partner_name VARCHAR(255), -- Documento de referencia document_type VARCHAR(50), document_number VARCHAR(100), -- Moneda original (si es diferente) original_currency VARCHAR(3), original_amount DECIMAL(18,2), -- Metadatos metadata JSONB, -- Auditoria created_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- ---------------------------------------------------------------------------- -- 4. Cuentas por Pagar (Accounts Payable) -- ---------------------------------------------------------------------------- CREATE TABLE finance.accounts_payable ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Numero de documento document_number VARCHAR(100) NOT NULL, document_type finance.ap_document_type NOT NULL DEFAULT 'invoice', -- Proveedor supplier_id UUID NOT NULL, supplier_name VARCHAR(255) NOT NULL, supplier_rfc VARCHAR(13), -- Estado status finance.ap_status NOT NULL DEFAULT 'pending', -- Fechas invoice_date DATE NOT NULL, received_date DATE, due_date DATE NOT NULL, payment_date DATE, -- Montos subtotal DECIMAL(18,2) NOT NULL, tax_amount DECIMAL(18,2) NOT NULL DEFAULT 0, retention_amount DECIMAL(18,2) NOT NULL DEFAULT 0, total_amount DECIMAL(18,2) NOT NULL, paid_amount DECIMAL(18,2) NOT NULL DEFAULT 0, balance DECIMAL(18,2) NOT NULL, -- Moneda currency VARCHAR(3) NOT NULL DEFAULT 'MXN', exchange_rate DECIMAL(12,6) NOT NULL DEFAULT 1, -- Origen (orden de compra, contrato) source_module VARCHAR(50), source_id UUID, purchase_order_number VARCHAR(50), -- Proyecto asociado project_id UUID, project_code VARCHAR(50), -- Centro de costo cost_center_id UUID, -- Cuenta contable de contrapartida expense_account_id UUID REFERENCES finance.chart_of_accounts(id), -- Condiciones de pago payment_terms VARCHAR(100), payment_days INTEGER NOT NULL DEFAULT 30, -- Dias de atraso (calculado) days_overdue INTEGER NOT NULL DEFAULT 0, -- CFDI (facturacion electronica Mexico) cfdi_uuid VARCHAR(36), cfdi_xml_path VARCHAR(500), cfdi_pdf_path VARCHAR(500), -- Aprobacion approved_for_payment BOOLEAN NOT NULL DEFAULT FALSE, approved_by_id UUID, approved_at TIMESTAMPTZ, -- Poliza contable generada accounting_entry_id UUID REFERENCES finance.accounting_entries(id), -- Notas y metadatos notes TEXT, metadata JSONB, -- Auditoria created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); -- ---------------------------------------------------------------------------- -- 5. Cuentas por Cobrar (Accounts Receivable) -- ---------------------------------------------------------------------------- CREATE TABLE finance.accounts_receivable ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Numero de documento document_number VARCHAR(100) NOT NULL, document_type finance.ar_document_type NOT NULL DEFAULT 'invoice', -- Cliente customer_id UUID NOT NULL, customer_name VARCHAR(255) NOT NULL, customer_rfc VARCHAR(13), -- Estado status finance.ar_status NOT NULL DEFAULT 'pending', -- Fechas invoice_date DATE NOT NULL, due_date DATE NOT NULL, collection_date DATE, -- Montos subtotal DECIMAL(18,2) NOT NULL, tax_amount DECIMAL(18,2) NOT NULL DEFAULT 0, retention_amount DECIMAL(18,2) NOT NULL DEFAULT 0, total_amount DECIMAL(18,2) NOT NULL, collected_amount DECIMAL(18,2) NOT NULL DEFAULT 0, balance DECIMAL(18,2) NOT NULL, -- Moneda currency VARCHAR(3) NOT NULL DEFAULT 'MXN', exchange_rate DECIMAL(12,6) NOT NULL DEFAULT 1, -- Origen (estimacion, venta) source_module VARCHAR(50), source_id UUID, estimation_number VARCHAR(50), -- Proyecto asociado project_id UUID, project_code VARCHAR(50), -- Condiciones de cobro payment_terms VARCHAR(100), payment_days INTEGER NOT NULL DEFAULT 30, -- Dias de atraso (calculado) days_overdue INTEGER NOT NULL DEFAULT 0, -- CFDI (facturacion electronica Mexico) cfdi_uuid VARCHAR(36), cfdi_xml_path VARCHAR(500), cfdi_pdf_path VARCHAR(500), -- Cuenta contable income_account_id UUID REFERENCES finance.chart_of_accounts(id), -- Poliza contable generada accounting_entry_id UUID REFERENCES finance.accounting_entries(id), -- Seguimiento de cobranza last_collection_attempt DATE, collection_attempts INTEGER NOT NULL DEFAULT 0, collection_notes TEXT, -- Notas y metadatos notes TEXT, metadata JSONB, -- Auditoria created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); -- ---------------------------------------------------------------------------- -- 6. Cuentas Bancarias (Bank Accounts) -- ---------------------------------------------------------------------------- CREATE TABLE finance.bank_accounts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Informacion de la cuenta name VARCHAR(100) NOT NULL, account_number VARCHAR(50) NOT NULL, clabe VARCHAR(18), account_type finance.bank_account_type NOT NULL DEFAULT 'checking', status finance.bank_account_status NOT NULL DEFAULT 'active', -- Banco bank_name VARCHAR(100) NOT NULL, bank_code VARCHAR(10), branch_name VARCHAR(100), branch_code VARCHAR(20), -- Moneda currency VARCHAR(3) NOT NULL DEFAULT 'MXN', -- Saldos initial_balance DECIMAL(18,2) NOT NULL DEFAULT 0, current_balance DECIMAL(18,2) NOT NULL DEFAULT 0, available_balance DECIMAL(18,2) NOT NULL DEFAULT 0, balance_updated_at TIMESTAMPTZ, -- Limites (para lineas de credito) credit_limit DECIMAL(18,2), minimum_balance DECIMAL(18,2), -- Proyecto asociado (si es cuenta especifica de proyecto) project_id UUID, project_code VARCHAR(50), -- Cuenta contable vinculada ledger_account_id UUID REFERENCES finance.chart_of_accounts(id), -- Contacto del banco bank_contact_name VARCHAR(255), bank_contact_phone VARCHAR(50), bank_contact_email VARCHAR(255), -- Conciliacion last_reconciliation_date DATE, last_reconciled_balance DECIMAL(18,2), -- Acceso banca en linea online_banking_user VARCHAR(100), supports_api BOOLEAN NOT NULL DEFAULT FALSE, -- Flags is_default BOOLEAN NOT NULL DEFAULT FALSE, allows_payments BOOLEAN NOT NULL DEFAULT TRUE, allows_collections BOOLEAN NOT NULL DEFAULT TRUE, -- Notas y metadatos notes TEXT, metadata JSONB, -- Auditoria created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ, -- Constraints CONSTRAINT uq_bank_accounts_tenant_number UNIQUE (tenant_id, account_number) ); -- ---------------------------------------------------------------------------- -- 7. Movimientos Bancarios (Bank Movements) -- ---------------------------------------------------------------------------- CREATE TABLE finance.bank_movements ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Cuenta bancaria bank_account_id UUID NOT NULL REFERENCES finance.bank_accounts(id), -- Referencia del movimiento movement_reference VARCHAR(100), bank_reference VARCHAR(100), -- Tipo y fecha movement_type finance.bank_movement_type NOT NULL, movement_date DATE NOT NULL, value_date DATE, -- Descripcion del banco description TEXT NOT NULL, bank_description TEXT, -- Monto amount DECIMAL(18,2) NOT NULL, currency VARCHAR(3) NOT NULL DEFAULT 'MXN', -- Saldo despues del movimiento balance_after DECIMAL(18,2), -- Estado de conciliacion status finance.bank_movement_status NOT NULL DEFAULT 'pending', -- Origen del movimiento source finance.bank_movement_source NOT NULL DEFAULT 'manual', import_batch_id UUID, -- Coincidencia automatica matched_payment_id UUID, matched_collection_id UUID, matched_entry_id UUID REFERENCES finance.accounting_entries(id), match_confidence DECIMAL(5,2), -- Conciliacion reconciliation_id UUID, reconciled_at TIMESTAMPTZ, reconciled_by_id UUID, -- Categorizacion category VARCHAR(100), subcategory VARCHAR(100), -- Tercero identificado partner_id UUID, partner_name VARCHAR(255), -- Flags is_duplicate BOOLEAN NOT NULL DEFAULT FALSE, requires_review BOOLEAN NOT NULL DEFAULT FALSE, -- Notas y metadatos notes TEXT, metadata JSONB, -- Datos originales del banco raw_data JSONB, -- Auditoria created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- ---------------------------------------------------------------------------- -- 8. Conciliaciones Bancarias (Bank Reconciliations) -- ---------------------------------------------------------------------------- CREATE TABLE finance.bank_reconciliations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Cuenta bancaria bank_account_id UUID NOT NULL REFERENCES finance.bank_accounts(id), -- Periodo de conciliacion period_start DATE NOT NULL, period_end DATE NOT NULL, -- Estado status finance.reconciliation_status NOT NULL DEFAULT 'draft', -- Saldos segun banco bank_opening_balance DECIMAL(18,2) NOT NULL, bank_closing_balance DECIMAL(18,2) NOT NULL, -- Saldos segun libros book_opening_balance DECIMAL(18,2) NOT NULL, book_closing_balance DECIMAL(18,2) NOT NULL, -- Partidas de conciliacion deposits_in_transit DECIMAL(18,2) NOT NULL DEFAULT 0, checks_in_transit DECIMAL(18,2) NOT NULL DEFAULT 0, bank_charges_not_recorded DECIMAL(18,2) NOT NULL DEFAULT 0, interest_not_recorded DECIMAL(18,2) NOT NULL DEFAULT 0, other_adjustments DECIMAL(18,2) NOT NULL DEFAULT 0, -- Saldo conciliado reconciled_balance DECIMAL(18,2) NOT NULL, -- Diferencia (debe ser 0 si esta conciliado) difference DECIMAL(18,2) NOT NULL DEFAULT 0, is_balanced BOOLEAN NOT NULL DEFAULT FALSE, -- Contadores total_movements INTEGER NOT NULL DEFAULT 0, reconciled_movements INTEGER NOT NULL DEFAULT 0, pending_movements INTEGER NOT NULL DEFAULT 0, -- Estado de cuenta bancario (archivo importado) statement_file_path VARCHAR(500), statement_import_date TIMESTAMPTZ, -- Fechas de proceso started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, -- Aprobacion approved_by_id UUID, approved_at TIMESTAMPTZ, -- Poliza de ajuste generada adjustment_entry_id UUID REFERENCES finance.accounting_entries(id), -- Notas y metadatos notes TEXT, reconciliation_items JSONB, metadata JSONB, -- Auditoria created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); -- ---------------------------------------------------------------------------- -- 9. Pagos a Proveedores (AP Payments) -- ---------------------------------------------------------------------------- CREATE TABLE finance.ap_payments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Numero de pago payment_number VARCHAR(50) NOT NULL, -- Cuenta por pagar asociada account_payable_id UUID NOT NULL REFERENCES finance.accounts_payable(id), -- Metodo de pago payment_method finance.payment_method NOT NULL, status finance.payment_status NOT NULL DEFAULT 'pending', -- Fecha de pago payment_date DATE NOT NULL, -- Monto amount DECIMAL(18,2) NOT NULL, currency VARCHAR(3) NOT NULL DEFAULT 'MXN', exchange_rate DECIMAL(12,6) NOT NULL DEFAULT 1, -- Cuenta bancaria de origen bank_account_id UUID REFERENCES finance.bank_accounts(id), -- Detalles del instrumento de pago check_number VARCHAR(50), transfer_reference VARCHAR(100), authorization_code VARCHAR(50), -- Beneficiario beneficiary_name VARCHAR(255), beneficiary_bank VARCHAR(100), beneficiary_account VARCHAR(50), beneficiary_clabe VARCHAR(18), -- Poliza contable generada accounting_entry_id UUID REFERENCES finance.accounting_entries(id), -- Conciliacion bancaria bank_movement_id UUID REFERENCES finance.bank_movements(id), reconciled_at TIMESTAMPTZ, -- Notas y metadatos notes TEXT, metadata JSONB, -- Auditoria created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); -- ---------------------------------------------------------------------------- -- 10. Cobros de Clientes (AR Payments) -- ---------------------------------------------------------------------------- CREATE TABLE finance.ar_payments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Numero de cobro collection_number VARCHAR(50) NOT NULL, -- Cuenta por cobrar asociada account_receivable_id UUID NOT NULL REFERENCES finance.accounts_receivable(id), -- Metodo de cobro collection_method finance.collection_method NOT NULL, status finance.collection_status NOT NULL DEFAULT 'pending', -- Fecha de cobro collection_date DATE NOT NULL, deposit_date DATE, -- Monto amount DECIMAL(18,2) NOT NULL, currency VARCHAR(3) NOT NULL DEFAULT 'MXN', exchange_rate DECIMAL(12,6) NOT NULL DEFAULT 1, -- Cuenta bancaria de destino bank_account_id UUID REFERENCES finance.bank_accounts(id), -- Detalles del instrumento de cobro check_number VARCHAR(50), check_bank VARCHAR(100), transfer_reference VARCHAR(100), -- Pagador (si es diferente al cliente) payer_name VARCHAR(255), payer_bank VARCHAR(100), payer_account VARCHAR(50), -- Poliza contable generada accounting_entry_id UUID REFERENCES finance.accounting_entries(id), -- Conciliacion bancaria bank_movement_id UUID REFERENCES finance.bank_movements(id), reconciled_at TIMESTAMPTZ, -- Notas y metadatos notes TEXT, metadata JSONB, -- Auditoria created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); -- ---------------------------------------------------------------------------- -- 11. Proyecciones de Flujo de Efectivo (Cash Flow Projections) -- ---------------------------------------------------------------------------- CREATE TABLE finance.cash_flow_projections ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, -- Tipo de flujo flow_type finance.cash_flow_type NOT NULL, period_type finance.cash_flow_period_type NOT NULL DEFAULT 'weekly', -- Periodo period_start DATE NOT NULL, period_end DATE NOT NULL, fiscal_year INTEGER NOT NULL, fiscal_period INTEGER NOT NULL, -- Proyecto (opcional, si es por proyecto) project_id UUID, project_code VARCHAR(50), -- Saldo inicial opening_balance DECIMAL(18,2) NOT NULL, -- INGRESOS OPERATIVOS income_estimations DECIMAL(18,2) NOT NULL DEFAULT 0, income_sales DECIMAL(18,2) NOT NULL DEFAULT 0, income_advances DECIMAL(18,2) NOT NULL DEFAULT 0, income_other DECIMAL(18,2) NOT NULL DEFAULT 0, total_income DECIMAL(18,2) NOT NULL DEFAULT 0, -- EGRESOS OPERATIVOS expense_suppliers DECIMAL(18,2) NOT NULL DEFAULT 0, expense_subcontractors DECIMAL(18,2) NOT NULL DEFAULT 0, expense_payroll DECIMAL(18,2) NOT NULL DEFAULT 0, expense_taxes DECIMAL(18,2) NOT NULL DEFAULT 0, expense_operating DECIMAL(18,2) NOT NULL DEFAULT 0, expense_other DECIMAL(18,2) NOT NULL DEFAULT 0, total_expenses DECIMAL(18,2) NOT NULL DEFAULT 0, -- FLUJO NETO OPERATIVO net_operating_flow DECIMAL(18,2) NOT NULL DEFAULT 0, -- INVERSION investing_income DECIMAL(18,2) NOT NULL DEFAULT 0, investing_expense DECIMAL(18,2) NOT NULL DEFAULT 0, net_investing_flow DECIMAL(18,2) NOT NULL DEFAULT 0, -- FINANCIAMIENTO financing_income DECIMAL(18,2) NOT NULL DEFAULT 0, financing_expense DECIMAL(18,2) NOT NULL DEFAULT 0, net_financing_flow DECIMAL(18,2) NOT NULL DEFAULT 0, -- TOTALES net_cash_flow DECIMAL(18,2) NOT NULL DEFAULT 0, closing_balance DECIMAL(18,2) NOT NULL, -- Varianza (para comparaciones) projected_amount DECIMAL(18,2), actual_amount DECIMAL(18,2), variance_amount DECIMAL(18,2), variance_percentage DECIMAL(8,2), -- Desglose detallado (JSON) income_breakdown JSONB, expense_breakdown JSONB, -- Estado is_locked BOOLEAN NOT NULL DEFAULT FALSE, locked_at TIMESTAMPTZ, -- Notas y metadatos notes TEXT, variance_notes TEXT, metadata JSONB, -- Auditoria created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); -- ============================================================================ -- INDICES -- ============================================================================ -- Chart of Accounts CREATE INDEX idx_chart_of_accounts_tenant ON finance.chart_of_accounts(tenant_id); CREATE INDEX idx_chart_of_accounts_tenant_type ON finance.chart_of_accounts(tenant_id, account_type); CREATE INDEX idx_chart_of_accounts_parent ON finance.chart_of_accounts(parent_id); -- Accounting Entries CREATE INDEX idx_accounting_entries_tenant ON finance.accounting_entries(tenant_id); CREATE INDEX idx_accounting_entries_tenant_date ON finance.accounting_entries(tenant_id, entry_date); CREATE INDEX idx_accounting_entries_tenant_status ON finance.accounting_entries(tenant_id, status); CREATE INDEX idx_accounting_entries_source ON finance.accounting_entries(tenant_id, source_module, source_id); -- Accounting Entry Lines CREATE INDEX idx_accounting_entry_lines_tenant ON finance.accounting_entry_lines(tenant_id); CREATE INDEX idx_accounting_entry_lines_entry ON finance.accounting_entry_lines(tenant_id, entry_id); CREATE INDEX idx_accounting_entry_lines_account ON finance.accounting_entry_lines(tenant_id, account_id); -- Accounts Payable CREATE INDEX idx_accounts_payable_tenant ON finance.accounts_payable(tenant_id); CREATE INDEX idx_accounts_payable_supplier ON finance.accounts_payable(tenant_id, supplier_id); CREATE INDEX idx_accounts_payable_status ON finance.accounts_payable(tenant_id, status); CREATE INDEX idx_accounts_payable_due_date ON finance.accounts_payable(tenant_id, due_date); CREATE INDEX idx_accounts_payable_project ON finance.accounts_payable(tenant_id, project_id); -- Accounts Receivable CREATE INDEX idx_accounts_receivable_tenant ON finance.accounts_receivable(tenant_id); CREATE INDEX idx_accounts_receivable_customer ON finance.accounts_receivable(tenant_id, customer_id); CREATE INDEX idx_accounts_receivable_status ON finance.accounts_receivable(tenant_id, status); CREATE INDEX idx_accounts_receivable_due_date ON finance.accounts_receivable(tenant_id, due_date); CREATE INDEX idx_accounts_receivable_project ON finance.accounts_receivable(tenant_id, project_id); -- Bank Accounts CREATE INDEX idx_bank_accounts_tenant ON finance.bank_accounts(tenant_id); CREATE INDEX idx_bank_accounts_status ON finance.bank_accounts(tenant_id, status); -- Bank Movements CREATE INDEX idx_bank_movements_tenant ON finance.bank_movements(tenant_id); CREATE INDEX idx_bank_movements_account ON finance.bank_movements(tenant_id, bank_account_id); CREATE INDEX idx_bank_movements_date ON finance.bank_movements(tenant_id, movement_date); CREATE INDEX idx_bank_movements_status ON finance.bank_movements(tenant_id, status); -- Bank Reconciliations CREATE INDEX idx_bank_reconciliations_tenant ON finance.bank_reconciliations(tenant_id); CREATE INDEX idx_bank_reconciliations_account ON finance.bank_reconciliations(tenant_id, bank_account_id); CREATE INDEX idx_bank_reconciliations_period ON finance.bank_reconciliations(tenant_id, period_end); CREATE INDEX idx_bank_reconciliations_status ON finance.bank_reconciliations(tenant_id, status); -- AP Payments CREATE INDEX idx_ap_payments_tenant ON finance.ap_payments(tenant_id); CREATE INDEX idx_ap_payments_ap ON finance.ap_payments(tenant_id, account_payable_id); CREATE INDEX idx_ap_payments_date ON finance.ap_payments(tenant_id, payment_date); CREATE INDEX idx_ap_payments_bank ON finance.ap_payments(tenant_id, bank_account_id); -- AR Payments CREATE INDEX idx_ar_payments_tenant ON finance.ar_payments(tenant_id); CREATE INDEX idx_ar_payments_ar ON finance.ar_payments(tenant_id, account_receivable_id); CREATE INDEX idx_ar_payments_date ON finance.ar_payments(tenant_id, collection_date); CREATE INDEX idx_ar_payments_bank ON finance.ar_payments(tenant_id, bank_account_id); -- Cash Flow Projections CREATE INDEX idx_cash_flow_tenant ON finance.cash_flow_projections(tenant_id); CREATE INDEX idx_cash_flow_project ON finance.cash_flow_projections(tenant_id, project_id); CREATE INDEX idx_cash_flow_period ON finance.cash_flow_projections(tenant_id, period_start, period_end); CREATE INDEX idx_cash_flow_type ON finance.cash_flow_projections(tenant_id, flow_type); -- ============================================================================ -- ROW LEVEL SECURITY (RLS) -- ============================================================================ -- Habilitar RLS en todas las tablas ALTER TABLE finance.chart_of_accounts ENABLE ROW LEVEL SECURITY; ALTER TABLE finance.accounting_entries ENABLE ROW LEVEL SECURITY; ALTER TABLE finance.accounting_entry_lines ENABLE ROW LEVEL SECURITY; ALTER TABLE finance.accounts_payable ENABLE ROW LEVEL SECURITY; ALTER TABLE finance.accounts_receivable ENABLE ROW LEVEL SECURITY; ALTER TABLE finance.bank_accounts ENABLE ROW LEVEL SECURITY; ALTER TABLE finance.bank_movements ENABLE ROW LEVEL SECURITY; ALTER TABLE finance.bank_reconciliations ENABLE ROW LEVEL SECURITY; ALTER TABLE finance.ap_payments ENABLE ROW LEVEL SECURITY; ALTER TABLE finance.ar_payments ENABLE ROW LEVEL SECURITY; ALTER TABLE finance.cash_flow_projections ENABLE ROW LEVEL SECURITY; -- Crear politicas de tenant isolation (asumiendo funcion current_tenant_id() existe) -- Estas politicas deben crearse despues de que exista la funcion en el schema auth -- ============================================================================ -- TRIGGERS DE AUDITORIA -- ============================================================================ -- Trigger para updated_at CREATE OR REPLACE FUNCTION finance.set_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; -- Aplicar trigger a todas las tablas con updated_at CREATE TRIGGER trg_chart_of_accounts_updated_at BEFORE UPDATE ON finance.chart_of_accounts FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); CREATE TRIGGER trg_accounting_entries_updated_at BEFORE UPDATE ON finance.accounting_entries FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); CREATE TRIGGER trg_accounting_entry_lines_updated_at BEFORE UPDATE ON finance.accounting_entry_lines FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); CREATE TRIGGER trg_accounts_payable_updated_at BEFORE UPDATE ON finance.accounts_payable FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); CREATE TRIGGER trg_accounts_receivable_updated_at BEFORE UPDATE ON finance.accounts_receivable FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); CREATE TRIGGER trg_bank_accounts_updated_at BEFORE UPDATE ON finance.bank_accounts FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); CREATE TRIGGER trg_bank_movements_updated_at BEFORE UPDATE ON finance.bank_movements FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); CREATE TRIGGER trg_bank_reconciliations_updated_at BEFORE UPDATE ON finance.bank_reconciliations FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); CREATE TRIGGER trg_ap_payments_updated_at BEFORE UPDATE ON finance.ap_payments FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); CREATE TRIGGER trg_ar_payments_updated_at BEFORE UPDATE ON finance.ar_payments FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); CREATE TRIGGER trg_cash_flow_projections_updated_at BEFORE UPDATE ON finance.cash_flow_projections FOR EACH ROW EXECUTE FUNCTION finance.set_updated_at(); -- ============================================================================ -- FUNCIONES AUXILIARES -- ============================================================================ -- Funcion para validar balance de poliza CREATE OR REPLACE FUNCTION finance.validate_entry_balance() RETURNS TRIGGER AS $$ DECLARE v_total_debit DECIMAL(18,2); v_total_credit DECIMAL(18,2); BEGIN SELECT COALESCE(SUM(debit), 0), COALESCE(SUM(credit), 0) INTO v_total_debit, v_total_credit FROM finance.accounting_entry_lines WHERE entry_id = NEW.entry_id; UPDATE finance.accounting_entries SET total_debit = v_total_debit, total_credit = v_total_credit, is_balanced = (v_total_debit = v_total_credit) WHERE id = NEW.entry_id; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_validate_entry_balance AFTER INSERT OR UPDATE OR DELETE ON finance.accounting_entry_lines FOR EACH ROW EXECUTE FUNCTION finance.validate_entry_balance(); -- Funcion para actualizar saldo de CxP CREATE OR REPLACE FUNCTION finance.update_ap_balance() RETURNS TRIGGER AS $$ DECLARE v_paid_amount DECIMAL(18,2); BEGIN SELECT COALESCE(SUM(amount), 0) INTO v_paid_amount FROM finance.ap_payments WHERE account_payable_id = COALESCE(NEW.account_payable_id, OLD.account_payable_id) AND status NOT IN ('cancelled', 'returned') AND deleted_at IS NULL; UPDATE finance.accounts_payable SET paid_amount = v_paid_amount, balance = total_amount - v_paid_amount, status = CASE WHEN v_paid_amount >= total_amount THEN 'paid'::finance.ap_status WHEN v_paid_amount > 0 THEN 'partial'::finance.ap_status ELSE status END WHERE id = COALESCE(NEW.account_payable_id, OLD.account_payable_id); RETURN COALESCE(NEW, OLD); END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_update_ap_balance AFTER INSERT OR UPDATE OR DELETE ON finance.ap_payments FOR EACH ROW EXECUTE FUNCTION finance.update_ap_balance(); -- Funcion para actualizar saldo de CxC CREATE OR REPLACE FUNCTION finance.update_ar_balance() RETURNS TRIGGER AS $$ DECLARE v_collected_amount DECIMAL(18,2); BEGIN SELECT COALESCE(SUM(amount), 0) INTO v_collected_amount FROM finance.ar_payments WHERE account_receivable_id = COALESCE(NEW.account_receivable_id, OLD.account_receivable_id) AND status NOT IN ('cancelled', 'returned') AND deleted_at IS NULL; UPDATE finance.accounts_receivable SET collected_amount = v_collected_amount, balance = total_amount - v_collected_amount, status = CASE WHEN v_collected_amount >= total_amount THEN 'collected'::finance.ar_status WHEN v_collected_amount > 0 THEN 'partial'::finance.ar_status ELSE status END WHERE id = COALESCE(NEW.account_receivable_id, OLD.account_receivable_id); RETURN COALESCE(NEW, OLD); END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_update_ar_balance AFTER INSERT OR UPDATE OR DELETE ON finance.ar_payments FOR EACH ROW EXECUTE FUNCTION finance.update_ar_balance(); -- ============================================================================ -- COMENTARIOS DE DOCUMENTACION -- ============================================================================ COMMENT ON SCHEMA finance IS 'Modulo de Finanzas y Controlling (MAE-014) - ERP Construccion'; COMMENT ON TABLE finance.chart_of_accounts IS 'Catalogo de cuentas contables con jerarquia'; COMMENT ON TABLE finance.accounting_entries IS 'Polizas contables (asientos contables)'; COMMENT ON TABLE finance.accounting_entry_lines IS 'Lineas de detalle de polizas contables'; COMMENT ON TABLE finance.accounts_payable IS 'Cuentas por pagar a proveedores'; COMMENT ON TABLE finance.accounts_receivable IS 'Cuentas por cobrar de clientes'; COMMENT ON TABLE finance.bank_accounts IS 'Cuentas bancarias de la empresa'; COMMENT ON TABLE finance.bank_movements IS 'Movimientos bancarios importados'; COMMENT ON TABLE finance.bank_reconciliations IS 'Procesos de conciliacion bancaria'; COMMENT ON TABLE finance.ap_payments IS 'Pagos realizados a proveedores'; COMMENT ON TABLE finance.ar_payments IS 'Cobros recibidos de clientes'; COMMENT ON TABLE finance.cash_flow_projections IS 'Proyecciones de flujo de efectivo'; -- ============================================================================ -- FIN DEL SCRIPT -- ============================================================================