mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 18:43:18 +00:00
604 lines
22 KiB
PL/PgSQL
604 lines
22 KiB
PL/PgSQL
--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;
|