I'm trying to send an email to a seller after a buyer completes their payment but I'm facing some issues and the email was not sent. I added a print statement and a try-except block so that I can use that to debug but the print statement did not bring any information in the console and the try block did not return any success or error message in the console too. Please help.
Here's my signals.py file
# Stdlib Imports
import uuid
# Django Imports
from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver
from django.core.mail import send_mail
from django.conf import settings
# Own Imports
from payment.models import PaymentHistory
@receiver(pre_save, sender=PaymentHistory)
def create_ref_code_if_does_not_exist(sender, instance, **kwargs):
"""
Creates a reference code that will be used by paysack;
if one does not exist.
"""
if not instance.ref_code:
instance.ref_code = uuid.uuid4()
@receiver(post_save, sender=PaymentHistory)
def send_payment_notification_email(sender, instance, created, **kwargs):
if created and instance.status == 'completed':
print("PaymentNotificationEmail signal triggered.") # For debugging
# PaymentHistory model has a ForeignKey to the BuyerOrderHistory model
buyer_order = instance.order
# BuyerOrderHistory has a ForeignKey to the Product model
product = buyer_order.product
# Get the seller's email address and name
seller_email = product.user.email
seller_name = product.user.full_name
# Compose the email subject and message
subject = 'Product Payment Notification'
message = f'Hello {seller_name},\n\n'
message += f'The product "{product.title}" has been paid for.\n'
message += f'Amount Paid: {instance.amount}\n\n'
message += 'Log in to your account to manage the order.'
# Send the email
try:
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [seller_email])
print("Email sent successfully.")
except Exception as e:
print(f"Error sending email: {e}")
My apps.py file looks like this
from django.apps import AppConfig
class PaymentConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "payment"
def ready(self):
"""Import payment signals when app load."""
import payment.signals
This is my payment/models.py file:
class PaymentHistory(ObjectTracker):
user_email = models.EmailField(
max_length=255, help_text="THe user email address.", editable=False
)
order = models.ForeignKey(
BuyerOrderHistory,
on_delete=models.DO_NOTHING,
help_text="The order on-which the payment action was initiated for.",
)
amount = models.FloatField(
help_text="The naira amount of the payment.", null=True, blank=True
)
status = models.CharField(
choices=PaymentStatus.choices, default="pending", max_length=100
)
remark = models.CharField(
max_length=300, help_text="What is this payment transaction for?"
)
The status field has a defualt value which is pending but when the buyer completes the transaction and it is verified, the value will be updated to 'completed'.
My settings.py has the app installed
INSTALLED_APPS = [
...
"payment",
...
]
Here is the code that updates the status:
def post(self, request: Request, ref_code: str) -> Response:
payment_history = get_payment_history_by_its_status_and_ref_code(
status="pending", ref_code=ref_code
)
if payment_history:
"""verify reference code from paystack"""
status, data = asyncio.run(paystack().verify_transaction(ref=ref_code))
if data["message"] is None and data["paid_at"] is None:
"""
Inform the user that the transaction hasn't been completed.
"""
payload = error_response(status=False, message=data["gateway_response"])
return Response(data=payload, status=res_status.HTTP_202_ACCEPTED)
elif status is True and data["status"] == "success":
"""
Complete payment transaction and update payment history.
"""
payment_history.status = "completed"
payment_history.save(update_fields=["status"])
"""Get buyer order"""
order = BuyerOrderHistory.objects.filter(
id=payment_history.order.id
).first()
"""Update order status"""
order.status = "confirmed"
order.save(update_fields=["status"])
payload = success_response(
status=True,
message="Payment transaction has been completed.",
data=data,
)
return Response(data=payload, status=res_status.HTTP_200_OK)
else:
payload = error_response(
status=False, message="No transaction found for this reference code."
)
return Response(data=payload, status=res_status.HTTP_400_BAD_REQUEST)
I've tried running the code and the operation was successful but the email in the signal file was not sent. It was as if my signal file is not being triggered at all.