🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1386 lines
52 KiB
PL/PgSQL
1386 lines
52 KiB
PL/PgSQL
-- =====================================================
|
|
-- SCHEMA: financial
|
|
-- PROPÓSITO: Contabilidad, facturas, pagos, finanzas
|
|
-- MÓDULOS: MGN-004 (Financiero Básico)
|
|
-- FECHA: 2025-11-24
|
|
-- =====================================================
|
|
|
|
-- Crear schema
|
|
CREATE SCHEMA IF NOT EXISTS financial;
|
|
|
|
-- =====================================================
|
|
-- TYPES (ENUMs)
|
|
-- =====================================================
|
|
|
|
CREATE TYPE financial.account_type AS ENUM (
|
|
'asset',
|
|
'liability',
|
|
'equity',
|
|
'revenue',
|
|
'expense'
|
|
);
|
|
|
|
CREATE TYPE financial.journal_type AS ENUM (
|
|
'sale',
|
|
'purchase',
|
|
'bank',
|
|
'cash',
|
|
'general'
|
|
);
|
|
|
|
CREATE TYPE financial.entry_status AS ENUM (
|
|
'draft',
|
|
'posted',
|
|
'cancelled'
|
|
);
|
|
|
|
CREATE TYPE financial.invoice_type AS ENUM (
|
|
'customer',
|
|
'supplier'
|
|
);
|
|
|
|
CREATE TYPE financial.invoice_status AS ENUM (
|
|
'draft',
|
|
'open',
|
|
'paid',
|
|
'cancelled'
|
|
);
|
|
|
|
CREATE TYPE financial.payment_type AS ENUM (
|
|
'inbound',
|
|
'outbound'
|
|
);
|
|
|
|
CREATE TYPE financial.payment_method AS ENUM (
|
|
'cash',
|
|
'bank_transfer',
|
|
'check',
|
|
'card',
|
|
'other'
|
|
);
|
|
|
|
CREATE TYPE financial.payment_status AS ENUM (
|
|
'draft',
|
|
'posted',
|
|
'reconciled',
|
|
'cancelled'
|
|
);
|
|
|
|
CREATE TYPE financial.tax_type AS ENUM (
|
|
'sales',
|
|
'purchase',
|
|
'all'
|
|
);
|
|
|
|
CREATE TYPE financial.fiscal_period_status AS ENUM (
|
|
'open',
|
|
'closed'
|
|
);
|
|
|
|
-- COR-004: Estado de pago separado del estado contable (Odoo alignment)
|
|
CREATE TYPE financial.payment_state AS ENUM (
|
|
'not_paid',
|
|
'in_payment',
|
|
'paid',
|
|
'partial',
|
|
'reversed'
|
|
);
|
|
|
|
-- =====================================================
|
|
-- TABLES
|
|
-- =====================================================
|
|
|
|
-- Tabla: account_types (Tipos de cuenta contable)
|
|
CREATE TABLE financial.account_types (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
code VARCHAR(20) NOT NULL UNIQUE,
|
|
name VARCHAR(100) NOT NULL,
|
|
account_type financial.account_type NOT NULL,
|
|
description TEXT,
|
|
|
|
-- Sin tenant_id: catálogo global
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Tabla: accounts (Plan de cuentas)
|
|
CREATE TABLE financial.accounts (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
code VARCHAR(50) NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
account_type_id UUID NOT NULL REFERENCES financial.account_types(id),
|
|
parent_id UUID REFERENCES financial.accounts(id),
|
|
|
|
-- Configuración
|
|
currency_id UUID REFERENCES core.currencies(id),
|
|
is_reconcilable BOOLEAN DEFAULT FALSE, -- ¿Permite conciliación?
|
|
is_deprecated BOOLEAN DEFAULT FALSE,
|
|
|
|
-- Notas
|
|
notes TEXT,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
deleted_at TIMESTAMP,
|
|
deleted_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT uq_accounts_code_company UNIQUE (company_id, code),
|
|
CONSTRAINT chk_accounts_no_self_parent CHECK (id != parent_id)
|
|
);
|
|
|
|
-- Tabla: journals (Diarios contables)
|
|
CREATE TABLE financial.journals (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
name VARCHAR(255) NOT NULL,
|
|
code VARCHAR(20) NOT NULL,
|
|
journal_type financial.journal_type NOT NULL,
|
|
|
|
-- Configuración
|
|
default_account_id UUID REFERENCES financial.accounts(id),
|
|
sequence_id UUID REFERENCES core.sequences(id),
|
|
currency_id UUID REFERENCES core.currencies(id),
|
|
|
|
-- Control
|
|
active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
deleted_at TIMESTAMP,
|
|
deleted_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT uq_journals_code_company UNIQUE (company_id, code)
|
|
);
|
|
|
|
-- Tabla: fiscal_years (Años fiscales)
|
|
CREATE TABLE financial.fiscal_years (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
name VARCHAR(100) NOT NULL,
|
|
code VARCHAR(20) NOT NULL,
|
|
start_date DATE NOT NULL,
|
|
end_date DATE NOT NULL,
|
|
status financial.fiscal_period_status NOT NULL DEFAULT 'open',
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT uq_fiscal_years_code_company UNIQUE (company_id, code),
|
|
CONSTRAINT chk_fiscal_years_dates CHECK (end_date > start_date)
|
|
);
|
|
|
|
-- Tabla: fiscal_periods (Períodos fiscales - meses)
|
|
CREATE TABLE financial.fiscal_periods (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
fiscal_year_id UUID NOT NULL REFERENCES financial.fiscal_years(id) ON DELETE CASCADE,
|
|
|
|
name VARCHAR(100) NOT NULL,
|
|
code VARCHAR(20) NOT NULL,
|
|
start_date DATE NOT NULL,
|
|
end_date DATE NOT NULL,
|
|
status financial.fiscal_period_status NOT NULL DEFAULT 'open',
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT uq_fiscal_periods_code_year UNIQUE (fiscal_year_id, code),
|
|
CONSTRAINT chk_fiscal_periods_dates CHECK (end_date > start_date)
|
|
);
|
|
|
|
-- Tabla: journal_entries (Asientos contables)
|
|
CREATE TABLE financial.journal_entries (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
journal_id UUID NOT NULL REFERENCES financial.journals(id),
|
|
name VARCHAR(100) NOT NULL, -- Número de asiento
|
|
ref VARCHAR(255), -- Referencia externa
|
|
date DATE NOT NULL,
|
|
status financial.entry_status NOT NULL DEFAULT 'draft',
|
|
|
|
-- Metadatos
|
|
notes TEXT,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
posted_at TIMESTAMP,
|
|
posted_by UUID REFERENCES auth.users(id),
|
|
cancelled_at TIMESTAMP,
|
|
cancelled_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT uq_journal_entries_name_journal UNIQUE (journal_id, name)
|
|
);
|
|
|
|
-- Tabla: journal_entry_lines (Líneas de asiento contable)
|
|
CREATE TABLE financial.journal_entry_lines (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
entry_id UUID NOT NULL REFERENCES financial.journal_entries(id) ON DELETE CASCADE,
|
|
|
|
account_id UUID NOT NULL REFERENCES financial.accounts(id),
|
|
partner_id UUID REFERENCES core.partners(id),
|
|
|
|
-- Montos
|
|
debit DECIMAL(15, 2) NOT NULL DEFAULT 0,
|
|
credit DECIMAL(15, 2) NOT NULL DEFAULT 0,
|
|
|
|
-- Analítica
|
|
analytic_account_id UUID, -- FK a analytics.analytic_accounts (se crea después)
|
|
|
|
-- Descripción
|
|
description TEXT,
|
|
ref VARCHAR(255),
|
|
|
|
-- Multi-moneda
|
|
currency_id UUID REFERENCES core.currencies(id),
|
|
amount_currency DECIMAL(15, 2),
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT chk_journal_lines_debit_positive CHECK (debit >= 0),
|
|
CONSTRAINT chk_journal_lines_credit_positive CHECK (credit >= 0),
|
|
CONSTRAINT chk_journal_lines_not_both CHECK (
|
|
(debit > 0 AND credit = 0) OR (credit > 0 AND debit = 0)
|
|
)
|
|
);
|
|
|
|
-- Índices para journal_entry_lines
|
|
CREATE INDEX idx_journal_entry_lines_tenant_id ON financial.journal_entry_lines(tenant_id);
|
|
CREATE INDEX idx_journal_entry_lines_entry_id ON financial.journal_entry_lines(entry_id);
|
|
CREATE INDEX idx_journal_entry_lines_account_id ON financial.journal_entry_lines(account_id);
|
|
|
|
-- RLS para journal_entry_lines
|
|
ALTER TABLE financial.journal_entry_lines ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY tenant_isolation_journal_entry_lines ON financial.journal_entry_lines
|
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
|
|
-- =====================================================
|
|
-- COR-005: Tabla tax_groups (Grupos de impuestos)
|
|
-- Equivalente a account.tax.group en Odoo
|
|
-- =====================================================
|
|
CREATE TABLE financial.tax_groups (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
name VARCHAR(100) NOT NULL,
|
|
sequence INTEGER DEFAULT 10,
|
|
country_id UUID, -- Futuro: countries table
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT uq_tax_groups_name_tenant UNIQUE (tenant_id, name)
|
|
);
|
|
|
|
COMMENT ON TABLE financial.tax_groups IS
|
|
'COR-005: Grupos de impuestos para clasificación y reporte (equivalente a account.tax.group Odoo)';
|
|
|
|
-- Tabla: taxes (Impuestos)
|
|
CREATE TABLE financial.taxes (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
name VARCHAR(100) NOT NULL,
|
|
code VARCHAR(20) NOT NULL,
|
|
rate DECIMAL(5, 4) NOT NULL, -- 0.1600 para 16%
|
|
tax_type financial.tax_type NOT NULL,
|
|
|
|
-- COR-005: Grupo de impuestos
|
|
tax_group_id UUID REFERENCES financial.tax_groups(id),
|
|
|
|
-- COR-005: Tipo de cálculo
|
|
amount_type VARCHAR(20) DEFAULT 'percent', -- percent, fixed, group, division
|
|
include_base_amount BOOLEAN DEFAULT FALSE,
|
|
price_include BOOLEAN DEFAULT FALSE,
|
|
children_tax_ids UUID[] DEFAULT '{}', -- Para impuestos compuestos
|
|
|
|
-- Configuración contable
|
|
account_id UUID REFERENCES financial.accounts(id),
|
|
refund_account_id UUID REFERENCES financial.accounts(id), -- COR-005: Cuenta para devoluciones
|
|
|
|
-- Control
|
|
active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT uq_taxes_code_company UNIQUE (company_id, code),
|
|
CONSTRAINT chk_taxes_rate CHECK (rate >= 0 AND rate <= 1),
|
|
CONSTRAINT chk_taxes_amount_type CHECK (amount_type IN ('percent', 'fixed', 'group', 'division'))
|
|
);
|
|
|
|
-- Tabla: payment_terms (Términos de pago)
|
|
CREATE TABLE financial.payment_terms (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
name VARCHAR(100) NOT NULL,
|
|
code VARCHAR(20) NOT NULL,
|
|
|
|
-- Configuración de términos (JSON)
|
|
-- Ejemplo: [{"days": 0, "percent": 100}] = Pago inmediato
|
|
-- Ejemplo: [{"days": 30, "percent": 100}] = 30 días
|
|
-- Ejemplo: [{"days": 15, "percent": 50}, {"days": 30, "percent": 50}] = 50% a 15 días, 50% a 30 días
|
|
terms JSONB NOT NULL DEFAULT '[]',
|
|
|
|
-- Control
|
|
active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT uq_payment_terms_code_company UNIQUE (company_id, code)
|
|
);
|
|
|
|
-- Tabla: invoices (Facturas)
|
|
CREATE TABLE financial.invoices (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
partner_id UUID NOT NULL REFERENCES core.partners(id),
|
|
invoice_type financial.invoice_type NOT NULL,
|
|
|
|
-- Numeración
|
|
number VARCHAR(100), -- Número de factura (generado al validar)
|
|
ref VARCHAR(100), -- Referencia del partner
|
|
|
|
-- Fechas
|
|
invoice_date DATE NOT NULL,
|
|
due_date DATE,
|
|
|
|
-- Montos
|
|
currency_id UUID NOT NULL REFERENCES core.currencies(id),
|
|
amount_untaxed DECIMAL(15, 2) NOT NULL DEFAULT 0,
|
|
amount_tax DECIMAL(15, 2) NOT NULL DEFAULT 0,
|
|
amount_total DECIMAL(15, 2) NOT NULL DEFAULT 0,
|
|
amount_paid DECIMAL(15, 2) NOT NULL DEFAULT 0,
|
|
amount_residual DECIMAL(15, 2) NOT NULL DEFAULT 0,
|
|
|
|
-- Estado
|
|
status financial.invoice_status NOT NULL DEFAULT 'draft',
|
|
|
|
-- COR-004: Estado de pago separado (Odoo alignment)
|
|
payment_state financial.payment_state DEFAULT 'not_paid',
|
|
|
|
-- Configuración
|
|
payment_term_id UUID REFERENCES financial.payment_terms(id),
|
|
journal_id UUID REFERENCES financial.journals(id),
|
|
|
|
-- Asiento contable (generado al validar)
|
|
journal_entry_id UUID REFERENCES financial.journal_entries(id),
|
|
|
|
-- Notas
|
|
notes TEXT,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
validated_at TIMESTAMP,
|
|
validated_by UUID REFERENCES auth.users(id),
|
|
cancelled_at TIMESTAMP,
|
|
cancelled_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT uq_invoices_number_company UNIQUE (company_id, number),
|
|
CONSTRAINT chk_invoices_amounts CHECK (
|
|
amount_total = amount_untaxed + amount_tax
|
|
),
|
|
CONSTRAINT chk_invoices_residual CHECK (
|
|
amount_residual = amount_total - amount_paid
|
|
)
|
|
);
|
|
|
|
-- Tabla: invoice_lines (Líneas de factura)
|
|
CREATE TABLE financial.invoice_lines (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
invoice_id UUID NOT NULL REFERENCES financial.invoices(id) ON DELETE CASCADE,
|
|
|
|
product_id UUID, -- FK a inventory.products (se crea después)
|
|
description TEXT NOT NULL,
|
|
|
|
-- Cantidades y precios
|
|
quantity DECIMAL(12, 4) NOT NULL DEFAULT 1,
|
|
uom_id UUID REFERENCES core.uom(id),
|
|
price_unit DECIMAL(15, 4) NOT NULL,
|
|
|
|
-- Impuestos (array de tax_ids)
|
|
tax_ids UUID[] DEFAULT '{}',
|
|
|
|
-- Montos calculados
|
|
amount_untaxed DECIMAL(15, 2) NOT NULL,
|
|
amount_tax DECIMAL(15, 2) NOT NULL,
|
|
amount_total DECIMAL(15, 2) NOT NULL,
|
|
|
|
-- Contabilidad
|
|
account_id UUID REFERENCES financial.accounts(id),
|
|
analytic_account_id UUID, -- FK a analytics.analytic_accounts
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP,
|
|
|
|
CONSTRAINT chk_invoice_lines_quantity CHECK (quantity > 0),
|
|
CONSTRAINT chk_invoice_lines_amounts CHECK (
|
|
amount_total = amount_untaxed + amount_tax
|
|
)
|
|
);
|
|
|
|
-- Índices para invoice_lines
|
|
CREATE INDEX idx_invoice_lines_tenant_id ON financial.invoice_lines(tenant_id);
|
|
CREATE INDEX idx_invoice_lines_invoice_id ON financial.invoice_lines(invoice_id);
|
|
CREATE INDEX idx_invoice_lines_product_id ON financial.invoice_lines(product_id);
|
|
|
|
-- RLS para invoice_lines
|
|
ALTER TABLE financial.invoice_lines ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY tenant_isolation_invoice_lines ON financial.invoice_lines
|
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
|
|
-- Tabla: payments (Pagos)
|
|
CREATE TABLE financial.payments (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
partner_id UUID NOT NULL REFERENCES core.partners(id),
|
|
payment_type financial.payment_type NOT NULL,
|
|
payment_method financial.payment_method NOT NULL,
|
|
|
|
-- Monto
|
|
amount DECIMAL(15, 2) NOT NULL,
|
|
currency_id UUID NOT NULL REFERENCES core.currencies(id),
|
|
|
|
-- Fecha y referencia
|
|
payment_date DATE NOT NULL,
|
|
ref VARCHAR(255),
|
|
|
|
-- Estado
|
|
status financial.payment_status NOT NULL DEFAULT 'draft',
|
|
|
|
-- Configuración
|
|
journal_id UUID NOT NULL REFERENCES financial.journals(id),
|
|
|
|
-- Asiento contable (generado al validar)
|
|
journal_entry_id UUID REFERENCES financial.journal_entries(id),
|
|
|
|
-- Notas
|
|
notes TEXT,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
posted_at TIMESTAMP,
|
|
posted_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT chk_payments_amount CHECK (amount > 0)
|
|
);
|
|
|
|
-- Tabla: payment_invoice (Conciliación pagos-facturas)
|
|
CREATE TABLE financial.payment_invoice (
|
|
payment_id UUID NOT NULL REFERENCES financial.payments(id) ON DELETE CASCADE,
|
|
invoice_id UUID NOT NULL REFERENCES financial.invoices(id) ON DELETE CASCADE,
|
|
amount DECIMAL(15, 2) NOT NULL,
|
|
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
PRIMARY KEY (payment_id, invoice_id),
|
|
CONSTRAINT chk_payment_invoice_amount CHECK (amount > 0)
|
|
);
|
|
|
|
-- Tabla: bank_accounts (Cuentas bancarias)
|
|
CREATE TABLE financial.bank_accounts (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID REFERENCES auth.companies(id),
|
|
|
|
partner_id UUID REFERENCES core.partners(id), -- Puede ser de la empresa o de un partner
|
|
|
|
bank_name VARCHAR(255) NOT NULL,
|
|
account_number VARCHAR(50) NOT NULL,
|
|
account_holder VARCHAR(255),
|
|
|
|
-- Configuración
|
|
currency_id UUID REFERENCES core.currencies(id),
|
|
journal_id UUID REFERENCES financial.journals(id), -- Diario asociado (si es cuenta de la empresa)
|
|
|
|
-- Control
|
|
active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id)
|
|
);
|
|
|
|
-- Tabla: reconciliations (Conciliaciones bancarias)
|
|
CREATE TABLE financial.reconciliations (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
|
|
|
|
bank_account_id UUID NOT NULL REFERENCES financial.bank_accounts(id),
|
|
|
|
-- Período de conciliación
|
|
start_date DATE NOT NULL,
|
|
end_date DATE NOT NULL,
|
|
|
|
-- Saldos
|
|
balance_start DECIMAL(15, 2) NOT NULL,
|
|
balance_end_real DECIMAL(15, 2) NOT NULL, -- Saldo real del banco
|
|
balance_end_computed DECIMAL(15, 2) NOT NULL, -- Saldo calculado
|
|
|
|
-- Líneas conciliadas (array de journal_entry_line_ids)
|
|
reconciled_line_ids UUID[] DEFAULT '{}',
|
|
|
|
-- Estado
|
|
status financial.entry_status NOT NULL DEFAULT 'draft',
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
updated_at TIMESTAMP,
|
|
updated_by UUID REFERENCES auth.users(id),
|
|
validated_at TIMESTAMP,
|
|
validated_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT chk_reconciliations_dates CHECK (end_date >= start_date)
|
|
);
|
|
|
|
-- =====================================================
|
|
-- COR-013: Tablas de Conciliación (Reconciliation Engine)
|
|
-- Equivalente a account.partial.reconcile y account.full.reconcile en Odoo
|
|
-- =====================================================
|
|
|
|
-- Tabla: account_full_reconcile (Conciliación completa)
|
|
CREATE TABLE financial.account_full_reconcile (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
name VARCHAR(100) NOT NULL,
|
|
exchange_move_id UUID REFERENCES financial.journal_entries(id),
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id)
|
|
);
|
|
|
|
-- Tabla: account_partial_reconcile (Conciliación parcial)
|
|
CREATE TABLE financial.account_partial_reconcile (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Líneas a conciliar
|
|
debit_move_id UUID NOT NULL REFERENCES financial.journal_entry_lines(id),
|
|
credit_move_id UUID NOT NULL REFERENCES financial.journal_entry_lines(id),
|
|
|
|
-- Montos
|
|
amount DECIMAL(15, 2) NOT NULL,
|
|
debit_amount_currency DECIMAL(15, 2),
|
|
credit_amount_currency DECIMAL(15, 2),
|
|
|
|
-- Moneda
|
|
company_currency_id UUID REFERENCES core.currencies(id),
|
|
debit_currency_id UUID REFERENCES core.currencies(id),
|
|
credit_currency_id UUID REFERENCES core.currencies(id),
|
|
|
|
-- Conciliación completa
|
|
full_reconcile_id UUID REFERENCES financial.account_full_reconcile(id),
|
|
|
|
-- Fecha máxima
|
|
max_date DATE,
|
|
|
|
-- Auditoría
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
|
|
CONSTRAINT chk_partial_reconcile_amount CHECK (amount > 0),
|
|
CONSTRAINT chk_partial_reconcile_different_lines CHECK (debit_move_id != credit_move_id)
|
|
);
|
|
|
|
COMMENT ON TABLE financial.account_full_reconcile IS
|
|
'COR-013: Conciliación completa - agrupa partial reconciles cuando las líneas están 100% conciliadas';
|
|
COMMENT ON TABLE financial.account_partial_reconcile IS
|
|
'COR-013: Conciliación parcial - vincula líneas de débito y crédito con el monto conciliado';
|
|
|
|
-- Agregar campos de reconciliación a journal_entry_lines
|
|
-- (Nota: En producción, esto sería ALTER TABLE)
|
|
|
|
-- =====================================================
|
|
-- INDICES
|
|
-- =====================================================
|
|
|
|
-- Account Types
|
|
CREATE INDEX idx_account_types_code ON financial.account_types(code);
|
|
|
|
-- Accounts
|
|
CREATE INDEX idx_accounts_tenant_id ON financial.accounts(tenant_id);
|
|
CREATE INDEX idx_accounts_company_id ON financial.accounts(company_id);
|
|
CREATE INDEX idx_accounts_code ON financial.accounts(code);
|
|
CREATE INDEX idx_accounts_parent_id ON financial.accounts(parent_id);
|
|
CREATE INDEX idx_accounts_type_id ON financial.accounts(account_type_id);
|
|
|
|
-- Journals
|
|
CREATE INDEX idx_journals_tenant_id ON financial.journals(tenant_id);
|
|
CREATE INDEX idx_journals_company_id ON financial.journals(company_id);
|
|
CREATE INDEX idx_journals_code ON financial.journals(code);
|
|
CREATE INDEX idx_journals_type ON financial.journals(journal_type);
|
|
|
|
-- Fiscal Years
|
|
CREATE INDEX idx_fiscal_years_tenant_id ON financial.fiscal_years(tenant_id);
|
|
CREATE INDEX idx_fiscal_years_company_id ON financial.fiscal_years(company_id);
|
|
CREATE INDEX idx_fiscal_years_dates ON financial.fiscal_years(start_date, end_date);
|
|
|
|
-- Fiscal Periods
|
|
CREATE INDEX idx_fiscal_periods_tenant_id ON financial.fiscal_periods(tenant_id);
|
|
CREATE INDEX idx_fiscal_periods_year_id ON financial.fiscal_periods(fiscal_year_id);
|
|
CREATE INDEX idx_fiscal_periods_dates ON financial.fiscal_periods(start_date, end_date);
|
|
|
|
-- Journal Entries
|
|
CREATE INDEX idx_journal_entries_tenant_id ON financial.journal_entries(tenant_id);
|
|
CREATE INDEX idx_journal_entries_company_id ON financial.journal_entries(company_id);
|
|
CREATE INDEX idx_journal_entries_journal_id ON financial.journal_entries(journal_id);
|
|
CREATE INDEX idx_journal_entries_date ON financial.journal_entries(date);
|
|
CREATE INDEX idx_journal_entries_status ON financial.journal_entries(status);
|
|
|
|
-- Journal Entry Lines
|
|
CREATE INDEX idx_journal_entry_lines_entry_id ON financial.journal_entry_lines(entry_id);
|
|
CREATE INDEX idx_journal_entry_lines_account_id ON financial.journal_entry_lines(account_id);
|
|
CREATE INDEX idx_journal_entry_lines_partner_id ON financial.journal_entry_lines(partner_id);
|
|
CREATE INDEX idx_journal_entry_lines_analytic ON financial.journal_entry_lines(analytic_account_id);
|
|
|
|
-- Taxes
|
|
CREATE INDEX idx_taxes_tenant_id ON financial.taxes(tenant_id);
|
|
CREATE INDEX idx_taxes_company_id ON financial.taxes(company_id);
|
|
CREATE INDEX idx_taxes_code ON financial.taxes(code);
|
|
CREATE INDEX idx_taxes_type ON financial.taxes(tax_type);
|
|
CREATE INDEX idx_taxes_active ON financial.taxes(active) WHERE active = TRUE;
|
|
|
|
-- Payment Terms
|
|
CREATE INDEX idx_payment_terms_tenant_id ON financial.payment_terms(tenant_id);
|
|
CREATE INDEX idx_payment_terms_company_id ON financial.payment_terms(company_id);
|
|
|
|
-- Invoices
|
|
CREATE INDEX idx_invoices_tenant_id ON financial.invoices(tenant_id);
|
|
CREATE INDEX idx_invoices_company_id ON financial.invoices(company_id);
|
|
CREATE INDEX idx_invoices_partner_id ON financial.invoices(partner_id);
|
|
CREATE INDEX idx_invoices_type ON financial.invoices(invoice_type);
|
|
CREATE INDEX idx_invoices_status ON financial.invoices(status);
|
|
CREATE INDEX idx_invoices_number ON financial.invoices(number);
|
|
CREATE INDEX idx_invoices_date ON financial.invoices(invoice_date);
|
|
CREATE INDEX idx_invoices_due_date ON financial.invoices(due_date);
|
|
|
|
-- Invoice Lines
|
|
CREATE INDEX idx_invoice_lines_invoice_id ON financial.invoice_lines(invoice_id);
|
|
CREATE INDEX idx_invoice_lines_product_id ON financial.invoice_lines(product_id);
|
|
CREATE INDEX idx_invoice_lines_account_id ON financial.invoice_lines(account_id);
|
|
|
|
-- Payments
|
|
CREATE INDEX idx_payments_tenant_id ON financial.payments(tenant_id);
|
|
CREATE INDEX idx_payments_company_id ON financial.payments(company_id);
|
|
CREATE INDEX idx_payments_partner_id ON financial.payments(partner_id);
|
|
CREATE INDEX idx_payments_type ON financial.payments(payment_type);
|
|
CREATE INDEX idx_payments_status ON financial.payments(status);
|
|
CREATE INDEX idx_payments_date ON financial.payments(payment_date);
|
|
|
|
-- Payment Invoice
|
|
CREATE INDEX idx_payment_invoice_payment_id ON financial.payment_invoice(payment_id);
|
|
CREATE INDEX idx_payment_invoice_invoice_id ON financial.payment_invoice(invoice_id);
|
|
|
|
-- Bank Accounts
|
|
CREATE INDEX idx_bank_accounts_tenant_id ON financial.bank_accounts(tenant_id);
|
|
CREATE INDEX idx_bank_accounts_company_id ON financial.bank_accounts(company_id);
|
|
CREATE INDEX idx_bank_accounts_partner_id ON financial.bank_accounts(partner_id);
|
|
|
|
-- Reconciliations
|
|
CREATE INDEX idx_reconciliations_tenant_id ON financial.reconciliations(tenant_id);
|
|
CREATE INDEX idx_reconciliations_company_id ON financial.reconciliations(company_id);
|
|
CREATE INDEX idx_reconciliations_bank_account_id ON financial.reconciliations(bank_account_id);
|
|
CREATE INDEX idx_reconciliations_dates ON financial.reconciliations(start_date, end_date);
|
|
|
|
-- =====================================================
|
|
-- FUNCTIONS
|
|
-- =====================================================
|
|
|
|
-- Función: validate_entry_balance
|
|
-- Valida que un asiento esté balanceado (debit = credit)
|
|
CREATE OR REPLACE FUNCTION financial.validate_entry_balance(p_entry_id UUID)
|
|
RETURNS BOOLEAN AS $$
|
|
DECLARE
|
|
v_total_debit DECIMAL;
|
|
v_total_credit DECIMAL;
|
|
BEGIN
|
|
SELECT
|
|
COALESCE(SUM(debit), 0),
|
|
COALESCE(SUM(credit), 0)
|
|
INTO v_total_debit, v_total_credit
|
|
FROM financial.journal_entry_lines
|
|
WHERE entry_id = p_entry_id;
|
|
|
|
IF v_total_debit != v_total_credit THEN
|
|
RAISE EXCEPTION 'Journal entry % is not balanced: debit=% credit=%',
|
|
p_entry_id, v_total_debit, v_total_credit;
|
|
END IF;
|
|
|
|
RETURN TRUE;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION financial.validate_entry_balance IS 'Valida que un asiento contable esté balanceado (debit = credit)';
|
|
|
|
-- Función: post_journal_entry
|
|
-- Contabiliza un asiento (cambiar estado a posted)
|
|
CREATE OR REPLACE FUNCTION financial.post_journal_entry(p_entry_id UUID)
|
|
RETURNS VOID AS $$
|
|
BEGIN
|
|
-- Validar balance
|
|
PERFORM financial.validate_entry_balance(p_entry_id);
|
|
|
|
-- Actualizar estado
|
|
UPDATE financial.journal_entries
|
|
SET status = 'posted',
|
|
posted_at = CURRENT_TIMESTAMP,
|
|
posted_by = get_current_user_id()
|
|
WHERE id = p_entry_id
|
|
AND status = 'draft';
|
|
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'Journal entry % not found or already posted', p_entry_id;
|
|
END IF;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION financial.post_journal_entry IS 'Contabiliza un asiento contable después de validar su balance';
|
|
|
|
-- Función: calculate_invoice_totals
|
|
-- Calcula los totales de una factura a partir de sus líneas
|
|
CREATE OR REPLACE FUNCTION financial.calculate_invoice_totals(p_invoice_id UUID)
|
|
RETURNS VOID AS $$
|
|
DECLARE
|
|
v_amount_untaxed DECIMAL;
|
|
v_amount_tax DECIMAL;
|
|
v_amount_total DECIMAL;
|
|
BEGIN
|
|
SELECT
|
|
COALESCE(SUM(amount_untaxed), 0),
|
|
COALESCE(SUM(amount_tax), 0),
|
|
COALESCE(SUM(amount_total), 0)
|
|
INTO v_amount_untaxed, v_amount_tax, v_amount_total
|
|
FROM financial.invoice_lines
|
|
WHERE invoice_id = p_invoice_id;
|
|
|
|
UPDATE financial.invoices
|
|
SET amount_untaxed = v_amount_untaxed,
|
|
amount_tax = v_amount_tax,
|
|
amount_total = v_amount_total,
|
|
amount_residual = v_amount_total - amount_paid,
|
|
updated_at = CURRENT_TIMESTAMP,
|
|
updated_by = get_current_user_id()
|
|
WHERE id = p_invoice_id;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION financial.calculate_invoice_totals IS 'Calcula los totales de una factura a partir de sus líneas';
|
|
|
|
-- Función: update_invoice_paid_amount
|
|
-- Actualiza el monto pagado de una factura
|
|
CREATE OR REPLACE FUNCTION financial.update_invoice_paid_amount(p_invoice_id UUID)
|
|
RETURNS VOID AS $$
|
|
DECLARE
|
|
v_amount_paid DECIMAL;
|
|
BEGIN
|
|
SELECT COALESCE(SUM(amount), 0)
|
|
INTO v_amount_paid
|
|
FROM financial.payment_invoice
|
|
WHERE invoice_id = p_invoice_id;
|
|
|
|
UPDATE financial.invoices
|
|
SET amount_paid = v_amount_paid,
|
|
amount_residual = amount_total - v_amount_paid,
|
|
status = CASE
|
|
WHEN v_amount_paid >= amount_total THEN 'paid'::financial.invoice_status
|
|
WHEN v_amount_paid > 0 THEN 'open'::financial.invoice_status
|
|
ELSE status
|
|
END
|
|
WHERE id = p_invoice_id;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION financial.update_invoice_paid_amount IS 'Actualiza el monto pagado y estado de una factura';
|
|
|
|
-- =====================================================
|
|
-- TRIGGERS
|
|
-- =====================================================
|
|
|
|
-- Trigger: Actualizar updated_at
|
|
CREATE TRIGGER trg_accounts_updated_at
|
|
BEFORE UPDATE ON financial.accounts
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
CREATE TRIGGER trg_journals_updated_at
|
|
BEFORE UPDATE ON financial.journals
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
CREATE TRIGGER trg_fiscal_years_updated_at
|
|
BEFORE UPDATE ON financial.fiscal_years
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
CREATE TRIGGER trg_fiscal_periods_updated_at
|
|
BEFORE UPDATE ON financial.fiscal_periods
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
CREATE TRIGGER trg_journal_entries_updated_at
|
|
BEFORE UPDATE ON financial.journal_entries
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
CREATE TRIGGER trg_taxes_updated_at
|
|
BEFORE UPDATE ON financial.taxes
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
CREATE TRIGGER trg_payment_terms_updated_at
|
|
BEFORE UPDATE ON financial.payment_terms
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
CREATE TRIGGER trg_invoices_updated_at
|
|
BEFORE UPDATE ON financial.invoices
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
CREATE TRIGGER trg_payments_updated_at
|
|
BEFORE UPDATE ON financial.payments
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
CREATE TRIGGER trg_bank_accounts_updated_at
|
|
BEFORE UPDATE ON financial.bank_accounts
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
CREATE TRIGGER trg_reconciliations_updated_at
|
|
BEFORE UPDATE ON financial.reconciliations
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auth.update_updated_at_column();
|
|
|
|
-- Trigger: Validar balance antes de contabilizar
|
|
CREATE OR REPLACE FUNCTION financial.trg_validate_entry_before_post()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF NEW.status = 'posted' AND OLD.status = 'draft' THEN
|
|
PERFORM financial.validate_entry_balance(NEW.id);
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER trg_journal_entries_validate_balance
|
|
BEFORE UPDATE OF status ON financial.journal_entries
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION financial.trg_validate_entry_before_post();
|
|
|
|
-- Trigger: Actualizar totales de factura al cambiar líneas
|
|
CREATE OR REPLACE FUNCTION financial.trg_update_invoice_totals()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF TG_OP = 'DELETE' THEN
|
|
PERFORM financial.calculate_invoice_totals(OLD.invoice_id);
|
|
ELSE
|
|
PERFORM financial.calculate_invoice_totals(NEW.invoice_id);
|
|
END IF;
|
|
RETURN NULL;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER trg_invoice_lines_update_totals
|
|
AFTER INSERT OR UPDATE OR DELETE ON financial.invoice_lines
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION financial.trg_update_invoice_totals();
|
|
|
|
-- Trigger: Actualizar monto pagado al conciliar
|
|
CREATE OR REPLACE FUNCTION financial.trg_update_invoice_paid()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF TG_OP = 'DELETE' THEN
|
|
PERFORM financial.update_invoice_paid_amount(OLD.invoice_id);
|
|
ELSE
|
|
PERFORM financial.update_invoice_paid_amount(NEW.invoice_id);
|
|
END IF;
|
|
RETURN NULL;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER trg_payment_invoice_update_paid
|
|
AFTER INSERT OR UPDATE OR DELETE ON financial.payment_invoice
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION financial.trg_update_invoice_paid();
|
|
|
|
-- =====================================================
|
|
-- TRACKING AUTOMÁTICO (mail.thread pattern)
|
|
-- =====================================================
|
|
|
|
-- Trigger: Tracking automático para facturas
|
|
CREATE TRIGGER track_invoice_changes
|
|
AFTER INSERT OR UPDATE OR DELETE ON financial.invoices
|
|
FOR EACH ROW EXECUTE FUNCTION system.track_field_changes();
|
|
|
|
COMMENT ON TRIGGER track_invoice_changes ON financial.invoices IS
|
|
'Registra automáticamente cambios en facturas (estado, monto, cliente, fechas)';
|
|
|
|
-- Trigger: Tracking automático para asientos contables
|
|
CREATE TRIGGER track_journal_entry_changes
|
|
AFTER INSERT OR UPDATE OR DELETE ON financial.journal_entries
|
|
FOR EACH ROW EXECUTE FUNCTION system.track_field_changes();
|
|
|
|
COMMENT ON TRIGGER track_journal_entry_changes ON financial.journal_entries IS
|
|
'Registra automáticamente cambios en asientos contables (estado, fecha, diario)';
|
|
|
|
-- =====================================================
|
|
-- ROW LEVEL SECURITY (RLS)
|
|
-- =====================================================
|
|
|
|
ALTER TABLE financial.accounts ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.journals ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.fiscal_years ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.fiscal_periods ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.journal_entries ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.taxes ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.payment_terms ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.invoices ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.payments ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.bank_accounts ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.reconciliations ENABLE ROW LEVEL SECURITY;
|
|
|
|
CREATE POLICY tenant_isolation_accounts ON financial.accounts
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
CREATE POLICY tenant_isolation_journals ON financial.journals
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
CREATE POLICY tenant_isolation_fiscal_years ON financial.fiscal_years
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
CREATE POLICY tenant_isolation_fiscal_periods ON financial.fiscal_periods
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
CREATE POLICY tenant_isolation_journal_entries ON financial.journal_entries
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
CREATE POLICY tenant_isolation_taxes ON financial.taxes
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
CREATE POLICY tenant_isolation_payment_terms ON financial.payment_terms
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
CREATE POLICY tenant_isolation_invoices ON financial.invoices
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
CREATE POLICY tenant_isolation_payments ON financial.payments
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
CREATE POLICY tenant_isolation_bank_accounts ON financial.bank_accounts
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
CREATE POLICY tenant_isolation_reconciliations ON financial.reconciliations
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
-- =====================================================
|
|
-- SEED DATA
|
|
-- =====================================================
|
|
|
|
-- Tipos de cuenta estándar
|
|
INSERT INTO financial.account_types (code, name, account_type, description) VALUES
|
|
('ASSET_CASH', 'Cash and Cash Equivalents', 'asset', 'Efectivo y equivalentes'),
|
|
('ASSET_RECEIVABLE', 'Accounts Receivable', 'asset', 'Cuentas por cobrar'),
|
|
('ASSET_CURRENT', 'Current Assets', 'asset', 'Activos circulantes'),
|
|
('ASSET_FIXED', 'Fixed Assets', 'asset', 'Activos fijos'),
|
|
('LIABILITY_PAYABLE', 'Accounts Payable', 'liability', 'Cuentas por pagar'),
|
|
('LIABILITY_CURRENT', 'Current Liabilities', 'liability', 'Pasivos circulantes'),
|
|
('LIABILITY_LONG', 'Long-term Liabilities', 'liability', 'Pasivos a largo plazo'),
|
|
('EQUITY_CAPITAL', 'Capital', 'equity', 'Capital social'),
|
|
('EQUITY_RETAINED', 'Retained Earnings', 'equity', 'Utilidades retenidas'),
|
|
('REVENUE_SALES', 'Sales Revenue', 'revenue', 'Ingresos por ventas'),
|
|
('REVENUE_OTHER', 'Other Revenue', 'revenue', 'Otros ingresos'),
|
|
('EXPENSE_COGS', 'Cost of Goods Sold', 'expense', 'Costo de ventas'),
|
|
('EXPENSE_OPERATING', 'Operating Expenses', 'expense', 'Gastos operativos'),
|
|
('EXPENSE_ADMIN', 'Administrative Expenses', 'expense', 'Gastos administrativos')
|
|
ON CONFLICT (code) DO NOTHING;
|
|
|
|
-- =====================================================
|
|
-- COMENTARIOS
|
|
-- =====================================================
|
|
|
|
COMMENT ON SCHEMA financial IS 'Schema de contabilidad, facturas, pagos y finanzas';
|
|
COMMENT ON TABLE financial.account_types IS 'Tipos de cuentas contables (asset, liability, equity, revenue, expense)';
|
|
COMMENT ON TABLE financial.accounts IS 'Plan de cuentas contables';
|
|
COMMENT ON TABLE financial.journals IS 'Diarios contables (ventas, compras, bancos, etc.)';
|
|
COMMENT ON TABLE financial.fiscal_years IS 'Años fiscales';
|
|
COMMENT ON TABLE financial.fiscal_periods IS 'Períodos fiscales (meses)';
|
|
COMMENT ON TABLE financial.journal_entries IS 'Asientos contables';
|
|
COMMENT ON TABLE financial.journal_entry_lines IS 'Líneas de asientos contables (partida doble)';
|
|
COMMENT ON TABLE financial.taxes IS 'Impuestos (IVA, retenciones, etc.)';
|
|
COMMENT ON TABLE financial.payment_terms IS 'Términos de pago (inmediato, 30 días, etc.)';
|
|
COMMENT ON TABLE financial.invoices IS 'Facturas de cliente y proveedor';
|
|
COMMENT ON TABLE financial.invoice_lines IS 'Líneas de factura';
|
|
COMMENT ON TABLE financial.payments IS 'Pagos y cobros';
|
|
COMMENT ON TABLE financial.payment_invoice IS 'Conciliación de pagos con facturas';
|
|
COMMENT ON TABLE financial.bank_accounts IS 'Cuentas bancarias de la empresa y partners';
|
|
COMMENT ON TABLE financial.reconciliations IS 'Conciliaciones bancarias';
|
|
|
|
-- =====================================================
|
|
-- COR-024: Tax Repartition Lines
|
|
-- Equivalente a account.tax.repartition.line de Odoo
|
|
-- =====================================================
|
|
|
|
CREATE TYPE financial.repartition_type AS ENUM ('invoice', 'refund');
|
|
|
|
CREATE TABLE financial.tax_repartition_lines (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
tax_id UUID NOT NULL REFERENCES financial.taxes(id) ON DELETE CASCADE,
|
|
repartition_type financial.repartition_type NOT NULL,
|
|
sequence INTEGER DEFAULT 1,
|
|
factor_percent DECIMAL(10,4) DEFAULT 100,
|
|
account_id UUID REFERENCES financial.accounts(id),
|
|
tag_ids UUID[],
|
|
use_in_tax_closing BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_tax_repartition_tax ON financial.tax_repartition_lines(tax_id);
|
|
CREATE INDEX idx_tax_repartition_type ON financial.tax_repartition_lines(repartition_type);
|
|
|
|
COMMENT ON TABLE financial.tax_repartition_lines IS 'COR-024: Tax repartition lines - Equivalent to account.tax.repartition.line';
|
|
|
|
-- =====================================================
|
|
-- COR-023: Bank Statements
|
|
-- Equivalente a account.bank.statement de Odoo
|
|
-- =====================================================
|
|
|
|
CREATE TYPE financial.statement_status AS ENUM ('draft', 'open', 'confirm', 'cancelled');
|
|
|
|
CREATE TABLE financial.bank_statements (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
journal_id UUID NOT NULL REFERENCES financial.journals(id),
|
|
name VARCHAR(100),
|
|
reference VARCHAR(255),
|
|
date DATE NOT NULL,
|
|
date_done DATE,
|
|
balance_start DECIMAL(20,6) DEFAULT 0,
|
|
balance_end_real DECIMAL(20,6) DEFAULT 0,
|
|
total_entry_encoding DECIMAL(20,6) DEFAULT 0,
|
|
status financial.statement_status DEFAULT 'draft',
|
|
currency_id UUID REFERENCES core.currencies(id),
|
|
is_complete BOOLEAN DEFAULT FALSE,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE financial.bank_statement_lines (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
statement_id UUID NOT NULL REFERENCES financial.bank_statements(id) ON DELETE CASCADE,
|
|
sequence INTEGER DEFAULT 10,
|
|
date DATE NOT NULL,
|
|
payment_ref VARCHAR(255),
|
|
ref VARCHAR(255),
|
|
partner_id UUID REFERENCES core.partners(id),
|
|
amount DECIMAL(20,6) NOT NULL,
|
|
amount_currency DECIMAL(20,6),
|
|
foreign_currency_id UUID REFERENCES core.currencies(id),
|
|
transaction_type VARCHAR(50),
|
|
narration TEXT,
|
|
is_reconciled BOOLEAN DEFAULT FALSE,
|
|
partner_bank_id UUID REFERENCES core.partner_banks(id),
|
|
account_number VARCHAR(64),
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_bank_statements_tenant ON financial.bank_statements(tenant_id);
|
|
CREATE INDEX idx_bank_statements_journal ON financial.bank_statements(journal_id);
|
|
CREATE INDEX idx_bank_statements_date ON financial.bank_statements(date);
|
|
CREATE INDEX idx_bank_statements_status ON financial.bank_statements(status);
|
|
CREATE INDEX idx_bank_statement_lines_statement ON financial.bank_statement_lines(statement_id);
|
|
CREATE INDEX idx_bank_statement_lines_partner ON financial.bank_statement_lines(partner_id);
|
|
|
|
-- RLS
|
|
ALTER TABLE financial.bank_statements ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE financial.bank_statement_lines ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY tenant_isolation_bank_statements ON financial.bank_statements
|
|
USING (tenant_id = get_current_tenant_id());
|
|
CREATE POLICY tenant_isolation_bank_statement_lines ON financial.bank_statement_lines
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
COMMENT ON TABLE financial.bank_statements IS 'COR-023: Bank statements - Equivalent to account.bank.statement';
|
|
COMMENT ON TABLE financial.bank_statement_lines IS 'COR-023: Bank statement lines - Equivalent to account.bank.statement.line';
|
|
|
|
-- =====================================================
|
|
-- COR-028: Fiscal Positions
|
|
-- Equivalente a account.fiscal.position de Odoo
|
|
-- =====================================================
|
|
|
|
CREATE TABLE financial.fiscal_positions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
name VARCHAR(255) NOT NULL,
|
|
sequence INTEGER DEFAULT 10,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
company_id UUID REFERENCES core.companies(id),
|
|
country_id UUID REFERENCES core.countries(id),
|
|
state_ids UUID[], -- Array of core.states IDs
|
|
zip_from VARCHAR(20),
|
|
zip_to VARCHAR(20),
|
|
auto_apply BOOLEAN DEFAULT FALSE,
|
|
vat_required BOOLEAN DEFAULT FALSE,
|
|
note TEXT,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE financial.fiscal_position_taxes (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
fiscal_position_id UUID NOT NULL REFERENCES financial.fiscal_positions(id) ON DELETE CASCADE,
|
|
tax_src_id UUID NOT NULL REFERENCES financial.taxes(id),
|
|
tax_dest_id UUID REFERENCES financial.taxes(id)
|
|
);
|
|
|
|
CREATE TABLE financial.fiscal_position_accounts (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
fiscal_position_id UUID NOT NULL REFERENCES financial.fiscal_positions(id) ON DELETE CASCADE,
|
|
account_src_id UUID NOT NULL REFERENCES financial.accounts(id),
|
|
account_dest_id UUID NOT NULL REFERENCES financial.accounts(id)
|
|
);
|
|
|
|
CREATE INDEX idx_fiscal_positions_tenant ON financial.fiscal_positions(tenant_id);
|
|
CREATE INDEX idx_fiscal_positions_country ON financial.fiscal_positions(country_id);
|
|
CREATE INDEX idx_fiscal_position_taxes_fp ON financial.fiscal_position_taxes(fiscal_position_id);
|
|
CREATE INDEX idx_fiscal_position_accounts_fp ON financial.fiscal_position_accounts(fiscal_position_id);
|
|
|
|
-- RLS
|
|
ALTER TABLE financial.fiscal_positions ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY tenant_isolation_fiscal_positions ON financial.fiscal_positions
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
COMMENT ON TABLE financial.fiscal_positions IS 'COR-028: Fiscal positions - Equivalent to account.fiscal.position';
|
|
COMMENT ON TABLE financial.fiscal_position_taxes IS 'COR-028: Tax mappings for fiscal positions';
|
|
COMMENT ON TABLE financial.fiscal_position_accounts IS 'COR-028: Account mappings for fiscal positions';
|
|
|
|
-- =====================================================
|
|
-- COR-035: Payment Term Lines (Detalle de terminos de pago)
|
|
-- Equivalente a account.payment.term.line de Odoo
|
|
-- =====================================================
|
|
|
|
CREATE TYPE financial.payment_term_value AS ENUM ('balance', 'percent', 'fixed');
|
|
|
|
CREATE TABLE financial.payment_term_lines (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
payment_term_id UUID NOT NULL REFERENCES financial.payment_terms(id) ON DELETE CASCADE,
|
|
value financial.payment_term_value NOT NULL DEFAULT 'balance',
|
|
value_amount DECIMAL(20,6) DEFAULT 0,
|
|
nb_days INTEGER DEFAULT 0,
|
|
delay_type VARCHAR(20) DEFAULT 'days_after', -- days_after, days_after_end_of_month, days_after_end_of_next_month
|
|
day_of_the_month INTEGER,
|
|
sequence INTEGER DEFAULT 10,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_payment_term_lines_term ON financial.payment_term_lines(payment_term_id);
|
|
COMMENT ON TABLE financial.payment_term_lines IS 'COR-035: Payment term lines - Equivalent to account.payment.term.line';
|
|
|
|
-- =====================================================
|
|
-- COR-036: Incoterms (Terminos de comercio internacional)
|
|
-- Equivalente a account.incoterms de Odoo
|
|
-- =====================================================
|
|
|
|
CREATE TABLE financial.incoterms (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name VARCHAR(255) NOT NULL,
|
|
code VARCHAR(10) NOT NULL UNIQUE,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Seed data para incoterms comunes
|
|
INSERT INTO financial.incoterms (name, code) VALUES
|
|
('Ex Works', 'EXW'),
|
|
('Free Carrier', 'FCA'),
|
|
('Carriage Paid To', 'CPT'),
|
|
('Carriage and Insurance Paid To', 'CIP'),
|
|
('Delivered at Place', 'DAP'),
|
|
('Delivered at Place Unloaded', 'DPU'),
|
|
('Delivered Duty Paid', 'DDP'),
|
|
('Free Alongside Ship', 'FAS'),
|
|
('Free on Board', 'FOB'),
|
|
('Cost and Freight', 'CFR'),
|
|
('Cost Insurance and Freight', 'CIF');
|
|
|
|
COMMENT ON TABLE financial.incoterms IS 'COR-036: Incoterms - Equivalent to account.incoterms';
|
|
|
|
-- =====================================================
|
|
-- COR-037: Payment Methods (Metodos de pago)
|
|
-- Equivalente a account.payment.method de Odoo
|
|
-- =====================================================
|
|
|
|
CREATE TABLE financial.payment_methods (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name VARCHAR(255) NOT NULL,
|
|
code VARCHAR(50) NOT NULL,
|
|
payment_type VARCHAR(20) NOT NULL, -- inbound, outbound
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(code, payment_type)
|
|
);
|
|
|
|
-- Seed data para metodos de pago comunes
|
|
INSERT INTO financial.payment_methods (name, code, payment_type) VALUES
|
|
('Manual', 'manual', 'inbound'),
|
|
('Manual', 'manual', 'outbound'),
|
|
('Bank Transfer', 'bank_transfer', 'inbound'),
|
|
('Bank Transfer', 'bank_transfer', 'outbound'),
|
|
('Check', 'check', 'inbound'),
|
|
('Check', 'check', 'outbound'),
|
|
('Credit Card', 'credit_card', 'inbound'),
|
|
('Direct Debit', 'direct_debit', 'inbound');
|
|
|
|
-- Agregar payment_method_id a payments
|
|
ALTER TABLE financial.payments ADD COLUMN IF NOT EXISTS payment_method_id UUID REFERENCES financial.payment_methods(id);
|
|
|
|
COMMENT ON TABLE financial.payment_methods IS 'COR-037: Payment methods - Equivalent to account.payment.method';
|
|
|
|
-- =====================================================
|
|
-- COR-038: Reconcile Models (Modelos de conciliacion)
|
|
-- Equivalente a account.reconcile.model de Odoo
|
|
-- =====================================================
|
|
|
|
CREATE TYPE financial.reconcile_model_type AS ENUM (
|
|
'writeoff_button',
|
|
'writeoff_suggestion',
|
|
'invoice_matching'
|
|
);
|
|
|
|
CREATE TABLE financial.reconcile_models (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
name VARCHAR(255) NOT NULL,
|
|
sequence INTEGER DEFAULT 10,
|
|
rule_type financial.reconcile_model_type DEFAULT 'writeoff_button',
|
|
auto_reconcile BOOLEAN DEFAULT FALSE,
|
|
match_nature VARCHAR(20) DEFAULT 'both', -- amount_received, amount_paid, both
|
|
match_amount VARCHAR(20) DEFAULT 'any', -- lower, greater, between, any
|
|
match_amount_min DECIMAL(20,6),
|
|
match_amount_max DECIMAL(20,6),
|
|
match_label VARCHAR(50),
|
|
match_label_param VARCHAR(255),
|
|
match_partner BOOLEAN DEFAULT FALSE,
|
|
match_partner_ids UUID[],
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
company_id UUID REFERENCES core.companies(id),
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE financial.reconcile_model_lines (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
model_id UUID NOT NULL REFERENCES financial.reconcile_models(id) ON DELETE CASCADE,
|
|
sequence INTEGER DEFAULT 10,
|
|
account_id UUID NOT NULL REFERENCES financial.accounts(id),
|
|
journal_id UUID REFERENCES financial.journals(id),
|
|
label VARCHAR(255),
|
|
amount_type VARCHAR(20) DEFAULT 'percentage', -- percentage, fixed, regex
|
|
amount_value DECIMAL(20,6) DEFAULT 100,
|
|
tax_ids UUID[],
|
|
analytic_account_id UUID REFERENCES analytics.analytic_accounts(id),
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_reconcile_models_tenant ON financial.reconcile_models(tenant_id);
|
|
CREATE INDEX idx_reconcile_model_lines_model ON financial.reconcile_model_lines(model_id);
|
|
|
|
ALTER TABLE financial.reconcile_models ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY tenant_isolation_reconcile_models ON financial.reconcile_models
|
|
USING (tenant_id = get_current_tenant_id());
|
|
|
|
COMMENT ON TABLE financial.reconcile_models IS 'COR-038: Reconcile models - Equivalent to account.reconcile.model';
|
|
COMMENT ON TABLE financial.reconcile_model_lines IS 'COR-038: Reconcile model lines';
|
|
|
|
-- =====================================================
|
|
-- COR-039: Campos adicionales en tablas existentes
|
|
-- =====================================================
|
|
|
|
-- Campos en journal_entries (account.move)
|
|
ALTER TABLE financial.journal_entries ADD COLUMN IF NOT EXISTS invoice_origin VARCHAR(255);
|
|
ALTER TABLE financial.journal_entries ADD COLUMN IF NOT EXISTS payment_reference VARCHAR(255);
|
|
ALTER TABLE financial.journal_entries ADD COLUMN IF NOT EXISTS invoice_date_due DATE;
|
|
ALTER TABLE financial.journal_entries ADD COLUMN IF NOT EXISTS incoterm_id UUID REFERENCES financial.incoterms(id);
|
|
ALTER TABLE financial.journal_entries ADD COLUMN IF NOT EXISTS incoterm_location VARCHAR(255);
|
|
ALTER TABLE financial.journal_entries ADD COLUMN IF NOT EXISTS qr_code_method VARCHAR(50);
|
|
ALTER TABLE financial.journal_entries ADD COLUMN IF NOT EXISTS invoice_source_email VARCHAR(255);
|
|
ALTER TABLE financial.journal_entries ADD COLUMN IF NOT EXISTS reversed_entry_id UUID REFERENCES financial.journal_entries(id);
|
|
ALTER TABLE financial.journal_entries ADD COLUMN IF NOT EXISTS auto_post VARCHAR(20) DEFAULT 'no'; -- no, at_date, monthly, quarterly, yearly
|
|
ALTER TABLE financial.journal_entries ADD COLUMN IF NOT EXISTS auto_post_until DATE;
|
|
|
|
-- Campos en journal_entry_lines (account.move.line)
|
|
ALTER TABLE financial.journal_entry_lines ADD COLUMN IF NOT EXISTS discount DECIMAL(10,4) DEFAULT 0;
|
|
ALTER TABLE financial.journal_entry_lines ADD COLUMN IF NOT EXISTS display_type VARCHAR(20); -- product, line_section, line_note
|
|
ALTER TABLE financial.journal_entry_lines ADD COLUMN IF NOT EXISTS is_rounding_line BOOLEAN DEFAULT FALSE;
|
|
ALTER TABLE financial.journal_entry_lines ADD COLUMN IF NOT EXISTS exclude_from_invoice_tab BOOLEAN DEFAULT FALSE;
|
|
|
|
-- Campos en taxes
|
|
ALTER TABLE financial.taxes ADD COLUMN IF NOT EXISTS tax_scope VARCHAR(20); -- service, consu
|
|
ALTER TABLE financial.taxes ADD COLUMN IF NOT EXISTS is_base_affected BOOLEAN DEFAULT FALSE;
|
|
ALTER TABLE financial.taxes ADD COLUMN IF NOT EXISTS hide_tax_exigibility BOOLEAN DEFAULT FALSE;
|
|
ALTER TABLE financial.taxes ADD COLUMN IF NOT EXISTS tax_exigibility VARCHAR(20) DEFAULT 'on_invoice'; -- on_invoice, on_payment
|
|
|
|
COMMENT ON COLUMN financial.journal_entries.invoice_origin IS 'COR-039: Source document reference';
|
|
COMMENT ON COLUMN financial.journal_entries.qr_code_method IS 'COR-039: QR code payment method';
|
|
|
|
-- =====================================================
|
|
-- FIN DEL SCHEMA FINANCIAL
|
|
-- =====================================================
|