annotate 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
rev   line source
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