"""procurement serial counters for concurrency-safe human numbers. Revision ID: 446 Revises: 445 Create Date: 2026-08-02 One transactional counter row per (prefix, calendar year). The allocator self-bootstraps from existing resource rows, so this migration never rewrites or deletes issued numbers and needs no speculative data cleanup. """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "446" down_revision = "445" branch_labels = None depends_on = None TABLE = "procurement_serial_counters" def _table_exists(bind, name: str) -> bool: return bind.execute( sa.text( "SELECT 1 FROM information_schema.TABLES " "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :name" ), {"name": name}, ).scalar() is not None def upgrade() -> None: bind = op.get_bind() if _table_exists(bind, TABLE): return op.create_table( TABLE, sa.Column("prefix", sa.String(length=16), nullable=False), sa.Column("serial_year", sa.Integer(), nullable=False), sa.Column("last_value", sa.BigInteger(), nullable=False), sa.Column( "updated_at", sa.DateTime(timezone=True), server_default=sa.text("CURRENT_TIMESTAMP"), nullable=False, ), sa.PrimaryKeyConstraint("prefix", "serial_year"), mysql_engine="InnoDB", mysql_charset="utf8mb4", mysql_collate="utf8mb4_unicode_ci", ) def downgrade() -> None: bind = op.get_bind() if _table_exists(bind, TABLE): op.drop_table(TABLE)