feat(topup): add expiry notification handling and SMS notification task

This commit is contained in:
2025-07-05 14:33:10 +05:00
parent 6fb70e82a3
commit 6ec31023c7
3 changed files with 77 additions and 0 deletions

View File

@ -0,0 +1,17 @@
# Generated by Django 5.2 on 2025-07-05 09:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("billing", "0009_remove_topup_expired"),
]
operations = [
migrations.AddField(
model_name="topup",
name="expiry_notification_sent",
field=models.BooleanField(default=False),
),
]

View File

@ -54,6 +54,7 @@ class Topup(models.Model):
paid_at = models.DateTimeField(null=True, blank=True)
mib_reference = models.CharField(default="", null=True, blank=True)
expires_at = models.DateTimeField(null=True, blank=True)
expiry_notification_sent = models.BooleanField(default=False)
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(auto_now=True)

59
billing/tasks.py Normal file
View File

@ -0,0 +1,59 @@
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.")