from __future__ import annotations from alembic import op import sqlalchemy as sa revision = "20260608_phase_7s1_email_notifications" down_revision = "20260607_phase_7r6a_cashfree" branch_labels = None depends_on = None def _has_table(bind, table_name: str) -> bool: return sa.inspect(bind).has_table(table_name) def upgrade() -> None: bind = op.get_bind() if not _has_table(bind, "email_settings"): op.create_table( "email_settings", 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("branch_id", sa.Integer(), sa.ForeignKey("branches.id", ondelete="SET NULL"), nullable=True), sa.Column("smtp_host", sa.String(length=255), nullable=True), sa.Column("smtp_port", sa.Integer(), nullable=True), sa.Column("smtp_username", sa.String(length=255), nullable=True), sa.Column("smtp_password", sa.String(length=500), nullable=True), sa.Column("smtp_security", sa.String(length=20), nullable=False, server_default="SSL"), sa.Column("smtp_timeout_seconds", sa.Integer(), nullable=False, server_default="20"), sa.Column("from_email", sa.String(length=255), nullable=True), sa.Column("from_name", sa.String(length=255), nullable=True), sa.Column("reply_to_email", sa.String(length=255), nullable=True), sa.Column("imap_host", sa.String(length=255), nullable=True), sa.Column("imap_port", sa.Integer(), nullable=True), sa.Column("imap_username", sa.String(length=255), nullable=True), sa.Column("imap_password", sa.String(length=500), nullable=True), sa.Column("imap_security", sa.String(length=20), nullable=False, server_default="SSL"), sa.Column("send_auth_emails", sa.Boolean(), nullable=False, server_default=sa.true()), sa.Column("send_alert_emails", sa.Boolean(), nullable=False, server_default=sa.false()), sa.Column("send_billing_emails", sa.Boolean(), nullable=False, server_default=sa.true()), sa.Column("send_task_emails", sa.Boolean(), nullable=False, server_default=sa.true()), sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.true()), sa.Column("created_by_user_id", sa.Integer(), sa.ForeignKey("users.id", ondelete="SET NULL"), nullable=True), sa.Column("updated_by_user_id", sa.Integer(), sa.ForeignKey("users.id", ondelete="SET NULL"), 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", "branch_id", name="uq_email_settings_tenant_branch"), ) op.create_index("ix_email_settings_tenant_id", "email_settings", ["tenant_id"]) op.create_index("ix_email_settings_branch_id", "email_settings", ["branch_id"]) op.create_index("ix_email_settings_is_active", "email_settings", ["is_active"]) if not _has_table(bind, "email_templates"): op.create_table( "email_templates", sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True), sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=True), sa.Column("branch_id", sa.Integer(), sa.ForeignKey("branches.id", ondelete="SET NULL"), nullable=True), sa.Column("template_code", sa.String(length=80), nullable=False), sa.Column("template_name", sa.String(length=160), nullable=False), sa.Column("subject_template", sa.String(length=500), nullable=False), sa.Column("body_template", sa.Text(), nullable=False), sa.Column("is_html", sa.Boolean(), nullable=False, server_default=sa.false()), sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.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", "branch_id", "template_code", name="uq_email_templates_scope_code"), ) op.create_index("ix_email_templates_tenant_id", "email_templates", ["tenant_id"]) op.create_index("ix_email_templates_branch_id", "email_templates", ["branch_id"]) op.create_index("ix_email_templates_template_code", "email_templates", ["template_code"]) op.create_index("ix_email_templates_is_active", "email_templates", ["is_active"]) if not _has_table(bind, "email_logs"): op.create_table( "email_logs", sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True), sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id", ondelete="CASCADE"), nullable=True), sa.Column("branch_id", sa.Integer(), sa.ForeignKey("branches.id", ondelete="SET NULL"), nullable=True), sa.Column("recipient_email", sa.String(length=255), nullable=False), sa.Column("subject", sa.String(length=500), nullable=False), sa.Column("body", sa.Text(), nullable=True), sa.Column("status", sa.String(length=30), nullable=False, server_default="PENDING"), sa.Column("error_message", sa.Text(), nullable=True), sa.Column("sent_at", sa.DateTime(timezone=True), nullable=True), sa.Column("related_module", sa.String(length=80), nullable=True), sa.Column("related_id", sa.Integer(), nullable=True), sa.Column("template_code", sa.String(length=80), nullable=True), sa.Column("provider_message_id", sa.String(length=255), nullable=True), sa.Column("created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), ) op.create_index("ix_email_logs_tenant_id", "email_logs", ["tenant_id"]) op.create_index("ix_email_logs_branch_id", "email_logs", ["branch_id"]) op.create_index("ix_email_logs_recipient_email", "email_logs", ["recipient_email"]) op.create_index("ix_email_logs_status", "email_logs", ["status"]) op.create_index("ix_email_logs_sent_at", "email_logs", ["sent_at"]) op.create_index("ix_email_logs_related_module", "email_logs", ["related_module"]) op.create_index("ix_email_logs_related_id", "email_logs", ["related_id"]) op.create_index("ix_email_logs_template_code", "email_logs", ["template_code"]) op.create_index("ix_email_logs_created_at_utc", "email_logs", ["created_at_utc"]) def downgrade() -> None: bind = op.get_bind() if _has_table(bind, "email_logs"): op.drop_table("email_logs") if _has_table(bind, "email_templates"): op.drop_table("email_templates") if _has_table(bind, "email_settings"): op.drop_table("email_settings")