"""Add a short ``code`` column to ``asset_legal_entities`` so the public-facing 公司主体信息 admin tab can stamp every entity with a 1-8-char identifier (e.g. ``CN``, ``US``, ``SG``, ``JP``) suitable for embedding in machine-readable strings. **Why now**: the new asset-tag auto-generation rule shipped in this PR is ``IT-{purchase_entity_code}-{category_code_without_leading_P}- {YYYYMMDDHHMMSS}`` (example: ``IT-CN-NB-20260508151325``) and needs a stable short code per legal entity. ``country_or_region`` is already on the table but is descriptive prose ("中国 / China") not a tag-safe slug; reusing it would couple the tag format to free-text admin input that's allowed to contain slashes / spaces / non-ASCII. A dedicated column lets admins choose the tag prefix deliberately and keeps the tag-format invariants in one place. **Schema**: nullable so existing rows backfill as NULL — the intake form's tag generation rejects (with a clear 422) when the selected purchase_entity has no ``code``, so admins are nudged to fill it in via the OfficeAddress 公司主体信息 tab on first use. **Uniqueness**: codes SHOULD be unique per active entity (otherwise two entities both stamp ``CN`` and the resulting tag prefix is ambiguous). Enforced by a unique index on ``(code)`` where ``code IS NOT NULL`` — MySQL/TiDB treat NULL values as distinct in unique indexes, so existing NULL rows coexist freely until admins fill them in. Schema-only; no data backfill. """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "132" down_revision = "131" branch_labels = None depends_on = None def upgrade() -> None: op.add_column( "asset_legal_entities", sa.Column("code", sa.String(16), nullable=True), ) op.create_index( "uq_asset_legal_entities_code", "asset_legal_entities", ["code"], unique=True, ) def downgrade() -> None: op.drop_index( "uq_asset_legal_entities_code", table_name="asset_legal_entities", ) op.drop_column("asset_legal_entities", "code")