refactor: remove obsolete member management API module
This commit is contained in:
@@ -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;
|
||||
Reference in New Issue
Block a user