Offline Support
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
-- Trigger to replicate attendance_check_in RPC side-effects when a new
|
||||
-- attendance_log row is inserted directly (e.g. from Brick's offline queue
|
||||
-- after sync). The RPC path is unchanged; this trigger only fires on plain
|
||||
-- INSERT and is a no-op when the RPC already handled the duty_schedule update
|
||||
-- (idempotent: ON CONFLICT (id) DO NOTHING is handled by Brick).
|
||||
--
|
||||
-- Side-effects replicated from attendance_check_in RPC:
|
||||
-- 1. duty_schedules.check_in_at ← attendance_log.check_in_at
|
||||
-- 2. duty_schedules.check_in_location ← lat/lng
|
||||
-- 3. duty_schedules.status ← 'arrival' if on time, 'late' if past start
|
||||
--
|
||||
-- For check-out, the trigger replicates attendance_check_out side-effects:
|
||||
-- 1. duty_schedules.check_out_at ← attendance_log.check_out_at
|
||||
-- 2. duty_schedules.check_out_location ← lat/lng
|
||||
-- 3. duty_schedules.status ← 'completed'
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.attendance_log_after_upsert()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
v_schedule duty_schedules%ROWTYPE;
|
||||
BEGIN
|
||||
-- Skip if we have no duty_schedule_id (shouldn't happen, but be defensive)
|
||||
IF NEW.duty_schedule_id IS NULL THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
SELECT * INTO v_schedule FROM duty_schedules WHERE id = NEW.duty_schedule_id;
|
||||
IF NOT FOUND THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
-- ── Check-in side-effects ────────────────────────────────────────────────
|
||||
-- Only apply when check_in_at changed or this is a new row.
|
||||
IF (TG_OP = 'INSERT') OR
|
||||
(TG_OP = 'UPDATE' AND
|
||||
(OLD.check_in_at IS DISTINCT FROM NEW.check_in_at OR
|
||||
OLD.check_in_lat IS DISTINCT FROM NEW.check_in_lat)) THEN
|
||||
|
||||
-- Skip if duty_schedules already has a check_in_at (RPC already ran)
|
||||
IF v_schedule.check_in_at IS NULL THEN
|
||||
UPDATE duty_schedules
|
||||
SET
|
||||
check_in_at = NEW.check_in_at,
|
||||
check_in_location = jsonb_build_object(
|
||||
'latitude', NEW.check_in_lat,
|
||||
'longitude', NEW.check_in_lng
|
||||
),
|
||||
status = CASE
|
||||
WHEN NEW.check_in_at <= v_schedule.start_time
|
||||
THEN 'arrival'
|
||||
ELSE 'late'
|
||||
END
|
||||
WHERE id = NEW.duty_schedule_id;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- ── Check-out side-effects ───────────────────────────────────────────────
|
||||
IF NEW.check_out_at IS NOT NULL AND
|
||||
(TG_OP = 'INSERT' OR OLD.check_out_at IS DISTINCT FROM NEW.check_out_at) THEN
|
||||
|
||||
UPDATE duty_schedules
|
||||
SET
|
||||
check_out_at = NEW.check_out_at,
|
||||
check_out_location = jsonb_build_object(
|
||||
'latitude', NEW.check_out_lat,
|
||||
'longitude', NEW.check_out_lng
|
||||
),
|
||||
status = 'completed'
|
||||
WHERE id = NEW.duty_schedule_id
|
||||
AND check_out_at IS NULL; -- idempotent: only if not already checked out
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- Fire AFTER INSERT and AFTER UPDATE so both offline-queued inserts and
|
||||
-- subsequent Brick upserts (when check_out_at is filled in) are handled.
|
||||
DROP TRIGGER IF EXISTS attendance_logs_after_upsert ON attendance_logs;
|
||||
CREATE TRIGGER attendance_logs_after_upsert
|
||||
AFTER INSERT OR UPDATE ON attendance_logs
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.attendance_log_after_upsert();
|
||||
Reference in New Issue
Block a user