fix(users): handle active discounts on delete

Ensure active_discounts cascades on user/promo removal, clean orphan rows during migration, and rely on DB cascade for user deletion.
This commit is contained in:
kavore
2026-02-03 11:25:53 +03:00
parent 4b5908d6cc
commit d11b0cabaa
2 changed files with 57 additions and 2 deletions
+47
View File
@@ -168,6 +168,48 @@ def _migration_0004_add_discount_promo_codes(connection: Connection) -> None:
)
)
def _migration_0005_fix_active_discounts_fk_cascade(connection: Connection) -> None:
inspector = inspect(connection)
if not inspector.has_table("active_discounts"):
return
connection.execute(
text(
"DELETE FROM active_discounts ad "
"WHERE NOT EXISTS (SELECT 1 FROM users u WHERE u.user_id = ad.user_id) "
"OR NOT EXISTS (SELECT 1 FROM promo_codes p WHERE p.promo_code_id = ad.promo_code_id)"
)
)
connection.execute(
text("ALTER TABLE active_discounts DROP CONSTRAINT IF EXISTS active_discounts_user_id_fkey")
)
connection.execute(
text("ALTER TABLE active_discounts DROP CONSTRAINT IF EXISTS fk_active_discounts_user")
)
connection.execute(
text("ALTER TABLE active_discounts DROP CONSTRAINT IF EXISTS active_discounts_promo_code_id_fkey")
)
connection.execute(
text("ALTER TABLE active_discounts DROP CONSTRAINT IF EXISTS fk_active_discounts_promo_code")
)
connection.execute(
text(
"ALTER TABLE active_discounts "
"ADD CONSTRAINT fk_active_discounts_user "
"FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE CASCADE"
)
)
connection.execute(
text(
"ALTER TABLE active_discounts "
"ADD CONSTRAINT fk_active_discounts_promo_code "
"FOREIGN KEY (promo_code_id) REFERENCES promo_codes (promo_code_id) ON DELETE CASCADE"
)
)
MIGRATIONS: List[Migration] = [
Migration(
id="0001_add_channel_subscription_fields",
@@ -189,6 +231,11 @@ MIGRATIONS: List[Migration] = [
description="Add support for percentage discount promo codes",
upgrade=_migration_0004_add_discount_promo_codes,
),
Migration(
id="0005_fix_active_discounts_fk_cascade",
description="Ensure active_discounts FKs cascade on user/promo delete",
upgrade=_migration_0005_fix_active_discounts_fk_cascade,
),
]
+10 -2
View File
@@ -210,8 +210,16 @@ class ActiveDiscount(Base):
"""Tracks pending discount promo codes awaiting payment (permanent until used)"""
__tablename__ = "active_discounts"
user_id = Column(BigInteger, ForeignKey("users.user_id"), primary_key=True)
promo_code_id = Column(Integer, ForeignKey("promo_codes.promo_code_id"), nullable=False)
user_id = Column(
BigInteger,
ForeignKey("users.user_id", ondelete="CASCADE"),
primary_key=True,
)
promo_code_id = Column(
Integer,
ForeignKey("promo_codes.promo_code_id", ondelete="CASCADE"),
nullable=False,
)
discount_percentage = Column(Integer, nullable=False)
activated_at = Column(DateTime(timezone=True), server_default=func.now())