comparison gpp/donations/views.py @ 36:296b610ee507

Added IPN logic to the donations module. Added a thank-you view. Need to add logging to the IPN function.
author Brian Neal <bgneal@gmail.com>
date Thu, 11 Jun 2009 00:54:44 +0000
parents f77a1cdd7a46
children 5dbfb7fec629
comparison
equal deleted inserted replaced
35:f77a1cdd7a46 36:296b610ee507
1 """ 1 """
2 Views for the donations application. 2 Views for the donations application.
3 """ 3 """
4 import urllib2
5 import decimal
6 import datetime
7
4 from django.shortcuts import render_to_response 8 from django.shortcuts import render_to_response
5 from django.template import RequestContext 9 from django.template import RequestContext
6 from django.http import Http404 # TODO: remove
7 from django.conf import settings 10 from django.conf import settings
8 from django.contrib.sites.models import Site 11 from django.contrib.sites.models import Site
12 from django.http import HttpResponse
13 from django.http import HttpResponseServerError
14 from django.contrib.auth.models import User
9 15
10 from donations.models import Donation 16 from donations.models import Donation
17
18 PP_DATE_FMT = '%H:%M:%S %b %d, %Y PST'
19
20 def paypal_params():
21 """
22 This function returns a tuple where the 1st element is the Paypal
23 URL and the 2nd element is the Paypal business email. This information
24 depends on the setting DONATIONS_DEBUG.
25 """
26 if settings.DONATIONS_DEBUG:
27 form_action = 'https://www.sandbox.paypal.com/cgi-bin/webscr'
28 business = settings.DONATIONS_BUSINESS_DEBUG
29 else:
30 form_action = 'https://www.paypal.com/cgi-bin/webscr'
31 business = settings.DONATIONS_BUSINESS
32
33 return form_action, business
11 34
12 35
13 def index(request): 36 def index(request):
14 gross, net, donations = Donation.objects.monthly_stats() 37 gross, net, donations = Donation.objects.monthly_stats()
15 current_site = Site.objects.get_current() 38 current_site = Site.objects.get_current()
16 39 form_action, business = paypal_params()
17 if settings.DEBUG:
18 form_action = 'https://www.sandbox.paypal.com/cgi-bin/webscr'
19 business = settings.DONATIONS_BUSINESS_DEBUG
20 else:
21 form_action = 'https://www.paypal.com/cgi-bin/webscr'
22 business = settings.DONATIONS_BUSINESS
23 40
24 return render_to_response('donations/index.html', { 41 return render_to_response('donations/index.html', {
25 'goal': settings.DONATIONS_GOAL, 42 'goal': settings.DONATIONS_GOAL,
26 'gross': gross, 43 'gross': gross,
27 'net': net, 44 'net': net,
37 }, 54 },
38 context_instance = RequestContext(request)) 55 context_instance = RequestContext(request))
39 56
40 57
41 def ipn(request): 58 def ipn(request):
42 raise Http404 #TODO 59 """
60 This function is the IPN listener and handles the IPN POST from Paypal.
61
62 TODO: Add logging.
63 """
64 parameters = None
65 try:
66 if request['payment_status'] == 'Completed':
67 if request.POST:
68 parameters = request.POST.copy()
69 else:
70 parameters = request.GET.copy()
71
72 if parameters:
73 parameters['cmd']='_notify-validate'
74 req = urllib2.Request(paypal_params()[0], parameters.urlencode())
75 req.add_header("Content-type", "application/x-www-form-urlencoded")
76 response = urllib2.urlopen(req)
77 status = response.read()
78 if status != "VERIFIED":
79 parameters = None
80
81 if parameters:
82 # is this a donation to the site?
83 try:
84 item_number = int(parameters['item_number'])
85 except ValueError:
86 pass
87 else:
88 if item_number == settings.DONATIONS_ITEM_NUM or \
89 item_number == settings.DONATIONS_ITEM_ANON_NUM:
90 process_donation(item_number, parameters)
91
92 return HttpResponse("Ok")
93
94 except Exception, e:
95 # print "An exeption was caught: " + str(e)
96 pass
97
98 return HttpResponseServerError("Error")
43 99
44 100
45 def thanks(request): 101 def process_donation(item_number, params):
46 raise Http404 #TODO 102 """
103 Constructs a donation object from the parameters and stores
104 in the database.
105 """
106 # Has this transaction been processed before?
107 if 'txn_id' not in params:
108 return
109 txn_id = params['txn_id']
110 try:
111 donation = Donation.objects.get(txn_id__exact=txn_id)
112 except Donation.DoesNotExist:
113 pass
114 else:
115 return # no exception, this is a duplicate
116
117 # Is the email address ours?
118 business = params.get('business')
119 if business != paypal_params()[1]:
120 return
121
122 # is this a payment received?
123 txn_type = params.get('txn_type')
124 if txn_type != 'web_accept':
125 return
126
127 # Looks like a donation, save it to the database.
128 # Determine which user this came from, if any.
129 # The username is stored in the custom field if the user was logged in when
130 # the donation was made.
131 user = None
132 if 'custom' in params:
133 try:
134 user = User.objects.get(username__exact=params['custom'])
135 except User.DoesNotExist:
136 pass
137
138 is_anonymous = item_number == settings.DONATIONS_ITEM_ANON_NUM
139 test_ipn = params.get('test_ipn') == '1'
140
141 first_name = params.get('first_name', '')
142 last_name = params.get('last_name', '')
143 payer_email = params.get('payer_email', '')
144 payer_id = params.get('payer_id', '')
145 memo = params.get('memo', '')
146 payer_status = params.get('payer_status', '')
147
148 try:
149 mc_gross = decimal.Decimal(params['mc_gross'])
150 mc_fee = decimal.Decimal(params['mc_fee'])
151 except KeyError, decimal.InvalidOperation:
152 return
153
154 try:
155 payment_date = datetime.datetime.strptime(params['payment_date'],
156 PP_DATE_FMT)
157 except KeyError, ValueError:
158 return
159
160 donation = Donation(
161 user=user,
162 is_anonymous=is_anonymous,
163 test_ipn=test_ipn,
164 txn_id=txn_id,
165 first_name=first_name,
166 last_name=last_name,
167 payer_email=payer_email,
168 payer_id=payer_id,
169 memo=memo,
170 payer_status=payer_status,
171 mc_gross=mc_gross,
172 mc_fee=mc_fee,
173 payment_date=payment_date)
174
175 donation.save()
176