"""phase52 — restrict forms to specific contracts Creates `template_contracts`: one row = "this inspection template is available on this contract". Backs per-customer forms — a customer's bespoke form must not be visible to, or startable against, another customer's facilities. **No rows for a template means SHARED (available on every contract)**, not "available nowhere". That convention is why this migration needs no backfill and cannot change behaviour on deploy: every template that exists today has no rows and therefore stays available everywhere, exactly as before. A form only becomes customer-specific once an admin attaches it to at least one contract. Inverting that default later would silently hide every shared form from every contract, so it is enforced in one place — InspectionTemplate.available_query() — which the pickers, their POST validation, and the mobile API all use. Table-existence check — safe to re-run. """ revision = 'phase52_template_contracts' down_revision = 'phase51_user_notif_matrix' branch_labels = None depends_on = None from alembic import op import sqlalchemy as sa def _has_table(conn, name): return conn.execute(sa.text( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES " "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :t" ), {'t': name}).scalar() > 0 def upgrade(): conn = op.get_bind() if _has_table(conn, 'template_contracts'): return op.create_table( 'template_contracts', sa.Column('id', sa.Integer, primary_key=True), sa.Column('template_id', sa.Integer, sa.ForeignKey('inspection_templates.id', ondelete='CASCADE'), nullable=False, index=True), sa.Column('project_id', sa.Integer, sa.ForeignKey('projects.id', ondelete='CASCADE'), nullable=False, index=True), sa.Column('created_at', sa.DateTime, nullable=False, server_default=sa.func.now()), sa.UniqueConstraint('template_id', 'project_id', name='uq_template_contract'), ) def downgrade(): conn = op.get_bind() if _has_table(conn, 'template_contracts'): # Dropping the table returns every form to shared — no form becomes # unusable, they just stop being restricted. op.drop_table('template_contracts')