mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 12:43:18 +00:00
Add PostgreSQL RPC functions for projects domain (009-rpc-projects)
Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
This commit is contained in:
parent
02098d37b3
commit
a73090bd11
1 changed files with 604 additions and 0 deletions
604
db/core/changesets/009-rpc-projects.sql
Normal file
604
db/core/changesets/009-rpc-projects.sql
Normal file
|
|
@ -0,0 +1,604 @@
|
|||
--liquibase formatted sql
|
||||
-- PANELS · core · RPC proyectos (obras)
|
||||
|
||||
--changeset panel:core-009a-fn-next-project-code endDelimiter:; splitStatements:true
|
||||
CREATE OR REPLACE FUNCTION core.fn_next_project_code(payload jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
SET search_path = core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_n integer;
|
||||
v_code text;
|
||||
BEGIN
|
||||
SELECT COALESCE(MAX(substring(code FROM 5)::integer), 0) + 1
|
||||
INTO v_n
|
||||
FROM projects
|
||||
WHERE code ~ '^PRY-[0-9]{4}' OR code ~ '^OBR-[0-9]{4}';
|
||||
v_code := 'PRY-' || lpad(v_n::text, 4, '0');
|
||||
RETURN core.rpc_ok(
|
||||
jsonb_build_object('code', v_code),
|
||||
format('Siguiente código de proyecto asignado: %s', v_code),
|
||||
jsonb_build_object('fn', 'fn_next_project_code', 'sequence', v_n)
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN core.rpc_from_exception('fn_next_project_code', SQLSTATE, SQLERRM);
|
||||
END;
|
||||
$$;
|
||||
|
||||
--changeset panel:core-009b-fn-project-assert-status endDelimiter:; splitStatements:true
|
||||
CREATE OR REPLACE FUNCTION core.fn_project_assert_status(payload jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
SET search_path = core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_id bigint := (payload->>'project_id')::bigint;
|
||||
v_allowed text[];
|
||||
v_proj record;
|
||||
BEGIN
|
||||
IF v_id IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_assert_status: project_id es obligatorio',
|
||||
jsonb_build_object('fn', 'fn_project_assert_status', 'field', 'project_id')
|
||||
);
|
||||
END IF;
|
||||
IF payload->'allowed_statuses' IS NULL OR jsonb_typeof(payload->'allowed_statuses') <> 'array' THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_assert_status: allowed_statuses debe ser un arreglo JSON',
|
||||
jsonb_build_object('fn', 'fn_project_assert_status', 'field', 'allowed_statuses')
|
||||
);
|
||||
END IF;
|
||||
SELECT array_agg(btrim(elem))
|
||||
INTO v_allowed
|
||||
FROM jsonb_array_elements_text(payload->'allowed_statuses') AS elem
|
||||
WHERE btrim(elem) IN ('activo', 'pausado', 'concluido', 'cancelado');
|
||||
IF v_allowed IS NULL OR cardinality(v_allowed) = 0 THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_assert_status: allowed_statuses no contiene estados válidos',
|
||||
jsonb_build_object('fn', 'fn_project_assert_status', 'field', 'allowed_statuses')
|
||||
);
|
||||
END IF;
|
||||
SELECT p.id, p.code, p.name, p.status
|
||||
INTO v_proj
|
||||
FROM projects p
|
||||
WHERE p.id = v_id;
|
||||
IF NOT FOUND THEN
|
||||
RETURN core.rpc_err(
|
||||
'NOT_FOUND',
|
||||
format('fn_project_assert_status: proyecto id=%s no encontrado', v_id),
|
||||
jsonb_build_object('fn', 'fn_project_assert_status', 'project_id', v_id)
|
||||
);
|
||||
END IF;
|
||||
IF NOT (v_proj.status = ANY (v_allowed)) THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
format('fn_project_assert_status: proyecto %s (%s) está en estado %s, no permitido para esta operación',
|
||||
v_proj.code, v_id, v_proj.status),
|
||||
jsonb_build_object(
|
||||
'fn', 'fn_project_assert_status',
|
||||
'project_id', v_id,
|
||||
'status', v_proj.status,
|
||||
'allowed_statuses', to_jsonb(v_allowed)
|
||||
)
|
||||
);
|
||||
END IF;
|
||||
RETURN core.rpc_ok(
|
||||
jsonb_build_object(
|
||||
'project_id', v_proj.id,
|
||||
'code', v_proj.code,
|
||||
'name', v_proj.name,
|
||||
'status', v_proj.status
|
||||
),
|
||||
format('Proyecto %s en estado %s válido para la operación', v_proj.code, v_proj.status),
|
||||
jsonb_build_object('fn', 'fn_project_assert_status', 'project_id', v_id)
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN core.rpc_from_exception('fn_project_assert_status', SQLSTATE, SQLERRM);
|
||||
END;
|
||||
$$;
|
||||
|
||||
--changeset panel:core-009c-fn-project-list endDelimiter:; splitStatements:true
|
||||
CREATE OR REPLACE FUNCTION core.fn_project_list(payload jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
SET search_path = core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_status_raw text := nullif(btrim(payload->>'status'), '');
|
||||
v_statuses text[];
|
||||
v_projects jsonb;
|
||||
BEGIN
|
||||
IF v_status_raw IS NOT NULL THEN
|
||||
SELECT array_agg(DISTINCT btrim(s))
|
||||
INTO v_statuses
|
||||
FROM unnest(string_to_array(v_status_raw, ',')) AS s
|
||||
WHERE btrim(s) IN ('activo', 'pausado', 'concluido', 'cancelado');
|
||||
IF v_statuses IS NULL OR cardinality(v_statuses) = 0 THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
format('fn_project_list: ningún estado válido en status=%s', v_status_raw),
|
||||
jsonb_build_object('fn', 'fn_project_list', 'field', 'status', 'value', v_status_raw)
|
||||
);
|
||||
END IF;
|
||||
END IF;
|
||||
SELECT COALESCE(jsonb_agg(row_to_json(x)::jsonb ORDER BY x.sort_key, x.id), '[]'::jsonb)
|
||||
INTO v_projects
|
||||
FROM (
|
||||
SELECT
|
||||
p.*,
|
||||
c.name AS company_name,
|
||||
c.code AS company_code,
|
||||
(SELECT COUNT(*) FROM assignments a WHERE a.project_id = p.id AND a.active = true) AS active_count,
|
||||
(SELECT COUNT(*) FROM project_document_types t
|
||||
WHERE t.required = true AND NOT EXISTS (
|
||||
SELECT 1 FROM project_documents d
|
||||
WHERE d.project_id = p.id AND d.type_code = t.code AND d.is_current = true
|
||||
)) AS missing_docs,
|
||||
(SELECT COUNT(*) FROM budget_items b WHERE b.project_id = p.id) AS budget_count,
|
||||
CASE p.status
|
||||
WHEN 'activo' THEN 0
|
||||
WHEN 'pausado' THEN 1
|
||||
WHEN 'concluido' THEN 2
|
||||
ELSE 3
|
||||
END AS sort_key
|
||||
FROM projects p
|
||||
LEFT JOIN companies c ON c.id = p.company_id
|
||||
WHERE v_statuses IS NULL OR p.status = ANY (v_statuses)
|
||||
) x;
|
||||
RETURN core.rpc_ok(
|
||||
jsonb_build_object('projects', v_projects),
|
||||
format('Listado de proyectos: %s registro(s)', jsonb_array_length(v_projects)),
|
||||
jsonb_build_object('fn', 'fn_project_list', 'count', jsonb_array_length(v_projects))
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN core.rpc_from_exception('fn_project_list', SQLSTATE, SQLERRM);
|
||||
END;
|
||||
$$;
|
||||
|
||||
--changeset panel:core-009d-fn-project-get endDelimiter:; splitStatements:true
|
||||
CREATE OR REPLACE FUNCTION core.fn_project_get(payload jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
SET search_path = core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_id bigint := (payload->>'id')::bigint;
|
||||
v_project jsonb;
|
||||
BEGIN
|
||||
IF v_id IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_get: id es obligatorio',
|
||||
jsonb_build_object('fn', 'fn_project_get', 'field', 'id')
|
||||
);
|
||||
END IF;
|
||||
SELECT row_to_json(x)::jsonb
|
||||
INTO v_project
|
||||
FROM (
|
||||
SELECT
|
||||
p.*,
|
||||
c.name AS company_name,
|
||||
c.code AS company_code,
|
||||
(SELECT COUNT(*) FROM assignments a WHERE a.project_id = p.id AND a.active = true) AS active_count
|
||||
FROM projects p
|
||||
LEFT JOIN companies c ON c.id = p.company_id
|
||||
WHERE p.id = v_id
|
||||
) x;
|
||||
IF v_project IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'NOT_FOUND',
|
||||
format('fn_project_get: proyecto id=%s no encontrado', v_id),
|
||||
jsonb_build_object('fn', 'fn_project_get', 'id', v_id)
|
||||
);
|
||||
END IF;
|
||||
RETURN core.rpc_ok(
|
||||
jsonb_build_object('project', v_project),
|
||||
format('Proyecto %s cargado', v_project->>'code'),
|
||||
jsonb_build_object('fn', 'fn_project_get', 'id', v_id)
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN core.rpc_from_exception('fn_project_get', SQLSTATE, SQLERRM);
|
||||
END;
|
||||
$$;
|
||||
|
||||
--changeset panel:core-009e-fn-project-create endDelimiter:; splitStatements:true
|
||||
CREATE OR REPLACE FUNCTION core.fn_project_create(payload jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
SET search_path = core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_tid integer := COALESCE(
|
||||
(payload->>'tenant_id')::integer,
|
||||
NULLIF(current_setting('app.tenant_id', true), '')::integer
|
||||
);
|
||||
v_name text := nullif(btrim(payload->>'name'), '');
|
||||
v_address text := coalesce(nullif(btrim(payload->>'address'), ''), '');
|
||||
v_theme_id text := coalesce(nullif(btrim(payload->>'theme_id'), ''), 'arctec-dos-logos-fold');
|
||||
v_status text := coalesce(nullif(btrim(payload->>'status'), ''), 'activo');
|
||||
v_company_id integer := (payload->>'company_id')::integer;
|
||||
v_contract_amount numeric(14,2) := (payload->>'contract_amount')::numeric(14,2);
|
||||
v_start_date date := nullif(btrim(payload->>'start_date'), '')::date;
|
||||
v_end_date date := nullif(btrim(payload->>'end_date'), '')::date;
|
||||
v_resident_name text := coalesce(nullif(btrim(payload->>'resident_name'), ''), '');
|
||||
v_siroc text := upper(coalesce(nullif(btrim(payload->>'siroc'), ''), ''));
|
||||
v_payroll_tax_pct numeric(5,2) := coalesce((payload->>'payroll_tax_pct')::numeric(5,2), 4);
|
||||
v_code_env jsonb;
|
||||
v_code text;
|
||||
v_row projects%ROWTYPE;
|
||||
BEGIN
|
||||
IF v_name IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_create: nombre de proyecto obligatorio',
|
||||
jsonb_build_object('fn', 'fn_project_create', 'field', 'name')
|
||||
);
|
||||
END IF;
|
||||
IF v_company_id IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_create: company_id es obligatorio',
|
||||
jsonb_build_object('fn', 'fn_project_create', 'field', 'company_id')
|
||||
);
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM companies WHERE id = v_company_id) THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
format('fn_project_create: empresa id=%s no encontrada', v_company_id),
|
||||
jsonb_build_object('fn', 'fn_project_create', 'company_id', v_company_id)
|
||||
);
|
||||
END IF;
|
||||
IF v_status NOT IN ('activo', 'pausado', 'concluido', 'cancelado') THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
format('fn_project_create: estado inválido %s', v_status),
|
||||
jsonb_build_object('fn', 'fn_project_create', 'field', 'status', 'value', v_status)
|
||||
);
|
||||
END IF;
|
||||
IF v_start_date IS NOT NULL AND v_end_date IS NOT NULL AND v_end_date < v_start_date THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_create: la fecha de término no puede ser anterior al inicio',
|
||||
jsonb_build_object('fn', 'fn_project_create', 'field', 'end_date')
|
||||
);
|
||||
END IF;
|
||||
v_code_env := core.fn_next_project_code('{}'::jsonb);
|
||||
IF NOT COALESCE((v_code_env->>'ok')::boolean, false) THEN
|
||||
RETURN v_code_env;
|
||||
END IF;
|
||||
v_code := v_code_env->'data'->>'code';
|
||||
INSERT INTO projects (
|
||||
code, name, address, theme_id, status, company_id, contract_amount,
|
||||
start_date, end_date, resident_name, siroc, payroll_tax_pct, tenant_id
|
||||
) VALUES (
|
||||
v_code, v_name, v_address, v_theme_id, v_status, v_company_id, v_contract_amount,
|
||||
v_start_date, v_end_date, v_resident_name, v_siroc, v_payroll_tax_pct, v_tid
|
||||
)
|
||||
RETURNING * INTO v_row;
|
||||
RETURN core.rpc_created(
|
||||
jsonb_build_object('id', v_row.id, 'code', v_row.code, 'status', v_row.status),
|
||||
format('Proyecto %s (%s) creado', v_row.code, v_row.name),
|
||||
jsonb_build_object('fn', 'fn_project_create', 'id', v_row.id, 'code', v_row.code)
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN core.rpc_from_exception('fn_project_create', SQLSTATE, SQLERRM);
|
||||
END;
|
||||
$$;
|
||||
|
||||
--changeset panel:core-009f-fn-project-update endDelimiter:; splitStatements:true
|
||||
CREATE OR REPLACE FUNCTION core.fn_project_update(payload jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
SET search_path = core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_id bigint := (payload->>'id')::bigint;
|
||||
v_cur projects%ROWTYPE;
|
||||
v_name text;
|
||||
v_address text;
|
||||
v_theme_id text;
|
||||
v_status text;
|
||||
v_company_id integer;
|
||||
v_contract_amount numeric(14,2);
|
||||
v_start_date date;
|
||||
v_end_date date;
|
||||
v_resident_name text;
|
||||
v_siroc text;
|
||||
v_payroll_tax_pct numeric(5,2);
|
||||
BEGIN
|
||||
IF v_id IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_update: id es obligatorio',
|
||||
jsonb_build_object('fn', 'fn_project_update', 'field', 'id')
|
||||
);
|
||||
END IF;
|
||||
SELECT * INTO v_cur FROM projects WHERE id = v_id;
|
||||
IF NOT FOUND THEN
|
||||
RETURN core.rpc_err(
|
||||
'NOT_FOUND',
|
||||
format('fn_project_update: proyecto id=%s no encontrado', v_id),
|
||||
jsonb_build_object('fn', 'fn_project_update', 'id', v_id)
|
||||
);
|
||||
END IF;
|
||||
v_name := coalesce(nullif(btrim(payload->>'name'), ''), v_cur.name);
|
||||
v_address := CASE WHEN payload ? 'address' THEN coalesce(nullif(btrim(payload->>'address'), ''), '') ELSE v_cur.address END;
|
||||
v_theme_id := coalesce(nullif(btrim(payload->>'theme_id'), ''), v_cur.theme_id);
|
||||
v_status := CASE
|
||||
WHEN payload ? 'status' AND btrim(payload->>'status') IN ('activo', 'pausado', 'concluido', 'cancelado')
|
||||
THEN btrim(payload->>'status')
|
||||
ELSE v_cur.status
|
||||
END;
|
||||
v_company_id := coalesce((payload->>'company_id')::integer, v_cur.company_id);
|
||||
v_contract_amount := CASE
|
||||
WHEN payload ? 'contract_amount' THEN (payload->>'contract_amount')::numeric(14,2)
|
||||
ELSE v_cur.contract_amount
|
||||
END;
|
||||
v_start_date := CASE
|
||||
WHEN payload ? 'start_date' THEN nullif(btrim(payload->>'start_date'), '')::date
|
||||
ELSE v_cur.start_date
|
||||
END;
|
||||
v_end_date := CASE
|
||||
WHEN payload ? 'end_date' THEN nullif(btrim(payload->>'end_date'), '')::date
|
||||
ELSE v_cur.end_date
|
||||
END;
|
||||
v_resident_name := CASE
|
||||
WHEN payload ? 'resident_name' THEN coalesce(nullif(btrim(payload->>'resident_name'), ''), '')
|
||||
ELSE v_cur.resident_name
|
||||
END;
|
||||
v_siroc := CASE
|
||||
WHEN payload ? 'siroc' THEN upper(coalesce(nullif(btrim(payload->>'siroc'), ''), ''))
|
||||
ELSE v_cur.siroc
|
||||
END;
|
||||
v_payroll_tax_pct := coalesce((payload->>'payroll_tax_pct')::numeric(5,2), v_cur.payroll_tax_pct);
|
||||
IF v_company_id IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_update: company_id es obligatorio',
|
||||
jsonb_build_object('fn', 'fn_project_update', 'field', 'company_id', 'id', v_id)
|
||||
);
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM companies WHERE id = v_company_id) THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
format('fn_project_update: empresa id=%s no encontrada', v_company_id),
|
||||
jsonb_build_object('fn', 'fn_project_update', 'company_id', v_company_id, 'id', v_id)
|
||||
);
|
||||
END IF;
|
||||
IF v_start_date IS NOT NULL AND v_end_date IS NOT NULL AND v_end_date < v_start_date THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_update: la fecha de término no puede ser anterior al inicio',
|
||||
jsonb_build_object('fn', 'fn_project_update', 'field', 'end_date', 'id', v_id)
|
||||
);
|
||||
END IF;
|
||||
UPDATE projects SET
|
||||
name = v_name,
|
||||
address = v_address,
|
||||
theme_id = v_theme_id,
|
||||
status = v_status,
|
||||
company_id = v_company_id,
|
||||
contract_amount = v_contract_amount,
|
||||
start_date = v_start_date,
|
||||
end_date = v_end_date,
|
||||
resident_name = v_resident_name,
|
||||
siroc = v_siroc,
|
||||
payroll_tax_pct = v_payroll_tax_pct
|
||||
WHERE id = v_id;
|
||||
RETURN core.rpc_ok(
|
||||
jsonb_build_object('id', v_id, 'code', v_cur.code, 'status', v_status),
|
||||
format('Proyecto %s actualizado', v_cur.code),
|
||||
jsonb_build_object('fn', 'fn_project_update', 'id', v_id, 'code', v_cur.code)
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN core.rpc_from_exception('fn_project_update', SQLSTATE, SQLERRM);
|
||||
END;
|
||||
$$;
|
||||
|
||||
--changeset panel:core-009g-fn-project-document-list endDelimiter:; splitStatements:true
|
||||
CREATE OR REPLACE FUNCTION core.fn_project_document_list(payload jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
SET search_path = core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_project_id bigint := (payload->>'project_id')::bigint;
|
||||
v_documents jsonb;
|
||||
BEGIN
|
||||
IF v_project_id IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_document_list: project_id es obligatorio',
|
||||
jsonb_build_object('fn', 'fn_project_document_list', 'field', 'project_id')
|
||||
);
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM projects WHERE id = v_project_id) THEN
|
||||
RETURN core.rpc_err(
|
||||
'NOT_FOUND',
|
||||
format('fn_project_document_list: proyecto id=%s no encontrado', v_project_id),
|
||||
jsonb_build_object('fn', 'fn_project_document_list', 'project_id', v_project_id)
|
||||
);
|
||||
END IF;
|
||||
SELECT COALESCE(jsonb_agg(to_jsonb(d) ORDER BY d.uploaded_at DESC), '[]'::jsonb)
|
||||
INTO v_documents
|
||||
FROM (
|
||||
SELECT id, type_code, original_name, mime, size_bytes, is_current, uploaded_at
|
||||
FROM project_documents
|
||||
WHERE project_id = v_project_id
|
||||
) d;
|
||||
RETURN core.rpc_ok(
|
||||
jsonb_build_object('documents', v_documents),
|
||||
format('Documentos del proyecto %s: %s archivo(s)', v_project_id, jsonb_array_length(v_documents)),
|
||||
jsonb_build_object('fn', 'fn_project_document_list', 'project_id', v_project_id, 'count', jsonb_array_length(v_documents))
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN core.rpc_from_exception('fn_project_document_list', SQLSTATE, SQLERRM);
|
||||
END;
|
||||
$$;
|
||||
|
||||
--changeset panel:core-009h-fn-company-document-list endDelimiter:; splitStatements:true
|
||||
CREATE OR REPLACE FUNCTION core.fn_company_document_list(payload jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
SET search_path = core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_company_id integer := (payload->>'company_id')::integer;
|
||||
v_documents jsonb;
|
||||
BEGIN
|
||||
IF v_company_id IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_company_document_list: company_id es obligatorio',
|
||||
jsonb_build_object('fn', 'fn_company_document_list', 'field', 'company_id')
|
||||
);
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM companies WHERE id = v_company_id) THEN
|
||||
RETURN core.rpc_err(
|
||||
'NOT_FOUND',
|
||||
format('fn_company_document_list: empresa id=%s no encontrada', v_company_id),
|
||||
jsonb_build_object('fn', 'fn_company_document_list', 'company_id', v_company_id)
|
||||
);
|
||||
END IF;
|
||||
SELECT COALESCE(jsonb_agg(to_jsonb(d) ORDER BY d.uploaded_at DESC), '[]'::jsonb)
|
||||
INTO v_documents
|
||||
FROM (
|
||||
SELECT id, type_code, original_name, mime, size_bytes, is_current, uploaded_at
|
||||
FROM company_documents
|
||||
WHERE company_id = v_company_id
|
||||
) d;
|
||||
RETURN core.rpc_ok(
|
||||
jsonb_build_object('documents', v_documents),
|
||||
format('Documentos de la empresa %s: %s archivo(s)', v_company_id, jsonb_array_length(v_documents)),
|
||||
jsonb_build_object('fn', 'fn_company_document_list', 'company_id', v_company_id, 'count', jsonb_array_length(v_documents))
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN core.rpc_from_exception('fn_company_document_list', SQLSTATE, SQLERRM);
|
||||
END;
|
||||
$$;
|
||||
|
||||
--changeset panel:core-009i-fn-project-checklist endDelimiter:; splitStatements:true
|
||||
CREATE OR REPLACE FUNCTION core.fn_project_checklist(payload jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
SET search_path = core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_project_id bigint := (payload->>'project_id')::bigint;
|
||||
v_checklist jsonb;
|
||||
BEGIN
|
||||
IF v_project_id IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_project_checklist: project_id es obligatorio',
|
||||
jsonb_build_object('fn', 'fn_project_checklist', 'field', 'project_id')
|
||||
);
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM projects WHERE id = v_project_id) THEN
|
||||
RETURN core.rpc_err(
|
||||
'NOT_FOUND',
|
||||
format('fn_project_checklist: proyecto id=%s no encontrado', v_project_id),
|
||||
jsonb_build_object('fn', 'fn_project_checklist', 'project_id', v_project_id)
|
||||
);
|
||||
END IF;
|
||||
SELECT COALESCE(jsonb_agg(
|
||||
jsonb_build_object(
|
||||
'code', t.code,
|
||||
'label', t.label,
|
||||
'required', t.required,
|
||||
'category', coalesce(t.category, 'otro'),
|
||||
'present', EXISTS (
|
||||
SELECT 1 FROM project_documents d
|
||||
WHERE d.project_id = v_project_id
|
||||
AND d.type_code = t.code
|
||||
AND d.is_current = true
|
||||
)
|
||||
) ORDER BY t.code
|
||||
), '[]'::jsonb)
|
||||
INTO v_checklist
|
||||
FROM project_document_types t;
|
||||
RETURN core.rpc_ok(
|
||||
jsonb_build_object('checklist', v_checklist),
|
||||
format('Checklist documental del proyecto %s: %s tipo(s)', v_project_id, jsonb_array_length(v_checklist)),
|
||||
jsonb_build_object('fn', 'fn_project_checklist', 'project_id', v_project_id, 'count', jsonb_array_length(v_checklist))
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN core.rpc_from_exception('fn_project_checklist', SQLSTATE, SQLERRM);
|
||||
END;
|
||||
$$;
|
||||
|
||||
--changeset panel:core-009j-fn-company-checklist endDelimiter:; splitStatements:true
|
||||
CREATE OR REPLACE FUNCTION core.fn_company_checklist(payload jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
SET search_path = core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_company_id integer := (payload->>'company_id')::integer;
|
||||
v_checklist jsonb;
|
||||
BEGIN
|
||||
IF v_company_id IS NULL THEN
|
||||
RETURN core.rpc_err(
|
||||
'VALIDATION',
|
||||
'fn_company_checklist: company_id es obligatorio',
|
||||
jsonb_build_object('fn', 'fn_company_checklist', 'field', 'company_id')
|
||||
);
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM companies WHERE id = v_company_id) THEN
|
||||
RETURN core.rpc_err(
|
||||
'NOT_FOUND',
|
||||
format('fn_company_checklist: empresa id=%s no encontrada', v_company_id),
|
||||
jsonb_build_object('fn', 'fn_company_checklist', 'company_id', v_company_id)
|
||||
);
|
||||
END IF;
|
||||
SELECT COALESCE(jsonb_agg(
|
||||
jsonb_build_object(
|
||||
'code', t.code,
|
||||
'label', t.label,
|
||||
'required', t.required,
|
||||
'category', coalesce(t.category, 'otro'),
|
||||
'present', EXISTS (
|
||||
SELECT 1 FROM company_documents d
|
||||
WHERE d.company_id = v_company_id
|
||||
AND d.type_code = t.code
|
||||
AND d.is_current = true
|
||||
)
|
||||
) ORDER BY t.code
|
||||
), '[]'::jsonb)
|
||||
INTO v_checklist
|
||||
FROM company_document_types t;
|
||||
RETURN core.rpc_ok(
|
||||
jsonb_build_object('checklist', v_checklist),
|
||||
format('Checklist documental de la empresa %s: %s tipo(s)', v_company_id, jsonb_array_length(v_checklist)),
|
||||
jsonb_build_object('fn', 'fn_company_checklist', 'company_id', v_company_id, 'count', jsonb_array_length(v_checklist))
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN core.rpc_from_exception('fn_company_checklist', SQLSTATE, SQLERRM);
|
||||
END;
|
||||
$$;
|
||||
|
||||
--changeset panel:core-009k-fn-projects-grants endDelimiter:; splitStatements:true
|
||||
GRANT EXECUTE ON FUNCTION core.fn_next_project_code(jsonb) TO panels_core_app;
|
||||
GRANT EXECUTE ON FUNCTION core.fn_project_assert_status(jsonb) TO panels_core_app;
|
||||
GRANT EXECUTE ON FUNCTION core.fn_project_list(jsonb) TO panels_core_app;
|
||||
GRANT EXECUTE ON FUNCTION core.fn_project_get(jsonb) TO panels_core_app;
|
||||
GRANT EXECUTE ON FUNCTION core.fn_project_create(jsonb) TO panels_core_app;
|
||||
GRANT EXECUTE ON FUNCTION core.fn_project_update(jsonb) TO panels_core_app;
|
||||
GRANT EXECUTE ON FUNCTION core.fn_project_document_list(jsonb) TO panels_core_app;
|
||||
GRANT EXECUTE ON FUNCTION core.fn_company_document_list(jsonb) TO panels_core_app;
|
||||
GRANT EXECUTE ON FUNCTION core.fn_project_checklist(jsonb) TO panels_core_app;
|
||||
GRANT EXECUTE ON FUNCTION core.fn_company_checklist(jsonb) TO panels_core_app;
|
||||
Loading…
Reference in a new issue