348 lines
12 KiB
PL/PgSQL
348 lines
12 KiB
PL/PgSQL
-- ============================================================
|
|
-- CRUCE DE CUENTAS GLM · HABILITAR EL SALVADOR (SV)
|
|
-- ============================================================
|
|
-- Ejecutar UNA VEZ en el SQL Editor del Supabase empresarial.
|
|
-- Es idempotente y conserva los datos existentes de Guatemala, Trinidad y Tobago y Panamá.
|
|
-- La tabla de reportes conserva su nombre legado cruces_cuentas_gt_reportes,
|
|
-- pero funciona como tabla multi-país mediante la columna country.
|
|
|
|
begin;
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 1. Checks de país en aliases/correcciones BambooHR
|
|
-- ------------------------------------------------------------
|
|
do $$
|
|
declare
|
|
r record;
|
|
begin
|
|
if to_regclass('public.cruce_cuentas_bamboo_aliases') is null then
|
|
raise exception 'No existe public.cruce_cuentas_bamboo_aliases. Ejecuta primero el SQL base de aliases BambooHR.';
|
|
end if;
|
|
|
|
if to_regclass('public.cruce_cuentas_bamboo_correcciones') is null then
|
|
raise exception 'No existe public.cruce_cuentas_bamboo_correcciones. Ejecuta primero el SQL base de correcciones BambooHR.';
|
|
end if;
|
|
|
|
for r in
|
|
select c.conname
|
|
from pg_constraint c
|
|
where c.conrelid = 'public.cruce_cuentas_bamboo_aliases'::regclass
|
|
and c.contype = 'c'
|
|
and pg_get_constraintdef(c.oid) ilike '%pais%'
|
|
and pg_get_constraintdef(c.oid) ilike '%GT%'
|
|
and pg_get_constraintdef(c.oid) ilike '%TT%'
|
|
and pg_get_constraintdef(c.oid) not ilike '%SV%'
|
|
loop
|
|
execute format('alter table public.cruce_cuentas_bamboo_aliases drop constraint %I', r.conname);
|
|
end loop;
|
|
|
|
if not exists (
|
|
select 1 from pg_constraint
|
|
where conrelid = 'public.cruce_cuentas_bamboo_aliases'::regclass
|
|
and conname = 'ck_cruce_cuentas_bamboo_aliases_pais'
|
|
) then
|
|
alter table public.cruce_cuentas_bamboo_aliases
|
|
add constraint ck_cruce_cuentas_bamboo_aliases_pais
|
|
check (upper(trim(pais)) in ('GT', 'TT', 'PA', 'SV'));
|
|
end if;
|
|
|
|
for r in
|
|
select c.conname
|
|
from pg_constraint c
|
|
where c.conrelid = 'public.cruce_cuentas_bamboo_correcciones'::regclass
|
|
and c.contype = 'c'
|
|
and pg_get_constraintdef(c.oid) ilike '%pais%'
|
|
and pg_get_constraintdef(c.oid) ilike '%GT%'
|
|
and pg_get_constraintdef(c.oid) ilike '%TT%'
|
|
and pg_get_constraintdef(c.oid) not ilike '%SV%'
|
|
loop
|
|
execute format('alter table public.cruce_cuentas_bamboo_correcciones drop constraint %I', r.conname);
|
|
end loop;
|
|
|
|
if not exists (
|
|
select 1 from pg_constraint
|
|
where conrelid = 'public.cruce_cuentas_bamboo_correcciones'::regclass
|
|
and conname = 'ck_cruce_cuentas_bamboo_correcciones_pais'
|
|
) then
|
|
alter table public.cruce_cuentas_bamboo_correcciones
|
|
add constraint ck_cruce_cuentas_bamboo_correcciones_pais
|
|
check (upper(trim(pais)) in ('GT', 'TT', 'PA', 'SV'));
|
|
end if;
|
|
end;
|
|
$$;
|
|
|
|
-- Si la tabla histórica tiene un CHECK antiguo limitado a GT/TT, se amplía.
|
|
do $$
|
|
declare
|
|
r record;
|
|
begin
|
|
if to_regclass('public.cruces_cuentas_gt_reportes') is null then
|
|
raise exception 'No existe public.cruces_cuentas_gt_reportes.';
|
|
end if;
|
|
|
|
for r in
|
|
select c.conname
|
|
from pg_constraint c
|
|
where c.conrelid = 'public.cruces_cuentas_gt_reportes'::regclass
|
|
and c.contype = 'c'
|
|
and pg_get_constraintdef(c.oid) ilike '%country%'
|
|
and pg_get_constraintdef(c.oid) ilike '%GT%'
|
|
and pg_get_constraintdef(c.oid) ilike '%TT%'
|
|
and pg_get_constraintdef(c.oid) not ilike '%SV%'
|
|
loop
|
|
execute format('alter table public.cruces_cuentas_gt_reportes drop constraint %I', r.conname);
|
|
end loop;
|
|
|
|
if not exists (
|
|
select 1 from pg_constraint
|
|
where conrelid = 'public.cruces_cuentas_gt_reportes'::regclass
|
|
and conname = 'ck_cruces_cuentas_reportes_country'
|
|
) then
|
|
alter table public.cruces_cuentas_gt_reportes
|
|
add constraint ck_cruces_cuentas_reportes_country
|
|
check (country is null or upper(trim(country)) in ('GT', 'TT', 'PA', 'SV'));
|
|
end if;
|
|
end;
|
|
$$;
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 2. Alias BambooHR activos: GT + TT + PA + SV
|
|
-- ------------------------------------------------------------
|
|
create or replace function public.cruce_cuentas_bamboo_aliases_activos(p_pais text)
|
|
returns jsonb
|
|
language sql
|
|
stable
|
|
security definer
|
|
set search_path = public
|
|
as $$
|
|
select jsonb_build_object(
|
|
'ok', true,
|
|
'pais', upper(trim(coalesce(p_pais, ''))),
|
|
'aliases', coalesce(
|
|
jsonb_agg(
|
|
jsonb_build_object(
|
|
'id', a.id,
|
|
'pais', a.pais,
|
|
'nombre_origen', a.nombre_origen,
|
|
'nombre_origen_normalizado', a.nombre_origen_normalizado,
|
|
'cuenta_bancaria', a.cuenta_bancaria,
|
|
'bamboo_employee_number', a.bamboo_employee_number,
|
|
'bamboo_employee_id', a.bamboo_employee_id,
|
|
'bamboo_nombre', a.bamboo_nombre,
|
|
'motivo', a.motivo,
|
|
'activo', a.activo
|
|
)
|
|
order by a.updated_at desc
|
|
) filter (where a.id is not null),
|
|
'[]'::jsonb
|
|
)
|
|
)
|
|
from public.cruce_cuentas_bamboo_aliases a
|
|
where a.activo = true
|
|
and a.pais = upper(trim(coalesce(p_pais, '')))
|
|
and upper(trim(coalesce(p_pais, ''))) in ('GT', 'TT', 'PA', 'SV');
|
|
$$;
|
|
|
|
revoke all on function public.cruce_cuentas_bamboo_aliases_activos(text) from public, anon, authenticated;
|
|
grant execute on function public.cruce_cuentas_bamboo_aliases_activos(text) to service_role;
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 3. Históricos paginados: GT + TT + PA + SV
|
|
-- ------------------------------------------------------------
|
|
create index if not exists idx_cruces_cuentas_reportes_country_created
|
|
on public.cruces_cuentas_gt_reportes (country, created_at desc);
|
|
|
|
create index if not exists idx_cruces_cuentas_reportes_country_status_created
|
|
on public.cruces_cuentas_gt_reportes (country, estado, created_at desc);
|
|
|
|
create or replace function public.cruce_cuentas_get_historicos(
|
|
p_country text,
|
|
p_page integer default 1,
|
|
p_page_size integer default 10,
|
|
p_search text default null,
|
|
p_status text default null
|
|
)
|
|
returns jsonb
|
|
language plpgsql
|
|
security definer
|
|
set search_path = public
|
|
as $$
|
|
declare
|
|
v_country text := upper(trim(coalesce(p_country, ''));
|
|
v_page integer := greatest(coalesce(p_page, 1), 1);
|
|
v_page_size integer := least(greatest(coalesce(p_page_size, 10), 1), 100);
|
|
v_offset integer;
|
|
v_search text := nullif(trim(coalesce(p_search, '')), '');
|
|
v_status text := nullif(trim(coalesce(p_status, '')), '');
|
|
v_total bigint;
|
|
v_filtered_total bigint;
|
|
v_reports jsonb;
|
|
begin
|
|
if v_country not in ('GT', 'TT', 'PA', 'SV') then
|
|
raise exception 'País no permitido: %', v_country;
|
|
end if;
|
|
|
|
v_offset := (v_page - 1) * v_page_size;
|
|
|
|
select count(*) into v_total
|
|
from public.cruces_cuentas_gt_reportes r
|
|
where upper(coalesce(r.country, 'GT')) = v_country;
|
|
|
|
select count(*) into v_filtered_total
|
|
from public.cruces_cuentas_gt_reportes r
|
|
where upper(coalesce(r.country, 'GT')) = v_country
|
|
and (v_status is null or r.estado = v_status)
|
|
and (
|
|
v_search is null
|
|
or coalesce(r.period_label, '') ilike '%' || v_search || '%'
|
|
or coalesce(r.payroll_file_name, '') ilike '%' || v_search || '%'
|
|
or coalesce(r.ejecutado_por_nombre, '') ilike '%' || v_search || '%'
|
|
or coalesce(r.resuelto_por_nombre, '') ilike '%' || v_search || '%'
|
|
or r.id::text ilike '%' || v_search || '%'
|
|
);
|
|
|
|
select coalesce(
|
|
jsonb_agg((to_jsonb(q) - 'detalle_banco_sin_bamboo') order by q.created_at desc),
|
|
'[]'::jsonb
|
|
) into v_reports
|
|
from (
|
|
select r.*
|
|
from public.cruces_cuentas_gt_reportes r
|
|
where upper(coalesce(r.country, 'GT')) = v_country
|
|
and (v_status is null or r.estado = v_status)
|
|
and (
|
|
v_search is null
|
|
or coalesce(r.period_label, '') ilike '%' || v_search || '%'
|
|
or coalesce(r.payroll_file_name, '') ilike '%' || v_search || '%'
|
|
or coalesce(r.ejecutado_por_nombre, '') ilike '%' || v_search || '%'
|
|
or coalesce(r.resuelto_por_nombre, '') ilike '%' || v_search || '%'
|
|
or r.id::text ilike '%' || v_search || '%'
|
|
)
|
|
order by r.created_at desc
|
|
limit v_page_size
|
|
offset v_offset
|
|
) q;
|
|
|
|
return jsonb_build_object(
|
|
'ok', true,
|
|
'country', v_country,
|
|
'page', v_page,
|
|
'page_size', v_page_size,
|
|
'total', v_total,
|
|
'filtered_total', v_filtered_total,
|
|
'total_pages', greatest(ceil(v_filtered_total::numeric / v_page_size)::integer, 1),
|
|
'reports', v_reports
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
revoke all on function public.cruce_cuentas_get_historicos(text, integer, integer, text, text) from public, anon;
|
|
grant execute on function public.cruce_cuentas_get_historicos(text, integer, integer, text, text) to authenticated;
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 4. Detalle Banco sin Bamboo desde Históricos: GT + TT + PA + SV
|
|
-- ------------------------------------------------------------
|
|
create or replace function public.cruce_cuentas_get_banco_sin_bamboo_reporte(
|
|
p_report_id text,
|
|
p_country text
|
|
)
|
|
returns jsonb
|
|
language plpgsql
|
|
stable
|
|
security definer
|
|
set search_path = public
|
|
as $$
|
|
declare
|
|
v_country text := upper(trim(coalesce(p_country, ''));
|
|
v_report public.cruces_cuentas_gt_reportes%rowtype;
|
|
v_corrections jsonb := '[]'::jsonb;
|
|
begin
|
|
if auth.uid() is null then
|
|
raise exception 'No autenticado.';
|
|
end if;
|
|
|
|
if v_country not in ('GT', 'TT', 'PA', 'SV') then
|
|
raise exception 'País no permitido: %', v_country;
|
|
end if;
|
|
|
|
select r.* into v_report
|
|
from public.cruces_cuentas_gt_reportes r
|
|
where r.id::text = trim(coalesce(p_report_id, ''))
|
|
and upper(coalesce(r.country, 'GT')) = v_country
|
|
limit 1;
|
|
|
|
if not found then
|
|
return jsonb_build_object('ok', false, 'message', 'No se encontró el reporte solicitado.');
|
|
end if;
|
|
|
|
select coalesce(
|
|
jsonb_agg(
|
|
jsonb_build_object(
|
|
'id', c.id,
|
|
'pais', c.pais,
|
|
'nombre_origen_principal', c.nombre_origen_principal,
|
|
'nombres_origen', c.nombres_origen,
|
|
'cuenta_bancaria', c.cuenta_bancaria,
|
|
'bamboo_employee_number', c.bamboo_employee_number,
|
|
'bamboo_nombre', c.bamboo_nombre,
|
|
'estado', c.estado,
|
|
'correo_enviado', c.correo_enviado,
|
|
'correo_enviado_at', c.correo_enviado_at,
|
|
'created_at', c.created_at
|
|
) order by c.created_at desc
|
|
),
|
|
'[]'::jsonb
|
|
) into v_corrections
|
|
from public.cruce_cuentas_bamboo_correcciones c
|
|
where c.pais = v_country
|
|
and (
|
|
c.execution_id = v_report.id::text
|
|
or (
|
|
nullif(trim(coalesce(c.execution_id, '')), '') is null
|
|
and nullif(trim(coalesce(c.report_url, '')), '') is not null
|
|
and c.report_url = v_report.report_url
|
|
)
|
|
);
|
|
|
|
return jsonb_build_object(
|
|
'ok', true,
|
|
'report', jsonb_build_object(
|
|
'id', v_report.id,
|
|
'country', v_report.country,
|
|
'period_label', v_report.period_label,
|
|
'period_start', v_report.period_start,
|
|
'period_end', v_report.period_end,
|
|
'report_url', v_report.report_url,
|
|
'banco_sin_bamboo', v_report.banco_sin_bamboo
|
|
),
|
|
'cases', coalesce(v_report.detalle_banco_sin_bamboo, '[]'::jsonb),
|
|
'corrections', v_corrections
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
revoke all on function public.cruce_cuentas_get_banco_sin_bamboo_reporte(text, text) from public, anon;
|
|
grant execute on function public.cruce_cuentas_get_banco_sin_bamboo_reporte(text, text) to authenticated;
|
|
|
|
commit;
|
|
|
|
-- ============================================================
|
|
-- VALIDACIONES OPCIONALES (solo lectura)
|
|
-- ============================================================
|
|
-- Debe devolver ok=true y aliases (aunque sea []).
|
|
select public.cruce_cuentas_bamboo_aliases_activos('SV');
|
|
|
|
-- Debe devolver country=SV, aunque todavía no existan reportes.
|
|
select public.cruce_cuentas_get_historicos('SV', 1, 10, null, null);
|
|
|
|
-- Verificar constraints finales.
|
|
select conrelid::regclass as tabla, conname, pg_get_constraintdef(oid) as definicion
|
|
from pg_constraint
|
|
where conrelid in (
|
|
'public.cruce_cuentas_bamboo_aliases'::regclass,
|
|
'public.cruce_cuentas_bamboo_correcciones'::regclass,
|
|
'public.cruces_cuentas_gt_reportes'::regclass
|
|
)
|
|
and contype = 'c'
|
|
order by 1, 2;
|