diff --git a/frontend/templates/pledge.html b/frontend/templates/pledge.html
index c545fa8a..184f20da 100644
--- a/frontend/templates/pledge.html
+++ b/frontend/templates/pledge.html
@@ -7,13 +7,7 @@
-
+
{% endblock %}
{% block doccontent %}
diff --git a/payment/amazon.py b/payment/amazon.py
index 6f4f1553..fde19710 100644
--- a/payment/amazon.py
+++ b/payment/amazon.py
@@ -57,10 +57,14 @@ try:
FPS_SECRET_KEY = Key.objects.get(name="FPS_SECRET_KEY").value
logger.info('Successful loading of FPS_*_KEYs')
except Exception, e:
- FPS_ACCESS_KEY = ''
- FPS_SECRET_KEY = ''
logger.info('EXCEPTION: unsuccessful loading of FPS_*_KEYs: {0}'.format(e))
+def get_ipn_url():
+
+ if settings.IPN_SECURE_URL:
+ return settings.BASE_URL_SECURE + reverse('HandleIPN', args=["amazon"])
+ else:
+ return settings.BASE_URL + reverse('HandleIPN', args=["amazon"])
def ProcessIPN(request):
'''
@@ -89,6 +93,7 @@ def ProcessIPN(request):
'''
try:
logging.debug("Amazon IPN called")
+ logging.debug(request.POST)
uri = request.build_absolute_uri()
parsed_url = urlparse.urlparse(uri)
@@ -338,7 +343,6 @@ class AmazonRequest:
def success(self):
- print "CALLING SUCCESS"
if self.errorMessage:
return False
else:
@@ -483,7 +487,7 @@ class Execute(AmazonRequest):
self.transaction = transaction
# BUGBUG, handle multiple receivers! For now we just send the money to ourselves
-
+ global_params = {"OverrideIPNURL": get_ipn_url()}
self.raw_response = self.connection.pay(transaction.amount,
transaction.pay_key,
recipientTokenId=None,
@@ -495,7 +499,8 @@ class Execute(AmazonRequest):
callerDescription=None,
metadata=None,
transactionDate=None,
- reserve=False)
+ reserve=False,
+ extra_params=global_params)
#
# BUGBUG:
@@ -653,14 +658,15 @@ class CancelPreapproval(AmazonRequest):
self.connection = FPSConnection(FPS_ACCESS_KEY, FPS_SECRET_KEY, host=settings.AMAZON_FPS_HOST)
self.transaction = transaction
- params = {}
+ global_params = {"OverrideIPNURL": get_ipn_url()}
+ params = global_params
params['TokenId'] = transaction.pay_key
params['ReasonText'] = "Cancel Reason"
fps_response = self.connection.make_request("CancelToken", params)
body = fps_response.read()
- print body
+
if(fps_response.status == 200):
rs = ResultSet()
@@ -716,7 +722,8 @@ class RefundPayment(AmazonRequest):
# We need to reference the transaction ID here, this is stored in the preapproval_key as this
# field is not used for amazon
#
- self.raw_response = self.connection.refund(transaction.secret, transaction.preapproval_key)
+ global_params = {"OverrideIPNURL": get_ipn_url()}
+ self.raw_response = self.connection.refund(transaction.secret, transaction.preapproval_key, extra_params=global_params)
self.response = self.raw_response[0]
logging.debug("Amazon REFUNDPAYMENT response was:")
diff --git a/payment/manager.py b/payment/manager.py
index fb90b3e8..7645cd97 100644
--- a/payment/manager.py
+++ b/payment/manager.py
@@ -24,7 +24,6 @@ import urllib, urlparse
from django.conf import settings
-
logger = logging.getLogger(__name__)
def append_element(doc, parent, name, text):
@@ -42,15 +41,18 @@ class PaymentManager( object ):
def __init__( self, embedded=False):
self.embedded = embedded
- def processIPN(self, request):
+ def processIPN(self, request, module):
# Forward to our payment processor
- return ProcessIPN(request)
+ mod = __import__("regluit.payment." + module, fromlist=[str(module)])
+ method = getattr(mod, "ProcessIPN")
+ return method(request)
def update_preapproval(self, transaction):
"""Update a transaction to hold the data from a PreapprovalDetails on that transaction"""
t = transaction
- p = PreapprovalDetails(t)
+ method = getattr(transaction.get_payment_class(), "PreapprovalDetails")
+ p = method(t)
preapproval_status = {'id':t.id, 'key':t.preapproval_key}
@@ -102,7 +104,8 @@ class PaymentManager( object ):
t = transaction
payment_status = {'id':t.id}
- p = PaymentDetails(t)
+ method = getattr(transaction.get_payment_class(), "PaymentDetails")
+ p = method(t)
if p.error() or not p.success():
logger.info("Error retrieving payment details for transaction %d" % t.id)
@@ -422,7 +425,8 @@ class PaymentManager( object ):
transaction.date_executed = now()
transaction.save()
- p = Finish(transaction)
+ method = getattr(transaction.get_payment_class(), "Finish")
+ p = method(transaction)
# Create a response for this
envelope = p.envelope()
@@ -476,7 +480,8 @@ class PaymentManager( object ):
transaction.date_payment = now()
transaction.save()
- p = Execute(transaction)
+ method = getattr(transaction.get_payment_class(), "Execute")
+ p = method(transaction)
# Create a response for this
envelope = p.envelope()
@@ -515,7 +520,8 @@ class PaymentManager( object ):
return value: True if successful, false otherwise
'''
- p = CancelPreapproval(transaction)
+ method = getattr(transaction.get_payment_class(), "CancelPreapproval")
+ p = method(transaction)
# Create a response for this
envelope = p.envelope()
@@ -593,8 +599,9 @@ class PaymentManager( object ):
urllib.urlencode({'tid':t.id}))
return_url = urlparse.urljoin(settings.BASE_URL, return_path)
- p = Preapproval(t, amount, expiry, return_url=return_url, cancel_url=cancel_url, paymentReason=paymentReason)
-
+ method = getattr(t.get_payment_class(), "Preapproval")
+ p = method(t, amount, expiry, return_url=return_url, cancel_url=cancel_url, paymentReason=paymentReason)
+
# Create a response for this
envelope = p.envelope()
@@ -716,7 +723,8 @@ class PaymentManager( object ):
logger.info("Refund Transaction failed, invalid transaction status")
return False
- p = RefundPayment(transaction)
+ method = getattr(transaction.get_payment_class(), "RefundPayment")
+ p = method(transaction)
# Create a response for this
envelope = p.envelope()
@@ -791,8 +799,8 @@ class PaymentManager( object ):
)
t.create_receivers(receiver_list)
-
- p = Pay(t,return_url=return_url, cancel_url=cancel_url)
+ method = getattr(t.get_payment_class(), "Pay")
+ p = method(t,return_url=return_url, cancel_url=cancel_url)
# Create a response for this
envelope = p.envelope()
@@ -825,4 +833,4 @@ class PaymentManager( object ):
logger.info("Pledge Error: %s" % p.error_string())
return t, None
-
\ No newline at end of file
+
diff --git a/payment/migrations/0007_auto__add_field_transaction_host.py b/payment/migrations/0007_auto__add_field_transaction_host.py
new file mode 100644
index 00000000..8400cbe5
--- /dev/null
+++ b/payment/migrations/0007_auto__add_field_transaction_host.py
@@ -0,0 +1,178 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'Transaction.host'
+ db.add_column('payment_transaction', 'host', self.gf('django.db.models.fields.CharField')(default='amazon', max_length=32), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'Transaction.host'
+ db.delete_column('payment_transaction', 'host')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'core.campaign': {
+ 'Meta': {'object_name': 'Campaign'},
+ 'activated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'deadline': ('django.db.models.fields.DateTimeField', [], {}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'details': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'null': 'True', 'to': "orm['core.Edition']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'left': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
+ 'license': ('django.db.models.fields.CharField', [], {'default': "'CC BY-NC-ND'", 'max_length': '255'}),
+ 'managers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'campaigns'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
+ 'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'INITIALIZED'", 'max_length': '15', 'null': 'True'}),
+ 'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"})
+ },
+ 'core.edition': {
+ 'Meta': {'object_name': 'Edition'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'public_domain': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"})
+ },
+ 'core.premium': {
+ 'Meta': {'object_name': 'Premium'},
+ 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '10', 'decimal_places': '0'}),
+ 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'premiums'", 'null': 'True', 'to': "orm['core.Campaign']"}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'limit': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '2'})
+ },
+ 'core.wishes': {
+ 'Meta': {'object_name': 'Wishes', 'db_table': "'core_wishlist_works'"},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'wishlist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Wishlist']"}),
+ 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'wishes'", 'to': "orm['core.Work']"})
+ },
+ 'core.wishlist': {
+ 'Meta': {'object_name': 'Wishlist'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}),
+ 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'through': "orm['core.Wishes']", 'to': "orm['core.Work']"})
+ },
+ 'core.work': {
+ 'Meta': {'ordering': "['title']", 'object_name': 'Work'},
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '2'}),
+ 'num_wishes': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'openlibrary_lookup': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'})
+ },
+ 'payment.paymentresponse': {
+ 'Meta': {'object_name': 'PaymentResponse'},
+ 'api': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'correlation_id': ('django.db.models.fields.CharField', [], {'max_length': '512', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'info': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'timestamp': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'transaction': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['payment.Transaction']"})
+ },
+ 'payment.receiver': {
+ 'Meta': {'object_name': 'Receiver'},
+ 'amount': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '14', 'decimal_places': '2'}),
+ 'currency': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
+ 'email': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'local_status': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'primary': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'transaction': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['payment.Transaction']"}),
+ 'txn_id': ('django.db.models.fields.CharField', [], {'max_length': '64'})
+ },
+ 'payment.transaction': {
+ 'Meta': {'object_name': 'Transaction'},
+ 'amount': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '14', 'decimal_places': '2'}),
+ 'anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'approved': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Campaign']", 'null': 'True'}),
+ 'currency': ('django.db.models.fields.CharField', [], {'default': "'USD'", 'max_length': '10', 'null': 'True'}),
+ 'date_authorized': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'date_executed': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'date_expired': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'date_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'date_payment': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'error': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True'}),
+ 'execution': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'host': ('django.db.models.fields.CharField', [], {'default': "'amazon'", 'max_length': '32'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Wishlist']", 'null': 'True'}),
+ 'local_status': ('django.db.models.fields.CharField', [], {'default': "'NONE'", 'max_length': '32', 'null': 'True'}),
+ 'max_amount': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '14', 'decimal_places': '2'}),
+ 'pay_key': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'preapproval_key': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'premium': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Premium']", 'null': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'receipt': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True'}),
+ 'secret': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'None'", 'max_length': '32'}),
+ 'target': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'type': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'})
+ }
+ }
+
+ complete_apps = ['payment']
diff --git a/payment/models.py b/payment/models.py
index 34e246b8..0ac60f8e 100644
--- a/payment/models.py
+++ b/payment/models.py
@@ -10,6 +10,9 @@ class Transaction(models.Model):
# type e.g., PAYMENT_TYPE_INSTANT or PAYMENT_TYPE_AUTHORIZATION -- defined in parameters.py
type = models.IntegerField(default=PAYMENT_TYPE_NONE, null=False)
+ # host: the payment processor. Named after the payment module that hosts the payment processing functions
+ host = models.CharField(default=PAYMENT_HOST_AMAZON, max_length=32, null=False)
+
# target: e.g, TARGET_TYPE_CAMPAIGN, TARGET_TYPE_LIST -- defined in parameters.py
target = models.IntegerField(default=TARGET_TYPE_NONE, null=False)
@@ -87,6 +90,16 @@ class Transaction(models.Model):
for r in receiver_list:
receiver = Receiver.objects.create(email=r['email'], amount=r['amount'], currency=self.currency, status="None", primary=primary, transaction=self)
primary = False
+
+ def get_payment_class(self):
+ '''
+ Returns the specific payment module that implements this transaction
+ '''
+ if self.host == PAYMENT_HOST_NONE:
+ return None
+ else:
+ mod = __import__("regluit.payment." + self.host, fromlist=[str(self.host)])
+ return mod
class PaymentResponse(models.Model):
diff --git a/payment/parameters.py b/payment/parameters.py
index f3fb32a1..10c35d82 100644
--- a/payment/parameters.py
+++ b/payment/parameters.py
@@ -2,6 +2,10 @@ PAYMENT_TYPE_NONE = 0
PAYMENT_TYPE_INSTANT = 1
PAYMENT_TYPE_AUTHORIZATION = 2
+PAYMENT_HOST_NONE = "none"
+PAYMENT_HOST_PAYPAL = "paypal"
+PAYMENT_HOST_AMAZON = "amazon"
+
EXECUTE_TYPE_NONE = 0
EXECUTE_TYPE_CHAINED_INSTANT = 1
EXECUTE_TYPE_CHAINED_DELAYED = 2
diff --git a/payment/paypal.py b/payment/paypal.py
index 153b09ca..3ca50903 100644
--- a/payment/paypal.py
+++ b/payment/paypal.py
@@ -336,7 +336,7 @@ class PaypalEnvelopeRequest:
url = None
def ack( self ):
-
+
if self.response and self.response.has_key( 'responseEnvelope' ) and self.response['responseEnvelope'].has_key( 'ack' ):
return self.response['responseEnvelope']['ack']
else:
@@ -344,6 +344,7 @@ class PaypalEnvelopeRequest:
def success(self):
status = self.ack()
+
# print status
if status == "Success" or status == "SuccessWithWarning":
return True
@@ -401,8 +402,7 @@ class PaypalEnvelopeRequest:
return self.response['responseEnvelope']['timestamp']
else:
return None
-
-
+
class Pay( PaypalEnvelopeRequest ):
def __init__( self, transaction, return_url=None, cancel_url=None, paymentReason=""):
@@ -472,7 +472,7 @@ class Pay( PaypalEnvelopeRequest ):
'returnUrl': return_url,
'cancelUrl': cancel_url,
'requestEnvelope': { 'errorLanguage': 'en_US' },
- 'ipnNotificationUrl': settings.BASE_URL + reverse('HandleIPN'),
+ 'ipnNotificationUrl': settings.BASE_URL + reverse('HandleIPN', args=["paypal"]),
'feesPayer': feesPayer,
'trackingId': transaction.secret
}
@@ -536,7 +536,15 @@ class Pay( PaypalEnvelopeRequest ):
return '%s/webapps/adaptivepayment/flow/pay?paykey=%s&expType=light' % ( settings.PAYPAL_PAYMENT_HOST, self.response['payKey'] )
-
+class Execute(Pay):
+ '''
+ For payapl, execute is the same as pay. The pay funciton detects whether an execute or a co-branded operation
+ is called for.
+ '''
+ def __init__(self, transaction, return_url=None, cancel_url=None):
+ # Call our super class. In python 2.2+, we can't use super here, so just call init directly
+ Pay.__init__(self, transaction, return_url, cancel_url)
+
class Finish(PaypalEnvelopeRequest):
def __init__(self, transaction=None):
@@ -817,7 +825,7 @@ class Preapproval( PaypalEnvelopeRequest ):
'returnUrl': return_url,
'cancelUrl': cancel_url,
'requestEnvelope': { 'errorLanguage': 'en_US' },
- 'ipnNotificationUrl': settings.BASE_URL + reverse('HandleIPN')
+ 'ipnNotificationUrl': settings.BASE_URL + reverse('HandleIPN', args=["paypal"])
}
# Is ipnNotificationUrl being computed properly
diff --git a/payment/urls.py b/payment/urls.py
index 82d32ccc..1237773d 100644
--- a/payment/urls.py
+++ b/payment/urls.py
@@ -4,8 +4,7 @@ from django.conf import settings
urlpatterns = patterns(
"regluit.payment.views",
- url(r"^paypalipn", "handleIPN", name="HandleIPN"),
- url(r"^amazonipn", "handleIPN", name="HandleIPN"),
+ url(r"^handleipn/(?P\w+)$", "handleIPN", name="HandleIPN"),
)
# Amazon payment URLs
diff --git a/payment/views.py b/payment/views.py
index 5fe977cf..2a44c9c2 100644
--- a/payment/views.py
+++ b/payment/views.py
@@ -26,7 +26,7 @@ import logging
logger = logging.getLogger(__name__)
# parameterize some test recipients
-TEST_RECEIVERS = ['raymond.yee@gmail.com', 'Buyer6_1325742408_per@gmail.com']
+TEST_RECEIVERS = ['seller_1317463643_biz@gmail.com', 'buyer5_1325740224_per@gmail.com']
#TEST_RECEIVERS = ['seller_1317463643_biz@gmail.com', 'Buyer6_1325742408_per@gmail.com']
#TEST_RECEIVERS = ['glueja_1317336101_biz@gluejar.com', 'rh1_1317336251_biz@gluejar.com', 'RH2_1317336302_biz@gluejar.com']
@@ -248,7 +248,7 @@ def testPledge(request):
receiver_list = [{'email':TEST_RECEIVERS[0], 'amount':pledge_amount}]
else:
receiver_list = [{'email':TEST_RECEIVERS[0], 'amount':78.90}, {'email':TEST_RECEIVERS[1], 'amount':34.56}]
-
+
if campaign_id:
campaign = Campaign.objects.get(id=int(campaign_id))
t, url = p.pledge('USD', TARGET_TYPE_CAMPAIGN, receiver_list, campaign=campaign, list=None, user=user, return_url=None)
@@ -294,11 +294,11 @@ def runTests(request):
traceback.print_exc()
@csrf_exempt
-def handleIPN(request):
+def handleIPN(request, module):
# Handler for paypal IPN notifications
p = PaymentManager()
- p.processIPN(request)
+ p.processIPN(request, module)
logger.info(str(request.POST))
return HttpResponse("ipn")
diff --git a/requirements.pip b/requirements.pip
index bf80d120..c0399a32 100644
--- a/requirements.pip
+++ b/requirements.pip
@@ -20,9 +20,9 @@ django-endless-pagination
django-selectable
pytz
django-notification
-boto
+git+ssh://git@github.com/Gluejar/boto.git@2.3.0
fabric
-git+git://github.com/agiliq/merchant.git#egg=django-merchant
+#git+git://github.com/agiliq/merchant.git#egg=django-merchant
paramiko
pyasn1
pycrypto
diff --git a/settings/dev.py b/settings/dev.py
index 20921ed5..c1056003 100644
--- a/settings/dev.py
+++ b/settings/dev.py
@@ -94,6 +94,8 @@ PAYPAL_NONPROFIT_PARTNER_EMAIL = "nppart_1318957063_per@gluejar.com"
PAYPAL_TEST_RH_EMAIL = "rh1_1317336251_biz@gluejar.com"
BASE_URL = 'http://0.0.0.0'
+BASE_URL_SECURE = 'https://0.0.0.0'
+IPN_SECURE_URL = True
# use database as queuing service in development
BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport"
diff --git a/settings/just.py b/settings/just.py
index e2bb2ac9..359879da 100644
--- a/settings/just.py
+++ b/settings/just.py
@@ -91,6 +91,8 @@ CELERYD_HIJACK_ROOT_LOGGER = False
# BASE_URL is a hard-coding of the domain name for site and used for PayPal IPN
# Next step to try https
BASE_URL = 'http://just.unglueit.com'
+BASE_URL_SECURE = 'https://just.unglueit.com'
+IPN_SECURE_URL = False
# use redis for production queue
BROKER_TRANSPORT = "redis"
diff --git a/settings/please.py b/settings/please.py
index 8f7c667e..54b0b14f 100644
--- a/settings/please.py
+++ b/settings/please.py
@@ -90,6 +90,8 @@ CELERYD_HIJACK_ROOT_LOGGER = False
# BASE_URL is a hard-coding of the domain name for site and used for PayPal IPN
# Next step to try https
BASE_URL = 'http://please.unglueit.com'
+BASE_URL_SECURE = 'https://please.unglueit.com'
+IPN_SECURE_URL = False
# use redis for production queue
BROKER_TRANSPORT = "redis"
diff --git a/settings/prod.py b/settings/prod.py
index b337f670..e9f894c6 100644
--- a/settings/prod.py
+++ b/settings/prod.py
@@ -92,6 +92,8 @@ CELERYD_HIJACK_ROOT_LOGGER = False
# BASE_URL is a hard-coding of the domain name for site and used for PayPal IPN
# Next step to try https
BASE_URL = 'http://unglue.it'
+BASE_URL_SECURE = 'https://unglue.it'
+IPN_SECURE_URL = False
# use redis for production queue
BROKER_TRANSPORT = "redis"
diff --git a/static/js/expand.js b/static/js/expand.js
index 10c39e4d..39bd284c 100644
--- a/static/js/expand.js
+++ b/static/js/expand.js
@@ -8,7 +8,7 @@ $j(document).ready(function(){
$j('#js-topsection').css({"opacity": "0.15"});
$j('#main-container').css({"opacity": "0.15"});
$j('#js-rightcol').css({"visibility":"hidden"});
- $j('#expandable').css({"position": "absolute", "z-index": "100", "left":"50%", "margin-left": "-115px"}).fadeTo("slow", 1);;
+ $j('#expandable').css({"position": "absolute", "z-index": "100", "left":"50%", "margin-left": "-115px"}).fadeTo("slow", 1);
});
$j('#collapser').click(function(){
$j('#js-topsection').fadeTo("slow", 1);
diff --git a/static/js/reconcile_pledge.js b/static/js/reconcile_pledge.js
new file mode 100644
index 00000000..e1df29f3
--- /dev/null
+++ b/static/js/reconcile_pledge.js
@@ -0,0 +1,67 @@
+var $j = jQuery.noConflict();
+// give pledge box focus
+$j(function() {
+ $j('#id_preapproval_amount').focus();
+});
+
+// if amount in pledge box is too small to qualify for premium, call attention to it
+// and disable the input button with a helpful message
+// when they fix it, revert to original styling and reactivate button
+
+$j().ready(function() {
+ // cache these to speed things up
+ var inputbox = $j('#id_preapproval_amount');
+ var submitbutton = $j('#pledgesubmit');
+
+ var canonicalize = function(amt) {
+ // takes an input button from the premiums list
+ // finds the premium amount its associated the span class
+ // converts to usable integer form and returns
+ amt = amt.siblings('span.menu-item-price').html();
+ amt = amt.split('$')[1];
+ amt = parseInt(amt);
+ return amt;
+ }
+
+ var mayday = function() {
+ // highlights pledge box and submit button in alert color
+ // disables submit button and overwrites with help text
+ inputbox.css({'border-color': '#e35351', 'background-color': '#e35351', 'color': 'white'});
+ submitbutton.css({'background-color': '#e35351', 'cursor': 'default', 'font-weight': 'normal', 'font-size': '15px'});
+ submitbutton.val("You must pledge at least $"+amount+" for that premium");
+ submitbutton.attr('disabled', 'disabled');
+ }
+
+ var allclear = function() {
+ // returns pledge box and submit button to conventional colors
+ // enables submit button and rewrites with original text
+ inputbox.css({'border-color': '#8dc63f', 'background-color': 'white', 'color': '#3d4e53'});
+ submitbutton.css({'background-color': '#8dc63f', 'cursor': 'pointer', 'font-weight': 'bold', 'font-size': '17px'});
+ submitbutton.val("Modify Pledge");
+ submitbutton.removeAttr('disabled');
+ }
+
+ $j('#premiums_list input').on("click", function() {
+ // when user clicks a premium, ensure it is compatible with the pledge box amount
+ amount = canonicalize($j(this));
+ current = inputbox.val();
+ if (current