--liquibase formatted sql -- PANELS · core · RPC documentos (metadata post-S3) --changeset panel:core-015a-fn-project-document-store endDelimiter:; splitStatements:true CREATE OR REPLACE FUNCTION core.fn_project_document_store(payload jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY INVOKER SET search_path = core AS $$ DECLARE v_project_id bigint := (payload->>'project_id')::bigint; v_type text := btrim(payload->>'type_code'); v_doc_id bigint; BEGIN IF v_project_id IS NULL OR v_type IS NULL OR v_type = '' THEN RETURN core.rpc_err('VALIDATION', 'fn_project_document_store: project_id y type_code son obligatorios', jsonb_build_object('fn', 'fn_project_document_store')); END IF; IF NOT EXISTS (SELECT 1 FROM project_document_types WHERE code = v_type) THEN RETURN core.rpc_err('VALIDATION', format('fn_project_document_store: tipo de documento %s no válido para proyectos', v_type), jsonb_build_object('fn', 'fn_project_document_store', 'type_code', v_type)); END IF; UPDATE project_documents SET is_current = false WHERE project_id = v_project_id AND type_code = v_type; INSERT INTO project_documents ( project_id, type_code, original_name, mime, size_bytes, sha256, iv, storage_name, is_current, parse_status, uploaded_by_id, uploaded_by_name ) VALUES ( v_project_id, v_type, payload->>'original_name', payload->>'mime', (payload->>'size_bytes')::integer, payload->>'sha256', payload->>'iv', payload->>'storage_name', true, 'manual', NULLIF(payload->>'uploaded_by_id', '')::integer, coalesce(payload->>'uploaded_by_name', '') ) RETURNING id INTO v_doc_id; RETURN core.rpc_ok(jsonb_build_object('id', v_doc_id), format('Documento %s guardado para proyecto id=%s (doc id=%s)', v_type, v_project_id, v_doc_id), jsonb_build_object('fn', 'fn_project_document_store', 'project_id', v_project_id, 'id', v_doc_id)); EXCEPTION WHEN OTHERS THEN RETURN core.rpc_from_exception('fn_project_document_store', SQLSTATE, SQLERRM); END; $$; --changeset panel:core-015b-fn-company-document-store endDelimiter:; splitStatements:true CREATE OR REPLACE FUNCTION core.fn_company_document_store(payload jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY INVOKER SET search_path = core AS $$ DECLARE v_company_id bigint := (payload->>'company_id')::bigint; v_type text := btrim(payload->>'type_code'); v_doc_id bigint; BEGIN IF v_company_id IS NULL OR v_type IS NULL OR v_type = '' THEN RETURN core.rpc_err('VALIDATION', 'fn_company_document_store: company_id y type_code son obligatorios', jsonb_build_object('fn', 'fn_company_document_store')); END IF; IF NOT EXISTS (SELECT 1 FROM company_document_types WHERE code = v_type) THEN RETURN core.rpc_err('VALIDATION', format('fn_company_document_store: tipo de documento %s no válido para empresas', v_type), jsonb_build_object('fn', 'fn_company_document_store', 'type_code', v_type)); END IF; UPDATE company_documents SET is_current = false WHERE company_id = v_company_id AND type_code = v_type; INSERT INTO company_documents ( company_id, type_code, original_name, mime, size_bytes, sha256, iv, storage_name, is_current, parse_status, uploaded_by_id, uploaded_by_name ) VALUES ( v_company_id, v_type, payload->>'original_name', payload->>'mime', (payload->>'size_bytes')::integer, payload->>'sha256', payload->>'iv', payload->>'storage_name', true, 'manual', NULLIF(payload->>'uploaded_by_id', '')::integer, coalesce(payload->>'uploaded_by_name', '') ) RETURNING id INTO v_doc_id; RETURN core.rpc_ok(jsonb_build_object('id', v_doc_id), format('Documento %s guardado para empresa id=%s (doc id=%s)', v_type, v_company_id, v_doc_id), jsonb_build_object('fn', 'fn_company_document_store', 'company_id', v_company_id, 'id', v_doc_id)); EXCEPTION WHEN OTHERS THEN RETURN core.rpc_from_exception('fn_company_document_store', SQLSTATE, SQLERRM); END; $$; --changeset panel:core-015c-fn-document-get endDelimiter:; splitStatements:true CREATE OR REPLACE FUNCTION core.fn_project_document_get(payload jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY INVOKER SET search_path = core AS $$ DECLARE v_project_id bigint := (payload->>'project_id')::bigint; v_doc_id bigint := (payload->>'doc_id')::bigint; v_doc jsonb; BEGIN SELECT to_jsonb(d) INTO v_doc FROM project_documents d WHERE d.id = v_doc_id AND d.project_id = v_project_id; IF v_doc IS NULL THEN RETURN core.rpc_err('NOT_FOUND', format('fn_project_document_get: documento id=%s no encontrado en proyecto %s', v_doc_id, v_project_id), jsonb_build_object('fn', 'fn_project_document_get', 'doc_id', v_doc_id, 'project_id', v_project_id)); END IF; RETURN core.rpc_ok(jsonb_build_object('document', v_doc), format('Documento id=%s del proyecto %s obtenido', v_doc_id, v_project_id), jsonb_build_object('fn', 'fn_project_document_get', 'doc_id', v_doc_id)); EXCEPTION WHEN OTHERS THEN RETURN core.rpc_from_exception('fn_project_document_get', SQLSTATE, SQLERRM); END; $$; CREATE OR REPLACE FUNCTION core.fn_company_document_get(payload jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY INVOKER SET search_path = core AS $$ DECLARE v_company_id bigint := (payload->>'company_id')::bigint; v_doc_id bigint := (payload->>'doc_id')::bigint; v_doc jsonb; BEGIN SELECT to_jsonb(d) INTO v_doc FROM company_documents d WHERE d.id = v_doc_id AND d.company_id = v_company_id; IF v_doc IS NULL THEN RETURN core.rpc_err('NOT_FOUND', format('fn_company_document_get: documento id=%s no encontrado en empresa %s', v_doc_id, v_company_id), jsonb_build_object('fn', 'fn_company_document_get', 'doc_id', v_doc_id, 'company_id', v_company_id)); END IF; RETURN core.rpc_ok(jsonb_build_object('document', v_doc), format('Documento id=%s de la empresa %s obtenido', v_doc_id, v_company_id), jsonb_build_object('fn', 'fn_company_document_get', 'doc_id', v_doc_id)); EXCEPTION WHEN OTHERS THEN RETURN core.rpc_from_exception('fn_company_document_get', SQLSTATE, SQLERRM); END; $$; CREATE OR REPLACE FUNCTION core.fn_worker_document_get(payload jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY INVOKER SET search_path = core AS $$ DECLARE v_worker_id bigint := (payload->>'worker_id')::bigint; v_doc_id bigint := (payload->>'doc_id')::bigint; v_doc jsonb; BEGIN SELECT to_jsonb(d) INTO v_doc FROM documents d WHERE d.id = v_doc_id AND d.worker_id = v_worker_id; IF v_doc IS NULL THEN RETURN core.rpc_err('NOT_FOUND', format('fn_worker_document_get: documento id=%s no encontrado para trabajador %s', v_doc_id, v_worker_id), jsonb_build_object('fn', 'fn_worker_document_get', 'doc_id', v_doc_id, 'worker_id', v_worker_id)); END IF; RETURN core.rpc_ok(jsonb_build_object('document', v_doc), format('Documento id=%s del trabajador %s obtenido', v_doc_id, v_worker_id), jsonb_build_object('fn', 'fn_worker_document_get', 'doc_id', v_doc_id)); EXCEPTION WHEN OTHERS THEN RETURN core.rpc_from_exception('fn_worker_document_get', SQLSTATE, SQLERRM); END; $$; --changeset panel:core-015d-fn-documents-grants endDelimiter:; splitStatements:true GRANT EXECUTE ON FUNCTION core.fn_project_document_store(jsonb) TO panels_core_app; GRANT EXECUTE ON FUNCTION core.fn_company_document_store(jsonb) TO panels_core_app; GRANT EXECUTE ON FUNCTION core.fn_project_document_get(jsonb) TO panels_core_app; GRANT EXECUTE ON FUNCTION core.fn_company_document_get(jsonb) TO panels_core_app; GRANT EXECUTE ON FUNCTION core.fn_worker_document_get(jsonb) TO panels_core_app;