Files
myeasycms-v2/apps/web/supabase/migrations/20260418000001_waitlist_management.sql
T. Zehetbauer 5c5aaabae5
Some checks failed
Workflow / ʦ TypeScript (pull_request) Failing after 5m57s
Workflow / ⚫️ Test (pull_request) Has been skipped
refactor: remove obsolete member management API module
2026-04-03 14:08:31 +02:00

147 lines
4.0 KiB
PL/PgSQL

-- =====================================================
-- Waitlist Management
--
-- A) Course cancellation with automatic waitlist promotion
-- B) Event cancellation with automatic waitlist promotion
--
-- When an enrolled/confirmed participant is cancelled,
-- the oldest waitlisted entry is atomically promoted.
-- =====================================================
-- -------------------------------------------------------
-- A) Course waitlist promotion
-- -------------------------------------------------------
CREATE OR REPLACE FUNCTION public.cancel_course_enrollment(p_participant_id uuid)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
v_participant record;
v_course record;
v_promoted_id uuid;
v_promoted_name text;
BEGIN
-- Lock participant
SELECT * INTO v_participant
FROM public.course_participants
WHERE id = p_participant_id
FOR UPDATE;
IF v_participant IS NULL THEN
RAISE EXCEPTION 'Teilnehmer nicht gefunden'
USING ERRCODE = 'P0002';
END IF;
-- Lock course
SELECT * INTO v_course
FROM public.courses
WHERE id = v_participant.course_id
FOR UPDATE;
-- Cancel
UPDATE public.course_participants
SET status = 'cancelled'::public.enrollment_status,
cancelled_at = now()
WHERE id = p_participant_id;
-- If was enrolled (not already waitlisted/cancelled), promote oldest waitlisted
IF v_participant.status = 'enrolled' THEN
UPDATE public.course_participants
SET status = 'enrolled'::public.enrollment_status
WHERE id = (
SELECT id FROM public.course_participants
WHERE course_id = v_participant.course_id
AND status = 'waitlisted'
ORDER BY enrolled_at ASC
LIMIT 1
FOR UPDATE SKIP LOCKED
)
RETURNING id, first_name || ' ' || last_name
INTO v_promoted_id, v_promoted_name;
END IF;
RETURN jsonb_build_object(
'cancelled_id', p_participant_id,
'promoted_id', v_promoted_id,
'promoted_name', v_promoted_name
);
END;
$$;
GRANT EXECUTE ON FUNCTION public.cancel_course_enrollment(uuid) TO authenticated;
GRANT EXECUTE ON FUNCTION public.cancel_course_enrollment(uuid) TO service_role;
-- -------------------------------------------------------
-- B) Event registration cancellation + waitlist promotion
-- -------------------------------------------------------
-- Add updated_at column if not present
ALTER TABLE public.event_registrations
ADD COLUMN IF NOT EXISTS updated_at timestamptz DEFAULT now();
CREATE OR REPLACE FUNCTION public.cancel_event_registration(p_registration_id uuid)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
v_registration record;
v_event record;
v_promoted_id uuid;
v_promoted_name text;
BEGIN
-- Lock registration
SELECT * INTO v_registration
FROM public.event_registrations
WHERE id = p_registration_id
FOR UPDATE;
IF v_registration IS NULL THEN
RAISE EXCEPTION 'Anmeldung nicht gefunden'
USING ERRCODE = 'P0002';
END IF;
-- Lock event
SELECT * INTO v_event
FROM public.events
WHERE id = v_registration.event_id
FOR UPDATE;
-- Cancel
UPDATE public.event_registrations
SET status = 'cancelled',
updated_at = now()
WHERE id = p_registration_id;
-- If was confirmed or pending, promote oldest waitlisted
IF v_registration.status IN ('confirmed', 'pending') THEN
UPDATE public.event_registrations
SET status = 'confirmed',
updated_at = now()
WHERE id = (
SELECT id FROM public.event_registrations
WHERE event_id = v_registration.event_id
AND status = 'waitlisted'
ORDER BY created_at ASC
LIMIT 1
FOR UPDATE SKIP LOCKED
)
RETURNING id, first_name || ' ' || last_name
INTO v_promoted_id, v_promoted_name;
END IF;
RETURN jsonb_build_object(
'cancelled_id', p_registration_id,
'promoted_id', v_promoted_id,
'promoted_name', v_promoted_name
);
END;
$$;
GRANT EXECUTE ON FUNCTION public.cancel_event_registration(uuid) TO authenticated;
GRANT EXECUTE ON FUNCTION public.cancel_event_registration(uuid) TO service_role;