panels-origin/scripts/verify-work-program-load.sql
Cursor Agent 2d661d7a81
fix: programado vs costo usa el almacén de la obra
warehouse_movements no tiene project_id; el ejecutado semanal se
suma por warehouses.project_id. El ejecutado por partida ya no se
duplica al cruzar varias semanas. Verificado en Postgres con las
cuatro lecturas de la pantalla (get, concepts, partidas, vs-cost).

Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
2026-09-08 21:54:32 +00:00

114 lines
4.5 KiB
PL/PgSQL

-- Verifica las 4 lecturas que carga Programa de obra (get, concepts, partidas, vs-cost).
-- Esquema mínimo con las columnas reales. No es Liquibase.
DROP SCHEMA IF EXISTS core CASCADE;
CREATE SCHEMA core;
SET search_path = core;
CREATE FUNCTION rpc_generic_messages() RETURNS text[] LANGUAGE sql IMMUTABLE AS $$
SELECT ARRAY['OK']::text[];
$$;
CREATE FUNCTION rpc_assert_message(p_message text) RETURNS void LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
IF p_message IS NULL OR btrim(p_message) = '' THEN RAISE EXCEPTION 'empty'; END IF;
END;
$$;
CREATE FUNCTION rpc_ok(p_data jsonb, p_message text, p_ctx jsonb DEFAULT '{}'::jsonb) RETURNS jsonb
LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
PERFORM rpc_assert_message(p_message);
RETURN jsonb_build_object('ok', true, 'code', 'OK', 'message', p_message, 'data', p_data);
END;
$$;
CREATE FUNCTION rpc_err(p_code text, p_message text, p_ctx jsonb DEFAULT '{}'::jsonb, p_errors jsonb DEFAULT NULL) RETURNS jsonb
LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
PERFORM rpc_assert_message(p_message);
RETURN jsonb_build_object('ok', false, 'code', p_code, 'message', p_message, 'data', NULL);
END;
$$;
CREATE FUNCTION rpc_from_exception(p_fn text, p_sqlstate text, p_message text, p_detail text DEFAULT NULL) RETURNS jsonb
LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
RETURN rpc_err('INTERNAL', format('Error inesperado en %s (sqlstate=%s): %s', p_fn, p_sqlstate, p_message),
jsonb_build_object('fn', p_fn, 'sqlstate', p_sqlstate));
END;
$$;
CREATE TABLE companies (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name text);
CREATE TABLE projects (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name text, status text DEFAULT 'activo', tenant_id int, start_date date, end_date date
);
CREATE TABLE budget_chapters (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
project_id BIGINT REFERENCES projects(id),
code text, name text, sort_order int DEFAULT 0
);
CREATE TABLE budget_items (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
project_id BIGINT REFERENCES projects(id),
chapter_id BIGINT REFERENCES budget_chapters(id),
code text, description text, unit text DEFAULT '', amount numeric(14,2) DEFAULT 0, sort_order int DEFAULT 0
);
CREATE TABLE work_programs (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
project_id BIGINT UNIQUE REFERENCES projects(id),
start_date date, end_date date, duration_days int, source text, status text
);
CREATE TABLE work_program_periods (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
program_id BIGINT REFERENCES work_programs(id),
period_index int, label text, start_date date, end_date date
);
CREATE TABLE work_program_partida_amounts (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
program_id BIGINT REFERENCES work_programs(id),
budget_chapter_id BIGINT REFERENCES budget_chapters(id),
period_id BIGINT REFERENCES work_program_periods(id),
amount numeric(14,2)
);
CREATE TABLE work_program_concept_slots (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
program_id BIGINT, budget_item_id BIGINT, period_id BIGINT, start_pct numeric, end_pct numeric
);
CREATE TABLE work_program_progress (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
program_id BIGINT, budget_item_id BIGINT, period_id BIGINT, pct_complete numeric
);
CREATE TABLE expense_entries (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
project_id BIGINT, expense_date date, subtotal numeric(14,2),
status text, counts_toward_budget boolean, budget_item_id BIGINT
);
CREATE TABLE warehouses (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
tenant_id int, kind text, project_id BIGINT
);
CREATE TABLE warehouse_materials (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, tenant_id int, code text, name text
);
CREATE TABLE warehouse_movements (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
tenant_id int,
warehouse_id BIGINT REFERENCES warehouses(id),
material_id BIGINT,
movement_type text,
movement_date date,
quantity numeric,
total_cost numeric(14,2),
budget_item_id BIGINT
);
CREATE FUNCTION _cost_executed_amount(p_budget_item_id bigint) RETURNS numeric
LANGUAGE sql STABLE SET search_path = core AS $$
SELECT round(COALESCE(
(SELECT SUM(e.subtotal) FROM expense_entries e
WHERE e.budget_item_id = p_budget_item_id AND e.status = 'confirmed' AND e.counts_toward_budget = true),
0
) + COALESCE(
(SELECT SUM(m.total_cost) FROM warehouse_movements m
WHERE m.budget_item_id = p_budget_item_id AND m.movement_type = 'exit'),
0
), 2);
$$;