Adding amazon FPS return view, execute and preapproval support
parent
125582eebd
commit
d370091db7
|
@ -10,7 +10,7 @@ from django.db.models.query_utils import Q
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from boto.fps.connection import FPSConnection
|
from boto.fps.connection import FPSConnection
|
||||||
|
from django.http import HttpResponse, HttpRequest, HttpResponseRedirect, HttpResponseBadRequest
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from regluit.utils.localdatetime import now, zuluformat
|
from regluit.utils.localdatetime import now, zuluformat
|
||||||
import dateutil
|
import dateutil
|
||||||
|
@ -29,10 +29,108 @@ import commands
|
||||||
import smtplib
|
import smtplib
|
||||||
import urlparse
|
import urlparse
|
||||||
import decimal
|
import decimal
|
||||||
import sys
|
import time
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
AMAZON_STATUS_SUCCESS_ABT = 'SA'
|
||||||
|
AMAZON_STATUS_SUCCESS_ACH = 'SB'
|
||||||
|
AMAZON_STATUS_SUCCESS_CREDIT = 'SC'
|
||||||
|
AMAZON_STATUS_ERROR = 'SE'
|
||||||
|
AMAZON_STATUS_ADBANDONED = 'A'
|
||||||
|
AMAZON_STATUS_EXCEPTION = 'CE'
|
||||||
|
AMAZON_STATUS_PAYMENT_MISMATCH = 'PE'
|
||||||
|
AMAZON_STATUS_INCOMPLETE = 'NP'
|
||||||
|
AMAZON_STATUS_NOT_REGISTERED = 'NM'
|
||||||
|
|
||||||
|
AMAZON_STATUS_CANCLLED = 'Cancelled'
|
||||||
|
AMAZON_STATUS_FAILURE = 'Failure'
|
||||||
|
AMAZON_STATUS_PENDING = 'Pending'
|
||||||
|
AMAZON_STATUS_RESERVED = 'Reserved'
|
||||||
|
AMAZON_STATUS_SUCCESS = 'Success'
|
||||||
|
|
||||||
|
AMAZON_IPN_STATUS_CANCELLED = 'CANCELLED'
|
||||||
|
AMAZON_IPN_STATUS_FAILURE = 'FAILURE'
|
||||||
|
AMAZON_IPN_STATUS_PENDING = 'PENDING'
|
||||||
|
AMAZON_IPN_STATUS_RESERVED = 'RESERVED'
|
||||||
|
AMAZON_IPN_STATUS_SUCCESS = 'SUCCESS'
|
||||||
|
|
||||||
|
def amazonPaymentReturn(request):
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
# pick up all get and post parameters and display
|
||||||
|
output = "payment complete"
|
||||||
|
output += request.method + "\n" + str(request.REQUEST.items())
|
||||||
|
print output
|
||||||
|
|
||||||
|
signature = request.GET['signature']
|
||||||
|
reference = request.GET['callerReference']
|
||||||
|
token = request.GET['tokenID']
|
||||||
|
status = request.GET['status']
|
||||||
|
|
||||||
|
# BUGUBG - Should we verify the signature here?
|
||||||
|
#
|
||||||
|
# Find the transaction by reference, there should only be one
|
||||||
|
# We will catch the exception if it does not exist
|
||||||
|
#
|
||||||
|
transaction = Transaction.objects.get(secret=reference)
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUGBUG, for now lets map amazon status code to paypal, just to keep things uninform
|
||||||
|
#
|
||||||
|
if transaction.type == PAYMENT_TYPE_INSTANT:
|
||||||
|
# Instant payments need to be executed now
|
||||||
|
|
||||||
|
if status == AMAZON_STATUS_SUCCESS_ABT or status == AMAZON_STATUS_SUCCESS_ACH or status == AMAZON_STATUS_SUCCESS_CREDIT:
|
||||||
|
# The above status code are unique to the return URL and are different than the pay API codes
|
||||||
|
|
||||||
|
# Store the token
|
||||||
|
transaction.pay_key = token
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUGBUG, need to handle multiple recipients
|
||||||
|
# Send the pay request now to ourselves
|
||||||
|
#
|
||||||
|
e = Execute(transaction=transaction)
|
||||||
|
|
||||||
|
transaction.status = e.status
|
||||||
|
|
||||||
|
if e.success() and not e.error():
|
||||||
|
# Success case, save the ID
|
||||||
|
print "Amazon Execute returned succesfully"
|
||||||
|
else:
|
||||||
|
print "Amazon Execute returned an error, status %s" % e.status
|
||||||
|
# Failure case
|
||||||
|
|
||||||
|
# Save some context for this transaction
|
||||||
|
|
||||||
|
else:
|
||||||
|
transaction.status = AMAZON_STATUS_FAILURE
|
||||||
|
|
||||||
|
elif transaction.type == PAYMENT_TYPE_AUTHORIZATION:
|
||||||
|
#
|
||||||
|
# Future payments, we only need to store the token. The authorization was requested with the default expidation
|
||||||
|
# date set in our settings. When we are ready, we can call execute on this
|
||||||
|
#
|
||||||
|
if status == AMAZON_STATUS_SUCCESS_ABT or status == AMAZON_STATUS_SUCCESS_ACH or status == AMAZON_STATUS_SUCCESS_CREDIT:
|
||||||
|
|
||||||
|
# The above status code are unique to the return URL and are different than the pay API codes
|
||||||
|
transaction.status = AMAZON_STATUS_PENDING
|
||||||
|
transaction.approved = True
|
||||||
|
transaction.pay_key = token
|
||||||
|
|
||||||
|
else:
|
||||||
|
transaction.status = AMAZON_STATUS_FAILURE
|
||||||
|
|
||||||
|
transaction.save()
|
||||||
|
return HttpResponse("Success")
|
||||||
|
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
return HttpResponseBadRequest("Error")
|
||||||
|
|
||||||
|
|
||||||
class AmazonRequest:
|
class AmazonRequest:
|
||||||
'''
|
'''
|
||||||
Handles common information that is processed from the response envelope of the amazon request.
|
Handles common information that is processed from the response envelope of the amazon request.
|
||||||
|
@ -43,12 +141,25 @@ class AmazonRequest:
|
||||||
response = None
|
response = None
|
||||||
raw_response = None
|
raw_response = None
|
||||||
errorMessage = None
|
errorMessage = None
|
||||||
|
status = None
|
||||||
url = None
|
url = None
|
||||||
|
|
||||||
def ack( self ):
|
def ack( self ):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def success(self):
|
def success(self):
|
||||||
|
|
||||||
|
print "CALLING SUCCESS"
|
||||||
|
if self.status:
|
||||||
|
#
|
||||||
|
# process the boto response if we have one. The status codes here are only boto response codes, not
|
||||||
|
# return_url codes
|
||||||
|
#
|
||||||
|
if self.status == AMAZON_STATUS_SUCCESS:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
if self.errorMessage:
|
if self.errorMessage:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
@ -71,17 +182,23 @@ class AmazonRequest:
|
||||||
return self.errorMessage
|
return self.errorMessage
|
||||||
|
|
||||||
def envelope(self):
|
def envelope(self):
|
||||||
return None
|
|
||||||
|
# The envelope is used to store info about this request
|
||||||
|
if self.response:
|
||||||
|
return str(self.response)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def correlation_id(self):
|
def correlation_id(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def timestamp(self):
|
def timestamp(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Pay( AmazonRequest ):
|
class Pay( AmazonRequest ):
|
||||||
def __init__( self, transaction, return_url=None, cancel_url=None, options=None):
|
|
||||||
|
def __init__( self, transaction, return_url=None, cancel_url=None, options=None, amount=None):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
@ -94,22 +211,29 @@ class Pay( AmazonRequest ):
|
||||||
receiver_list = []
|
receiver_list = []
|
||||||
receivers = transaction.receiver_set.all()
|
receivers = transaction.receiver_set.all()
|
||||||
|
|
||||||
if len(receivers) == 0:
|
if not amount:
|
||||||
raise Exception
|
# by setting primary_string of the first receiver to 'true', we are doing a Chained payment
|
||||||
|
amount = 0
|
||||||
# by setting primary_string of the first receiver to 'true', we are doing a Chained payment
|
for r in receivers:
|
||||||
total_amount = 0
|
amount += r.amount
|
||||||
for r in receivers:
|
|
||||||
total_amount += r.amount
|
|
||||||
|
|
||||||
logger.info(receiver_list)
|
logger.info(receiver_list)
|
||||||
|
|
||||||
# Data fields for amazon
|
# Data fields for amazon
|
||||||
data = {}
|
|
||||||
|
expiry = now() + timedelta( days=settings.PREAPPROVAL_PERIOD )
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'amountType':'Maximum', # The transaction amount is the maximum amount
|
||||||
|
'callerReference': transaction.secret,
|
||||||
|
'currencyCode': 'USD',
|
||||||
|
'globalAmountLimit': str(amount),
|
||||||
|
'validityExpiry': str(int(time.mktime(expiry.timetuple()))), # use the preapproval date by default
|
||||||
|
}
|
||||||
|
|
||||||
print "Amazon PURCHASE url request data: %s" % data
|
print "Amazon PURCHASE url request data: %s" % data
|
||||||
|
|
||||||
self.url = self.connection.make_url(return_url, "Test Payment", "SingleUse", str(total_amount), **data)
|
self.url = self.connection.make_url(return_url, "Test Payment", "MultiUse", str(amount), **data)
|
||||||
print "Amazon PURCHASE url was: %s" % self.url
|
print "Amazon PURCHASE url was: %s" % self.url
|
||||||
|
|
||||||
except:
|
except:
|
||||||
|
@ -133,4 +257,46 @@ class Pay( AmazonRequest ):
|
||||||
|
|
||||||
def embedded_url(self):
|
def embedded_url(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
class Preapproval(Pay):
|
||||||
|
|
||||||
|
def __init__( self, transaction, amount, expiry=None, return_url=None, cancel_url=None):
|
||||||
|
|
||||||
|
# Call into our parent class
|
||||||
|
Pay.__init__(self, transaction, return_url=return_url, cancel_url=cancel_url, options=None, amount=amount)
|
||||||
|
|
||||||
|
class Execute(AmazonRequest):
|
||||||
|
|
||||||
|
def __init__(self, transaction=None):
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
# Use the boto class top open a connection
|
||||||
|
self.connection = FPSConnection(settings.FPS_ACCESS_KEY, settings.FPS_SECRET_KEY)
|
||||||
|
|
||||||
|
# BUGBUG, handle multiple receivers! For now we just send the money to ourselves
|
||||||
|
|
||||||
|
self.raw_response = self.connection.pay(transaction.amount,
|
||||||
|
transaction.pay_key,
|
||||||
|
recipientTokenId=None,
|
||||||
|
callerReference=transaction.secret,
|
||||||
|
senderReference=None,
|
||||||
|
recipientReference=None,
|
||||||
|
senderDescription=None,
|
||||||
|
recipientDescription=None,
|
||||||
|
callerDescription=None,
|
||||||
|
metadata=None,
|
||||||
|
transactionDate=None,
|
||||||
|
reserve=False)
|
||||||
|
|
||||||
|
print "Amazon EXECUTE response was: %s" % self.raw_response
|
||||||
|
|
||||||
|
self.response = self.raw_response[0]
|
||||||
|
print "RESPONSE: %s" % self.response
|
||||||
|
self.status = self.response.TransactionStatus
|
||||||
|
print "STATUS: %s" % self.status
|
||||||
|
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
self.errorMessage = "Error: Server Error"
|
||||||
|
|
|
@ -6,13 +6,13 @@ from django.conf import settings
|
||||||
from regluit.payment.parameters import *
|
from regluit.payment.parameters import *
|
||||||
|
|
||||||
if settings.PAYMENT_PROCESSOR == 'paypal':
|
if settings.PAYMENT_PROCESSOR == 'paypal':
|
||||||
from regluit.payment.paypal import Pay
|
from regluit.payment.paypal import Pay, Execute, Preapproval
|
||||||
|
|
||||||
elif settings.PAYMENT_PROCESSOR == 'amazon':
|
elif settings.PAYMENT_PROCESSOR == 'amazon':
|
||||||
from regluit.payment.amazon import Pay
|
from regluit.payment.amazon import Pay, Execute, Preapproval
|
||||||
|
|
||||||
from regluit.payment.paypal import Execute, IPN, IPN_TYPE_PAYMENT, IPN_TYPE_PREAPPROVAL, IPN_TYPE_ADJUSTMENT, IPN_PREAPPROVAL_STATUS_ACTIVE, IPN_PAY_STATUS_INCOMPLETE, IPN_PAY_STATUS_NONE
|
from regluit.payment.paypal import IPN, IPN_TYPE_PAYMENT, IPN_TYPE_PREAPPROVAL, IPN_TYPE_ADJUSTMENT, IPN_PREAPPROVAL_STATUS_ACTIVE, IPN_PAY_STATUS_INCOMPLETE, IPN_PAY_STATUS_NONE
|
||||||
from regluit.payment.paypal import Preapproval, IPN_PAY_STATUS_COMPLETED, CancelPreapproval, PaymentDetails, PreapprovalDetails, IPN_SENDER_STATUS_COMPLETED, IPN_TXN_STATUS_COMPLETED
|
from regluit.payment.paypal import IPN_PAY_STATUS_COMPLETED, CancelPreapproval, PaymentDetails, PreapprovalDetails, IPN_SENDER_STATUS_COMPLETED, IPN_TXN_STATUS_COMPLETED
|
||||||
from regluit.payment.paypal import RefundPayment
|
from regluit.payment.paypal import RefundPayment
|
||||||
import uuid
|
import uuid
|
||||||
import traceback
|
import traceback
|
||||||
|
|
|
@ -10,7 +10,12 @@ fps_recur_obj = get_integration("fps")
|
||||||
urlpatterns = patterns(
|
urlpatterns = patterns(
|
||||||
"regluit.payment.views",
|
"regluit.payment.views",
|
||||||
url(r"^paypalipn", "paypalIPN", name="PayPalIPN"),
|
url(r"^paypalipn", "paypalIPN", name="PayPalIPN"),
|
||||||
url(r"^amazonpaymentreturn", "amazonPaymentReturn", name="AmazonPaymentReturn"),
|
)
|
||||||
|
|
||||||
|
# Amazon payment URLs
|
||||||
|
urlpatterns += patterns(
|
||||||
|
"regluit.payment.amazon",
|
||||||
|
url(r"^amazonpaymentreturn", "amazonPaymentReturn", name="AmazonPaymentReturn"),
|
||||||
)
|
)
|
||||||
|
|
||||||
if not settings.IS_PREVIEW:
|
if not settings.IS_PREVIEW:
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.shortcuts import render_to_response
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.sites.models import RequestSite
|
from django.contrib.sites.models import RequestSite
|
||||||
from regluit.payment.parameters import *
|
from regluit.payment.parameters import *
|
||||||
from django.http import HttpResponse, HttpRequest, HttpResponseRedirect
|
from django.http import HttpResponse, HttpRequest, HttpResponseRedirect, HttpResponseBadRequest
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.test.utils import setup_test_environment
|
from django.test.utils import setup_test_environment
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
|
@ -114,12 +114,18 @@ def testAuthorize(request):
|
||||||
receiver_list = [{'email': TEST_RECEIVERS[0], 'amount':20.00},
|
receiver_list = [{'email': TEST_RECEIVERS[0], 'amount':20.00},
|
||||||
{'email': TEST_RECEIVERS[1], 'amount':10.00}]
|
{'email': TEST_RECEIVERS[1], 'amount':10.00}]
|
||||||
|
|
||||||
|
# Set the return url for the processor
|
||||||
|
if settings.PAYMENT_PROCESSOR == 'amazon':
|
||||||
|
return_url = settings.BASE_URL + reverse('AmazonPaymentReturn')
|
||||||
|
else:
|
||||||
|
return_url = None
|
||||||
|
|
||||||
if campaign_id:
|
if campaign_id:
|
||||||
campaign = Campaign.objects.get(id=int(campaign_id))
|
campaign = Campaign.objects.get(id=int(campaign_id))
|
||||||
t, url = p.authorize('USD', TARGET_TYPE_CAMPAIGN, amount, campaign=campaign, list=None, user=None)
|
t, url = p.authorize('USD', TARGET_TYPE_CAMPAIGN, amount, campaign=campaign, return_url=return_url, list=None, user=None)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
t, url = p.authorize('USD', TARGET_TYPE_NONE, amount, campaign=None, list=None, user=None)
|
t, url = p.authorize('USD', TARGET_TYPE_NONE, amount, campaign=None, return_url=return_url, list=None, user=None)
|
||||||
|
|
||||||
if url:
|
if url:
|
||||||
logger.info("testAuthorize: " + url)
|
logger.info("testAuthorize: " + url)
|
||||||
|
@ -309,12 +315,7 @@ def paypalIPN(request):
|
||||||
|
|
||||||
logger.info(str(request.POST))
|
logger.info(str(request.POST))
|
||||||
return HttpResponse("ipn")
|
return HttpResponse("ipn")
|
||||||
|
|
||||||
def amazonPaymentReturn(request):
|
|
||||||
# pick up all get and post parameters and display
|
|
||||||
output = "payment complete"
|
|
||||||
output += request.method + "\n" + str(request.REQUEST.items())
|
|
||||||
return HttpResponse(output)
|
|
||||||
|
|
||||||
def paymentcomplete(request):
|
def paymentcomplete(request):
|
||||||
# pick up all get and post parameters and display
|
# pick up all get and post parameters and display
|
||||||
|
|
Loading…
Reference in New Issue