erp-construccion-database-v2/schemas/08-finance-schema-ddl.sql
Adrian Flores Cortes 3e3d2d6eac [MAE-014] feat: Add finance schema DDL with 11 tables and 20 ENUMs
- chart_of_accounts: Catalogo de cuentas contables con jerarquia
- accounting_entries: Polizas contables
- accounting_entry_lines: Lineas de poliza
- accounts_payable: Cuentas por pagar
- accounts_receivable: Cuentas por cobrar
- bank_accounts: Cuentas bancarias
- bank_movements: Movimientos bancarios
- bank_reconciliations: Conciliacion bancaria
- ap_payments: Pagos a proveedores
- ar_payments: Cobros de clientes
- cash_flow_projections: Flujo de efectivo

Includes: RLS, indices, triggers, audit functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 05:08:19 -06:00

1236 lines
40 KiB
PL/PgSQL

-- ============================================================================
-- 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
-- ============================================================================