refactor: remove obsolete member management API module
Some checks failed
Workflow / ʦ TypeScript (pull_request) Failing after 5m57s
Workflow / ⚫️ Test (pull_request) Has been skipped

This commit is contained in:
T. Zehetbauer
2026-04-03 14:08:31 +02:00
parent 124c6a632a
commit 5c5aaabae5
132 changed files with 10107 additions and 3442 deletions

View File

@@ -0,0 +1,294 @@
-- =====================================================
-- Module Statistics RPCs
--
-- A) Course statistics — counts per status, participants,
-- average occupancy, total revenue
-- B) Event statistics — counts, upcoming/past, registrations,
-- average occupancy
-- C) Booking statistics — counts, revenue, avg stay,
-- occupancy rate for a date range
-- D) Event registration counts — batch lookup replacing
-- N+1 JS iteration
-- =====================================================
-- -------------------------------------------------------
-- A) Course statistics
-- -------------------------------------------------------
CREATE OR REPLACE FUNCTION public.get_course_statistics(p_account_id uuid)
RETURNS TABLE (
total_courses bigint,
open_courses bigint,
running_courses bigint,
completed_courses bigint,
cancelled_courses bigint,
total_participants bigint,
total_waitlisted bigint,
avg_occupancy_rate numeric,
total_revenue numeric
)
LANGUAGE plpgsql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
-- Access check
IF NOT public.has_role_on_account(p_account_id) THEN
RAISE EXCEPTION 'Access denied'
USING ERRCODE = '42501';
END IF;
RETURN QUERY
WITH course_stats AS (
SELECT
count(*)::bigint AS total_courses,
count(*) FILTER (WHERE c.status = 'open')::bigint AS open_courses,
count(*) FILTER (WHERE c.status = 'running')::bigint AS running_courses,
count(*) FILTER (WHERE c.status = 'completed')::bigint AS completed_courses,
count(*) FILTER (WHERE c.status = 'cancelled')::bigint AS cancelled_courses
FROM public.courses c
WHERE c.account_id = p_account_id
),
participant_stats AS (
SELECT
count(*) FILTER (WHERE cp.status = 'enrolled')::bigint AS total_participants,
count(*) FILTER (WHERE cp.status = 'waitlisted')::bigint AS total_waitlisted
FROM public.course_participants cp
JOIN public.courses c ON c.id = cp.course_id
WHERE c.account_id = p_account_id
),
occupancy_stats AS (
SELECT
ROUND(
AVG(
CASE WHEN c.capacity > 0 THEN
enrolled_ct::numeric / c.capacity * 100
ELSE 0 END
),
1
) AS avg_occupancy_rate
FROM public.courses c
LEFT JOIN LATERAL (
SELECT count(*)::numeric AS enrolled_ct
FROM public.course_participants cp
WHERE cp.course_id = c.id AND cp.status = 'enrolled'
) ec ON true
WHERE c.account_id = p_account_id
AND c.status != 'cancelled'
),
revenue_stats AS (
SELECT
COALESCE(SUM(c.fee * enrolled_ct), 0)::numeric AS total_revenue
FROM public.courses c
LEFT JOIN LATERAL (
SELECT count(*)::numeric AS enrolled_ct
FROM public.course_participants cp
WHERE cp.course_id = c.id AND cp.status IN ('enrolled', 'completed')
) ec ON true
WHERE c.account_id = p_account_id
AND c.status != 'cancelled'
)
SELECT
cs.total_courses,
cs.open_courses,
cs.running_courses,
cs.completed_courses,
cs.cancelled_courses,
ps.total_participants,
ps.total_waitlisted,
os.avg_occupancy_rate,
rs.total_revenue
FROM course_stats cs
CROSS JOIN participant_stats ps
CROSS JOIN occupancy_stats os
CROSS JOIN revenue_stats rs;
END;
$$;
GRANT EXECUTE ON FUNCTION public.get_course_statistics(uuid) TO authenticated;
GRANT EXECUTE ON FUNCTION public.get_course_statistics(uuid) TO service_role;
-- -------------------------------------------------------
-- B) Event statistics
-- -------------------------------------------------------
CREATE OR REPLACE FUNCTION public.get_event_statistics(p_account_id uuid)
RETURNS TABLE (
total_events bigint,
upcoming_events bigint,
past_events bigint,
total_registrations bigint,
avg_occupancy_rate numeric
)
LANGUAGE plpgsql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
-- Access check
IF NOT public.has_role_on_account(p_account_id) THEN
RAISE EXCEPTION 'Access denied'
USING ERRCODE = '42501';
END IF;
RETURN QUERY
WITH event_counts AS (
SELECT
count(*)::bigint AS total_events,
count(*) FILTER (
WHERE e.event_date >= current_date
AND e.status NOT IN ('cancelled', 'completed')
)::bigint AS upcoming_events,
count(*) FILTER (
WHERE e.event_date < current_date
OR e.status IN ('completed')
)::bigint AS past_events
FROM public.events e
WHERE e.account_id = p_account_id
),
reg_counts AS (
SELECT count(*)::bigint AS total_registrations
FROM public.event_registrations er
JOIN public.events e ON e.id = er.event_id
WHERE e.account_id = p_account_id
AND er.status IN ('confirmed', 'pending')
),
occupancy AS (
SELECT
ROUND(
AVG(
CASE WHEN e.capacity IS NOT NULL AND e.capacity > 0 THEN
reg_ct::numeric / e.capacity * 100
ELSE NULL END
),
1
) AS avg_occupancy_rate
FROM public.events e
LEFT JOIN LATERAL (
SELECT count(*)::numeric AS reg_ct
FROM public.event_registrations er
WHERE er.event_id = e.id AND er.status IN ('confirmed', 'pending')
) rc ON true
WHERE e.account_id = p_account_id
AND e.status != 'cancelled'
)
SELECT
ec.total_events,
ec.upcoming_events,
ec.past_events,
rc.total_registrations,
COALESCE(occ.avg_occupancy_rate, 0)::numeric
FROM event_counts ec
CROSS JOIN reg_counts rc
CROSS JOIN occupancy occ;
END;
$$;
GRANT EXECUTE ON FUNCTION public.get_event_statistics(uuid) TO authenticated;
GRANT EXECUTE ON FUNCTION public.get_event_statistics(uuid) TO service_role;
-- -------------------------------------------------------
-- C) Booking statistics
-- -------------------------------------------------------
CREATE OR REPLACE FUNCTION public.get_booking_statistics(
p_account_id uuid,
p_from date DEFAULT NULL,
p_to date DEFAULT NULL
)
RETURNS TABLE (
total_bookings bigint,
active_bookings bigint,
checked_in_count bigint,
total_revenue numeric,
avg_stay_nights numeric,
occupancy_rate numeric
)
LANGUAGE plpgsql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
v_from date;
v_to date;
v_total_rooms bigint;
v_total_room_nights numeric;
v_booked_room_nights numeric;
BEGIN
-- Access check
IF NOT public.has_role_on_account(p_account_id) THEN
RAISE EXCEPTION 'Access denied'
USING ERRCODE = '42501';
END IF;
-- Default date range: current month
v_from := COALESCE(p_from, date_trunc('month', current_date)::date);
v_to := COALESCE(p_to, (date_trunc('month', current_date) + interval '1 month' - interval '1 day')::date);
-- Calculate total available room-nights
SELECT count(*)::bigint INTO v_total_rooms
FROM public.rooms
WHERE account_id = p_account_id
AND is_active = true;
v_total_room_nights := v_total_rooms::numeric * (v_to - v_from + 1);
-- Calculate booked room-nights in range (non-cancelled)
SELECT COALESCE(SUM(
LEAST(b.check_out, v_to + 1) - GREATEST(b.check_in, v_from)
), 0)::numeric
INTO v_booked_room_nights
FROM public.bookings b
WHERE b.account_id = p_account_id
AND b.status NOT IN ('cancelled', 'no_show')
AND b.check_in <= v_to
AND b.check_out > v_from;
RETURN QUERY
SELECT
count(*)::bigint AS total_bookings,
count(*) FILTER (WHERE b.status IN ('confirmed', 'checked_in'))::bigint AS active_bookings,
count(*) FILTER (WHERE b.status = 'checked_in')::bigint AS checked_in_count,
COALESCE(SUM(b.total_price) FILTER (WHERE b.status != 'cancelled'), 0)::numeric AS total_revenue,
ROUND(
COALESCE(AVG((b.check_out - b.check_in)::numeric) FILTER (WHERE b.status != 'cancelled'), 0),
1
) AS avg_stay_nights,
CASE WHEN v_total_room_nights > 0 THEN
ROUND(v_booked_room_nights / v_total_room_nights * 100, 1)
ELSE 0 END AS occupancy_rate
FROM public.bookings b
WHERE b.account_id = p_account_id
AND b.check_in <= v_to
AND b.check_out > v_from;
END;
$$;
GRANT EXECUTE ON FUNCTION public.get_booking_statistics(uuid, date, date) TO authenticated;
GRANT EXECUTE ON FUNCTION public.get_booking_statistics(uuid, date, date) TO service_role;
-- -------------------------------------------------------
-- D) Event registration counts (batch lookup)
-- -------------------------------------------------------
CREATE OR REPLACE FUNCTION public.get_event_registration_counts(p_event_ids uuid[])
RETURNS TABLE (event_id uuid, registration_count bigint)
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
SELECT
er.event_id,
count(*)::bigint AS registration_count
FROM public.event_registrations er
WHERE er.event_id = ANY(p_event_ids)
AND er.status IN ('confirmed', 'pending')
GROUP BY er.event_id;
$$;
GRANT EXECUTE ON FUNCTION public.get_event_registration_counts(uuid[]) TO authenticated;
GRANT EXECUTE ON FUNCTION public.get_event_registration_counts(uuid[]) TO service_role;