Files
arrr-erp/alembic/versions/20260805_scope_aware_client_services.py
T
2026-08-05 19:36:55 +05:30

140 lines
8.8 KiB
Python

"""Scope-aware client services using the existing registrations module."""
from alembic import op
import sqlalchemy as sa
revision = "20260805_scope_aware_services"
down_revision = "20260805_client_service_plan_master"
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"client_business_units",
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False),
sa.Column("client_id", sa.Integer(), sa.ForeignKey("clients.id", ondelete="CASCADE"), nullable=False),
sa.Column("business_code", sa.String(50), nullable=False),
sa.Column("business_name", sa.String(200), nullable=False),
sa.Column("trade_name", sa.String(200), nullable=True),
sa.Column("nature_of_business", sa.String(200), nullable=True),
sa.Column("is_primary", sa.Boolean(), nullable=False, server_default=sa.false()),
sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.true()),
sa.Column("created_by_user_id", sa.Integer(), sa.ForeignKey("users.id"), nullable=True),
sa.Column("updated_by_user_id", sa.Integer(), sa.ForeignKey("users.id"), nullable=True),
sa.Column("created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
sa.Column("updated_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
sa.UniqueConstraint("tenant_id", "client_id", "business_code", name="uq_cbu_tenant_client_code"),
)
op.create_index("ix_client_business_units_tenant_id", "client_business_units", ["tenant_id"])
op.create_index("ix_client_business_units_client_id", "client_business_units", ["client_id"])
op.create_table(
"client_branches",
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False),
sa.Column("client_id", sa.Integer(), sa.ForeignKey("clients.id", ondelete="CASCADE"), nullable=False),
sa.Column("business_unit_id", sa.Integer(), sa.ForeignKey("client_business_units.id", ondelete="CASCADE"), nullable=False),
sa.Column("branch_code", sa.String(50), nullable=False),
sa.Column("branch_name", sa.String(200), nullable=False),
sa.Column("branch_type", sa.String(40), nullable=False, server_default="branch"),
sa.Column("address_line_1", sa.String(255), nullable=True),
sa.Column("address_line_2", sa.String(255), nullable=True),
sa.Column("city", sa.String(100), nullable=True),
sa.Column("state", sa.String(100), nullable=True),
sa.Column("pincode", sa.String(20), nullable=True),
sa.Column("is_primary", sa.Boolean(), nullable=False, server_default=sa.false()),
sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.true()),
sa.Column("created_by_user_id", sa.Integer(), sa.ForeignKey("users.id"), nullable=True),
sa.Column("updated_by_user_id", sa.Integer(), sa.ForeignKey("users.id"), nullable=True),
sa.Column("created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
sa.Column("updated_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
sa.UniqueConstraint("tenant_id", "business_unit_id", "branch_code", name="uq_cbranch_tenant_business_code"),
)
op.create_index("ix_client_branches_tenant_id", "client_branches", ["tenant_id"])
op.create_index("ix_client_branches_client_id", "client_branches", ["client_id"])
op.create_index("ix_client_branches_business_unit_id", "client_branches", ["business_unit_id"])
# Reuse and extend the production client_registrations table introduced in Phase 4.
with op.batch_alter_table("client_registrations") as batch:
batch.add_column(sa.Column("business_unit_id", sa.Integer(), nullable=True))
batch.add_column(sa.Column("client_branch_id", sa.Integer(), nullable=True))
batch.add_column(sa.Column("legal_name", sa.String(200), nullable=True))
batch.add_column(sa.Column("trade_name", sa.String(200), nullable=True))
batch.add_column(sa.Column("state", sa.String(100), nullable=True))
batch.create_foreign_key(
"fk_client_registrations_business_unit",
"client_business_units", ["business_unit_id"], ["id"], ondelete="SET NULL"
)
batch.create_foreign_key(
"fk_client_registrations_client_branch",
"client_branches", ["client_branch_id"], ["id"], ondelete="SET NULL"
)
batch.create_index("ix_client_registrations_business_unit_id", ["business_unit_id"])
batch.create_index("ix_client_registrations_client_branch_id", ["client_branch_id"])
with op.batch_alter_table("service_catalogues") as batch:
batch.add_column(sa.Column("service_scope_type", sa.String(30), nullable=False, server_default="client"))
batch.add_column(sa.Column("required_registration_type", sa.String(40), nullable=True))
batch.create_index("ix_service_catalogues_service_scope_type", ["service_scope_type"])
batch.create_index("ix_service_catalogues_required_registration_type", ["required_registration_type"])
for table in ("client_service_plans", "client_service_subscriptions"):
with op.batch_alter_table(table) as batch:
batch.add_column(sa.Column("scope_type", sa.String(30), nullable=False, server_default="client"))
batch.add_column(sa.Column("scope_key", sa.String(80), nullable=False, server_default=""))
batch.add_column(sa.Column("business_unit_id", sa.Integer(), nullable=True))
batch.add_column(sa.Column("client_branch_id", sa.Integer(), nullable=True))
batch.add_column(sa.Column("registration_id", sa.Integer(), nullable=True))
batch.create_foreign_key(f"fk_{table}_business_unit", "client_business_units", ["business_unit_id"], ["id"], ondelete="SET NULL")
batch.create_foreign_key(f"fk_{table}_client_branch", "client_branches", ["client_branch_id"], ["id"], ondelete="SET NULL")
batch.create_foreign_key(f"fk_{table}_registration", "client_registrations", ["registration_id"], ["id"], ondelete="SET NULL")
batch.create_index(f"ix_{table}_scope_type", ["scope_type"])
batch.create_index(f"ix_{table}_scope_key", ["scope_key"])
batch.create_index(f"ix_{table}_business_unit_id", ["business_unit_id"])
batch.create_index(f"ix_{table}_client_branch_id", ["client_branch_id"])
batch.create_index(f"ix_{table}_registration_id", ["registration_id"])
op.execute("UPDATE client_service_plans SET scope_key = 'CLIENT:' || client_id WHERE scope_key = ''")
op.execute("UPDATE client_service_subscriptions SET scope_key = 'CLIENT:' || client_id WHERE scope_key = ''")
with op.batch_alter_table("client_service_plans") as batch:
batch.drop_constraint("uq_csp_tenant_client_service", type_="unique")
batch.create_unique_constraint("uq_csp_tenant_service_scope", ["tenant_id", "service_catalogue_id", "scope_key"])
with op.batch_alter_table("client_service_subscriptions") as batch:
batch.drop_constraint("uq_css_tenant_client_service_fy_period", type_="unique")
batch.create_unique_constraint(
"uq_css_tenant_service_scope_fy_period",
["tenant_id", "service_catalogue_id", "scope_key", "financial_year", "period_label"],
)
def downgrade():
with op.batch_alter_table("client_service_subscriptions") as batch:
batch.drop_constraint("uq_css_tenant_service_scope_fy_period", type_="unique")
batch.create_unique_constraint(
"uq_css_tenant_client_service_fy_period",
["tenant_id", "client_id", "service_catalogue_id", "financial_year", "period_label"],
)
for name in ("registration_id", "client_branch_id", "business_unit_id", "scope_key", "scope_type"):
batch.drop_column(name)
with op.batch_alter_table("client_service_plans") as batch:
batch.drop_constraint("uq_csp_tenant_service_scope", type_="unique")
batch.create_unique_constraint("uq_csp_tenant_client_service", ["tenant_id", "client_id", "service_catalogue_id"])
for name in ("registration_id", "client_branch_id", "business_unit_id", "scope_key", "scope_type"):
batch.drop_column(name)
with op.batch_alter_table("service_catalogues") as batch:
batch.drop_column("required_registration_type")
batch.drop_column("service_scope_type")
with op.batch_alter_table("client_registrations") as batch:
for name in ("state", "trade_name", "legal_name", "client_branch_id", "business_unit_id"):
batch.drop_column(name)
op.drop_table("client_branches")
op.drop_table("client_business_units")