Merge branch 'master' into goodreads
commit
db957c7ff6
|
@ -18,28 +18,28 @@
|
|||
}
|
||||
);
|
||||
$j('.tabs1').click(function(){
|
||||
$j('#tabs').find('.active').removeClass('active');
|
||||
$j('.tabs').find('.active').removeClass('active');
|
||||
$j(this).addClass('active');
|
||||
$j('.content-block-content').find('.active').removeClass('active');
|
||||
$j('#tabs-1').addClass('active').show(300);
|
||||
$j('#tabs-2').hide(200);
|
||||
$j('#tabs-3').hide(200);
|
||||
$j('.tabs-1').addClass('active').show(300);
|
||||
$j('.tabs-2').hide(200);
|
||||
$j('.tabs-3').hide(200);
|
||||
});
|
||||
$j('.tabs2').click(function(){
|
||||
$j('#tabs').find('.active').removeClass('active');
|
||||
$j('.tabs').find('.active').removeClass('active');
|
||||
$j(this).addClass('active');
|
||||
$j('.content-block-content').find('.active').removeClass('active');
|
||||
$j('#tabs-2').addClass('active').show(300);
|
||||
$j('#tabs-1').hide(200);
|
||||
$j('#tabs-3').hide(200);
|
||||
$j('.tabs-2').addClass('active').show(300);
|
||||
$j('.tabs-1').hide(200);
|
||||
$j('.tabs-3').hide(200);
|
||||
});
|
||||
$j('.tabs3').click(function(){
|
||||
$j('#tabs').find('.active').removeClass('active');
|
||||
$j('.tabs').find('.active').removeClass('active');
|
||||
$j(this).addClass('active');
|
||||
$j('.content-block-content').find('.active').removeClass('active');
|
||||
$j('#tabs-3').addClass('active').show(300);
|
||||
$j('#tabs-2').hide(200);
|
||||
$j('#tabs-1').hide(200);
|
||||
$j('.tabs-3').addClass('active').show(300);
|
||||
$j('.tabs-2').hide(200);
|
||||
$j('.tabs-1').hide(200);
|
||||
});
|
||||
$j('.empty-wishlist span.bounce-search').click(function(){
|
||||
$j('div.js-search-inner').effect("bounce", 500, function() {
|
||||
|
@ -193,7 +193,7 @@ how do I integrate the your wishlist thing with the tabs thing?
|
|||
<ul class="tabs">
|
||||
<li class="tabs1"><a href="#">Unglued</a></li>
|
||||
<li class="tabs2"><a href="#">Being Unglued</a></li>
|
||||
<li class="tabs3"><a href="#">Want to Unglue</a></li>
|
||||
<li class="tabs3 active"><a href="#">Want to Unglue</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="book-list-view">
|
||||
|
@ -232,7 +232,14 @@ how do I integrate the your wishlist thing with the tabs thing?
|
|||
{% endifequal %}
|
||||
{% else %}
|
||||
{% for work in wishlist.works.all %}
|
||||
<div id="tabs-1" class="tabs">
|
||||
<!-- classify which tab depending on work.last_campaign_status -->
|
||||
{% if work.last_campaign_status == 'SUCCESSFUL' %}
|
||||
<div class="tabs tabs-1">
|
||||
{% else %}{% if work.last_campaign_status == 'ACTIVE' %}
|
||||
<div class="tabs tabs-2">
|
||||
{% else %}
|
||||
<div class="tabs tabs-3">
|
||||
{% endif %}{% endif %}
|
||||
<div class="book-list {% cycle 'row1' 'row2' %}">
|
||||
<div class="book-thumb">
|
||||
<a href="#"><img src="{{ work.cover_image_small }}" alt="Book name" title="book name" /></a>
|
||||
|
|
|
@ -2,17 +2,85 @@ from regluit.core.models import Campaign, Wishlist
|
|||
from regluit.payment.models import Transaction, Receiver
|
||||
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, IPN_SENDER_STATUS_COMPLETED, IPN_TXN_STATUS_COMPLETED
|
||||
from regluit.payment.paypal import Pay, IPN, IPN_TYPE_PAYMENT, IPN_TYPE_PREAPPROVAL, IPN_TYPE_ADJUSTMENT, Preapproval, IPN_PAY_STATUS_COMPLETED, CancelPreapproval, PaymentDetails, IPN_SENDER_STATUS_COMPLETED, IPN_TXN_STATUS_COMPLETED
|
||||
import uuid
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import logging
|
||||
from decimal import Decimal as D
|
||||
from xml.dom import minidom
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def append_element(doc, parent, name, text):
|
||||
|
||||
element = doc.createElement(name)
|
||||
parent.appendChild(element)
|
||||
text_node = doc.createTextNode(text)
|
||||
element.appendChild(text_node)
|
||||
|
||||
return element
|
||||
|
||||
# at this point, there is no internal context and therefore, the methods of PaymentManager can be recast into static methods
|
||||
class PaymentManager( object ):
|
||||
|
||||
def checkStatus(self):
|
||||
|
||||
'''
|
||||
Run through all pay transactions and verify that their current status is as we think.
|
||||
For now this only checks things submitted to the PAY api using the PaymentDetails. We
|
||||
Should also implement PreapprovalDetails for more info
|
||||
'''
|
||||
|
||||
doc = minidom.Document()
|
||||
head = doc.createElement('transactions')
|
||||
doc.appendChild(head)
|
||||
|
||||
# look at all transacitons in the last 3 days
|
||||
ref_date = datetime.now() - relativedelta(days=3)
|
||||
transactions = Transaction.objects.filter(date_payment__gte=ref_date)
|
||||
|
||||
for t in transactions:
|
||||
|
||||
p = PaymentDetails(t)
|
||||
|
||||
if p.error():
|
||||
logger.info("Error retrieving payment details for transaction %d" % t.id)
|
||||
|
||||
else:
|
||||
|
||||
tran = doc.createElement('transaction')
|
||||
tran.setAttribute("id", str(t.id))
|
||||
head.appendChild(tran)
|
||||
|
||||
# Check the transaction satus
|
||||
if t.status != p.status:
|
||||
append_element(doc, tran, "status_ours", t.status)
|
||||
append_element(doc, tran, "status_theirs", p.status)
|
||||
t.status = p.status
|
||||
t.save()
|
||||
|
||||
for r in p.transactions:
|
||||
|
||||
try:
|
||||
receiver = Receiver.objects.get(transaction=t, email=r['email'])
|
||||
|
||||
# Check for updates on each receiver's status
|
||||
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()
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
return doc.toxml()
|
||||
|
||||
|
||||
def processIPN(self, request):
|
||||
'''
|
||||
processIPN
|
||||
|
@ -28,13 +96,14 @@ class PaymentManager( object ):
|
|||
|
||||
if ipn.success():
|
||||
logger.info("Valid IPN")
|
||||
|
||||
logger.info("IPN Transaction Type: %s" % ipn.transaction_type)
|
||||
|
||||
if ipn.transaction_type == IPN_TYPE_PAYMENT:
|
||||
# payment IPN
|
||||
# payment IPN. we use our unique reference for the transaction as the key
|
||||
# is only valid for 3 hours
|
||||
|
||||
key = ipn.key()
|
||||
t = Transaction.objects.get(reference=key)
|
||||
uniqueID = ipn.uniqueID()
|
||||
t = Transaction.objects.get(secret=uniqueID)
|
||||
|
||||
# The status is always one of the IPN_PAY_STATUS codes defined in paypal.py
|
||||
t.status = ipn.status
|
||||
|
@ -52,14 +121,20 @@ class PaymentManager( object ):
|
|||
except:
|
||||
# Log an excecption if we have a receiver that is not found
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
t.save()
|
||||
|
||||
logger.info("Final transaction status: %s" % t.status)
|
||||
|
||||
elif ipn.transaction_type == IPN_TYPE_ADJUSTMENT:
|
||||
# a chargeback, reversal or refund for an existng payment
|
||||
|
||||
key = ipn.key()
|
||||
t = Transaction.objects.get(reference=key)
|
||||
uniqueID = ipn.uniqueID()
|
||||
if uniqueID:
|
||||
t = Transaction.objects.get(secret=uniqueID)
|
||||
else:
|
||||
key = ipn.key()
|
||||
t = Transaction.objects.get(reference=key)
|
||||
|
||||
# The status is always one of the IPN_PAY_STATUS codes defined in paypal.py
|
||||
t.status = ipn.status
|
||||
|
@ -70,7 +145,7 @@ 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)
|
||||
|
||||
|
@ -229,7 +304,11 @@ class PaymentManager( object ):
|
|||
transaction.receiver_set.all().delete()
|
||||
|
||||
transaction.create_receivers(receiver_list)
|
||||
|
||||
|
||||
# Mark as payment attempted so we will poll this periodically for status changes
|
||||
transaction.date_payment = datetime.now()
|
||||
transaction.save()
|
||||
|
||||
p = Pay(transaction)
|
||||
|
||||
# We will update our transaction status when we receive the IPN
|
||||
|
@ -285,7 +364,6 @@ class PaymentManager( object ):
|
|||
type=PAYMENT_TYPE_AUTHORIZATION,
|
||||
target=target,
|
||||
currency=currency,
|
||||
secret = str(uuid.uuid1()),
|
||||
status='NONE',
|
||||
campaign=campaign,
|
||||
list=list,
|
||||
|
@ -339,11 +417,11 @@ class PaymentManager( object ):
|
|||
type=PAYMENT_TYPE_INSTANT,
|
||||
target=target,
|
||||
currency=currency,
|
||||
secret = str(uuid.uuid1()),
|
||||
status='NONE',
|
||||
campaign=campaign,
|
||||
list=list,
|
||||
user=user
|
||||
user=user,
|
||||
date_payment=datetime.now()
|
||||
)
|
||||
|
||||
t.create_receivers(receiver_list)
|
||||
|
|
|
@ -3,6 +3,7 @@ from django.contrib.auth.models import User
|
|||
from regluit.core.models import Campaign, Wishlist
|
||||
from regluit.payment.parameters import *
|
||||
from decimal import Decimal
|
||||
import uuid
|
||||
|
||||
class Transaction(models.Model):
|
||||
|
||||
|
@ -11,7 +12,7 @@ class Transaction(models.Model):
|
|||
status = models.CharField(max_length=32, default='NONE', null=False)
|
||||
amount = models.DecimalField(default=Decimal('0.00'), max_digits=14, decimal_places=2) # max 999,999,999,999.99
|
||||
currency = models.CharField(max_length=10, default='USD', null=True)
|
||||
secret = models.CharField(max_length=64, null=True)
|
||||
secret = models.CharField(max_length=64)
|
||||
reference = models.CharField(max_length=128, null=True)
|
||||
receipt = models.CharField(max_length=256, null=True)
|
||||
error = models.CharField(max_length=256, null=True)
|
||||
|
@ -25,6 +26,11 @@ class Transaction(models.Model):
|
|||
campaign = models.ForeignKey(Campaign, null=True)
|
||||
list = models.ForeignKey(Wishlist, null=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.secret:
|
||||
self.secret = str(uuid.uuid1())
|
||||
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)
|
||||
|
||||
|
|
|
@ -155,14 +155,17 @@ class Pay( object ):
|
|||
'cancelUrl': cancel_url,
|
||||
'requestEnvelope': { 'errorLanguage': 'en_US' },
|
||||
'ipnNotificationUrl': settings.BASE_URL + reverse('PayPalIPN'),
|
||||
'feesPayer': feesPayer
|
||||
'feesPayer': feesPayer,
|
||||
'trackingId': transaction.secret
|
||||
}
|
||||
|
||||
logging.info("paypal PAY data: %s" % data)
|
||||
|
||||
# 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()
|
||||
|
@ -211,7 +214,7 @@ class PaymentDetails(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' },
|
||||
'payKey':transaction.reference
|
||||
'trackingId':transaction.secret
|
||||
}
|
||||
|
||||
self.raw_request = json.dumps(data)
|
||||
|
@ -221,6 +224,25 @@ class PaymentDetails(object):
|
|||
self.response = json.loads( self.raw_response )
|
||||
logger.info(self.response)
|
||||
|
||||
self.status = self.response.get("status", None)
|
||||
self.trackingId = self.response.get("trackingId", None)
|
||||
self.feesPayer = self.response.get("feesPayer", None)
|
||||
payment_info_list = self.response.get("paymentInfoList", None)
|
||||
payment_info = payment_info_list.get("paymentInfo", None)
|
||||
|
||||
self.transactions = []
|
||||
for payment in payment_info:
|
||||
receiver = {}
|
||||
receiver['status'] = payment.get("transactionStatus", None)
|
||||
receiver['txn_id'] = payment.get("transactionId")
|
||||
|
||||
r = payment.get("receiver", None)
|
||||
if r:
|
||||
receiver['email'] = r.get('email')
|
||||
|
||||
|
||||
self.transactions.append(receiver)
|
||||
|
||||
def error(self):
|
||||
if self.response.has_key('error'):
|
||||
error = self.response['error']
|
||||
|
@ -228,10 +250,7 @@ class PaymentDetails(object):
|
|||
return error[0]['message']
|
||||
else:
|
||||
return None
|
||||
|
||||
def status(self):
|
||||
return self.response.get("status")
|
||||
|
||||
|
||||
def compare(self):
|
||||
"""compare current status information from what's in the current transaction object"""
|
||||
# I don't think we do anything with fundingtypeList, memo
|
||||
|
@ -411,6 +430,7 @@ class IPN( object ):
|
|||
self.preapproval_key = request.POST.get('preapproval_key', None)
|
||||
self.transaction_type = request.POST.get('transaction_type', None)
|
||||
self.reason_code = request.POST.get('reason_code', None)
|
||||
self.trackingId = request.POST.get('tracking_id', None)
|
||||
|
||||
self.process_transactions(request)
|
||||
|
||||
|
@ -418,6 +438,13 @@ class IPN( object ):
|
|||
self.error = "Error: ServerError"
|
||||
traceback.print_exc()
|
||||
|
||||
def uniqueID(self):
|
||||
|
||||
if self.trackingId:
|
||||
return self.trackingId
|
||||
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
|
||||
|
|
|
@ -9,5 +9,6 @@ urlpatterns = patterns(
|
|||
url(r"^querycampaign", "queryCampaign"),
|
||||
url(r"^paypalipn", "paypalIPN", name="PayPalIPN"),
|
||||
url(r"^runtests", "runTests"),
|
||||
url(r"^paymentcomplete","paymentcomplete")
|
||||
url(r"^paymentcomplete","paymentcomplete"),
|
||||
url(r"^checkstatus", "checkStatus")
|
||||
)
|
||||
|
|
|
@ -68,8 +68,8 @@ def testExecute(request):
|
|||
for t in transactions:
|
||||
|
||||
# Note, set this to 1-5 different receivers with absolute amounts for each
|
||||
receiver_list = [{'email':TEST_RECEIVERS[0], 'amount':t.amount * 0.80},
|
||||
{'email':TEST_RECEIVERS[1], 'amount':t.amount * 0.20}]
|
||||
receiver_list = [{'email':TEST_RECEIVERS[0], 'amount':float(t.amount) * 0.80},
|
||||
{'email':TEST_RECEIVERS[1], 'amount':float(t.amount) * 0.20}]
|
||||
|
||||
p.execute_transaction(t, receiver_list)
|
||||
output += str(t)
|
||||
|
@ -225,5 +225,15 @@ def paymentcomplete(request):
|
|||
output = "payment complete"
|
||||
output += request.method + "\n" + str(request.REQUEST.items())
|
||||
return HttpResponse(output)
|
||||
|
||||
def checkStatus(request):
|
||||
# Check the status of all PAY transactions and flag any errors
|
||||
p = PaymentManager()
|
||||
error_data = p.checkStatus()
|
||||
|
||||
return HttpResponse(error_data, mimetype="text/xml")
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ PAYPAL_GLUEJAR_EMAIL = "glueja_1317336101_biz@gluejar.com"
|
|||
PAYPAL_TEST_RH_EMAIL = "rh1_1317336251_biz@gluejar.com"
|
||||
PAYPAL_TEST_NONPROFIT_PARTNER_EMAIL = "nppart_1318957063_per@gluejar.com"
|
||||
|
||||
BASE_URL = 'http://0.0.0.0/'
|
||||
BASE_URL = 'http://0.0.0.0'
|
||||
|
||||
# use database as queuing service in development
|
||||
BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport"
|
||||
|
|
Loading…
Reference in New Issue