"""Re-trigger the ``hris.full_sync`` cron after the ``list_all_users`` filter fix. Revision ID: 234 Revises: 233 Create Date: 2026-06-01 (Renumbered post-merge from 233 → 234 because PR #637 (this script) and PR #639 (Access Review FK collation hotfix) both landed migration ID ``233`` concurrently — different filenames so git saw no conflict, but Alembic refused with "Revision 233 is present more than once" and main CI failed on every commit after both merged. PR #639's 233 stays put; this one chains off it.) Why this migration exists ------------------------- Migration 230 seeded ``hris.full_sync`` with ``last_run_at='1970-01-01'`` so the worker's "missed beat" branch would fire the first run ~90s after deploy. That run executed at 08:19 UTC on 2026-06-01 but staged ZERO offboard events because ``SuccessFactorsClient.list_all_users`` omitted ``$filter`` entirely. PingCAP's SF tenant returns only ``status='t'`` users when ``$filter`` is missing, so all 48 historical leavers (including the user-reported wangdi P0175) were silently dropped from the staged batch. This PR fixes ``list_all_users`` to pin ``$filter=status eq 't' or status eq 'f'`` explicitly. To re-fire the cron on the next deploy (now that the fix is live), reset ``last_run_at`` back to ``1970-01-01`` — same trick migration 230 used to bootstrap the first run. After this run succeeds the cron self-updates ``last_run_at`` to ``now`` and settles into its weekly Sunday 05:00 SGT cadence. Idempotent: only resets when the row currently has the post-bug timestamp (``last_run_at > '1970-01-01'``). A second migration apply after the fix has already taken effect is a no-op so we don't re-trigger an already-correct run on every deploy. """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "234" down_revision = "233" branch_labels = None depends_on = None _JOB_NAME = "hris.full_sync" def upgrade() -> None: bind = op.get_bind() bind.execute( sa.text( """ UPDATE scheduled_jobs SET last_run_at = '1970-01-01 00:00:00' WHERE name = :n AND last_run_at > '1970-01-02' """ ), {"n": _JOB_NAME}, ) def downgrade() -> None: # No downgrade path — the previous ``last_run_at`` value isn't # captured anywhere recoverable. A revert leaves the row at the # 1970-01-01 sentinel; the next worker restart fires the cron # again, which is harmless (the live sync path is idempotent). pass