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