--liquibase formatted sql -- PANELS · core · fn_work_program_get: v_row es jsonb, no un record (.value = 42P01) --changeset panel:core-037-fn-work-program-get-curve-vrow splitStatements:false CREATE OR REPLACE FUNCTION core.fn_work_program_get(payload jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY INVOKER SET search_path = core AS $$ DECLARE v_project_id bigint := NULLIF(payload->>'project_id', '')::bigint; v_program jsonb; v_periods jsonb; v_budget_total numeric(14,2); v_curve jsonb; BEGIN IF v_project_id IS NULL THEN RETURN core.rpc_err('VALIDATION', 'fn_work_program_get: project_id es obligatorio', jsonb_build_object('fn', 'fn_work_program_get')); END IF; SELECT to_jsonb(wp) INTO v_program FROM work_programs wp WHERE wp.project_id = v_project_id; IF v_program IS NULL THEN SELECT COALESCE(SUM(amount), 0) INTO v_budget_total FROM budget_items WHERE project_id = v_project_id; RETURN core.rpc_ok( jsonb_build_object( 'program', NULL, 'periods', '[]'::jsonb, 'budget_subtotal', v_budget_total, 'curve', '[]'::jsonb ), format('Proyecto %s sin programa de obra', v_project_id), jsonb_build_object('fn', 'fn_work_program_get', 'project_id', v_project_id) ); END IF; SELECT COALESCE(jsonb_agg(to_jsonb(p) ORDER BY p.period_index), '[]'::jsonb) INTO v_periods FROM work_program_periods p WHERE p.program_id = (v_program->>'id')::bigint; SELECT COALESCE(SUM(amount), 0) INTO v_budget_total FROM budget_items WHERE project_id = v_project_id; -- Sin FOR + v_row.value (eso lo toma Postgres como tabla.columna → 42P01). -- SUM de montos en subquery; jsonb_agg y el acumulado van en capas distintas -- para no anidar agregados (42803). SELECT COALESCE(jsonb_agg(to_jsonb(y) ORDER BY y.period_index), '[]'::jsonb) INTO v_curve FROM ( SELECT x.period_index, x.label, x.amount, CASE WHEN v_budget_total > 0 THEN round(x.amount / v_budget_total, 6) ELSE 0 END AS pct_period, CASE WHEN v_budget_total > 0 THEN round(SUM(x.amount) OVER (ORDER BY x.period_index) / v_budget_total, 6) ELSE 0 END AS pct_cumulative FROM ( SELECT pr.period_index, pr.label, round(COALESCE(SUM(pa.amount), 0), 2) AS amount FROM work_program_periods pr LEFT JOIN work_program_partida_amounts pa ON pa.period_id = pr.id WHERE pr.program_id = (v_program->>'id')::bigint GROUP BY pr.period_index, pr.label ) x ) y; RETURN core.rpc_ok( jsonb_build_object( 'program', v_program, 'periods', v_periods, 'budget_subtotal', v_budget_total, 'curve', v_curve ), format('Programa de obra del proyecto %s', v_project_id), jsonb_build_object('fn', 'fn_work_program_get', 'project_id', v_project_id) ); EXCEPTION WHEN OTHERS THEN RETURN core.rpc_from_exception('fn_work_program_get', SQLSTATE, SQLERRM); END; $$;