"""phase50 — inspection schedule receipt acknowledgement Ports single-tenant phase47 onto MT's `inspection_schedules` table. Adds: acknowledged_at DATETIME NULL Stamped when the assigned inspector confirms they have received/seen a scheduled inspection request. NULL = awaiting confirmation. Scope of the acknowledgement ---------------------------- It is per ASSIGNMENT, not per occurrence. `fulfill()` and `advance_due_date()` deliberately leave this column alone as the schedule rolls forward — an inspector who confirmed "yes, this weekly restroom round is mine" should not be asked again every week. The edit route resets it to NULL when the schedule is reassigned to a DIFFERENT inspector, because the new assignee has confirmed nothing. The acknowledger is always the assigned inspector — the only person the routes permit to confirm — so no separate `acknowledged_by` column is stored. Only meaningful for `plan` mode: an `auto` schedule materialises its inspection without anyone starting it, so there is no request to receive. The UI shows the control for plan-mode rows only. No backfill: legacy rows keep NULL and render as "awaiting confirmation", which is the correct initial state for an assignment nobody has confirmed yet. Revision id note ---------------- `alembic_version.version_num` is VARCHAR(32); the id below is 24 characters. The filename stays descriptive — Alembic keys on the `revision` string. Uses an INFORMATION_SCHEMA check — safe to re-run on every tenant DB. Additive only: nothing is renamed, retyped or dropped. """ revision = 'phase50_sched_acknowledged' down_revision = 'phase49_followup_req_by' branch_labels = None depends_on = None from alembic import op import sqlalchemy as sa _TABLE = 'inspection_schedules' _COLUMN = 'acknowledged_at' def _table_exists(conn, table): return conn.execute(sa.text( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES " "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :t" ), {"t": table}).scalar() > 0 def _column_exists(conn, table, column): return conn.execute(sa.text( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS " "WHERE TABLE_SCHEMA = DATABASE() " "AND TABLE_NAME = :t AND COLUMN_NAME = :c" ), {"t": table, "c": column}).scalar() > 0 def upgrade(): bind = op.get_bind() if not _table_exists(bind, _TABLE): return if not _column_exists(bind, _TABLE, _COLUMN): op.execute(sa.text( f"ALTER TABLE {_TABLE} ADD COLUMN {_COLUMN} DATETIME NULL" )) def downgrade(): bind = op.get_bind() if not _table_exists(bind, _TABLE): return if _column_exists(bind, _TABLE, _COLUMN): op.execute(sa.text( f"ALTER TABLE {_TABLE} DROP COLUMN {_COLUMN}" ))