Files
cdc-project-management/supabase_cdc_brief_reapprove_rejected.sql

192 lines
6.1 KiB
PL/PgSQL

-- =============================================================
-- TABLERO CDC — APROBAR BRIEFS DESDE "RECHAZADOS"
-- Ejecutar una sola vez si ya instalaste la bandeja Nuevos/Rechazados.
--
-- Este parche NO crea tablas ni modifica proyectos existentes.
-- Solo reemplaza la RPC de aprobación para permitir:
-- new -> approved
-- rejected -> approved
-- Mantiene idempotencia para approved y crea el proyecto como Activo.
-- =============================================================
create or replace function public.tablero_cdc_approve_brief(p_inbox_id uuid)
returns jsonb
language plpgsql
security definer
set search_path = public, auth
as $$
declare
v_item public.tablero_cdc_brief_inbox%rowtype;
v_project_id uuid;
v_email text;
v_name text;
v_country_manager text := '';
v_title text;
v_description text;
v_activity_description text;
begin
if auth.uid() is null or not public.tablero_cdc_is_active_allowed_user() then
raise exception 'No tienes permiso para revisar briefs del Tablero CDC.';
end if;
select *
into v_item
from public.tablero_cdc_brief_inbox
where id = p_inbox_id
for update;
if not found then
raise exception 'No se encontró el brief solicitado.';
end if;
-- Idempotencia: si el usuario repite el clic o se reintenta la petición
-- después de haber completado la transacción, devolvemos el mismo proyecto.
if v_item.review_status = 'approved' and v_item.approved_project_id is not null then
return jsonb_build_object(
'ok', true,
'already_approved', true,
'project_id', v_item.approved_project_id,
'brief_id', v_item.brief_id
);
end if;
if v_item.review_status not in ('new', 'rejected') then
raise exception 'Este brief ya fue revisado y no puede aprobarse desde esta bandeja.';
end if;
-- Seguridad adicional: un brief rechazado no debe conservar un proyecto asociado.
-- Si existiera una inconsistencia manual, detenemos la operación para evitar duplicados.
if v_item.review_status = 'rejected' and v_item.approved_project_id is not null then
raise exception 'Este brief rechazado ya tiene un proyecto asociado. Revisa los datos antes de aprobarlo.';
end if;
v_activity_description := case
when v_item.review_status = 'rejected'
then 'El brief fue recuperado de Rechazados y aprobado como proyecto Activo.'
else 'El brief fue revisado y aprobado desde la bandeja Nuevos.'
end;
v_email := lower(trim(coalesce(auth.jwt() ->> 'email', '')));
select coalesce(nullif(trim(u.full_name), ''), nullif(trim(u.email), ''), 'Usuario CDC')
into v_name
from public.tablero_cdc_allowed_users u
where lower(trim(u.email)) = v_email
and u.is_active = true
limit 1;
v_name := coalesce(v_name, nullif(v_email, ''), 'Usuario CDC');
-- Si existe el mapeo BU -> CM en las listas dinámicas, lo reutilizamos.
-- Si no existe, se deja vacío y el proyecto continúa siendo válido/editable.
begin
select coalesce(nullif(trim(l.label), ''), '')
into v_country_manager
from public.tablero_cdc_app_lists l
where l.is_active = true
and lower(trim(coalesce(l.value, ''))) = lower(trim(coalesce(v_item.country, '')))
and lower(trim(coalesce(l.category, ''))) in (
'country_manager', 'country manager', 'cm', 'bu_cm', 'bu cm', 'manager', 'managers'
)
order by coalesce(l.sort_order, 999999), l.label
limit 1;
exception
when undefined_table then
v_country_manager := '';
end;
v_title := coalesce(
nullif(trim(v_item.title), ''),
nullif(trim(v_item.client), ''),
'Brief CDC ' || v_item.brief_id
);
v_description := coalesce(nullif(trim(v_item.summary), ''), '');
insert into public.tablero_cdc_projects (
title,
client,
brand,
country,
requested_by,
country_manager,
description,
status,
internal_amount,
brief_link,
extra_data,
created_by,
updated_by
)
values (
v_title,
coalesce(v_item.client, ''),
coalesce(v_item.brand, ''),
coalesce(v_item.country, ''),
coalesce(v_item.requested_by, ''),
coalesce(v_country_manager, ''),
v_description,
'Activo',
null,
coalesce(nullif(trim(v_item.brief_link), ''), nullif(trim(v_item.document_link), ''), ''),
jsonb_strip_nulls(
jsonb_build_object(
'source', 'cdc_brief',
'source_brief_id', v_item.brief_id,
'source_brief_inbox_id', v_item.id,
'source_brief_created_at', v_item.source_created_at,
'cdc_brief_document_link', nullif(trim(v_item.document_link), ''),
'delivery_date', nullif(trim(v_item.delivery_date), ''),
'request_type', nullif(trim(v_item.request_type), ''),
'deliverable_type', nullif(trim(v_item.deliverable_type), ''),
'cdc_brief_fields', v_item.raw_fields,
'color', 'blue'
)
),
auth.uid(),
auth.uid()
)
returning id into v_project_id;
update public.tablero_cdc_brief_inbox
set
review_status = 'approved',
approved_project_id = v_project_id,
reviewed_by = auth.uid(),
reviewed_by_name = v_name,
reviewed_by_email = v_email,
reviewed_at = now(),
rejection_reason = null
where id = v_item.id;
-- Mantiene el historial existente cuando el módulo de actividad ya está instalado,
-- sin convertirlo en una dependencia obligatoria de esta migración.
if to_regclass('public.tablero_cdc_project_activity') is not null then
execute $activity$
insert into public.tablero_cdc_project_activity (
project_id,
activity_type,
title,
description,
actor_id,
actor_name,
actor_email
)
values ($1, 'created', 'Proyecto creado desde CDC Brief',
$5, $2, $3, $4)
$activity$
using v_project_id, auth.uid(), v_name, v_email, v_activity_description;
end if;
return jsonb_build_object(
'ok', true,
'already_approved', false,
'project_id', v_project_id,
'brief_id', v_item.brief_id
);
end;
$$;
revoke all on function public.tablero_cdc_approve_brief(uuid) from public;
grant execute on function public.tablero_cdc_approve_brief(uuid) to authenticated;