I have been attempting to get the django-paypal app working within my Django project. I'm using the dcramer fork, with Django 1.4. I am also using a Paypal developer account with business and personal accounts, processing transactions through the Paypal sandbox website.
If I have no receiver function connected to the payment_was_successful
signal, things seem to work as expected. After a transaction has occured, a new row is created in the paypal_ipn
table of the database which has a value of 'VERIFIED' in the response
column. The Paypal IPN log reports that there were no retries for this transaction.
When I do have a receiver function connected to the payment_was_successful
signal, the paypal_ipn
table includes two new rows with created_at
timestamps 10-15 seconds apart. They both have a value of 'VERIFIED' in the response column, but the latter of the two is flagged with flag_info
indicating something like:
'Duplicate txn_id. (5M907276M1007902B)'
The Paypal business account reports that the IPN was retried 1 time.
I have found possible solutions that mention the use of dispatch_uid
when connecting a receiver function to the signal which I am yet to try. My issue is that I have looked through the relevant django-paypal source code and I can't understand why Paypal would retry the IPN when the postback on the first one was verified.
Has anybody else come up against this and found a solution that they understand?
Update:
I have discovered that there was an error in my receiver function code, which would have been raising an exception. Now that I have fixed this, Paypal is no longer retrying the IPN. I'm glad that the problem has gone away, but I still can't figure out why it was happening.
Below is an excerpt of the most recent duplicate records in the database. Note that the first row was created and updated at least 10 seconds before the subsequent one.
created_at updated_at response flag
2013-02-03 07:53:56.628013+00 2013-02-03 07:53:56.628057+00 VERIFIED FALSE
2013-02-03 07:54:07.393795+00 2013-02-03 07:54:07.403008+00 VERIFIED TRUE
I have figured this one out. The short answer is to make sure your receiver functions are working correctly.
When Paypal sends an IPN to the URL you have specified, they are expecting a response with HTTP status code 200. If the response code is anything else, they will retry. Even if you process a callback and get a VERIFIED message, the IPN from Paypal needs a response of 200 OK.
I had a look through my Apache access logs and discovered that when I had errors in my receiver function for the
payment_was_successful
signal, the initial IPN from paypal received a HTTP status code 500.The django-paypal package responds with
HttpResponse("OKAY")
only after everything else has been processed, including the postback to Paypal which was returning "VERIFIED", thePayPalIPN
object being saved to the database, and the sending of signals. When things went wrong in my signal receiver function and an unhandled exception was raised, Django was responding with a HTTP status code 500.When Paypal retried the IPN, the django-paypal package was detecting a duplicate txn_id and sending the
payment_was_flagged
signal. My receiver function for this signal was error free, so Paypal received the HTTP status code 200 it was expecting and stopped retrying.Hopefully this helps someone else out there in the future.