import logging from django.db import transaction from django.utils import timezone from procrastinate.contrib.django import app from api.notifications import send_sms from billing.models import Topup logger = logging.getLogger(__name__) @app.periodic( cron="*/30 * * * * *", periodic_id="notify_expired_topups", queue="heavy_tasks" ) # every 30 seconds @app.task def update_expired_topups(timestamp: int): expired_topups_qs = Topup.objects.filter( expires_at__lte=timezone.now(), expiry_notification_sent=False ).select_related("user") with transaction.atomic(): count = expired_topups_qs.count() logger.info(f"Found {count} topups to expire.") for topup in expired_topups_qs: if topup.user and topup.user.mobile and not topup.expiry_notification_sent: send_sms_task.defer( mobile=topup.user.mobile, amount=topup.amount, topup_id=str(topup.id), ) else: # Mark as notified even if we can't send SMS (no mobile number) topup.expiry_notification_sent = True topup.save() return { "total_expired_topups": count, } # Assuming you have a separate task for sending SMS if you go that route @app.task def send_sms_task(mobile: str, amount: float, topup_id: str): message = ( f"Dear {mobile}, \n\nYour topup of {amount} MVR has expired. " "Please make a new topup to update your wallet. \n\n- SAR Link" ) send_sms(mobile, message) logger.info(f"SMS sent to {mobile} for expired topup of {amount} MVR.") # Mark the topup as notified after successful SMS sending try: topup = Topup.objects.get(id=topup_id) topup.expiry_notification_sent = True topup.save() logger.info(f"Marked topup {topup_id} as notified.") except Topup.DoesNotExist: logger.error(f"Topup {topup_id} not found when trying to mark as notified.")