Updating payment code to support delayed chained payments. Adding entry points for delayed execution of payments. Creating common parent class for all paypal transactions to more accurately track metadata
parent
7bfc4849a4
commit
c2c3168e5a
|
@ -1,8 +1,8 @@
|
|||
from regluit.core.models import Campaign, Wishlist
|
||||
from regluit.payment.models import Transaction, Receiver
|
||||
from regluit.payment.models import Transaction, Receiver, PaymentResponse
|
||||
from django.contrib.auth.models import User
|
||||
from regluit.payment.parameters import *
|
||||
from regluit.payment.paypal import Pay, IPN, IPN_TYPE_PAYMENT, IPN_TYPE_PREAPPROVAL, IPN_TYPE_ADJUSTMENT, Preapproval, IPN_PAY_STATUS_COMPLETED, CancelPreapproval, PaymentDetails, PreapprovalDetails, IPN_SENDER_STATUS_COMPLETED, IPN_TXN_STATUS_COMPLETED
|
||||
from regluit.payment.paypal import Pay, Execute, IPN, IPN_TYPE_PAYMENT, IPN_TYPE_PREAPPROVAL, IPN_TYPE_ADJUSTMENT, Preapproval, IPN_PAY_STATUS_COMPLETED, CancelPreapproval, PaymentDetails, PreapprovalDetails, IPN_SENDER_STATUS_COMPLETED, IPN_TXN_STATUS_COMPLETED
|
||||
import uuid
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
|
@ -56,7 +56,7 @@ class PaymentManager( object ):
|
|||
|
||||
p = PaymentDetails(t)
|
||||
|
||||
if p.error():
|
||||
if p.error() or not p.success():
|
||||
logger.info("Error retrieving payment details for transaction %d" % t.id)
|
||||
append_element(doc, tran, "error", "An error occurred while verifying this transaction, see server logs for details")
|
||||
|
||||
|
@ -73,15 +73,23 @@ class PaymentManager( object ):
|
|||
|
||||
try:
|
||||
receiver = Receiver.objects.get(transaction=t, email=r['email'])
|
||||
|
||||
# Check for updates on each receiver's status
|
||||
print r
|
||||
print receiver
|
||||
|
||||
# Check for updates on each receiver's status. Note that unprocessed delayed chained payments
|
||||
# will not have a status code or txn id code
|
||||
if receiver.status != r['status']:
|
||||
append_element(doc, tran, "receiver_status_ours", receiver.status)
|
||||
append_element(doc, tran, "receiver_status_theirs", r['status'])
|
||||
receiver.status = r['status']
|
||||
receiver.txn_id = r['txn_id']
|
||||
|
||||
receiver.save()
|
||||
|
||||
if receiver.txn_id != r['txn_id']:
|
||||
append_element(doc, tran, "txn_id_ours", receiver.txn_id)
|
||||
append_element(doc, tran, "txn_id_theirs", r['txn_id'])
|
||||
receiver.txn_id = r['txn_id']
|
||||
receiver.save()
|
||||
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
|
@ -93,10 +101,10 @@ class PaymentManager( object ):
|
|||
p = PreapprovalDetails(t)
|
||||
|
||||
tran = doc.createElement('preapproval')
|
||||
tran.setAttribute("key", str(t.reference))
|
||||
tran.setAttribute("key", str(t.preapproval_key))
|
||||
head.appendChild(tran)
|
||||
|
||||
if p.error():
|
||||
if p.error() or not p.success():
|
||||
logger.info("Error retrieving preapproval details for transaction %d" % t.id)
|
||||
append_element(doc, tran, "error", "An error occurred while verifying this transaction, see server logs for details")
|
||||
|
||||
|
@ -160,12 +168,14 @@ class PaymentManager( object ):
|
|||
try:
|
||||
r = Receiver.objects.get(transaction=t, email=item['receiver'])
|
||||
logger.info(item)
|
||||
# one of the IPN_SENDER_STATUS codes defined in paypal.py
|
||||
# one of the IPN_SENDER_STATUS codes defined in paypal.py, If we are doing delayed chained
|
||||
# payments, then there is no status or id for non-primary receivers. Leave their status alone
|
||||
r.status = item['status_for_sender_txn']
|
||||
r.txn_id = item['id_for_sender_txn']
|
||||
r.save()
|
||||
except:
|
||||
# Log an excecption if we have a receiver that is not found
|
||||
# Log an exception if we have a receiver that is not found. This will be hit
|
||||
# for delayed chained payments as there is no status or id for the non-primary receivers yet
|
||||
traceback.print_exc()
|
||||
|
||||
t.save()
|
||||
|
@ -179,8 +189,8 @@ class PaymentManager( object ):
|
|||
if uniqueID:
|
||||
t = Transaction.objects.get(secret=uniqueID)
|
||||
else:
|
||||
key = ipn.key()
|
||||
t = Transaction.objects.get(reference=key)
|
||||
key = ipn.pay_key
|
||||
t = Transaction.objects.get(pay_key=key)
|
||||
|
||||
# The status is always one of the IPN_PAY_STATUS codes defined in paypal.py
|
||||
t.status = ipn.status
|
||||
|
@ -192,8 +202,8 @@ class PaymentManager( object ):
|
|||
elif ipn.transaction_type == IPN_TYPE_PREAPPROVAL:
|
||||
|
||||
# IPN for preapproval always uses the key to ref the transaction as this is always valid
|
||||
key = ipn.key()
|
||||
t = Transaction.objects.get(reference=key)
|
||||
key = ipn.preapproval_key
|
||||
t = Transaction.objects.get(preapproval_key=key)
|
||||
|
||||
# The status is always one of the IPN_PREAPPROVAL_STATUS codes defined in paypal.py
|
||||
t.status = ipn.status
|
||||
|
@ -326,6 +336,49 @@ class PaymentManager( object ):
|
|||
return transactions
|
||||
|
||||
|
||||
def finish_transaction(self, transaction):
|
||||
'''
|
||||
finish_transaction
|
||||
|
||||
calls the paypal API to excute payment to non-primary receivers
|
||||
|
||||
transaction: the transaction we want to complete
|
||||
|
||||
'''
|
||||
|
||||
if transaction.execution != EXECUTE_TYPE_CHAINED_DELAYED:
|
||||
logger.error("FinishTransaction called with invalid execution type")
|
||||
return False
|
||||
|
||||
# mark this transaction as executed
|
||||
transaction.date_executed = datetime.now()
|
||||
transaction.save()
|
||||
|
||||
p = Execute(transaction)
|
||||
|
||||
# Create a response for this
|
||||
envelope = p.envelope()
|
||||
|
||||
if envelope:
|
||||
correlation = p.correlation_id()
|
||||
timestamp = p.timestamp()
|
||||
|
||||
r = PaymentResponse.objects.create(api=p.url,
|
||||
correlation_id = correlation,
|
||||
timestamp = timestamp,
|
||||
info = p.raw_response,
|
||||
transaction=transaction)
|
||||
|
||||
if p.success() and not p.error():
|
||||
logger.info("finish_transaction Success")
|
||||
return True
|
||||
|
||||
else:
|
||||
transaction.error = p.error_string()
|
||||
transaction.save()
|
||||
logger.info("finish_transaction error " + p.error_string())
|
||||
return False
|
||||
|
||||
def execute_transaction(self, transaction, receiver_list):
|
||||
'''
|
||||
execute_transaction
|
||||
|
@ -357,15 +410,31 @@ class PaymentManager( object ):
|
|||
|
||||
p = Pay(transaction)
|
||||
|
||||
# We will update our transaction status when we receive the IPN
|
||||
# Create a response for this
|
||||
envelope = p.envelope()
|
||||
|
||||
if p.status() == IPN_PAY_STATUS_COMPLETED:
|
||||
logger.info("Execute Success")
|
||||
if envelope:
|
||||
|
||||
correlation = p.correlation_id()
|
||||
timestamp = p.timestamp()
|
||||
|
||||
r = PaymentResponse.objects.create(api=p.api(),
|
||||
correlation_id = correlation,
|
||||
timestamp = timestamp,
|
||||
info = p.raw_response,
|
||||
transaction=transaction)
|
||||
|
||||
# We will update our transaction status when we receive the IPN
|
||||
if p.success() and not p.error():
|
||||
transaction.pay_key = p.key()
|
||||
transaction.save()
|
||||
logger.info("execute_transaction Success")
|
||||
return True
|
||||
|
||||
else:
|
||||
transaction.error = p.error()
|
||||
logger.info("Execute Error: " + p.error())
|
||||
transaction.error = p.error_string()
|
||||
transaction.save()
|
||||
logger.info("execute_transaction Error: " + p.error_string())
|
||||
return False
|
||||
|
||||
def cancel(self, transaction):
|
||||
|
@ -379,13 +448,28 @@ class PaymentManager( object ):
|
|||
|
||||
p = CancelPreapproval(transaction)
|
||||
|
||||
if p.success():
|
||||
# Create a response for this
|
||||
envelope = p.envelope()
|
||||
|
||||
if envelope:
|
||||
|
||||
correlation = p.correlation_id()
|
||||
timestamp = p.timestamp()
|
||||
|
||||
r = PaymentResponse.objects.create(api=p.url,
|
||||
correlation_id = correlation,
|
||||
timestamp = timestamp,
|
||||
info = p.raw_response,
|
||||
transaction=transaction)
|
||||
|
||||
if p.success() and not p.error():
|
||||
logger.info("Cancel Transaction " + str(transaction.id) + " Completed")
|
||||
return True
|
||||
|
||||
else:
|
||||
logger.info("Cancel Transaction " + str(transaction.id) + " Failed with error: " + p.error())
|
||||
transaction.error = p.error()
|
||||
transaction.error = p.error_string()
|
||||
transaction.save()
|
||||
logger.info("Cancel Transaction " + str(transaction.id) + " Failed with error: " + p.error_string())
|
||||
return False
|
||||
|
||||
def authorize(self, currency, target, amount, campaign=None, list=None, user=None, return_url=None, cancel_url=None, anonymous=False):
|
||||
|
@ -407,7 +491,8 @@ class PaymentManager( object ):
|
|||
'''
|
||||
|
||||
t = Transaction.objects.create(amount=amount,
|
||||
type=PAYMENT_TYPE_AUTHORIZATION,
|
||||
type=PAYMENT_TYPE_AUTHORIZATION,
|
||||
execution = EXECUTE_TYPE_CHAINED_DELAYED,
|
||||
target=target,
|
||||
currency=currency,
|
||||
status='NONE',
|
||||
|
@ -419,8 +504,18 @@ class PaymentManager( object ):
|
|||
|
||||
p = Preapproval(t, amount, return_url=return_url, cancel_url=cancel_url)
|
||||
|
||||
if p.status() == 'Success':
|
||||
t.reference = p.paykey()
|
||||
# Create a response for this
|
||||
envelope = p.envelope()
|
||||
|
||||
if envelope:
|
||||
r = PaymentResponse.objects.create(api=p.url,
|
||||
correlation_id = p.correlation_id(),
|
||||
timestamp = p.timestamp(),
|
||||
info = p.raw_response,
|
||||
transaction=t)
|
||||
|
||||
if p.success() and not p.error():
|
||||
t.preapproval_key = p.key()
|
||||
t.save()
|
||||
|
||||
url = p.next_url()
|
||||
|
@ -430,9 +525,9 @@ class PaymentManager( object ):
|
|||
|
||||
|
||||
else:
|
||||
t.error = p.error()
|
||||
t.error = p.error_string()
|
||||
t.save()
|
||||
logger.info("Authorize Error: " + p.error())
|
||||
logger.info("Authorize Error: " + p.error_string())
|
||||
return t, None
|
||||
|
||||
def pledge(self, currency, target, receiver_list, campaign=None, list=None, user=None, return_url=None, cancel_url=None, anonymous=False):
|
||||
|
@ -465,7 +560,8 @@ class PaymentManager( object ):
|
|||
amount = D(receiver_list[0]['amount'])
|
||||
|
||||
t = Transaction.objects.create(amount=amount,
|
||||
type=PAYMENT_TYPE_INSTANT,
|
||||
type=PAYMENT_TYPE_INSTANT,
|
||||
execution=EXECUTE_TYPE_CHAINED_INSTANT,
|
||||
target=target,
|
||||
currency=currency,
|
||||
status='NONE',
|
||||
|
@ -480,8 +576,19 @@ class PaymentManager( object ):
|
|||
|
||||
p = Pay(t,return_url=return_url, cancel_url=cancel_url)
|
||||
|
||||
if p.status() == 'CREATED':
|
||||
t.reference = p.paykey()
|
||||
# Create a response for this
|
||||
envelope = p.envelope()
|
||||
print envelope
|
||||
|
||||
if envelope:
|
||||
r = PaymentResponse.objects.create(api=p.api(),
|
||||
correlation_id = p.correlation_id(),
|
||||
timestamp = p.timestamp(),
|
||||
info = p.raw_response,
|
||||
transaction=t)
|
||||
|
||||
if p.success() and not p.error():
|
||||
t.pay_key = p.key()
|
||||
t.status = 'CREATED'
|
||||
t.save()
|
||||
|
||||
|
@ -495,9 +602,9 @@ class PaymentManager( object ):
|
|||
return t, url
|
||||
|
||||
else:
|
||||
t.error = p.error()
|
||||
t.error = p.error_string()
|
||||
t.save()
|
||||
logger.info("Pledge Error: " + p.error())
|
||||
logger.info("Pledge Error: " + p.error_string())
|
||||
return t, None
|
||||
|
||||
|
|
@ -4,7 +4,7 @@ from regluit.core.models import Campaign, Wishlist
|
|||
from regluit.payment.parameters import *
|
||||
from decimal import Decimal
|
||||
import uuid
|
||||
|
||||
|
||||
class Transaction(models.Model):
|
||||
|
||||
# type e.g., PAYMENT_TYPE_INSTANT or PAYMENT_TYPE_AUTHORIZATION -- defined in parameters.py
|
||||
|
@ -13,6 +13,9 @@ class Transaction(models.Model):
|
|||
# target: e.g, TARGET_TYPE_CAMPAIGN, TARGET_TYPE_LIST -- defined in parameters.py
|
||||
target = models.IntegerField(default=TARGET_TYPE_NONE, null=False)
|
||||
|
||||
#execution: e.g. EXECUTE_TYPE_CHAINED_INSTANT, EXECUTE_TYPE_CHAINED_DELAYED, EXECUTE_TYPE_PARALLEL
|
||||
execution = models.IntegerField(default=EXECUTE_TYPE_NONE, null=False)
|
||||
|
||||
# status: constants defined in paypal.py (e.g., IPN_PAY_STATUS_ACTIVE, IPN_PAY_STATUS_CREATED)
|
||||
status = models.CharField(max_length=32, default='NONE', null=False)
|
||||
|
||||
|
@ -24,7 +27,10 @@ class Transaction(models.Model):
|
|||
secret = models.CharField(max_length=64, null=True)
|
||||
|
||||
# a paykey that PayPal generates to identify this transaction
|
||||
reference = models.CharField(max_length=128, null=True)
|
||||
pay_key = models.CharField(max_length=128, null=True)
|
||||
|
||||
# a preapproval key that Paypal generates to identify this transaction
|
||||
preapproval_key = models.CharField(max_length=128, null=True)
|
||||
|
||||
# (RY is not sure what receipt is for)
|
||||
receipt = models.CharField(max_length=256, null=True)
|
||||
|
@ -39,9 +45,12 @@ class Transaction(models.Model):
|
|||
date_created = models.DateTimeField(auto_now_add=True)
|
||||
date_modified = models.DateTimeField(auto_now=True)
|
||||
|
||||
# date_payment: when an attempt is made to make the payment
|
||||
# date_payment: when an attempt is made to make the primary payment
|
||||
date_payment = models.DateTimeField(null=True)
|
||||
|
||||
# date_executed: when an attempt is made to send money to non-primary chained receivers
|
||||
date_executed = models.DateTimeField(null=True)
|
||||
|
||||
# datetime for creation of preapproval and for its expiration
|
||||
date_authorized = models.DateTimeField(null=True)
|
||||
date_expired = models.DateTimeField(null=True)
|
||||
|
@ -62,7 +71,7 @@ class Transaction(models.Model):
|
|||
super(Transaction, self).save(*args, **kwargs) # Call the "real" save() method.
|
||||
|
||||
def __unicode__(self):
|
||||
return u"-- Transaction:\n \tstatus: %s\n \t amount: %s\n \treference: %s\n \terror: %s\n" % (self.status, str(self.amount), self.reference, self.error)
|
||||
return u"-- Transaction:\n \tstatus: %s\n \t amount: %s\n \treference: %s\n \terror: %s\n" % (self.status, str(self.amount), self.preapproval_key, self.error)
|
||||
|
||||
def create_receivers(self, receiver_list):
|
||||
|
||||
|
@ -72,6 +81,22 @@ class Transaction(models.Model):
|
|||
primary = False
|
||||
|
||||
|
||||
class PaymentResponse(models.Model):
|
||||
# The API used
|
||||
api = models.CharField(max_length=64, null=False)
|
||||
|
||||
# The correlation ID
|
||||
correlation_id = models.CharField(max_length=512, null=True)
|
||||
|
||||
# the paypal timestamp
|
||||
timestamp = models.CharField(max_length=128, null=True)
|
||||
|
||||
# extra info we want to store if an error occurs such as the response message
|
||||
info = models.CharField(max_length=1024, null=True)
|
||||
|
||||
transaction = models.ForeignKey(Transaction, null=False)
|
||||
|
||||
|
||||
class Receiver(models.Model):
|
||||
|
||||
email = models.CharField(max_length=64)
|
||||
|
@ -92,10 +117,13 @@ import regluit.payment.manager
|
|||
|
||||
def handle_transaction_change(sender, instance, created, **kwargs):
|
||||
campaign = instance.campaign
|
||||
p = regluit.payment.manager.PaymentManager()
|
||||
amount = p.query_campaign(campaign=instance.campaign,summary=True)
|
||||
instance.campaign.left=instance.campaign.target - amount
|
||||
instance.campaign.save()
|
||||
|
||||
if campaign:
|
||||
p = regluit.payment.manager.PaymentManager()
|
||||
amount = p.query_campaign(campaign=instance.campaign,summary=True)
|
||||
instance.campaign.left=instance.campaign.target - amount
|
||||
instance.campaign.save()
|
||||
|
||||
return True
|
||||
|
||||
post_save.connect(handle_transaction_change,sender=Transaction)
|
||||
|
|
|
@ -2,6 +2,12 @@ PAYMENT_TYPE_NONE = 0
|
|||
PAYMENT_TYPE_INSTANT = 1
|
||||
PAYMENT_TYPE_AUTHORIZATION = 2
|
||||
|
||||
EXECUTE_TYPE_NONE = 0
|
||||
EXECUTE_TYPE_CHAINED_INSTANT = 1
|
||||
EXECUTE_TYPE_CHAINED_DELAYED = 2
|
||||
EXECUTE_TYPE_PARALLEL = 3
|
||||
|
||||
|
||||
TARGET_TYPE_NONE = 0
|
||||
TARGET_TYPE_CAMPAIGN = 1
|
||||
TARGET_TYPE_LIST = 2
|
||||
|
|
|
@ -82,10 +82,10 @@ class PaypalError(RuntimeError):
|
|||
|
||||
class url_request( object ):
|
||||
|
||||
def __init__( self, base, url, data=None, headers={} ):
|
||||
def __init__( self, request):
|
||||
|
||||
conn = httplib.HTTPSConnection(base)
|
||||
conn.request("POST", url, data, headers)
|
||||
conn = httplib.HTTPSConnection(settings.PAYPAL_ENDPOINT)
|
||||
conn.request("POST", request.url, request.raw_request, request.headers)
|
||||
|
||||
#Check the response - should be 200 OK.
|
||||
self.response = conn.getresponse()
|
||||
|
@ -96,11 +96,241 @@ class url_request( object ):
|
|||
def code( self ):
|
||||
return self.response.status
|
||||
|
||||
class PaypalEnvelopeRequest:
|
||||
'''
|
||||
Handles common information that is processed from the response envelope of the paypal request.
|
||||
|
||||
All of our requests have a response envelope of the following format:
|
||||
|
||||
ack common:AckCode
|
||||
Acknowledgement code. It is one of the following values:
|
||||
Success - The operation completed successfully.
|
||||
Failure - The operation failed.
|
||||
Warning - Warning.
|
||||
SuccessWithWarning - The operation completed successfully; however, there is a warning message.
|
||||
FailureWithWarning - The operation failed with a warning message.
|
||||
build Build number; it is used only by Developer Technical Support.
|
||||
correlationId Correlation ID; it is used only by Developer Technical Support.
|
||||
timestamp Date on which the response was sent. The time is currently not supported.
|
||||
|
||||
class Pay( object ):
|
||||
Additionally, our subclasses may set the error_message field if an undetermined error occurs. Examples of undertmined errors are:
|
||||
HTTP error codes(not 200)
|
||||
Invalid parameters
|
||||
Python exceptions during processing
|
||||
|
||||
All clients should check both the success() and the error() functions to determine the result of the operation
|
||||
|
||||
'''
|
||||
|
||||
# Global values for the class
|
||||
response = None
|
||||
raw_response = None
|
||||
errorMessage = None
|
||||
raw_request = None
|
||||
url = None
|
||||
|
||||
def ack( self ):
|
||||
if self.response.has_key( 'responseEnvelope' ) and self.response['responseEnvelope'].has_key( 'ack' ):
|
||||
return self.response['responseEnvelope']['ack']
|
||||
else:
|
||||
return None
|
||||
|
||||
def success(self):
|
||||
status = self.ack()
|
||||
print status
|
||||
if status == "Success" or status == "SuccessWithWarning":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def error(self):
|
||||
message = self.errorMessage
|
||||
print message
|
||||
if message:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def error_data(self):
|
||||
if self.response.has_key('error'):
|
||||
return self.response['error']
|
||||
else:
|
||||
return None
|
||||
|
||||
def error_id(self):
|
||||
if self.response.has_key('error'):
|
||||
return self.response['error'][0]['errorId']
|
||||
|
||||
def error_string(self):
|
||||
if self.response.has_key('error'):
|
||||
return self.response['error'][0]['message']
|
||||
|
||||
elif self.errorMessage:
|
||||
return self.errorMessage
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
def envelope(self):
|
||||
if self.response.has_key('responseEnvelope'):
|
||||
return self.response['responseEnvelope']
|
||||
else:
|
||||
return None
|
||||
|
||||
def correlation_id(self):
|
||||
if self.response.has_key('responseEnvelope') and self.response['responseEnvelope'].has_key('correlationId'):
|
||||
return self.response['responseEnvelope']['correlationId']
|
||||
else:
|
||||
return None
|
||||
|
||||
def timestamp(self):
|
||||
if self.response.has_key('responseEnvelope') and self.response['responseEnvelope'].has_key('timestamp'):
|
||||
return self.response['responseEnvelope']['timestamp']
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class Pay( PaypalEnvelopeRequest ):
|
||||
def __init__( self, transaction, return_url=None, cancel_url=None):
|
||||
|
||||
headers = {
|
||||
try:
|
||||
|
||||
headers = {
|
||||
'X-PAYPAL-SECURITY-USERID':settings.PAYPAL_USERNAME,
|
||||
'X-PAYPAL-SECURITY-PASSWORD':settings.PAYPAL_PASSWORD,
|
||||
'X-PAYPAL-SECURITY-SIGNATURE':settings.PAYPAL_SIGNATURE,
|
||||
'X-PAYPAL-APPLICATION-ID':settings.PAYPAL_APPID,
|
||||
'X-PAYPAL-REQUEST-DATA-FORMAT':'JSON',
|
||||
'X-PAYPAL-RESPONSE-DATA-FORMAT':'JSON'
|
||||
}
|
||||
|
||||
if return_url is None:
|
||||
return_url = settings.BASE_URL + COMPLETE_URL
|
||||
if cancel_url is None:
|
||||
cancel_url = settings.BASE_URL + CANCEL_URL
|
||||
|
||||
logger.info("Return URL: " + return_url)
|
||||
logger.info("Cancel URL: " + cancel_url)
|
||||
|
||||
receiver_list = []
|
||||
receivers = transaction.receiver_set.all()
|
||||
|
||||
if len(receivers) == 0:
|
||||
raise Exception
|
||||
|
||||
# by setting primary_string of the first receiver to 'true', we are doing a Chained payment
|
||||
for r in receivers:
|
||||
if len(receivers) > 1:
|
||||
if r.primary and (transaction.execution == EXECUTE_TYPE_CHAINED_INSTANT or transaction.execution == EXECUTE_TYPE_CHAINED_DELAYED):
|
||||
# Only set a primary if we are using chained payments
|
||||
primary_string = 'true'
|
||||
else:
|
||||
primary_string = 'false'
|
||||
|
||||
receiver_list.append({'email':r.email,'amount':str(r.amount), 'primary':primary_string})
|
||||
else:
|
||||
receiver_list.append({'email':r.email,'amount':str(r.amount)})
|
||||
|
||||
logger.info(receiver_list)
|
||||
|
||||
# actionType can be 'PAY', 'CREATE', or 'PAY_PRIMARY'
|
||||
# PAY_PRIMARY': "For chained payments only, specify this value to delay payments to the secondary receivers; only the payment to the primary receiver is processed"
|
||||
|
||||
if transaction.execution == EXECUTE_TYPE_CHAINED_DELAYED:
|
||||
self.actionType = 'PAY_PRIMARY'
|
||||
else:
|
||||
self.actionType = 'PAY'
|
||||
|
||||
# feesPayer: SENDER, PRIMARYRECEIVER, EACHRECEIVER, SECONDARYONLY
|
||||
# if only one receiver, set to EACHRECEIVER, otherwise set to SECONDARYONLY
|
||||
|
||||
if len(receivers) == 1:
|
||||
feesPayer = 'EACHRECEIVER'
|
||||
else:
|
||||
feesPayer = 'SECONDARYONLY'
|
||||
|
||||
data = {
|
||||
'actionType': self.actionType,
|
||||
'receiverList': { 'receiver': receiver_list },
|
||||
'currencyCode': transaction.currency,
|
||||
'returnUrl': return_url,
|
||||
'cancelUrl': cancel_url,
|
||||
'requestEnvelope': { 'errorLanguage': 'en_US' },
|
||||
'ipnNotificationUrl': settings.BASE_URL + reverse('PayPalIPN'),
|
||||
'feesPayer': feesPayer,
|
||||
'trackingId': transaction.secret
|
||||
}
|
||||
|
||||
logging.info("paypal PAY data: %s" % data)
|
||||
print >> sys.stderr, "paypal PAY data:", data
|
||||
# Is ipnNotificationUrl being computed properly
|
||||
print >> sys.stderr, 'ipnNotificationUrl', settings.BASE_URL + reverse('PayPalIPN')
|
||||
|
||||
# a Pay operation can be for a payment that goes through immediately or for setting up a preapproval.
|
||||
# transaction.reference is not null if it represents a preapproved payment, which has a preapprovalKey.
|
||||
if transaction.preapproval_key:
|
||||
data['preapprovalKey'] = transaction.preapproval_key
|
||||
|
||||
self.raw_request = json.dumps(data)
|
||||
self.url = "/AdaptivePayments/Pay"
|
||||
self.headers = headers
|
||||
self.connection = url_request(self)
|
||||
self.code = self.connection.code()
|
||||
|
||||
if self.code != 200:
|
||||
self.errorMessage = 'PayPal response code was %i' % self.code
|
||||
return
|
||||
|
||||
self.raw_response = self.connection.content()
|
||||
print >> sys.stderr, "PAY request", settings.PAYPAL_ENDPOINT, "/AdaptivePayments/Pay", self.raw_request, headers
|
||||
logger.info("paypal PAY response was: %s" % self.raw_response)
|
||||
print >> sys.stderr, "paypal PAY response was:", self.raw_response
|
||||
self.response = json.loads( self.raw_response )
|
||||
logger.info(self.response)
|
||||
|
||||
except:
|
||||
traceback.print_exc()
|
||||
self.errorMessage = "Error: Server Error"
|
||||
|
||||
def api(self):
|
||||
return self.actionType
|
||||
|
||||
def exec_status( self ):
|
||||
if self.response.has_key( 'paymentExecStatus' ):
|
||||
return self.response['paymentExecStatus']
|
||||
else:
|
||||
return None
|
||||
|
||||
def amount( self ):
|
||||
if self.response.has_key('payment_gross'):
|
||||
return self.response['payment_gross']
|
||||
else:
|
||||
return None
|
||||
|
||||
def key( self ):
|
||||
if self.response.has_key('payKey'):
|
||||
return self.response['payKey']
|
||||
else:
|
||||
return None
|
||||
|
||||
def next_url( self ):
|
||||
return '%s?cmd=_ap-payment&paykey=%s' % (settings.PAYPAL_PAYMENT_HOST, self.response['payKey'] )
|
||||
|
||||
def embedded_url(self):
|
||||
return '%s/webapps/adaptivepayment/flow/pay?paykey=%s&expType=light' % ( settings.PAYPAL_PAYMENT_HOST, self.response['payKey'] )
|
||||
|
||||
|
||||
|
||||
class Execute(PaypalEnvelopeRequest):
|
||||
|
||||
def __init__(self, transaction=None):
|
||||
|
||||
try:
|
||||
|
||||
self.errorMessage = None
|
||||
self.response = None
|
||||
|
||||
headers = {
|
||||
'X-PAYPAL-SECURITY-USERID':settings.PAYPAL_USERNAME,
|
||||
'X-PAYPAL-SECURITY-PASSWORD':settings.PAYPAL_PASSWORD,
|
||||
'X-PAYPAL-SECURITY-SIGNATURE':settings.PAYPAL_SIGNATURE,
|
||||
|
@ -108,110 +338,47 @@ class Pay( object ):
|
|||
'X-PAYPAL-REQUEST-DATA-FORMAT':'JSON',
|
||||
'X-PAYPAL-RESPONSE-DATA-FORMAT':'JSON'
|
||||
}
|
||||
|
||||
|
||||
if transaction.execution != EXECUTE_TYPE_CHAINED_DELAYED:
|
||||
self.errorMessage = "Invalid transaction type for execution"
|
||||
return
|
||||
|
||||
if not transaction.pay_key:
|
||||
self.errorMessage = "No Paykey Found in transaction"
|
||||
return
|
||||
|
||||
data = {
|
||||
'payKey': transaction.pay_key,
|
||||
'requestEnvelope': { 'errorLanguage': 'en_US' }
|
||||
}
|
||||
|
||||
logging.info("paypal EXECUTE data: %s" % data)
|
||||
self.raw_request = json.dumps(data)
|
||||
self.url = "/AdaptivePayments/ExecutePayment"
|
||||
self.headers = headers
|
||||
self.connection = url_request(self)
|
||||
self.code = self.connection.code()
|
||||
|
||||
if self.code != 200:
|
||||
self.errorMessage = 'PayPal response code was %i' % self.code
|
||||
return
|
||||
|
||||
self.raw_response = self.connection.content()
|
||||
|
||||
logger.info("paypal EXECUTE response was: %s" % self.raw_response)
|
||||
self.response = json.loads( self.raw_response )
|
||||
|
||||
except:
|
||||
traceback.print_exc()
|
||||
self.errorMessage = "Error: Server error occurred"
|
||||
|
||||
|
||||
if return_url is None:
|
||||
return_url = settings.BASE_URL + COMPLETE_URL
|
||||
if cancel_url is None:
|
||||
cancel_url = settings.BASE_URL + CANCEL_URL
|
||||
|
||||
logger.info("Return URL: " + return_url)
|
||||
logger.info("Cancel URL: " + cancel_url)
|
||||
|
||||
receiver_list = []
|
||||
receivers = transaction.receiver_set.all()
|
||||
|
||||
if len(receivers) == 0:
|
||||
raise Exception
|
||||
|
||||
# by setting primary_string of the first receiver to 'true', we are doing a Chained payment
|
||||
for r in receivers:
|
||||
if len(receivers) > 1:
|
||||
if r.primary:
|
||||
primary_string = 'true'
|
||||
else:
|
||||
primary_string = 'false'
|
||||
|
||||
receiver_list.append({'email':r.email,'amount':str(r.amount), 'primary':primary_string})
|
||||
else:
|
||||
receiver_list.append({'email':r.email,'amount':str(r.amount)})
|
||||
|
||||
logger.info(receiver_list)
|
||||
|
||||
# actionType can be 'PAY', 'CREATE', or 'PAY_PRIMARY'
|
||||
# PAY_PRIMARY': "For chained payments only, specify this value to delay payments to the secondary receivers; only the payment to the primary receiver is processed"
|
||||
|
||||
# feesPayer: SENDER, PRIMARYRECEIVER, EACHRECEIVER, SECONDARYONLY
|
||||
# if only one receiver, set to EACHRECEIVER, otherwise set to SECONDARYONLY
|
||||
|
||||
if len(receivers) == 1:
|
||||
feesPayer = 'EACHRECEIVER'
|
||||
else:
|
||||
feesPayer = 'SECONDARYONLY'
|
||||
|
||||
data = {
|
||||
'actionType': 'PAY',
|
||||
'receiverList': { 'receiver': receiver_list },
|
||||
'currencyCode': transaction.currency,
|
||||
'returnUrl': return_url,
|
||||
'cancelUrl': cancel_url,
|
||||
'requestEnvelope': { 'errorLanguage': 'en_US' },
|
||||
'ipnNotificationUrl': settings.BASE_URL + reverse('PayPalIPN'),
|
||||
'feesPayer': feesPayer,
|
||||
'trackingId': transaction.secret
|
||||
}
|
||||
|
||||
logging.info("paypal PAY data: %s" % data)
|
||||
print >> sys.stderr, "paypal PAY data:", data
|
||||
# Is ipnNotificationUrl being computed properly
|
||||
print >> sys.stderr, 'ipnNotificationUrl', settings.BASE_URL + reverse('PayPalIPN')
|
||||
|
||||
# a Pay operation can be for a payment that goes through immediately or for setting up a preapproval.
|
||||
# transaction.reference is not null if it represents a preapproved payment, which has a preapprovalKey.
|
||||
if transaction.reference:
|
||||
data['preapprovalKey'] = transaction.reference
|
||||
|
||||
self.raw_request = json.dumps(data)
|
||||
|
||||
self.raw_response = url_request(settings.PAYPAL_ENDPOINT, "/AdaptivePayments/Pay", data=self.raw_request, headers=headers ).content()
|
||||
print >> sys.stderr, "PAY request", settings.PAYPAL_ENDPOINT, "/AdaptivePayments/Pay", self.raw_request, headers
|
||||
logger.info("paypal PAY response was: %s" % self.raw_response)
|
||||
print >> sys.stderr, "paypal PAY response was:", self.raw_response
|
||||
self.response = json.loads( self.raw_response )
|
||||
logger.info(self.response)
|
||||
|
||||
def status( self ):
|
||||
if self.response.has_key( 'paymentExecStatus' ):
|
||||
return self.response['paymentExecStatus']
|
||||
else:
|
||||
return None
|
||||
|
||||
def error( self ):
|
||||
if self.response.has_key('error'):
|
||||
error = self.response['error']
|
||||
logger.info(error)
|
||||
return error[0]['message']
|
||||
else:
|
||||
return 'Paypal PAY: Unknown Error'
|
||||
|
||||
def amount( self ):
|
||||
return decimal.Decimal(self.results[ 'payment_gross' ])
|
||||
|
||||
def paykey( self ):
|
||||
return self.response['payKey']
|
||||
|
||||
def next_url( self ):
|
||||
return '%s?cmd=_ap-payment&paykey=%s' % (settings.PAYPAL_PAYMENT_HOST, self.response['payKey'] )
|
||||
|
||||
def embedded_url(self):
|
||||
return '%s/webapps/adaptivepayment/flow/pay?paykey=%s&expType=light' % ( settings.PAYPAL_PAYMENT_HOST, self.response['payKey'] )
|
||||
|
||||
class PaymentDetails(object):
|
||||
class PaymentDetails(PaypalEnvelopeRequest):
|
||||
def __init__(self, transaction=None):
|
||||
|
||||
try:
|
||||
self.transaction = transaction
|
||||
self.errorMessage = None
|
||||
self.response = None
|
||||
|
||||
headers = {
|
||||
'X-PAYPAL-SECURITY-USERID':settings.PAYPAL_USERNAME,
|
||||
|
@ -230,14 +397,17 @@ class PaymentDetails(object):
|
|||
}
|
||||
|
||||
self.raw_request = json.dumps(data)
|
||||
|
||||
self.connection = url_request(settings.PAYPAL_ENDPOINT, "/AdaptivePayments/PaymentDetails", data=self.raw_request, headers=headers )
|
||||
self.raw_response = self.connection.content()
|
||||
self.headers = headers
|
||||
self.url = "/AdaptivePayments/PaymentDetails"
|
||||
self.connection = url_request(self)
|
||||
|
||||
self.code = self.connection.code()
|
||||
|
||||
if self.code != 200:
|
||||
self.errorMessage = 'PayPal response code was %i' % self.code
|
||||
return
|
||||
|
||||
self.raw_response = self.connection.content()
|
||||
|
||||
logger.info("paypal PaymentDetails response was: %s" % self.raw_response)
|
||||
self.response = json.loads( self.raw_response )
|
||||
|
@ -266,17 +436,6 @@ class PaymentDetails(object):
|
|||
self.errorMessage = "Error: ServerError"
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def error(self):
|
||||
if self.response and self.response.has_key('error'):
|
||||
error = self.response['error']
|
||||
logger.info(error)
|
||||
return error[0]['message']
|
||||
|
||||
elif self.errorMessage:
|
||||
return self.errorMessage
|
||||
else:
|
||||
return None
|
||||
|
||||
def compare(self):
|
||||
"""compare current status information from what's in the current transaction object"""
|
||||
|
@ -308,99 +467,109 @@ class PaymentDetails(object):
|
|||
# paymentInfoList -- holds info for each recipient
|
||||
|
||||
|
||||
class CancelPreapproval(object):
|
||||
class CancelPreapproval(PaypalEnvelopeRequest):
|
||||
|
||||
def __init__(self, transaction):
|
||||
|
||||
headers = {
|
||||
'X-PAYPAL-SECURITY-USERID':settings.PAYPAL_USERNAME,
|
||||
'X-PAYPAL-SECURITY-PASSWORD':settings.PAYPAL_PASSWORD,
|
||||
'X-PAYPAL-SECURITY-SIGNATURE':settings.PAYPAL_SIGNATURE,
|
||||
'X-PAYPAL-APPLICATION-ID':settings.PAYPAL_APPID,
|
||||
'X-PAYPAL-REQUEST-DATA-FORMAT':'JSON',
|
||||
'X-PAYPAL-RESPONSE-DATA-FORMAT':'JSON',
|
||||
}
|
||||
|
||||
data = {
|
||||
'preapprovalKey':transaction.reference,
|
||||
'requestEnvelope': { 'errorLanguage': 'en_US' }
|
||||
}
|
||||
|
||||
self.raw_request = json.dumps(data)
|
||||
self.raw_response = url_request(settings.PAYPAL_ENDPOINT, "/AdaptivePayments/CancelPreapproval", data=self.raw_request, headers=headers ).content()
|
||||
logger.info("paypal CANCEL PREAPPROBAL response was: %s" % self.raw_response)
|
||||
self.response = json.loads( self.raw_response )
|
||||
logger.info(self.response)
|
||||
|
||||
def success(self):
|
||||
if self.status() == 'Success' or self.status() == "SuccessWithWarning":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def error(self):
|
||||
if self.response.has_key('error'):
|
||||
error = self.response['error']
|
||||
logger.info(error)
|
||||
return error[0]['message']
|
||||
else:
|
||||
return 'Paypal Preapproval Cancel: Unknown Error'
|
||||
|
||||
def status(self):
|
||||
if self.response.has_key( 'responseEnvelope' ) and self.response['responseEnvelope'].has_key( 'ack' ):
|
||||
return self.response['responseEnvelope']['ack']
|
||||
else:
|
||||
return None
|
||||
try:
|
||||
|
||||
headers = {
|
||||
'X-PAYPAL-SECURITY-USERID':settings.PAYPAL_USERNAME,
|
||||
'X-PAYPAL-SECURITY-PASSWORD':settings.PAYPAL_PASSWORD,
|
||||
'X-PAYPAL-SECURITY-SIGNATURE':settings.PAYPAL_SIGNATURE,
|
||||
'X-PAYPAL-APPLICATION-ID':settings.PAYPAL_APPID,
|
||||
'X-PAYPAL-REQUEST-DATA-FORMAT':'JSON',
|
||||
'X-PAYPAL-RESPONSE-DATA-FORMAT':'JSON',
|
||||
}
|
||||
|
||||
data = {
|
||||
'preapprovalKey':transaction.preapproval_key,
|
||||
'requestEnvelope': { 'errorLanguage': 'en_US' }
|
||||
}
|
||||
|
||||
self.raw_request = json.dumps(data)
|
||||
self.headers = headers
|
||||
self.url = "/AdaptivePayments/CancelPreapproval"
|
||||
self.connection = url_request(self)
|
||||
self.code = self.connection.code()
|
||||
|
||||
if self.code != 200:
|
||||
self.errorMessage = 'PayPal response code was %i' % self.code
|
||||
return
|
||||
|
||||
self.raw_response = self.connection.content()
|
||||
logger.info("paypal CANCEL PREAPPROBAL response was: %s" % self.raw_response)
|
||||
self.response = json.loads( self.raw_response )
|
||||
logger.info(self.response)
|
||||
|
||||
except:
|
||||
traceback.print_exc()
|
||||
self.errorMessage = "Error: Server Error"
|
||||
|
||||
|
||||
class Preapproval( object ):
|
||||
class Preapproval( PaypalEnvelopeRequest ):
|
||||
def __init__( self, transaction, amount, return_url=None, cancel_url=None):
|
||||
|
||||
headers = {
|
||||
'X-PAYPAL-SECURITY-USERID':settings.PAYPAL_USERNAME,
|
||||
'X-PAYPAL-SECURITY-PASSWORD':settings.PAYPAL_PASSWORD,
|
||||
'X-PAYPAL-SECURITY-SIGNATURE':settings.PAYPAL_SIGNATURE,
|
||||
'X-PAYPAL-APPLICATION-ID':settings.PAYPAL_APPID,
|
||||
'X-PAYPAL-REQUEST-DATA-FORMAT':'JSON',
|
||||
'X-PAYPAL-RESPONSE-DATA-FORMAT':'JSON',
|
||||
}
|
||||
|
||||
if return_url is None:
|
||||
return_url = settings.BASE_URL + COMPLETE_URL
|
||||
if cancel_url is None:
|
||||
cancel_url = settings.BASE_URL + CANCEL_URL
|
||||
|
||||
# set the expiration date for the preapproval
|
||||
now = datetime.datetime.utcnow()
|
||||
expiry = now + datetime.timedelta( days=PREAPPROVAL_PERIOD )
|
||||
transaction.date_authorized = now
|
||||
transaction.date_expired = expiry
|
||||
transaction.save()
|
||||
|
||||
data = {
|
||||
'endingDate': expiry.isoformat(),
|
||||
'startingDate': now.isoformat(),
|
||||
'maxTotalAmountOfAllPayments': '%.2f' % transaction.amount,
|
||||
'maxNumberOfPayments':1,
|
||||
'maxAmountPerPayment': '%.2f' % transaction.amount,
|
||||
'currencyCode': transaction.currency,
|
||||
'returnUrl': return_url,
|
||||
'cancelUrl': cancel_url,
|
||||
'requestEnvelope': { 'errorLanguage': 'en_US' },
|
||||
'ipnNotificationUrl': settings.BASE_URL + reverse('PayPalIPN')
|
||||
}
|
||||
|
||||
# Is ipnNotificationUrl being computed properly
|
||||
print >> sys.stderr, 'ipnNotificationUrl', settings.BASE_URL + reverse('PayPalIPN')
|
||||
|
||||
self.raw_request = json.dumps(data)
|
||||
self.raw_response = url_request(settings.PAYPAL_ENDPOINT, "/AdaptivePayments/Preapproval", data=self.raw_request, headers=headers ).content()
|
||||
logger.info("paypal PREAPPROVAL response was: %s" % self.raw_response)
|
||||
print >> sys.stderr, "paypal PREAPPROVAL response was:", self.raw_response
|
||||
self.response = json.loads( self.raw_response )
|
||||
logger.info(self.response)
|
||||
|
||||
def paykey( self ):
|
||||
try:
|
||||
|
||||
headers = {
|
||||
'X-PAYPAL-SECURITY-USERID':settings.PAYPAL_USERNAME,
|
||||
'X-PAYPAL-SECURITY-PASSWORD':settings.PAYPAL_PASSWORD,
|
||||
'X-PAYPAL-SECURITY-SIGNATURE':settings.PAYPAL_SIGNATURE,
|
||||
'X-PAYPAL-APPLICATION-ID':settings.PAYPAL_APPID,
|
||||
'X-PAYPAL-REQUEST-DATA-FORMAT':'JSON',
|
||||
'X-PAYPAL-RESPONSE-DATA-FORMAT':'JSON',
|
||||
}
|
||||
|
||||
if return_url is None:
|
||||
return_url = settings.BASE_URL + COMPLETE_URL
|
||||
if cancel_url is None:
|
||||
cancel_url = settings.BASE_URL + CANCEL_URL
|
||||
|
||||
# set the expiration date for the preapproval
|
||||
now = datetime.datetime.utcnow()
|
||||
expiry = now + datetime.timedelta( days=PREAPPROVAL_PERIOD )
|
||||
transaction.date_authorized = now
|
||||
transaction.date_expired = expiry
|
||||
transaction.save()
|
||||
|
||||
data = {
|
||||
'endingDate': expiry.isoformat(),
|
||||
'startingDate': now.isoformat(),
|
||||
'maxTotalAmountOfAllPayments': '%.2f' % transaction.amount,
|
||||
'maxNumberOfPayments':1,
|
||||
'maxAmountPerPayment': '%.2f' % transaction.amount,
|
||||
'currencyCode': transaction.currency,
|
||||
'returnUrl': return_url,
|
||||
'cancelUrl': cancel_url,
|
||||
'requestEnvelope': { 'errorLanguage': 'en_US' },
|
||||
'ipnNotificationUrl': settings.BASE_URL + reverse('PayPalIPN')
|
||||
}
|
||||
|
||||
# Is ipnNotificationUrl being computed properly
|
||||
print >> sys.stderr, 'ipnNotificationUrl', settings.BASE_URL + reverse('PayPalIPN')
|
||||
|
||||
self.raw_request = json.dumps(data)
|
||||
self.url = "/AdaptivePayments/Preapproval"
|
||||
self.headers = headers
|
||||
self.connection = url_request(self)
|
||||
self.code = self.connection.code()
|
||||
|
||||
if self.code != 200:
|
||||
self.errorMessage = 'PayPal response code was %i' % self.code
|
||||
return
|
||||
|
||||
self.raw_response = self.connection.content()
|
||||
logger.info("paypal PREAPPROVAL response was: %s" % self.raw_response)
|
||||
print >> sys.stderr, "paypal PREAPPROVAL response was:", self.raw_response
|
||||
self.response = json.loads( self.raw_response )
|
||||
logger.info(self.response)
|
||||
|
||||
except:
|
||||
traceback.print_exc()
|
||||
self.errorMessage = "Error: Server Error Occurred"
|
||||
|
||||
def key( self ):
|
||||
if self.response.has_key( 'preapprovalKey' ):
|
||||
return self.response['preapprovalKey']
|
||||
else:
|
||||
|
@ -409,29 +578,12 @@ class Preapproval( object ):
|
|||
def next_url( self ):
|
||||
return '%s?cmd=_ap-preapproval&preapprovalkey=%s' % ( settings.PAYPAL_PAYMENT_HOST, self.response['preapprovalKey'] )
|
||||
|
||||
def error( self ):
|
||||
if self.response.has_key('error'):
|
||||
error = self.response['error']
|
||||
logger.info(error)
|
||||
return error[0]['message']
|
||||
else:
|
||||
return 'Paypal Preapproval: Unknown Error'
|
||||
|
||||
def status( self ):
|
||||
if self.response.has_key( 'responseEnvelope' ) and self.response['responseEnvelope'].has_key( 'ack' ):
|
||||
return self.response['responseEnvelope']['ack']
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
class PreapprovalDetails(object):
|
||||
class PreapprovalDetails(PaypalEnvelopeRequest):
|
||||
def __init__(self, transaction):
|
||||
|
||||
try:
|
||||
self.transaction = transaction
|
||||
self.response = None
|
||||
self.errorMessage = None
|
||||
|
||||
headers = {
|
||||
'X-PAYPAL-SECURITY-USERID':settings.PAYPAL_USERNAME,
|
||||
|
@ -446,19 +598,20 @@ class PreapprovalDetails(object):
|
|||
# I think we've been tracking payKey. We might want to use our own trackingId (what's Transaction.secret for?)
|
||||
data = {
|
||||
'requestEnvelope': { 'errorLanguage': 'en_US' },
|
||||
'preapprovalKey':transaction.reference
|
||||
'preapprovalKey':transaction.preapproval_key
|
||||
}
|
||||
|
||||
self.raw_request = json.dumps(data)
|
||||
|
||||
self.connection = url_request(settings.PAYPAL_ENDPOINT, "/AdaptivePayments/PreapprovalDetails", data=self.raw_request, headers=headers )
|
||||
self.raw_response = self.connection.content()
|
||||
self.headers = headers
|
||||
self.url = "/AdaptivePayments/PreapprovalDetails"
|
||||
self.connection = url_request(self)
|
||||
self.code = self.connection.code()
|
||||
|
||||
if self.code != 200:
|
||||
self.errorMessage = 'PayPal response code was %i' % self.code
|
||||
return
|
||||
|
||||
self.raw_response = self.connection.content()
|
||||
logger.info("paypal PreapprovalDetails response was: %s" % self.raw_response)
|
||||
self.response = json.loads( self.raw_response )
|
||||
logger.info(self.response)
|
||||
|
@ -474,15 +627,6 @@ class PreapprovalDetails(object):
|
|||
self.errorMessage = "Error: ServerError"
|
||||
traceback.print_exc()
|
||||
|
||||
def error(self):
|
||||
if self.response and self.response.has_key('error'):
|
||||
error = self.response['error']
|
||||
logger.info(error)
|
||||
return error[0]['message']
|
||||
elif self.errorMessage:
|
||||
return self.errorMessage
|
||||
else:
|
||||
return None
|
||||
|
||||
class IPN( object ):
|
||||
|
||||
|
@ -532,16 +676,6 @@ class IPN( object ):
|
|||
else:
|
||||
return None
|
||||
|
||||
def key(self):
|
||||
# We only keep one reference, either a prapproval key, or a pay key, for the transaction. This avoids the
|
||||
# race condition that may result if the IPN for an executed pre-approval(with both a pay key and preapproval key) is received
|
||||
# before we have time to store the pay key
|
||||
if self.preapproval_key:
|
||||
return self.preapproval_key
|
||||
elif self.pay_key:
|
||||
return self.pay_key
|
||||
else:
|
||||
return None
|
||||
|
||||
def success( self ):
|
||||
return self.error == None
|
||||
|
|
|
@ -10,5 +10,6 @@ urlpatterns = patterns(
|
|||
url(r"^paypalipn", "paypalIPN", name="PayPalIPN"),
|
||||
url(r"^runtests", "runTests"),
|
||||
url(r"^paymentcomplete","paymentcomplete"),
|
||||
url(r"^checkstatus", "checkStatus")
|
||||
url(r"^checkstatus", "checkStatus"),
|
||||
url(r"^testfinish", "testFinish"),
|
||||
)
|
||||
|
|
|
@ -16,8 +16,8 @@ import logging
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
# parameterize some test recipients
|
||||
#TEST_RECEIVERS = ['jakace_1309677337_biz@gmail.com', 'seller_1317463643_biz@gmail.com']
|
||||
TEST_RECEIVERS = ['glueja_1317336101_biz@gluejar.com', 'rh1_1317336251_biz@gluejar.com', 'RH2_1317336302_biz@gluejar.com']
|
||||
TEST_RECEIVERS = ['jakace_1309677337_biz@gmail.com', 'seller_1317463643_biz@gmail.com']
|
||||
#TEST_RECEIVERS = ['glueja_1317336101_biz@gluejar.com', 'rh1_1317336251_biz@gluejar.com', 'RH2_1317336302_biz@gluejar.com']
|
||||
|
||||
|
||||
'''
|
||||
|
@ -135,6 +135,26 @@ def testCancel(request):
|
|||
else:
|
||||
message = "Error: " + t.error
|
||||
return HttpResponse(message)
|
||||
|
||||
|
||||
'''
|
||||
http://BASE/testfinish?transaction=2
|
||||
|
||||
Example that finishes a delayed chained transaction
|
||||
'''
|
||||
def testFinish(request):
|
||||
|
||||
if "transaction" not in request.GET.keys():
|
||||
return HttpResponse("No Transaction in Request")
|
||||
|
||||
t = Transaction.objects.get(id=int(request.GET['transaction']))
|
||||
p = PaymentManager()
|
||||
if p.finish_transaction(t):
|
||||
return HttpResponse("Success")
|
||||
else:
|
||||
message = "Error: " + t.error
|
||||
return HttpResponse(message)
|
||||
|
||||
|
||||
|
||||
'''
|
||||
|
|
Loading…
Reference in New Issue