What is the correct way to write signal(s) to receive PayPal IPNs from 3 different models

173 Views Asked by At

I am using Django-Paypal to receive payments for 3 different services. Each service has a separate model (say, ServiceA, ServiceB and ServiceC) but all are within the same app. I need to update the payment status of the correct model to ‘paid=True’ after receiving payment for the corresponding service.

I have 3 payment processing views (each per service) which are working well, as all payments are completed successfully. Similarly, I have created 3 signals/receiver functions (each per model) and placed them in signals.py. When I test one signal at a time, it works well. The payment status is successfully updated to ‘paid=True’. However, when I include all the three signals in signals.py, things stop working. I noted that each time a payment is received, the first 2 receiver functions are fired, leading to an error. See the code at the bottom

How do I specify which receiver function should be called when a payment is received from a specific model? Or which is the best way to implement the above successfully? When I am using inbuilt signals such as pre-save, it is possible to specify the model to be updated by adding the sender at the decorator e.g.

@receiver(pre-save, sender = MyModel)

As for the PayPal IPN signal, I am completely stuck and any assistance, including ideas, are welcome. Thanks in advance.

@receiver(valid_ipn_received)
def Servicea_order_item_paid(sender, **kwargs):
    ipn_obj = sender
    if ipn_obj.payment_status == ST_PP_COMPLETED:
        servicea = ServiceA.objects.get(order_id =ipn_obj.invoice)
        if (
            ipn_obj.mc_gross == servicea.total_cost() 
            and ipn_obj.mc_currency == 'USD' 
            and ipn_obj.receiver_email == "[email protected]"
            ):
            servicea.paid = True
            servicea.save()

@receiver(valid_ipn_received)
def serviceb_order_item_paid(sender, **kwargs):
    ipn_obj = sender
    if ipn_obj.payment_status == ST_PP_COMPLETED:
        serviceb = ServiceB.objects.get(order_id =ipn_obj.invoice)
        if (
            ipn_obj.mc_gross == serviceb.total_cost() 
            and ipn_obj.mc_currency == 'USD' 
            and ipn_obj.receiver_email == "[email protected]"
            ):
            serviceb.paid = True
            serviceb.save()

@receiver(valid_ipn_received)
def servicec_order_item_paid(sender, **kwargs):
    ipn_obj = sender
    if ipn_obj.payment_status == ST_PP_COMPLETED:
        servicec = ServiceC.objects.get(order_id =ipn_obj.invoice)
        if (
            ipn_obj.mc_gross == servicec.total_cost() 
            and ipn_obj.mc_currency == 'USD' 
            and ipn_obj.receiver_email == "[email protected]"
            ):
            servicec.paid = True
            servicec.save()

1

There are 1 best solutions below

0
Mechdev On BEST ANSWER

Though I wasn't able to get an answer here, I finally solved the problem. I did so by combining the three signals into a single 'compound' signal using:

  • Filters
  • if-statements and
  • The exists() method

The final code is lengthy but it's working well without any errors. Even the 'Duplicate txn_id' error finally disappeared. For the purposes of sharing code, I have replaced the actual services with ServiceA, B and C respectively. See the code below:

@receiver(valid_ipn_received)
def order_item_paid(sender, **kwargs):
    ipn_obj = sender
    if ipn_obj.payment_status == ST_PP_COMPLETED:
        print('Payment was sucessful!!!!, pending other verifications')

        if ServiceA.objects.filter(order_id =ipn_obj.invoice).exists():
            print('!!!! ServiceA Oder object exists')
            servicea = get_object_or_404(ServiceA, order_id =ipn_obj.invoice)
            
            if (
                ipn_obj.mc_gross == servicea.total_cost() 
                and ipn_obj.mc_currency == 'USD' 
                and ipn_obj.receiver_email == "[email protected]"
                ):

                print('!!!. Amount, Currency and Email Verified')

                servicea.paid = True
                servicea.save()
        else:
            print('!!!! ServiceA order item does not exist')

        if ServiceB.objects.filter(order_id =ipn_obj.invoice).exists():
            print('!!!! ServiceB order item exists')
            serviceb = get_object_or_404(ServiceB, order_id =ipn_obj.invoice)
        
            if (
                ipn_obj.mc_gross == serviceb.total_cost() 
                and ipn_obj.mc_currency == 'USD' 
                and ipn_obj.receiver_email == "[email protected]"
                ):

                print('!!!!!!. Amount, Currency and Email Verified')

                serviceb.paid = True
                serviceb.save()
        else:
             print('!!!!!!!!Service B Order object does not exist')


        if ServiceC.objects.filter(order_id =ipn_obj.invoice).exists():
            print('!!!!!!!!Service C order item exists')
            servicec = get_object_or_404(ServiceC, order_id =ipn_obj.invoice)
       
            if (
                ipn_obj.mc_gross == servicec.total_cost() 
                and ipn_obj.mc_currency == 'USD' 
                and ipn_obj.receiver_email == "[email protected]"
                ):

                print('!!!!!!. Amount, Currency and Email Verified')

                servicec.paid = True
                servicec.save()
            
        else:
            print('!!! Service C order object does not exist')