2012-04-18 16:51:54 +00:00
|
|
|
from regluit.payment.parameters import *
|
|
|
|
from django.core.urlresolvers import reverse
|
|
|
|
from django.conf import settings
|
|
|
|
from regluit.payment.models import Transaction
|
|
|
|
from django.contrib.auth.models import User
|
|
|
|
from django.utils import simplejson as json
|
|
|
|
from django.utils.xmlutils import SimplerXMLGenerator
|
|
|
|
from django.db import IntegrityError
|
|
|
|
from django.db.models.query_utils import Q
|
|
|
|
from django.shortcuts import render_to_response
|
|
|
|
from django.template import RequestContext
|
|
|
|
from boto.fps.connection import FPSConnection
|
2012-04-18 20:22:00 +00:00
|
|
|
from django.http import HttpResponse, HttpRequest, HttpResponseRedirect, HttpResponseBadRequest
|
2012-04-18 16:51:54 +00:00
|
|
|
from datetime import timedelta
|
|
|
|
from regluit.utils.localdatetime import now, zuluformat
|
|
|
|
import dateutil
|
|
|
|
|
|
|
|
import dateutil.parser
|
|
|
|
import hashlib
|
|
|
|
import httplib
|
|
|
|
import traceback
|
|
|
|
import uuid
|
|
|
|
import os
|
|
|
|
import urllib
|
|
|
|
import urllib2
|
|
|
|
import logging
|
|
|
|
import random
|
|
|
|
import commands
|
|
|
|
import smtplib
|
|
|
|
import urlparse
|
|
|
|
import decimal
|
2012-04-18 20:22:00 +00:00
|
|
|
import time
|
2012-04-18 16:51:54 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2012-04-18 20:22:00 +00:00
|
|
|
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")
|
|
|
|
|
|
|
|
|
2012-04-18 16:51:54 +00:00
|
|
|
class AmazonRequest:
|
|
|
|
'''
|
|
|
|
Handles common information that is processed from the response envelope of the amazon request.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
# Global values for the class
|
|
|
|
response = None
|
|
|
|
raw_response = None
|
|
|
|
errorMessage = None
|
2012-04-18 20:22:00 +00:00
|
|
|
status = None
|
2012-04-18 16:51:54 +00:00
|
|
|
url = None
|
|
|
|
|
|
|
|
def ack( self ):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def success(self):
|
2012-04-18 20:22:00 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2012-04-18 16:51:54 +00:00
|
|
|
if self.errorMessage:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
|
|
|
|
def error(self):
|
|
|
|
if self.errorMessage:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def error_data(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def error_id(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def error_string(self):
|
|
|
|
|
|
|
|
return self.errorMessage
|
|
|
|
|
|
|
|
def envelope(self):
|
2012-04-18 20:22:00 +00:00
|
|
|
|
|
|
|
# The envelope is used to store info about this request
|
|
|
|
if self.response:
|
|
|
|
return str(self.response)
|
|
|
|
else:
|
|
|
|
return None
|
2012-04-18 16:51:54 +00:00
|
|
|
|
|
|
|
def correlation_id(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def timestamp(self):
|
|
|
|
return None
|
2012-04-18 20:22:00 +00:00
|
|
|
|
|
|
|
|
2012-04-18 16:51:54 +00:00
|
|
|
class Pay( AmazonRequest ):
|
2012-04-18 20:22:00 +00:00
|
|
|
|
|
|
|
def __init__( self, transaction, return_url=None, cancel_url=None, options=None, amount=None):
|
2012-04-18 16:51:54 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
if not options:
|
|
|
|
options = {}
|
|
|
|
|
|
|
|
# Use the boto class top open a connection
|
|
|
|
self.connection = FPSConnection(settings.FPS_ACCESS_KEY, settings.FPS_SECRET_KEY, **options)
|
|
|
|
|
|
|
|
receiver_list = []
|
|
|
|
receivers = transaction.receiver_set.all()
|
|
|
|
|
2012-04-18 20:22:00 +00:00
|
|
|
if not amount:
|
|
|
|
# by setting primary_string of the first receiver to 'true', we are doing a Chained payment
|
|
|
|
amount = 0
|
|
|
|
for r in receivers:
|
|
|
|
amount += r.amount
|
2012-04-18 16:51:54 +00:00
|
|
|
|
2012-04-18 20:22:00 +00:00
|
|
|
logger.info(receiver_list)
|
2012-04-18 16:51:54 +00:00
|
|
|
|
|
|
|
# Data fields for amazon
|
2012-04-18 20:22:00 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2012-04-18 16:51:54 +00:00
|
|
|
|
|
|
|
print "Amazon PURCHASE url request data: %s" % data
|
|
|
|
|
2012-04-18 20:22:00 +00:00
|
|
|
self.url = self.connection.make_url(return_url, "Test Payment", "MultiUse", str(amount), **data)
|
2012-04-18 16:51:54 +00:00
|
|
|
print "Amazon PURCHASE url was: %s" % self.url
|
|
|
|
|
|
|
|
except:
|
|
|
|
traceback.print_exc()
|
|
|
|
self.errorMessage = "Error: Server Error"
|
|
|
|
|
|
|
|
def api(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def exec_status( self ):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def amount( self ):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def key( self ):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def next_url( self ):
|
|
|
|
return self.url
|
|
|
|
|
|
|
|
def embedded_url(self):
|
|
|
|
return None
|
2012-04-18 20:22:00 +00:00
|
|
|
|
|
|
|
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"
|
|
|
|
|