Auto-sync system default tasks to firms and open engagements

This commit is contained in:
A R R R Associates
2026-09-19 12:47:53 +05:30
parent f6776cc96a
commit 2d6043962b
9 changed files with 857 additions and 313 deletions
@@ -0,0 +1,80 @@
"""System default task inheritance and firm update review.
Revision ID: 20260919_task_inheritance
Revises: 20260918_accounting_mirror_ver
"""
from alembic import op
import sqlalchemy as sa
revision = "20260919_task_inheritance"
down_revision = "20260918_accounting_mirror_ver"
branch_labels = None
depends_on = None
def upgrade() -> None:
bind = op.get_bind()
inspector = sa.inspect(bind)
columns = {c["name"] for c in inspector.get_columns("firm_service_task_templates")}
fks = {fk.get("name") for fk in inspector.get_foreign_keys("firm_service_task_templates")}
# batch_alter_table keeps this migration compatible with both production
# PostgreSQL and the project's supported SQLite development database.
with op.batch_alter_table("firm_service_task_templates") as batch:
if "source_system_task_id" not in columns:
batch.add_column(sa.Column("source_system_task_id", sa.Integer(), nullable=True))
if "is_customized" not in columns:
batch.add_column(sa.Column("is_customized", sa.Boolean(), nullable=False, server_default=sa.false()))
if "last_synced_system_hash" not in columns:
batch.add_column(sa.Column("last_synced_system_hash", sa.String(length=64), nullable=True))
if "last_reviewed_system_hash" not in columns:
batch.add_column(sa.Column("last_reviewed_system_hash", sa.String(length=64), nullable=True))
if "system_update_available" not in columns:
batch.add_column(sa.Column("system_update_available", sa.Boolean(), nullable=False, server_default=sa.false()))
if "system_update_detected_at_utc" not in columns:
batch.add_column(sa.Column("system_update_detected_at_utc", sa.DateTime(timezone=True), nullable=True))
if "fk_firm_task_source_system_task" not in fks:
batch.create_foreign_key(
"fk_firm_task_source_system_task",
"service_default_task_templates",
["source_system_task_id"],
["id"],
ondelete="SET NULL",
)
inspector = sa.inspect(bind)
indexes = {i.get("name") for i in inspector.get_indexes("firm_service_task_templates")}
if "ix_firm_service_task_templates_source_system_task_id" not in indexes:
op.create_index("ix_firm_service_task_templates_source_system_task_id", "firm_service_task_templates", ["source_system_task_id"], unique=False)
if "ix_firm_service_task_templates_is_customized" not in indexes:
op.create_index("ix_firm_service_task_templates_is_customized", "firm_service_task_templates", ["is_customized"], unique=False)
if "ix_firm_service_task_templates_system_update_available" not in indexes:
op.create_index("ix_firm_service_task_templates_system_update_available", "firm_service_task_templates", ["system_update_available"], unique=False)
def downgrade() -> None:
bind = op.get_bind()
inspector = sa.inspect(bind)
indexes = {i.get("name") for i in inspector.get_indexes("firm_service_task_templates")}
if "ix_firm_service_task_templates_system_update_available" in indexes:
op.drop_index("ix_firm_service_task_templates_system_update_available", table_name="firm_service_task_templates")
if "ix_firm_service_task_templates_is_customized" in indexes:
op.drop_index("ix_firm_service_task_templates_is_customized", table_name="firm_service_task_templates")
if "ix_firm_service_task_templates_source_system_task_id" in indexes:
op.drop_index("ix_firm_service_task_templates_source_system_task_id", table_name="firm_service_task_templates")
columns = {c["name"] for c in sa.inspect(bind).get_columns("firm_service_task_templates")}
fks = {fk.get("name") for fk in sa.inspect(bind).get_foreign_keys("firm_service_task_templates")}
with op.batch_alter_table("firm_service_task_templates") as batch:
if "fk_firm_task_source_system_task" in fks:
batch.drop_constraint("fk_firm_task_source_system_task", type_="foreignkey")
for name in (
"system_update_detected_at_utc",
"system_update_available",
"last_reviewed_system_hash",
"last_synced_system_hash",
"is_customized",
"source_system_task_id",
):
if name in columns:
batch.drop_column(name)