-- Add location quality metadata columns to attendance_logs. -- These are populated by the extended RPCs and used for admin audit of -- suspicious check-ins (mock location, low accuracy). ALTER TABLE attendance_logs ADD COLUMN IF NOT EXISTS check_in_accuracy double precision, ADD COLUMN IF NOT EXISTS check_in_is_mocked boolean NOT NULL DEFAULT false, ADD COLUMN IF NOT EXISTS check_out_accuracy double precision, ADD COLUMN IF NOT EXISTS check_out_is_mocked boolean NOT NULL DEFAULT false; -- Extend attendance_check_in to accept and store location metadata. -- New params have defaults so existing callers without them continue to work. CREATE OR REPLACE FUNCTION public.attendance_check_in( p_duty_id uuid, p_lat double precision, p_lng double precision, p_accuracy double precision DEFAULT NULL, p_is_mocked boolean DEFAULT false ) RETURNS uuid LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE v_schedule duty_schedules%ROWTYPE; v_log_id uuid; v_now timestamptz := now(); v_status text; BEGIN SELECT * INTO v_schedule FROM duty_schedules WHERE id = p_duty_id; IF NOT FOUND THEN RAISE EXCEPTION 'Duty schedule not found'; END IF; IF v_schedule.user_id != auth.uid() THEN RAISE EXCEPTION 'Not your duty schedule'; END IF; IF v_now < (v_schedule.start_time - interval '2 hours') THEN RAISE EXCEPTION 'Too early to check in (2-hour window)'; END IF; IF v_now > v_schedule.end_time THEN RAISE EXCEPTION 'Duty has already ended'; END IF; IF v_now <= v_schedule.start_time THEN v_status := 'arrival'; ELSE v_status := 'late'; END IF; INSERT INTO attendance_logs ( user_id, duty_schedule_id, check_in_at, check_in_lat, check_in_lng, check_in_accuracy, check_in_is_mocked ) VALUES ( auth.uid(), p_duty_id, v_now, p_lat, p_lng, p_accuracy, p_is_mocked ) RETURNING id INTO v_log_id; UPDATE duty_schedules SET check_in_at = COALESCE(check_in_at, v_now), check_in_location = ST_SetSRID(ST_MakePoint(p_lng, p_lat), 4326)::geography, status = CASE WHEN check_in_at IS NULL THEN v_status::duty_status ELSE status END WHERE id = p_duty_id; RETURN v_log_id; END; $$; -- Extend attendance_check_out to accept and store location metadata. CREATE OR REPLACE FUNCTION public.attendance_check_out( p_attendance_id uuid, p_lat double precision, p_lng double precision, p_justification text DEFAULT NULL, p_accuracy double precision DEFAULT NULL, p_is_mocked boolean DEFAULT false ) RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE v_log attendance_logs%ROWTYPE; BEGIN SELECT * INTO v_log FROM attendance_logs WHERE id = p_attendance_id; IF NOT FOUND THEN RAISE EXCEPTION 'Attendance log not found'; END IF; IF v_log.user_id != auth.uid() THEN RAISE EXCEPTION 'Not your attendance log'; END IF; IF v_log.check_out_at IS NOT NULL THEN RAISE EXCEPTION 'Already checked out'; END IF; UPDATE attendance_logs SET check_out_at = now(), check_out_lat = p_lat, check_out_lng = p_lng, justification = COALESCE(p_justification, justification), check_out_accuracy = p_accuracy, check_out_is_mocked = p_is_mocked WHERE id = p_attendance_id; END; $$;