1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 | """
Classes for accepting PayPal's Instant Payment Notification messages in a
Django application (or Django-on-App-Engine):
https://www.paypal.com/ipn
Usage:
from paypal import Endpoint # Or AppEngineEndpoint as Endpoint
class MyEndPoint(Endpoint):
def process(self, data):
# Do something with valid data from PayPal - e-mail it to yourself,
# stick it in a database, generate a license key and e-mail it to the
# user... whatever
def process_invalid(self, data):
# Do something with invalid data (could be from anywhere) - you
# should probably log this somewhere
These methods can optionally return an HttpResponse - if they don't, a
default response will be sent.
Then in urls.py:
(r'^endpoint/$', MyEndPoint()),
"data" looks something like this:
{
'business': 'your-business@example.com',
'charset': 'windows-1252',
'cmd': '_notify-validate',
'first_name': 'S',
'last_name': 'Willison',
'mc_currency': 'GBP',
'mc_fee': '0.01',
'mc_gross': '0.01',
'notify_version': '2.4',
'payer_business_name': 'Example Ltd',
'payer_email': 'payer@example.com',
'payer_id': '5YKXXXXXX6',
'payer_status': 'verified',
'payment_date': '11:45:00 Aug 13, 2008 PDT',
'payment_fee': '',
'payment_gross': '',
'payment_status': 'Completed',
'payment_type': 'instant',
'receiver_email': 'your-email@example.com',
'receiver_id': 'CXZXXXXXQ',
'residence_country': 'GB',
'txn_id': '79F58253T2487374D',
'txn_type': 'send_money',
'verify_sign': 'AOH.JxXLRThnyE4toeuh-.oeurch23.QyBY-O1N'
}
"""
from django.http import HttpResponse
import urllib
class Endpoint:
default_response_text = 'Nothing to see here'
verify_url = "https://www.paypal.com/cgi-bin/webscr"
def do_post(self, url, args):
return urllib.urlopen(url, urllib.urlencode(args)).read()
def verify(self, data):
args = {
'cmd': '_notify-validate',
}
args.update(data)
return self.do_post(self.verify_url, args) == 'VERIFIED'
def default_response(self):
return HttpResponse(self.default_response_text)
def __call__(self, request):
r = None
if request.method == 'POST':
data = dict(request.POST.items())
# We need to post that BACK to PayPal to confirm it
if self.verify(data):
r = self.process(data)
else:
r = self.process_invalid(data)
if r:
return r
else:
return self.default_response()
def process(self, data):
pass
def process_invalid(self, data):
pass
class AppEngineEndpoint(Endpoint):
def do_post(self, url, args):
from google.appengine.api import urlfetch
return urlfetch.fetch(
url = url,
method = urlfetch.POST,
payload = urllib.urlencode(args)
).content
|
Comments
By default, PayPal sends IPN notification encoded using windows-1252 - which means characters used outside of Europe will get lost or mangled.
You can tell PayPal to send IPN notifications in UTF8 instead. Here's the process:
If you don't do this, you'll need to tell Django to expect submissions in windows-1252, by setting request.encoding = 'windows-1252' at some point before the PayPal processing logic runs. It's a better idea to just tell PayPal to send UTF8 though.
#
PayPal have an IPN simulation tool for testing, which you can use to send example requests to your endpoint URL:
https://developer.paypal.com/cgi-bin/devscr?cmd=_ipn-link-session
(You'll need to sign up for a PayPal developer account to use it)
Annoyingly, it doesn't look like it's possible to get that tool to send UTF8 rather than windows-1252.
#
Great snippet. Much cleaner than the paypalipn app I created.
One thing though, I think you should make the Endpoint class inherit 'object' at it's base..
class Endpoint(object):
So that when over writing methods like __init__ you can call super() without any problems.
For instance, I wanted to change the obj.verify_url when calling the class for testing purposes..
def __init__(self, *args, **kwargs): is_test = kwargs.pop('is_test', False) super(PaypalIPN, self).__init__(*args, **kwargs) if is_test: self.verify_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr'Without object as the base inheritance this raises a TypeError.
Thanks again!
#
does anyone managed to make express checkout work?
#
I ran into Unicode errors when processing orders from some countries (Encode/Decode errors)..
I fixed it by replacing args.update(data) in the verify method with the following:
Seemed to solve my issues..
#
I've uploaded a pluggable app for PayPal Website Standard Payments - it includes IPN notification handling based on this code!
Django PayPal @ Github
Cheers,
John
#
Konsep pendidikan melalui rekreasi pertama kali diterapkan untuk pengembangan anak-anak di abad ke-19. [12] Pada awal abad ke-20, konsep ini diperluas untuk mencakup orang dewasa muda namun penekanannya adalah pada kegiatan fisik. [13] pendidik Lawrence LP Jacks, yang juga seorang pendukung awal pembelajaran seumur hidup, baik dijelaskan konsep modern pendidikan melalui rekreasi dalam kutipan berikut "seorang guru dalam seni hidup tidak menarik perbedaan yang tajam antara pekerjaan dan dramanya, tenaga kerja dan waktu luang, pikirannya dan tubuhnya, pendidikan dan rekreasi nya. dia tidak tahu yang mana. soal ulangan harian sd dia hanya mengejar visinya keunggulan tips cepat hamil melalui apa pun yang dia lakukan dan meninggalkan orang lain untuk menentukan apakah ia bekerja atau bermain. untuk dirinya sendiri ia sepertinya selalu melakukan keduanya Cukup. baginya bahwa ia melakukannya dengan baik. "(Jacks, 1932). [14] Pendidikan melalui rekreasi adalah kesempatan teknisi komputer untuk belajar secara mulus melalui semua kegiatan hidup. [15] konsep ini telah dihidupkan kembali oleh Universitas Western Ontario kursus bahasa inggris untuk mengajarkan anatomi mahasiswa kedokteran. [15]
#