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