--liquibase formatted sql -- PANELS · core · gastos, IVA y configuración de control de costos --changeset panel:core-018a-tenant-cost-settings endDelimiter:; splitStatements:true --preconditions onFail:MARK_RAN --precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='core' AND table_name='tenant_cost_settings' CREATE TABLE core.tenant_cost_settings ( tenant_id INTEGER PRIMARY KEY, budget_warn_pct NUMERIC(5,2) NOT NULL DEFAULT 85, budget_critical_pct NUMERIC(5,2) NOT NULL DEFAULT 100, default_iva_rate NUMERIC(5,4) NOT NULL DEFAULT 0.16, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); --changeset panel:core-018b-expense-entries endDelimiter:; splitStatements:true --preconditions onFail:MARK_RAN --precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='core' AND table_name='expense_entries' CREATE TABLE core.expense_entries ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, tenant_id INTEGER NOT NULL, company_id BIGINT NOT NULL REFERENCES core.companies(id), project_id BIGINT REFERENCES core.projects(id) ON DELETE SET NULL, expense_date DATE NOT NULL, source TEXT NOT NULL DEFAULT 'manual' CHECK (source IN ('manual', 'payroll', 'destajo')), source_ref_id BIGINT, description TEXT NOT NULL DEFAULT '', supplier_name TEXT NOT NULL DEFAULT '', supplier_rfc TEXT NOT NULL DEFAULT '', budget_chapter_id BIGINT REFERENCES core.budget_chapters(id) ON DELETE SET NULL, budget_item_id BIGINT REFERENCES core.budget_items(id) ON DELETE SET NULL, quantity NUMERIC(14,4) NOT NULL DEFAULT 0, unit TEXT NOT NULL DEFAULT '', unit_price NUMERIC(14,4) NOT NULL DEFAULT 0, subtotal NUMERIC(14,2) NOT NULL DEFAULT 0, iva_rate NUMERIC(5,4) NOT NULL DEFAULT 0.16, iva_amount NUMERIC(14,2) NOT NULL DEFAULT 0, total NUMERIC(14,2) NOT NULL DEFAULT 0, tax_included BOOLEAN NOT NULL DEFAULT false, is_deductible BOOLEAN NOT NULL DEFAULT true, counts_toward_budget BOOLEAN NOT NULL DEFAULT true, is_locked BOOLEAN NOT NULL DEFAULT false, status TEXT NOT NULL DEFAULT 'confirmed' CHECK (status IN ('draft', 'confirmed', 'void')), created_by_id INTEGER, created_by_name TEXT NOT NULL DEFAULT '', notes TEXT NOT NULL DEFAULT '', created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX idx_core_expense_entries_tenant ON core.expense_entries(tenant_id); CREATE INDEX idx_core_expense_entries_project_date ON core.expense_entries(project_id, expense_date); CREATE INDEX idx_core_expense_entries_budget_item ON core.expense_entries(budget_item_id); CREATE UNIQUE INDEX idx_core_expense_entries_source_ref ON core.expense_entries(source, source_ref_id) WHERE source_ref_id IS NOT NULL AND status <> 'void'; --changeset panel:core-018c-expense-attachments endDelimiter:; splitStatements:true --preconditions onFail:MARK_RAN --precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='core' AND table_name='expense_attachments' CREATE TABLE core.expense_attachments ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, expense_id BIGINT NOT NULL REFERENCES core.expense_entries(id) ON DELETE CASCADE, original_name TEXT NOT NULL, mime TEXT NOT NULL, size_bytes BIGINT NOT NULL, sha256 TEXT NOT NULL, iv TEXT NOT NULL, storage_name TEXT NOT NULL, uploaded_by_id INTEGER, uploaded_by_name TEXT NOT NULL DEFAULT '', uploaded_at TIMESTAMPTZ NOT NULL DEFAULT now() ); --changeset panel:core-018d-iva-period-manual endDelimiter:; splitStatements:true --preconditions onFail:MARK_RAN --precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='core' AND table_name='iva_period_entries' CREATE TABLE core.iva_period_entries ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, tenant_id INTEGER NOT NULL, company_id BIGINT NOT NULL REFERENCES core.companies(id), period_year INTEGER NOT NULL, period_month INTEGER NOT NULL CHECK (period_month BETWEEN 1 AND 12), iva_trasladado NUMERIC(14,2) NOT NULL DEFAULT 0, notes TEXT NOT NULL DEFAULT '', updated_by_name TEXT NOT NULL DEFAULT '', updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE (tenant_id, company_id, period_year, period_month) ); CREATE INDEX idx_core_iva_period_tenant ON core.iva_period_entries(tenant_id); --changeset panel:core-018e-destajo-budget-item endDelimiter:; splitStatements:true ALTER TABLE core.destajo_jobs ADD COLUMN IF NOT EXISTS budget_item_id BIGINT REFERENCES core.budget_items(id) ON DELETE SET NULL; --changeset panel:core-018f-warehouse-material-budget-links endDelimiter:; splitStatements:true --preconditions onFail:MARK_RAN --precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='core' AND table_name='warehouse_material_budget_links' CREATE TABLE core.warehouse_material_budget_links ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, material_id BIGINT NOT NULL, budget_item_id BIGINT NOT NULL REFERENCES core.budget_items(id) ON DELETE CASCADE, conversion_factor NUMERIC(14,6) NOT NULL DEFAULT 1, UNIQUE (material_id, budget_item_id) );