231f983429
- Add subscription_change_pending_tier and subscription_change_pending_date fields to UserProfile - Create migration 019_add_subscription_change_pending - Add apply_pending_subscription_changes(), request_subscription_change(), cancel_pending_subscription_change() utilities - Add POST /api/subscriptions/change and DELETE /api/subscriptions/change endpoints - Update GET /api/subscriptions/my to apply pending changes and return pending change info - Update subscription view to apply pending changes and pass period_start + pending info - Update subscription.html: per-tier action buttons (upgrade/downgrade/cancel), pending-change banner, period start date - Add Celery daily task apply_pending_subscription_changes_all at 00:05 UTC - Add 19 new tests covering all new utility functions and API endpoints Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
51 lines
1.6 KiB
Python
51 lines
1.6 KiB
Python
"""Celery task to apply pending subscription changes that have become due.
|
|
|
|
Runs daily to ensure that scheduled downgrades are applied on time.
|
|
"""
|
|
|
|
import logging
|
|
|
|
from app.celery_app import celery
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@celery.task(name="app.tasks.subscription_tasks.apply_pending_subscription_changes_all")
|
|
def apply_pending_subscription_changes_all() -> dict[str, int]:
|
|
"""Apply all pending subscription changes whose effective date has arrived.
|
|
|
|
Iterates over every ``UserProfile`` that has a pending change and calls
|
|
:func:`app.utils.subscription.apply_pending_subscription_changes` for
|
|
each one.
|
|
|
|
Returns:
|
|
A dict with ``{"applied": <count>, "checked": <count>}``.
|
|
"""
|
|
from app.database import SessionLocal
|
|
from app.models import UserProfile
|
|
from app.utils.subscription import apply_pending_subscription_changes
|
|
|
|
db = SessionLocal()
|
|
applied = 0
|
|
checked = 0
|
|
try:
|
|
profiles = (
|
|
db.query(UserProfile)
|
|
.filter(
|
|
UserProfile.subscription_change_pending_tier.isnot(None),
|
|
UserProfile.subscription_change_pending_date.isnot(None),
|
|
)
|
|
.all()
|
|
)
|
|
for profile in profiles:
|
|
checked += 1
|
|
if apply_pending_subscription_changes(db, profile.user_id):
|
|
applied += 1
|
|
except Exception as exc:
|
|
logger.error("Error in apply_pending_subscription_changes_all: %s", exc)
|
|
finally:
|
|
db.close()
|
|
|
|
logger.info("apply_pending_subscription_changes_all: checked=%d applied=%d", checked, applied)
|
|
return {"checked": checked, "applied": applied}
|