SET search_path = core; INSERT INTO projects (name, start_date, end_date) VALUES ('Obra test', '2026-09-07', '2026-09-19'); -- id = 1 INSERT INTO budget_chapters (project_id, code, name, sort_order) VALUES (1, 'A001', 'PRELIMINARES', 1); INSERT INTO budget_items (project_id, chapter_id, code, description, amount, sort_order) VALUES (1, 1, '10301-001', 'Trazo', 1000, 1); INSERT INTO work_programs (project_id, start_date, end_date, duration_days, source, status) VALUES (1, '2026-09-07', '2026-09-19', 13, 'import', 'active'); INSERT INTO work_program_periods (program_id, period_index, label, start_date, end_date) VALUES (1, 1, 'Sem 1', '2026-09-07', '2026-09-13'), (1, 2, 'Sem 2', '2026-09-14', '2026-09-19'); INSERT INTO work_program_partida_amounts (program_id, budget_chapter_id, period_id, amount) VALUES (1, 1, 1, 400.00), (1, 1, 2, 600.00); INSERT INTO work_program_concept_slots (program_id, budget_item_id, period_id, start_pct, end_pct) VALUES (1, 1, 1, 0, 50); INSERT INTO expense_entries (project_id, expense_date, subtotal, status, counts_toward_budget, budget_item_id) VALUES (1, '2026-09-08', 50.00, 'confirmed', true, 1); INSERT INTO warehouses (tenant_id, kind, project_id) VALUES (1, 'project', 1); INSERT INTO warehouse_materials (tenant_id, code, name) VALUES (1, 'CEM', 'Cemento'); INSERT INTO warehouse_movements (tenant_id, warehouse_id, material_id, movement_type, movement_date, quantity, total_cost, budget_item_id) VALUES (1, 1, 1, 'exit', '2026-09-09', 1, 25.00, 1); DO $$ DECLARE v_get jsonb; v_concepts jsonb; v_partidas jsonb; v_vs jsonb; v_broken jsonb; BEGIN v_get := fn_work_program_get(jsonb_build_object('project_id', 1)); IF NOT COALESCE((v_get->>'ok')::boolean, false) THEN RAISE EXCEPTION 'fn_work_program_get failed: %', v_get->>'message'; END IF; IF jsonb_array_length(v_get->'data'->'curve') <> 2 THEN RAISE EXCEPTION 'curve expected 2 periods, got %', v_get->'data'->'curve'; END IF; IF (v_get->'data'->'curve'->0->>'amount')::numeric <> 400 THEN RAISE EXCEPTION 'curve week1 amount %, expected 400', v_get->'data'->'curve'->0->>'amount'; END IF; IF (v_get->'data'->'curve'->1->>'amount')::numeric <> 600 THEN RAISE EXCEPTION 'curve week2 amount %, expected 600', v_get->'data'->'curve'->1->>'amount'; END IF; v_concepts := fn_work_program_list_concepts(jsonb_build_object('project_id', 1)); IF NOT COALESCE((v_concepts->>'ok')::boolean, false) THEN RAISE EXCEPTION 'fn_work_program_list_concepts failed: %', v_concepts->>'message'; END IF; IF jsonb_array_length(v_concepts->'data'->'items') < 1 THEN RAISE EXCEPTION 'concepts empty: %', v_concepts; END IF; v_partidas := fn_work_program_list_partidas(jsonb_build_object('project_id', 1)); IF NOT COALESCE((v_partidas->>'ok')::boolean, false) THEN RAISE EXCEPTION 'fn_work_program_list_partidas failed: %', v_partidas->>'message'; END IF; IF (v_partidas->'data'->'chapters'->0->>'code') <> 'A001' THEN RAISE EXCEPTION 'partida code %, expected A001', v_partidas->'data'->'chapters'->0->>'code'; END IF; v_vs := fn_work_program_vs_cost(jsonb_build_object('project_id', 1)); IF NOT COALESCE((v_vs->>'ok')::boolean, false) THEN RAISE EXCEPTION 'fn_work_program_vs_cost failed: %', v_vs->>'message'; END IF; -- Sem 1: gasto 50 + salida almacén 25 = 75 IF (v_vs->'data'->'by_period'->0->>'executed_amount')::numeric <> 75 THEN RAISE EXCEPTION 'vs-cost week1 executed %, expected 75. payload=%', v_vs->'data'->'by_period'->0->>'executed_amount', v_vs; END IF; IF (v_vs->'data'->'by_period'->0->>'scheduled_amount')::numeric <> 400 THEN RAISE EXCEPTION 'vs-cost week1 scheduled %, expected 400', v_vs->'data'->'by_period'->0->>'scheduled_amount'; END IF; IF (v_vs->'data'->'by_chapter'->0->>'executed_amount')::numeric <> 75 THEN RAISE EXCEPTION 'vs-cost chapter executed %, expected 75', v_vs->'data'->'by_chapter'->0->>'executed_amount'; END IF; IF (v_vs->'data'->'by_chapter'->0->>'scheduled_amount')::numeric <> 1000 THEN RAISE EXCEPTION 'vs-cost chapter scheduled %, expected 1000', v_vs->'data'->'by_chapter'->0->>'scheduled_amount'; END IF; RAISE NOTICE 'OK get+concepts+partidas+vs-cost'; END; $$;