147 lines
4.0 KiB
PL/PgSQL
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;
|