mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 18:43:18 +00:00
Postgres no tiene jsonb_object_length; fn_work_program_replace tronaba al confirmar el Excel. El conteo de semanas ahora usa un contador en el loop de periodos. Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
123 lines
4.8 KiB
PL/PgSQL
123 lines
4.8 KiB
PL/PgSQL
--liquibase formatted sql
|
|
-- PANELS · core · fn_work_program_replace: jsonb_object_length no existe en PostgreSQL
|
|
|
|
--changeset panel:core-032a-fn-work-program-replace-period-count splitStatements:false
|
|
CREATE OR REPLACE FUNCTION core.fn_work_program_replace(payload jsonb)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
SECURITY INVOKER
|
|
SET search_path = core
|
|
AS $$
|
|
DECLARE
|
|
v_project_id bigint := NULLIF(payload->>'project_id', '')::bigint;
|
|
v_source text := COALESCE(nullif(btrim(payload->>'source'), ''), 'import');
|
|
v_status text := COALESCE(nullif(btrim(payload->>'status'), ''), 'active');
|
|
v_start date;
|
|
v_end date;
|
|
v_program_id bigint;
|
|
v_period jsonb;
|
|
v_period_id bigint;
|
|
v_period_map jsonb := '{}'::jsonb;
|
|
v_period_count integer := 0;
|
|
v_slot jsonb;
|
|
v_partida jsonb;
|
|
v_chapter jsonb;
|
|
v_ch jsonb;
|
|
v_slot_count integer := 0;
|
|
v_partida_count integer := 0;
|
|
v_err jsonb;
|
|
BEGIN
|
|
IF v_project_id IS NULL THEN
|
|
RETURN core.rpc_err('VALIDATION', 'fn_work_program_replace: project_id es obligatorio',
|
|
jsonb_build_object('fn', 'fn_work_program_replace'));
|
|
END IF;
|
|
|
|
v_err := core._wp_assert_project_ready(v_project_id);
|
|
IF v_err IS NOT NULL THEN RETURN v_err; END IF;
|
|
|
|
SELECT start_date, end_date INTO v_start, v_end FROM projects WHERE id = v_project_id;
|
|
|
|
DELETE FROM work_programs WHERE project_id = v_project_id;
|
|
|
|
INSERT INTO work_programs (project_id, start_date, end_date, duration_days, source, status)
|
|
VALUES (v_project_id, v_start, v_end, (v_end - v_start + 1), v_source, v_status)
|
|
RETURNING id INTO v_program_id;
|
|
|
|
FOR v_period IN SELECT * FROM jsonb_array_elements(core._wp_generate_periods(v_start, v_end)) LOOP
|
|
INSERT INTO work_program_periods (program_id, period_index, label, start_date, end_date)
|
|
VALUES (
|
|
v_program_id,
|
|
(v_period->>'period_index')::integer,
|
|
v_period->>'label',
|
|
(v_period->>'start_date')::date,
|
|
(v_period->>'end_date')::date
|
|
)
|
|
RETURNING id INTO v_period_id;
|
|
v_period_map := v_period_map || jsonb_build_object(v_period->>'period_index', v_period_id);
|
|
v_period_count := v_period_count + 1;
|
|
END LOOP;
|
|
|
|
FOR v_slot IN SELECT * FROM jsonb_array_elements(COALESCE(payload->'concept_slots', '[]'::jsonb)) LOOP
|
|
v_period_id := (v_period_map->>(v_slot->>'period_index'))::bigint;
|
|
IF v_period_id IS NULL THEN CONTINUE; END IF;
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM budget_items bi
|
|
WHERE bi.id = (v_slot->>'budget_item_id')::bigint AND bi.project_id = v_project_id
|
|
) THEN CONTINUE; END IF;
|
|
IF core._wp_slot_weight((v_slot->>'start_pct')::numeric, (v_slot->>'end_pct')::numeric) <= 0 THEN CONTINUE; END IF;
|
|
INSERT INTO work_program_concept_slots (program_id, budget_item_id, period_id, start_pct, end_pct)
|
|
VALUES (
|
|
v_program_id,
|
|
(v_slot->>'budget_item_id')::bigint,
|
|
v_period_id,
|
|
COALESCE((v_slot->>'start_pct')::numeric, 0),
|
|
COALESCE((v_slot->>'end_pct')::numeric, 0)
|
|
);
|
|
v_slot_count := v_slot_count + 1;
|
|
END LOOP;
|
|
|
|
FOR v_ch IN SELECT * FROM jsonb_array_elements(COALESCE(payload->'chapters_to_create', '[]'::jsonb)) LOOP
|
|
INSERT INTO budget_chapters (project_id, parent_id, code, name, wbs, sort_order)
|
|
VALUES (
|
|
v_project_id,
|
|
NULLIF(v_ch->>'parent_id', '')::bigint,
|
|
upper(COALESCE(nullif(btrim(v_ch->>'code'), ''), '')),
|
|
COALESCE(nullif(btrim(v_ch->>'name'), ''), 'Partida'),
|
|
COALESCE(nullif(btrim(v_ch->>'wbs'), ''), ''),
|
|
COALESCE((v_ch->>'sort_order')::integer, 0)
|
|
);
|
|
END LOOP;
|
|
|
|
FOR v_partida IN SELECT * FROM jsonb_array_elements(COALESCE(payload->'partida_amounts', '[]'::jsonb)) LOOP
|
|
v_period_id := (v_period_map->>(v_partida->>'period_index'))::bigint;
|
|
IF v_period_id IS NULL THEN CONTINUE; END IF;
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM budget_chapters bc
|
|
WHERE bc.id = (v_partida->>'budget_chapter_id')::bigint AND bc.project_id = v_project_id
|
|
) THEN CONTINUE; END IF;
|
|
IF COALESCE((v_partida->>'amount')::numeric, 0) = 0 THEN CONTINUE; END IF;
|
|
INSERT INTO work_program_partida_amounts (program_id, budget_chapter_id, period_id, amount)
|
|
VALUES (
|
|
v_program_id,
|
|
(v_partida->>'budget_chapter_id')::bigint,
|
|
v_period_id,
|
|
round(COALESCE((v_partida->>'amount')::numeric, 0), 2)
|
|
);
|
|
v_partida_count := v_partida_count + 1;
|
|
END LOOP;
|
|
|
|
RETURN core.rpc_ok(
|
|
jsonb_build_object(
|
|
'program_id', v_program_id,
|
|
'concept_slots', v_slot_count,
|
|
'partida_amounts', v_partida_count,
|
|
'period_count', v_period_count
|
|
),
|
|
format('Programa de obra del proyecto %s reemplazado (%s slots, %s erogaciones)',
|
|
v_project_id, v_slot_count, v_partida_count),
|
|
jsonb_build_object('fn', 'fn_work_program_replace', 'project_id', v_project_id)
|
|
);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
RETURN core.rpc_from_exception('fn_work_program_replace', SQLSTATE, SQLERRM);
|
|
END;
|
|
$$;
|