"""phase34 — recurring inspection schedules Creates the inspection_schedules table. A schedule materialises a real Inspection row on a fixed cadence via the token-protected cron endpoint POST /inspection-schedules/run (see app/routes/inspection_schedules.py). Idempotent: guarded by an INFORMATION_SCHEMA table-existence check so it is safe to re-run across every tenant DB (CLAUDE.md rule 14). """ import sqlalchemy as sa from alembic import op revision = 'phase34_inspection_schedules' down_revision = 'phase33_tenant_settings' branch_labels = None depends_on = None def _table_exists(bind, table: str) -> bool: result = bind.execute(sa.text( "SELECT COUNT(*) FROM information_schema.tables " "WHERE table_schema = DATABASE() AND table_name = :t" ), {'t': table}) return result.scalar() > 0 def upgrade(): bind = op.get_bind() if not _table_exists(bind, 'inspection_schedules'): op.execute(sa.text(""" CREATE TABLE inspection_schedules ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, template_id INT NOT NULL, facility_id INT NOT NULL, area_id INT NULL, inspector_id INT NOT NULL, frequency ENUM('daily','weekly','monthly','quarterly') NOT NULL DEFAULT 'weekly', active TINYINT(1) NOT NULL DEFAULT 1, created_by INT NULL, created_at DATETIME NOT NULL, last_run_at DATETIME NULL, next_run_at DATETIME NULL, CONSTRAINT fk_ischd_template FOREIGN KEY (template_id) REFERENCES inspection_templates(id) ON DELETE CASCADE, CONSTRAINT fk_ischd_facility FOREIGN KEY (facility_id) REFERENCES facilities(id) ON DELETE CASCADE, CONSTRAINT fk_ischd_area FOREIGN KEY (area_id) REFERENCES areas(id) ON DELETE SET NULL, CONSTRAINT fk_ischd_inspector FOREIGN KEY (inspector_id) REFERENCES users(id) ON DELETE CASCADE, CONSTRAINT fk_ischd_creator FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL, INDEX ix_ischd_active_next (active, next_run_at), INDEX ix_ischd_facility (facility_id), INDEX ix_ischd_inspector (inspector_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 """)) def downgrade(): bind = op.get_bind() if _table_exists(bind, 'inspection_schedules'): op.execute(sa.text('DROP TABLE inspection_schedules'))