mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 23:03:18 +00:00
Implementa el módulo integral de costos según el plan acordado: - Esquema Liquibase: expense_entries, almacén (central + obra), IVA, tenant_cost_settings, permisos IAM y RLS - Funciones RPC core: gastos, almacén, control presupuestal, sync nómina, cierre de almacén al concluir proyecto - API HTTP: expenses_http, warehouse_http, cost_control_http, iam_http - Middleware requirePermission con matriz IAM - UI web-panel: /gastos, /almacen, /control-presupuesto, /usuarios - Componentes BudgetItemPicker, CostSemaphore y semáforos CSS - Smoke tests extendidos para gastos/almacén/control Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
103 lines
5.1 KiB
SQL
103 lines
5.1 KiB
SQL
--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)
|
|
);
|