Although you have ${{request.user.credit.available}} in donation credits, you can't support a campaign with a mixture of credit card pledges and donations.{% endif %}
-
-
+
+
-
-
{% endblock %}
-
diff --git a/frontend/views.py b/frontend/views.py
index f7ed48cf..8a107d9a 100755
--- a/frontend/views.py
+++ b/frontend/views.py
@@ -53,7 +53,7 @@ from regluit.payment.manager import PaymentManager
from regluit.payment.models import Transaction, Account
from regluit.payment.parameters import TRANSACTION_STATUS_ACTIVE, TRANSACTION_STATUS_COMPLETE, TRANSACTION_STATUS_CANCELED, TRANSACTION_STATUS_ERROR, TRANSACTION_STATUS_FAILED, TRANSACTION_STATUS_INCOMPLETE, TRANSACTION_STATUS_NONE, TRANSACTION_STATUS_MODIFIED
from regluit.payment.parameters import PAYMENT_TYPE_AUTHORIZATION, PAYMENT_TYPE_INSTANT
-from regluit.payment.parameters import PAYMENT_HOST_STRIPE
+from regluit.payment.parameters import PAYMENT_HOST_STRIPE, PAYMENT_HOST_NONE
from regluit.payment.credit import credit_transaction
from regluit.core import goodreads
from tastypie.models import ApiKey
@@ -627,6 +627,7 @@ class PledgeView(FormView):
return preapproval_amount
def get_form_kwargs(self):
+
assert self.request.user.is_authenticated()
self.work = get_object_or_404(models.Work, id=self.kwargs["work_id"])
@@ -701,7 +702,7 @@ class PledgeView(FormView):
return HttpResponse("No modification made")
else:
t, url = p.process_transaction('USD', form.cleaned_data["preapproval_amount"],
- host = None,
+ host = PAYMENT_HOST_NONE,
campaign=self.campaign,
user=self.request.user,
paymentReason="Unglue.it Pledge for {0}".format(self.campaign.name),
@@ -766,67 +767,43 @@ class FundPledgeView(FormView):
# first pass -- we have a token -- also do more direct coupling to stripelib -- then move to
# abstraction of payment.manager / payment.baseprocessor
- # demonstrate two possibilities: 1) token -> charge or 2) token->customer->charge
+ # we should getting a stripe_token only if we had asked for CC data
+ # BUGBUG -- don't know whether transaction.host should be None -- but if it is, set to the
+ # default processor
+
+ transaction = self.transaction
+ if transaction.host is None or transaction.host == PAYMENT_HOST_NONE:
+ transaction.host = settings.PAYMENT_PROCESSOR
+
stripe_token = form.cleaned_data["stripe_token"]
preapproval_amount = form.cleaned_data["preapproval_amount"]
- retain_cc_info = form.cleaned_data["retain_cc_info"]
-
- sc = stripelib.StripeClient()
- # let's figure out what part of transaction can be used to store info
- # try placing charge id in transaction.pay_key
- # need to set amount
- # how does max_amount get set? -- coming from /pledge/xxx/?
- # max_amount is set -- but I don't think we need it for stripe
-
- if retain_cc_info:
- # create customer and charge id and then charge the customer
- customer = sc.create_customer(card=stripe_token, description=self.request.user.username,
- email=self.request.user.email)
-
- account = Account(host = PAYMENT_HOST_STRIPE,
- account_id = customer.id,
- card_last4 = customer.active_card.last4,
- card_type = customer.active_card.type,
- card_exp_month = customer.active_card.exp_month,
- card_exp_year = customer.active_card.exp_year,
- card_fingerprint = customer.active_card.fingerprint,
- card_country = customer.active_card.country,
- user = self.request.user
- )
+ logger.info('stripe_token:{0}, preapproval_amount:{1}'.format(stripe_token, preapproval_amount))
- account.save()
-
- charge = sc.create_charge(preapproval_amount, customer=customer, description="${0} for test / retain cc".format(preapproval_amount))
-
+ p = PaymentManager()
+
+ # if we get a stripe_token, create a new stripe account
+
+ try:
+ account = p.make_account(transaction.user, stripe_token, host=transaction.host)
+ logger.info('account.id: {0}'.format(account.id))
+ except Exception, e:
+ raise e
+
+ # GOAL: deactivate any older accounts associated with user
+
+ # with the Account in hand, now authorize transaction
+ transaction.amount = preapproval_amount
+ t, url = p.authorize(transaction)
+ logger.info("t, url: {0} {1}".format(t, url))
+
+ # redirecting user to pledge_complete on successful preapproval (in the case of stripe)
+ # BUGBUG: Make sure we are testing properly for successful authorization properly here
+ if url is not None:
+ return HttpResponseRedirect(url)
else:
- customer = None
-
- charge = sc.create_charge(preapproval_amount, card=stripe_token, description="${0} for test / cc not retained".format(preapproval_amount))
-
- # set True for now -- wondering whether we should actually wait for a webhook -- don't think so.
-
- ## settings to apply to transaction for TRANSACTION_STATUS_COMPLETE
- #self.transaction.type = PAYMENT_TYPE_INSTANT
- #self.transaction.approved = True
- #self.transaction.status = TRANSACTION_STATUS_COMPLETE
- #self.transaction.pay_key = charge.id
-
- # settings to apply to transaction for TRANSACTION_STATUS_ACTIVE
- # should approved be set to False and wait for a webhook?
- self.transaction.type = PAYMENT_TYPE_AUTHORIZATION
- self.transaction.approved = True
- self.transaction.status = TRANSACTION_STATUS_ACTIVE
- self.transaction.preapproval_key = charge.id
-
- self.transaction.currency = 'USD'
- self.transaction.amount = preapproval_amount
- self.transaction.date_payment = now()
-
- self.transaction.save()
-
- return HttpResponse("charge id: {0} / customer: {1}".format(charge.id, customer))
+ return HttpResponse("preapproval_key: {0}".format(transaction.preapproval_key))
class NonprofitCampaign(FormView):
diff --git a/payment/baseprocessor.py b/payment/baseprocessor.py
index 138c3ec0..b166a8c5 100644
--- a/payment/baseprocessor.py
+++ b/payment/baseprocessor.py
@@ -1,4 +1,5 @@
-from regluit.payment.models import Transaction, PaymentResponse
+from regluit.payment.models import PaymentResponse
+
from django.http import HttpResponseForbidden
from datetime import timedelta
from regluit.utils.localdatetime import now, zuluformat
@@ -7,11 +8,6 @@ import datetime
import time
-
-def ProcessIPN(request):
- return HttpResponseForbidden()
-
-
class BasePaymentRequest:
'''
Handles common information incident to payment processing
@@ -63,120 +59,131 @@ class BasePaymentRequest:
def timestamp(self):
return str(datetime.datetime.now())
+class Processor:
+ """a function that returns for the given payment processor"""
+ requires_explicit_preapprovals=False
-class Pay( BasePaymentRequest ):
-
- '''
- The pay function generates a redirect URL to approve the transaction
- '''
+ def make_account(self, user, token):
+ """template function for return a payment.Account corresponding to the payment system"""
+ return None
- def __init__( self, transaction, return_url=None, amount=None, paymentReason=""):
- self.transaction=transaction
-
- def api(self):
- return "null api"
-
- def exec_status( self ):
- return None
-
- def amount( self ):
- return None
-
- def key( self ):
- return None
-
- def next_url( self ):
- return self.url
-
-class Preapproval(Pay):
-
- def __init__( self, transaction, amount, expiry=None, return_url=None, paymentReason=""):
-
- # set the expiration date for the preapproval if not passed in. This is what the paypal library does
- now_val = now()
- if expiry is None:
- expiry = now_val + timedelta( days=settings.PREAPPROVAL_PERIOD )
- transaction.date_authorized = now_val
- transaction.date_expired = expiry
- transaction.save()
-
- # Call into our parent class
- Pay.__init__(self, transaction, return_url=return_url, amount=amount, paymentReason=paymentReason)
-
-
-class Execute(BasePaymentRequest):
-
- '''
- The Execute function sends an existing token(generated via the URL from the pay operation), and collects
- the money.
- '''
-
- def __init__(self, transaction=None):
- self.transaction = transaction
-
- def api(self):
- return "Base Pay"
-
- def key(self):
- # IN paypal land, our key is updated from a preapproval to a pay key here, just return the existing key
- return self.transaction.pay_key
-
-
-
-class Finish(BasePaymentRequest):
- '''
- The Finish function handles the secondary receiver in a chained payment.
- '''
- def __init__(self, transaction):
+ def ProcessIPN(self, request):
+ return HttpResponseForbidden()
- print "Finish"
-
-
-class PaymentDetails(BasePaymentRequest):
- '''
- Get details about executed PAY operation
-
- This api must set the following class variables to work with the code in manager.py
-
- status - one of the global transaction status codes
- transactions -- Not supported for amazon, used by paypal
-
- '''
- def __init__(self, transaction=None):
- self.transaction = transaction
+
+ class Pay( BasePaymentRequest ):
+
+ '''
+ The pay function generates a redirect URL to approve the transaction
+ '''
+
+ def __init__( self, transaction, return_url=None, amount=None, paymentReason=""):
+ self.transaction=transaction
-
-
-class CancelPreapproval(BasePaymentRequest):
- '''
- Cancels an exisiting token.
- '''
+ def api(self):
+ return "null api"
+
+ def exec_status( self ):
+ return None
+
+ def amount( self ):
+ return None
+
+ def key( self ):
+ return None
- def __init__(self, transaction):
- self.transaction = transaction
-
-
-class RefundPayment(BasePaymentRequest):
+ def next_url( self ):
+ return self.url
+
+ class Preapproval(Pay):
+
+ def __init__( self, transaction, amount, expiry=None, return_url=None, paymentReason=""):
+
+ # set the expiration date for the preapproval if not passed in. This is what the paypal library does
+ now_val = now()
+ if expiry is None:
+ expiry = now_val + timedelta( days=settings.PREAPPROVAL_PERIOD )
+ transaction.date_authorized = now_val
+ transaction.date_expired = expiry
+ transaction.save()
+
+ # Call into our parent class
+ Pay.__init__(self, transaction, return_url=return_url, amount=amount, paymentReason=paymentReason)
+
+
+ class Execute(BasePaymentRequest):
+
+ '''
+ The Execute function sends an existing token(generated via the URL from the pay operation), and collects
+ the money.
+ '''
+
+ def __init__(self, transaction=None):
+ self.transaction = transaction
+
+ def api(self):
+ return "Base Pay"
+
+ def key(self):
+ # IN paypal land, our key is updated from a preapproval to a pay key here, just return the existing key
+ return self.transaction.pay_key
+
+
- def __init__(self, transaction):
- self.transaction = transaction
+ class Finish(BasePaymentRequest):
+ '''
+ The Finish function handles the secondary receiver in a chained payment.
+ '''
+ def __init__(self, transaction):
-
-
-
-
-class PreapprovalDetails(BasePaymentRequest):
- '''
- Get details about an authorized token
-
- This api must set 4 different class variables to work with the code in manager.py
-
- status - one of the global transaction status codes
- approved - boolean value
- currency - not used in this API, but we can get some more info via other APIs - TODO
- amount - not used in this API, but we can get some more info via other APIs - TODO
-
- '''
- def __init__(self, transaction=None):
- self.transaction = transaction
-
\ No newline at end of file
+ print "Finish"
+
+
+ class PaymentDetails(BasePaymentRequest):
+ '''
+ Get details about executed PAY operation
+
+ This api must set the following class variables to work with the code in manager.py
+
+ status - one of the global transaction status codes
+ transactions -- Not supported for amazon, used by paypal
+
+ '''
+ def __init__(self, transaction=None):
+ self.transaction = transaction
+
+
+
+ class CancelPreapproval(BasePaymentRequest):
+ '''
+ Cancels an exisiting token.
+ '''
+
+ def __init__(self, transaction):
+ self.transaction = transaction
+
+
+ class RefundPayment(BasePaymentRequest):
+
+ def __init__(self, transaction):
+ self.transaction = transaction
+
+
+
+
+
+ class PreapprovalDetails(BasePaymentRequest):
+ '''
+ Get details about an authorized token
+
+ This api must set 4 different class variables to work with the code in manager.py
+
+ status - one of the global transaction status codes
+ approved - boolean value
+ currency - not used in this API, but we can get some more info via other APIs - TODO
+ amount - not used in this API, but we can get some more info via other APIs - TODO
+
+ '''
+ def __init__(self, transaction=None):
+ self.transaction = transaction
+
\ No newline at end of file
diff --git a/payment/credit.py b/payment/credit.py
index 4976089d..c6cf52ec 100644
--- a/payment/credit.py
+++ b/payment/credit.py
@@ -4,6 +4,7 @@ from django.contrib.auth.models import User
from django.conf import settings
from regluit.payment.parameters import *
+from regluit.payment import baseprocessor
from regluit.payment.baseprocessor import BasePaymentRequest
@@ -28,28 +29,29 @@ def credit_transaction(t,user,amount):
user.credit.add_to_pledged(pledge_amount)
t.set_credit_approved(pledge_amount)
-class CancelPreapproval(BasePaymentRequest):
- '''
- Cancels an exisiting token.
- '''
+class Processor(baseprocessor.Processor):
+ class CancelPreapproval(BasePaymentRequest):
+ '''
+ Cancels an exisiting token.
+ '''
+
+ def __init__(self, transaction):
+ self.transaction = transaction
+ if transaction.user.credit.add_to_pledged(-transaction.amount):
+ #success
+ transaction.status=TRANSACTION_STATUS_CANCELED
+ transaction.save()
+ else:
+ self.errorMessage="couldn't cancel the transaction"
+ self.status = 'Credit Cancel Failure'
- def __init__(self, transaction):
- self.transaction = transaction
- if transaction.user.credit.add_to_pledged(-transaction.amount):
- #success
- transaction.status=TRANSACTION_STATUS_CANCELED
- transaction.save()
- else:
- self.errorMessage="couldn't cancel the transaction"
- self.status = 'Credit Cancel Failure'
-
-class PreapprovalDetails(BasePaymentRequest):
- status = None
- approved = None
- currency = None
- amount = None
- def __init__(self, transaction):
- self.status = transaction.status
- self.approved = transaction.approved
- self.currency = transaction.currency
- self.amount = transaction.amount
+ class PreapprovalDetails(BasePaymentRequest):
+ status = None
+ approved = None
+ currency = None
+ amount = None
+ def __init__(self, transaction):
+ self.status = transaction.status
+ self.approved = transaction.approved
+ self.currency = transaction.currency
+ self.amount = transaction.amount
diff --git a/payment/forms.py b/payment/forms.py
index db65a947..764eb7e0 100644
--- a/payment/forms.py
+++ b/payment/forms.py
@@ -4,4 +4,4 @@ import logging
logger = logging.getLogger(__name__)
class StripePledgeForm(forms.Form):
- stripe_token = forms.CharField(required=False, widget=forms.HiddenInput())
+ stripeToken = forms.CharField(required=False, widget=forms.HiddenInput())
diff --git a/payment/management/commands/test_stripe_charge.py b/payment/management/commands/test_stripe_charge.py
new file mode 100644
index 00000000..24bf035e
--- /dev/null
+++ b/payment/management/commands/test_stripe_charge.py
@@ -0,0 +1,16 @@
+from django.core.management.base import BaseCommand
+from regluit.payment import stripelib
+from decimal import Decimal as D
+
+class Command(BaseCommand):
+ help = "create a credit card record and charge it -- for testing"
+
+ def handle(self, *args, **kwargs):
+ # test card
+ sc = stripelib.StripeClient()
+ card = stripelib.card(number="4242424242424242", exp_month="01", exp_year="2013", cvc="123")
+ cust = sc.create_customer(card=card, description="William Shakespeare XIV (via test_stripe_charge)", email="bill.shakespeare@gmail.com")
+ print cust
+ # let's charge RY $1.00
+ charge = sc.create_charge(D('1.00'), customer=cust.id, description="$1 TEST CHARGE for Will S. XIV")
+ print charge
\ No newline at end of file
diff --git a/payment/manager.py b/payment/manager.py
index 64389779..7eadc79e 100644
--- a/payment/manager.py
+++ b/payment/manager.py
@@ -1,4 +1,3 @@
-from regluit.core.models import Campaign, Wishlist
from regluit.payment.models import Transaction, Receiver, PaymentResponse
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
@@ -7,8 +6,6 @@ from regluit.payment.parameters import *
from regluit.payment.signals import transaction_charged, pledge_modified, pledge_created
from regluit.payment import credit
-from regluit.payment.baseprocessor import Pay, Finish, Preapproval, ProcessIPN, CancelPreapproval, PaymentDetails, PreapprovalDetails, RefundPayment
-
import uuid
import traceback
from regluit.utils.localdatetime import now
@@ -40,14 +37,12 @@ class PaymentManager( object ):
# Forward to our payment processor
mod = __import__("regluit.payment." + module, fromlist=[str(module)])
- method = getattr(mod, "ProcessIPN")
- return method(request)
+ return mod.Processor().ProcessIPN(request)
def update_preapproval(self, transaction):
"""Update a transaction to hold the data from a PreapprovalDetails on that transaction"""
t = transaction
- method = getattr(transaction.get_payment_class(), "PreapprovalDetails")
- p = method(t)
+ p = transaction.get_payment_class().PreapprovalDetails(t)
preapproval_status = {'id':t.id, 'key':t.preapproval_key}
@@ -99,8 +94,7 @@ class PaymentManager( object ):
t = transaction
payment_status = {'id':t.id}
- method = getattr(transaction.get_payment_class(), "PaymentDetails")
- p = method(t)
+ p = transaction.get_payment_class().PaymentDetails(t)
if p.error() or not p.success():
logger.info("Error retrieving payment details for transaction %d" % t.id)
@@ -414,8 +408,7 @@ class PaymentManager( object ):
transaction.date_executed = now()
transaction.save()
- method = getattr(transaction.get_payment_class(), "Finish")
- p = method(transaction)
+ p = transaction.get_payment_class().Finish(transaction)
# Create a response for this
envelope = p.envelope()
@@ -469,8 +462,7 @@ class PaymentManager( object ):
transaction.date_payment = now()
transaction.save()
- method = getattr(transaction.get_payment_class(), "Execute")
- p = method(transaction)
+ p = transaction.get_payment_class().Execute(transaction)
# Create a response for this
envelope = p.envelope()
@@ -509,32 +501,43 @@ class PaymentManager( object ):
return value: True if successful, false otherwise
'''
- method = getattr(transaction.get_payment_class(), "CancelPreapproval")
- p = method(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("Cancel Transaction " + str(transaction.id) + " Completed")
- return True
+ # does this transaction explicity require preapprovals?
+ requires_explicit_preapprovals = transaction.get_payment_class().requires_explicit_preapprovals
+ if requires_explicit_preapprovals:
+
+ p = transaction.get_payment_class().CancelPreapproval(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("Cancel Transaction " + str(transaction.id) + " Completed")
+ return True
+
+ else:
+ transaction.error = p.error_string()
+ transaction.save()
+ logger.info("Cancel Transaction " + str(transaction.id) + " Failed with error: " + p.error_string())
+ return False
+
else:
- transaction.error = p.error_string()
+
+ # if no explicit preapproval required, we just have to mark the transaction as cancelled.
+ transaction.status = TRANSACTION_STATUS_CANCELED
transaction.save()
- logger.info("Cancel Transaction " + str(transaction.id) + " Failed with error: " + p.error_string())
- return False
+ return True
def authorize(self, transaction, expiry= None, return_url=None, paymentReason="unglue.it Pledge", modification=False):
'''
@@ -551,9 +554,9 @@ class PaymentManager( object ):
'''
- if host==None:
- #TODO send user to select a payment processor
- pass
+ if transaction.host == PAYMENT_HOST_NONE:
+ #TODO send user to select a payment processor -- for now, set to a system setting
+ transaction.host = settings.PAYMENT_PROCESSOR
# we might want to not allow for a return_url to be passed in but calculated
# here because we have immediate access to the Transaction object.
@@ -561,11 +564,10 @@ class PaymentManager( object ):
if return_url is None:
return_path = "{0}?{1}".format(reverse('pledge_complete'),
- urllib.urlencode({'tid':t.id}))
+ urllib.urlencode({'tid':transaction.id}))
return_url = urlparse.urljoin(settings.BASE_URL, return_path)
- method = getattr(t.get_payment_class(), "Preapproval")
- p = method(transaction, transaction.max_amount, expiry, return_url=return_url, paymentReason=paymentReason)
+ p = transaction.get_payment_class().Preapproval(transaction, transaction.amount, expiry, return_url=return_url, paymentReason=paymentReason)
# Create a response for this
envelope = p.envelope()
@@ -581,9 +583,15 @@ class PaymentManager( object ):
transaction.preapproval_key = p.key()
transaction.save()
+ # it make sense for the payment processor library to calculate next_url when
+ # user is redirected there. But if no redirection is required, send user
+ # straight on to the return_url
url = p.next_url()
+
+ if url is None:
+ url = return_url
- logger.info("Authorize Success: " + url)
+ logger.info("Authorize Success: " + url if url is not None else '')
# modification and initial pledge use different notification templates --
# decide which to send
@@ -610,7 +618,7 @@ class PaymentManager( object ):
logger.info("Authorize Error: " + p.error_string())
return transaction, None
- def process_transaction(self, currency, amount, host=None, campaign=None, user=None,
+ def process_transaction(self, currency, amount, host=PAYMENT_HOST_NONE, campaign=None, user=None,
return_url=None, paymentReason="unglue.it Pledge", pledge_extra=None,
modification=False):
'''
@@ -634,7 +642,8 @@ class PaymentManager( object ):
# set the expiry date based on the campaign deadline
expiry = campaign.deadline + timedelta( days=settings.PREAPPROVAL_PERIOD_AFTER_CAMPAIGN )
- t = Transaction.create(amount=0,
+ t = Transaction.create(amount=0,
+ host = host,
max_amount=amount,
currency=currency,
campaign=campaign,
@@ -718,6 +727,16 @@ class PaymentManager( object ):
return value: True if successful, False otherwise. An optional second parameter for the forward URL if a new authorhization is needed
'''
+ logger.info("transaction.id: {0}, amount:{1}".format(transaction.id, amount))
+
+ # if expiry is None, use the existing value
+ if expiry is None:
+ expiry = transaction.date_expired
+
+ # does this transaction explicity require preapprovals?
+
+ requires_explicit_preapprovals = transaction.get_payment_class().requires_explicit_preapprovals
+
if transaction.type != PAYMENT_TYPE_AUTHORIZATION:
logger.info("Error, attempt to modify an invalid transaction type")
return False, None
@@ -757,7 +776,7 @@ class PaymentManager( object ):
credit.CancelPreapproval(transaction)
return t, reverse('fund_pledge', args=[t.id])
- elif amount > transaction.max_amount or expiry != transaction.date_expired:
+ elif requires_explicit_preapprovals and (amount > transaction.max_amount or expiry != transaction.date_expired):
# set the expiry date based on the campaign deadline
expiry = transaction.campaign.deadline + timedelta( days=settings.PREAPPROVAL_PERIOD_AFTER_CAMPAIGN )
@@ -800,7 +819,7 @@ class PaymentManager( object ):
# corresponding notification to the user? that would go here.
return False, None
- elif amount <= transaction.max_amount:
+ elif (requires_explicit_preapprovals and amount <= transaction.max_amount) or (not requires_explicit_preapprovals):
# Update transaction but leave the preapproval alone
transaction.amount = amount
transaction.set_pledge_extra(pledge_extra)
@@ -833,8 +852,7 @@ class PaymentManager( object ):
logger.info("Refund Transaction failed, invalid transaction status")
return False
- method = getattr(transaction.get_payment_class(), "RefundPayment")
- p = method(transaction)
+ p = transaction.get_payment_class().RefundPayment(transaction)
# Create a response for this
envelope = p.envelope()
@@ -892,8 +910,7 @@ class PaymentManager( object ):
t.date_payment=now()
t.execution=EXECUTE_TYPE_CHAINED_INSTANT
t.type=PAYMENT_TYPE_INSTANT
- method = getattr(t.get_payment_class(), "Pay")
- p = method(t,return_url=return_url, nevermind_url=nevermind_url)
+ p = t.get_payment_class().Pay(t,return_url=return_url, nevermind_url=nevermind_url)
# Create a response for this
envelope = p.envelope()
@@ -921,5 +938,13 @@ class PaymentManager( object ):
t.save()
logger.info("Pledge Error: %s" % p.error_string())
return t, None
+
+ def make_account(self, user, token, host):
+
+ """delegate to a specific payment module the task of creating a payment account"""
+ mod = __import__("regluit.payment." + host, fromlist=[host])
+ return mod.Processor().make_account(user, token)
+
+
diff --git a/payment/models.py b/payment/models.py
index 1f5d5a6e..e8310e37 100644
--- a/payment/models.py
+++ b/payment/models.py
@@ -1,7 +1,7 @@
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
-from regluit.core.models import Campaign, Wishlist, Premium, PledgeExtra
+
from regluit.payment.parameters import *
from regluit.payment.signals import credit_balance_added, pledge_created
from regluit.utils.localdatetime import now
@@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
# c.card.fingerprint, c.card.type, c.card.last4, c.card.exp_month, c.card.exp_year
# promising fields
-
+
class Transaction(models.Model):
# type e.g., PAYMENT_TYPE_INSTANT or PAYMENT_TYPE_AUTHORIZATION -- defined in parameters.py
@@ -78,8 +78,8 @@ class Transaction(models.Model):
# associated User, Campaign, and Premium for this Transaction
user = models.ForeignKey(User, null=True)
- campaign = models.ForeignKey(Campaign, null=True)
- premium = models.ForeignKey(Premium, null=True)
+ campaign = models.ForeignKey('core.Campaign', null=True)
+ premium = models.ForeignKey('core.Premium', null=True)
# how to acknowledge the user on the supporter page of the campaign ebook
ack_name = models.CharField(max_length=64, null=True)
@@ -109,13 +109,13 @@ class Transaction(models.Model):
def get_payment_class(self):
'''
- Returns the specific payment module that implements this transaction
+ Returns the specific payment processor 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
+ return mod.Processor()
def set_credit_approved(self, amount):
self.amount=amount
@@ -137,10 +137,12 @@ class Transaction(models.Model):
self.ack_dedication = pledge_extra.ack_dedication
def get_pledge_extra(self, pledge_extra):
- return PledgeExtra(anonymous=self.anonymous,
- premium=self.premium,
- ack_name=self.ack_name,
- ack_dedication=self.ack_dedication)
+ class pe:
+ premium=self.premium
+ anonymous=self.anonymous
+ ack_name=self.ack_name
+ ack_dedication=self.ack_dedication
+ return pe
@classmethod
def create(cls,amount=0.00, host=PAYMENT_HOST_NONE, max_amount=0.00, currency='USD',
diff --git a/payment/parameters.py b/payment/parameters.py
index 0d408751..027bb7f6 100644
--- a/payment/parameters.py
+++ b/payment/parameters.py
@@ -5,7 +5,7 @@ PAYMENT_TYPE_AUTHORIZATION = 2
PAYMENT_HOST_NONE = "none"
PAYMENT_HOST_PAYPAL = "paypal"
PAYMENT_HOST_AMAZON = "amazon"
-PAYMENT_HOST_STRIPE = "stripe"
+PAYMENT_HOST_STRIPE = "stripelib"
PAYMENT_HOST_TEST = "test"
PAYMENT_HOST_CREDIT = "credit"
diff --git a/payment/stripelib.py b/payment/stripelib.py
index 8e6fa9f0..87050e7a 100644
--- a/payment/stripelib.py
+++ b/payment/stripelib.py
@@ -1,11 +1,25 @@
# https://github.com/stripe/stripe-python
# https://stripe.com/docs/api?lang=python#top
-from datetime import datetime
+import logging
+from datetime import datetime, timedelta
from pytz import utc
+from django.conf import settings
+
+from regluit.payment.models import Account
+from regluit.payment.parameters import PAYMENT_HOST_STRIPE
+from regluit.payment.parameters import TRANSACTION_STATUS_ACTIVE, TRANSACTION_STATUS_COMPLETE, PAYMENT_TYPE_AUTHORIZATION, TRANSACTION_STATUS_CANCELED
+from regluit.payment import baseprocessor
+from regluit.utils.localdatetime import now, zuluformat
+
import stripe
+logger = logging.getLogger(__name__)
+
+class StripeError(Exception):
+ pass
+
try:
import unittest
from unittest import TestCase
@@ -25,15 +39,11 @@ try:
from regluit.core.models import Key
STRIPE_PK = Key.objects.get(name="STRIPE_PK").value
STRIPE_SK = Key.objects.get(name="STRIPE_SK").value
- STRIPE_PARTNER_PK = Key.objects.get(name="STRIPE_PARTNER_PK").value
- STRIPE_PARTNER_SK = Key.objects.get(name="STRIPE_PARTNER_SK").value
logger.info('Successful loading of STRIPE_*_KEYs')
except Exception, e:
# currently test keys for Gluejar and for raymond.yee@gmail.com as standin for non-profit
STRIPE_PK = 'pk_0EajXPn195ZdF7Gt7pCxsqRhNN5BF'
STRIPE_SK = 'sk_0EajIO4Dnh646KPIgLWGcO10f9qnH'
- STRIPE_PARTNER_PK ='pk_0AnIkNu4WRiJYzxMKgruiUwxzXP2T'
- STRIPE_PARTNER_SK = 'sk_0AnIvBrnrJoFpfD3YmQBVZuTUAbjs'
# set default stripe api_key to that of unglue.it
@@ -149,14 +159,14 @@ class StripeClient(object):
def create_charge(self, amount, currency="usd", customer=None, card=None, description=None ):
# https://stripe.com/docs/api?lang=python#create_charge
- # customer or card required but not both
+ # customer.id or card required but not both
# charge the Customer instead of the card
# amount in cents
charge = stripe.Charge(api_key=self.api_key).create(
amount=int(100*amount), # in cents
currency=currency,
- customer=customer.id if customer is not None else None,
+ customer=customer,
card=card,
description=description
)
@@ -217,7 +227,7 @@ class PledgeScenarioTest(TestCase):
cls._cust_bad_card = cls._sc.create_customer(card=card1, description="test bad customer", email="rdhyee@gluejar.com")
def test_charge_good_cust(self):
- charge = self._sc.create_charge(10, customer=self._good_cust, description="$10 for good cust")
+ charge = self._sc.create_charge(10, customer=self._good_cust.id, description="$10 for good cust")
self.assertEqual(type(charge.id), str)
# print out all the pieces of Customer and Charge objects
@@ -232,7 +242,7 @@ class PledgeScenarioTest(TestCase):
def test_charge_bad_cust(self):
# expect the card to be declined -- and for us to get CardError
self.assertRaises(stripe.CardError, self._sc.create_charge, 10,
- customer = self._cust_bad_card, description="$10 for bad cust")
+ customer = self._cust_bad_card.id, description="$10 for bad cust")
@classmethod
@@ -251,6 +261,158 @@ class PledgeScenarioTest(TestCase):
print "list of events", cls._sc.event.all()
print [(i, e.id, e.type, e.created, e.pending_webhooks, e.data) for (i,e) in enumerate(cls._sc.event.all()['data'])]
+class StripePaymentRequest(baseprocessor.BasePaymentRequest):
+ """so far there is no need to have a separate class here"""
+ pass
+
+class Processor(baseprocessor.Processor):
+
+ def make_account(self, user, token):
+ """returns a payment.models.Account based on stripe token and user"""
+
+ sc = StripeClient()
+
+ # create customer and charge id and then charge the customer
+ customer = sc.create_customer(card=token, description=user.username,
+ email=user.email)
+
+ account = Account(host = PAYMENT_HOST_STRIPE,
+ account_id = customer.id,
+ card_last4 = customer.active_card.last4,
+ card_type = customer.active_card.type,
+ card_exp_month = customer.active_card.exp_month,
+ card_exp_year = customer.active_card.exp_year,
+ card_fingerprint = customer.active_card.fingerprint,
+ card_country = customer.active_card.country,
+ user = user
+ )
+
+ account.save()
+
+ return account
+
+ class Pay(StripePaymentRequest, baseprocessor.Processor.Pay):
+ pass
+
+ class Preapproval(StripePaymentRequest, baseprocessor.Processor.Preapproval):
+
+ def __init__( self, transaction, amount, expiry=None, return_url=None, paymentReason=""):
+
+ # set the expiration date for the preapproval if not passed in. This is what the paypal library does
+
+ self.transaction = transaction
+
+ now_val = now()
+ if expiry is None:
+ expiry = now_val + timedelta( days=settings.PREAPPROVAL_PERIOD )
+ transaction.date_authorized = now_val
+ transaction.date_expired = expiry
+
+ sc = StripeClient()
+
+ # let's figure out what part of transaction can be used to store info
+ # try placing charge id in transaction.pay_key
+ # need to set amount
+ # how does transaction.max_amount get set? -- coming from /pledge/xxx/ -> manager.process_transaction
+ # max_amount is set -- but I don't think we need it for stripe
+
+ # ASSUMPTION: a user has any given moment one and only one active payment Account
+
+ if transaction.user.account_set.filter(date_deactivated__isnull=True).count() > 1:
+ logger.warning("user {0} has more than one active payment account".format(transaction.user))
+ elif transaction.user.account_set.filter(date_deactivated__isnull=True).count() == 0:
+ logger.warning("user {0} has no active payment account".format(transaction.user))
+ raise StripeError("user {0} has no active payment account".format(transaction.user))
+
+ account = transaction.user.account_set.filter(date_deactivated__isnull=True)[0]
+ logger.info("user: {0} customer.id is {1}".format(transaction.user, account.account_id))
+
+ # settings to apply to transaction for TRANSACTION_STATUS_ACTIVE
+ # should approved be set to False and wait for a webhook?
+ transaction.approved = True
+ transaction.type = PAYMENT_TYPE_AUTHORIZATION
+ transaction.host = PAYMENT_HOST_STRIPE
+ transaction.status = TRANSACTION_STATUS_ACTIVE
+
+ transaction.preapproval_key = account.account_id
+
+ transaction.currency = 'USD'
+ transaction.amount = amount
+
+ transaction.save()
+
+ def key(self):
+ return self.transaction.preapproval_key
+
+ def next_url(self):
+ """return None because no redirection to stripe is required"""
+ return None
+
+
+ class Execute(StripePaymentRequest):
+
+ '''
+ The Execute function sends an existing token(generated via the URL from the pay operation), and collects
+ the money.
+ '''
+
+ def __init__(self, transaction=None):
+ self.transaction = transaction
+
+ # execute transaction
+ assert transaction.host == PAYMENT_HOST_STRIPE
+
+ sc = StripeClient()
+
+ # look at transaction.preapproval_key
+ # is it a customer or a token?
+
+ # BUGBUG: replace description with somethin more useful
+ if transaction.preapproval_key.startswith('cus_'):
+ charge = sc.create_charge(transaction.amount, customer=transaction.preapproval_key, description="${0} for test / retain cc".format(transaction.amount))
+ elif transaction.preapproval_key.startswith('tok_'):
+ charge = sc.create_charge(transaction.amount, card=transaction.preapproval_key, description="${0} for test / cc not retained".format(transaction.amount))
+
+ transaction.status = TRANSACTION_STATUS_COMPLETE
+ transaction.pay_key = charge.id
+ transaction.date_payment = now()
+ transaction.save()
+
+ self.charge = charge
+
+ def api(self):
+ return "Base Pay"
+
+ def key(self):
+ # IN paypal land, our key is updated from a preapproval to a pay key here, just return the existing key
+ return self.transaction.pay_key
+
+
+ class PreapprovalDetails(StripePaymentRequest):
+ '''
+ Get details about an authorized token
+
+ This api must set 4 different class variables to work with the code in manager.py
+
+ status - one of the global transaction status codes
+ approved - boolean value
+ currency - not used in this API, but we can get some more info via other APIs - TODO
+ amount - not used in this API, but we can get some more info via other APIs - TODO
+
+ '''
+ def __init__(self, transaction):
+
+ self.transaction = transaction
+ self.status = self.transaction.status
+ if self.status == TRANSACTION_STATUS_CANCELED:
+ self.approved = False
+ else:
+ self.approved = True
+
+ # Set the other fields that are expected. We don't have values for these now, so just copy the transaction
+ self.currency = transaction.currency
+ self.amount = transaction.amount
+
def suite():
testcases = [PledgeScenarioTest]
diff --git a/payment/templates/stripe.html b/payment/templates/stripe.html
index 83e7962f..488a7585 100644
--- a/payment/templates/stripe.html
+++ b/payment/templates/stripe.html
@@ -6,33 +6,80 @@
{% block extra_extra_head %}
-
-
+
+
-{% endblock %}
-
-{% block doccontent %}
-Stripe Test!:
-
-
-
+
+{% endblock %}
+
+{% block doccontent %}
+Stripe Test:
+
+
+
{% endblock %}
diff --git a/payment/views.py b/payment/views.py
index c0950859..35397d07 100644
--- a/payment/views.py
+++ b/payment/views.py
@@ -3,7 +3,6 @@ from regluit.payment.models import Transaction
from regluit.core.models import Campaign, Wishlist
from regluit.payment.stripelib import STRIPE_PK
-
from regluit.payment.forms import StripePledgeForm
from django.conf import settings
@@ -21,8 +20,7 @@ from django.views.generic.edit import FormView
from django.views.generic.base import TemplateView
from unittest import TestResult
-
-
+from regluit.payment.tests import PledgeTest, AuthorizeTest
import uuid
from decimal import Decimal as D
@@ -121,8 +119,12 @@ def testAuthorize(request):
receiver_list = [{'email': TEST_RECEIVERS[0], 'amount':20.00},
{'email': TEST_RECEIVERS[1], 'amount':10.00}]
- campaign = Campaign.objects.get(id=int(campaign_id))
- t, url = p.authorize(Transaction.objects.create(currency='USD', max_amount=amount, campaign=campaign, user=None), return_url=None)
+ if campaign_id:
+ campaign = Campaign.objects.get(id=int(campaign_id))
+ t, url = p.authorize('USD', TARGET_TYPE_CAMPAIGN, amount, campaign=campaign, return_url=None, list=None, user=None)
+
+ else:
+ t, url = p.authorize('USD', TARGET_TYPE_NONE, amount, campaign=None, return_url=None, list=None, user=None)
if url:
logger.info("testAuthorize: " + url)
@@ -253,9 +255,12 @@ def testPledge(request):
else:
receiver_list = [{'email':TEST_RECEIVERS[0], 'amount':78.90}, {'email':TEST_RECEIVERS[1], 'amount':34.56}]
- campaign = Campaign.objects.get(id=int(campaign_id))
- t, url = p.pledge('USD', receiver_list, campaign=campaign, list=None, user=user, return_url=None)
+ 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)
+ else:
+ t, url = p.pledge('USD', TARGET_TYPE_NONE, receiver_list, campaign=None, list=None, user=user, return_url=None)
if url:
logger.info("testPledge: " + url)
@@ -266,6 +271,33 @@ def testPledge(request):
logger.info("testPledge: Error " + str(t.error))
return HttpResponse(response)
+def runTests(request):
+
+ try:
+ # Setup the test environement. We need to run these tests on a live server
+ # so our code can receive IPN notifications from paypal
+ setup_test_environment()
+ result = TestResult()
+
+ # Run the authorize test
+ test = AuthorizeTest('test_authorize')
+ test.run(result)
+
+ # Run the pledge test
+ test = PledgeTest('test_pledge_single_receiver')
+ test.run(result)
+
+ # Run the pledge failure test
+ test = PledgeTest('test_pledge_too_much')
+ test.run(result)
+
+ output = "Tests Run: " + str(result.testsRun) + str(result.errors) + str(result.failures)
+ logger.info(output)
+
+ return HttpResponse(output)
+
+ except:
+ traceback.print_exc()
@csrf_exempt
def handleIPN(request, module):
@@ -278,6 +310,11 @@ def handleIPN(request, module):
return HttpResponse("ipn")
+def paymentcomplete(request):
+ # pick up all get and post parameters and display
+ output = "payment complete"
+ output += request.method + "\n" + str(request.REQUEST.items())
+ return HttpResponse(output)
def checkStatus(request):
# Check the status of all PAY transactions and flag any errors
@@ -305,11 +342,7 @@ class StripeView(FormView):
return context
def form_valid(self, form):
- stripe_token = form.cleaned_data["stripe_token"]
+ stripeToken = form.cleaned_data["stripeToken"]
# e.g., tok_0C0k4jG5B2Oxox
#
- return HttpResponse("stripe_token: {0}".format(stripe_token))
-
-
-
-
+ return HttpResponse("stripeToken: {0}".format(stripeToken))
diff --git a/requirements_versioned.pip b/requirements_versioned.pip
index c4e36f49..84e806f1 100644
--- a/requirements_versioned.pip
+++ b/requirements_versioned.pip
@@ -46,6 +46,7 @@ requests==0.14.0
selenium==2.25.0
six==1.2.0
ssh==1.7.14
+stevedore==0.4
stripe==1.7.4
virtualenv==1.4.9
virtualenvwrapper==3.6
diff --git a/settings/common.py b/settings/common.py
index 6504d44f..b0820fc9 100644
--- a/settings/common.py
+++ b/settings/common.py
@@ -278,7 +278,7 @@ EBOOK_NOTIFICATIONS_JOB = {
# by default, in common, we don't turn any of the celerybeat jobs on -- turn them on in the local settings file
# amazon or paypal for now.
-PAYMENT_PROCESSOR = 'test'
+PAYMENT_PROCESSOR = 'stripelib'
# a SECRET_KEY to be used for encrypting values in core.models.Key -- you should store in settings/local.py
SECRET_KEY = ''
diff --git a/test/campaign_starter.sql b/test/campaign_starter.sql
index c0b7e342..0895b54a 100644
--- a/test/campaign_starter.sql
+++ b/test/campaign_starter.sql
@@ -582,6 +582,19 @@ INSERT INTO `core_identifier` VALUES (1,'goog','wtPxGztYx-UC',1,1),(2,'isbn','97
/*!40000 ALTER TABLE `core_identifier` ENABLE KEYS */;
UNLOCK TABLES;
+--
+-- Create empty core_key
+--
+DROP TABLE IF EXISTS `core_key`;
+CREATE TABLE `core_key` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` varchar(255) NOT NULL,
+ `encrypted_value` longtext,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `core_key_name_2fdc7c2d_uniq` (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
--
-- Table structure for table `core_premium`
--
diff --git a/test/campaigntest.py b/test/campaigntest.py
index 7418602f..48b04290 100644
--- a/test/campaigntest.py
+++ b/test/campaigntest.py
@@ -1,7 +1,6 @@
from regluit.core import models
from regluit.payment.models import Transaction, PaymentResponse, Receiver
from regluit.payment.manager import PaymentManager
-from regluit.payment.paypal import IPN_PREAPPROVAL_STATUS_ACTIVE, IPN_PAY_STATUS_INCOMPLETE, IPN_PAY_STATUS_COMPLETED
import django
from django.conf import settings
@@ -14,9 +13,6 @@ import unittest, time, re
import logging
import os
-# PayPal developer sandbox
-from regluit.payment.tests import loginSandbox, paySandbox, payAmazonSandbox
-
def setup_selenium():
# Set the display window for our xvfb
os.environ['DISPLAY'] = ':99'
@@ -154,15 +150,9 @@ def recipient_status(clist):
# res = [pm.finish_campaign(c) for c in campaigns_incomplete()]
-
-def support_campaign(unglue_it_url = settings.LIVE_SERVER_TEST_URL, do_local=True, backend='amazon', browser='firefox'):
- """
- programatically fire up selenium to make a Pledge
- do_local should be True only if you are running support_campaign on db tied to LIVE_SERVER_TEST_URL
- """
-
+def test_relaunch(unglue_it_url = settings.LIVE_SERVER_TEST_URL, do_local=True, backend='amazon', browser='chrome'):
django.db.transaction.enter_transaction_management()
-
+
UNGLUE_IT_URL = unglue_it_url
USER = settings.UNGLUEIT_TEST_USER
PASSWORD = settings.UNGLUEIT_TEST_PASSWORD
@@ -179,17 +169,12 @@ def support_campaign(unglue_it_url = settings.LIVE_SERVER_TEST_URL, do_local=Tru
else:
sel = webdriver.Firefox()
- time.sleep(10)
+ time.sleep(5)
- # find a campaign to pledge to
- if backend == 'paypal':
- loginSandbox(sel)
- time.sleep(2)
-
print "now opening unglue.it"
#sel.get("http://www.google.com")
- sel.get(UNGLUE_IT_URL)
+ sel.get(UNGLUE_IT_URL)
# long wait because sel is slow after PayPal
sign_in_link = WebDriverWait(sel, 100).until(lambda d : d.find_element_by_xpath("//span[contains(text(),'Sign In')]/.."))
@@ -199,7 +184,7 @@ def support_campaign(unglue_it_url = settings.LIVE_SERVER_TEST_URL, do_local=Tru
input_username = WebDriverWait(sel,20).until(lambda d : d.find_element_by_css_selector("input#id_username"))
input_username.send_keys(USER)
sel.find_element_by_css_selector("input#id_password").send_keys(PASSWORD)
- sel.find_element_by_css_selector("input[value*='sign in']").click()
+ sel.find_element_by_css_selector("input[value*='sign in']").click()
# click on biggest campaign list
# I have no idea why selenium thinks a is not displayed....so that's why I'm going up one element.
@@ -225,62 +210,49 @@ def support_campaign(unglue_it_url = settings.LIVE_SERVER_TEST_URL, do_local=Tru
print "yes: Error in just hitting pledge button as expected"
else:
print "ooops: there should be an error message when pledge button hit"
-
- # fill out a premium -- the first one for now
- premium_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector('input[type="radio"][value="1"]'))
- premium_button.click()
print "making $10 pledge"
# now we have to replace the current preapproval amount with 10
sel.execute_script("""document.getElementById("id_preapproval_amount").value="10";""")
- # must also pick a premium level -- otherwise there will not be a pledge_button -- let's pick the first premium ($1)
- premium_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector('input[type="radio"][value="1"]'))
- premium_button.click()
+ radio_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='150']"))
+ radio_button.click()
- pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Pledge']"))
- pledge_button.click()
+ support_button = WebDriverWait(sel,10).until(lambda d: d.find_element_by_css_selector("input[value*='Pledge Now']"))
+ support_button.click()
- # grab the URL where sel is now?
-
- if backend == 'paypal':
- print "Now trying to pay PayPal", sel.current_url
- paySandbox(None, sel, sel.current_url, authorize=True, already_at_url=True, sleep_time=5)
- elif backend == 'amazon':
- payAmazonSandbox(sel)
+ # now fill out the credit card
+ sel.execute_script("""document.getElementById("card_Number").value="4242424242424242";""")
+ sel.execute_script("""document.getElementById("card_ExpiryMonth").value="01";""")
+ sel.execute_script("""document.getElementById("card_ExpiryYear").value="14";""")
+ sel.execute_script("""document.getElementById("card_CVC").value="123";""")
+
+ verify_cc_button = WebDriverWait(sel,10).until(lambda d: d.find_element_by_css_selector("input[value*='Verify Credit Card']"))
+ verify_cc_button.click()
+
+ # verify that we are at pledge_complete
+ # sleep a bit to give enough time for redirecto pledge_complete to finish
+
+ time.sleep(3)
+
# should be back on a pledge complete page
print sel.current_url, re.search(r"/pledge/complete",sel.current_url)
- time.sleep(2)
- django.db.transaction.commit()
-
- # time out to simulate an IPN -- update all the transactions
- if do_local:
- django.db.transaction.enter_transaction_management()
- pm = PaymentManager()
- print pm.checkStatus()
- transaction0 = Transaction.objects.all()[0]
- print "transaction amount:{0}, transaction premium:{1}".format(transaction0.amount, transaction0.premium.id)
- django.db.transaction.commit()
-
-
- django.db.transaction.enter_transaction_management()
-
- # I have no idea what the a[href*="/work/"] is not displayed....so that's why I'm going up one element.
work_url = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector('p > a[href*="/work/"]'))
work_url.click()
-
+
# change_pledge
print "clicking Modify Pledge button"
change_pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Modify Pledge']"))
change_pledge_button.click()
# enter a new pledge, which is less than the previous amount and therefore doesn't require a new PayPal transaction
- print "changing pledge to $5 -- should not need to go to PayPal"
- preapproval_amount_input = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input#id_preapproval_amount"))
- preapproval_amount_input.clear() # get rid of existing pledge
- preapproval_amount_input.send_keys("5")
+ print "changing pledge to $5 -- should not need to go to Stripe"
+ sel.execute_script("""document.getElementById("id_preapproval_amount").value="5";""")
+ radio_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='150']"))
+ radio_button.click()
+
pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Modify Pledge']"))
pledge_button.click()
@@ -289,31 +261,16 @@ def support_campaign(unglue_it_url = settings.LIVE_SERVER_TEST_URL, do_local=Tru
work_url.click()
change_pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Modify Pledge']"))
change_pledge_button.click()
-
- # enter a new pledge, which is more than the previous amount and therefore requires a new PayPal transaction
- preapproval_amount_input = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input#id_preapproval_amount"))
- preapproval_amount_input.clear() # get rid of existing pledge
- preapproval_amount_input.send_keys("25")
+
+ # modify pledge to $25
+ sel.execute_script("""document.getElementById("id_preapproval_amount").value="25";""")
+ radio_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='150']"))
+ radio_button.click()
+
pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Modify Pledge']"))
pledge_button.click()
- if backend == 'paypal':
- paySandbox(None, sel, sel.current_url, authorize=True, already_at_url=True, sleep_time=5)
- elif backend == 'amazon':
- payAmazonSandbox(sel)
-
- # wait a bit to allow PayPal sandbox to be update the status of the Transaction
- time.sleep(10)
- django.db.transaction.commit()
-
- # time out to simulate an IPN -- update all the transactions
- if do_local:
- django.db.transaction.enter_transaction_management()
- pm = PaymentManager()
- print pm.checkStatus()
- django.db.transaction.commit()
-
- django.db.transaction.enter_transaction_management()
+ # now cancel transaction
# now go back to the work page, hit modify pledge, and then the cancel link
work_url = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector('p > a[href*="/work/"]'))
work_url.click()
@@ -324,26 +281,27 @@ def support_campaign(unglue_it_url = settings.LIVE_SERVER_TEST_URL, do_local=Tru
# hit the confirm cancellation button
cancel_pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Confirm Pledge Cancellation']"))
- cancel_pledge_button.click()
+ cancel_pledge_button.click()
+ time.sleep(10)
django.db.transaction.commit()
-
- # Why is the status of the new transaction not being updated?
- # force a db lookup -- see whether there are 1 or 2 transactions
- # they should both be cancelled
- if do_local:
- transactions = list(Transaction.objects.all())
- print "number of transactions", Transaction.objects.count()
-
- print "transactions before pm.checkStatus"
- print [(t.id, t.type, t.preapproval_key, t.status, t.premium, t.amount) for t in Transaction.objects.all()]
-
- print "checkStatus:", pm.checkStatus(transactions=transactions)
-
-
yield sel
- #sel.quit()
+
+
+ # now use the transaction manager to make the charge
+ w = models.Work.objects.get(id=48)
+ c = w.campaigns.all()[0]
+ pm = PaymentManager()
+ result = pm.execute_campaign(c)
+
+ # should have a Complete transaction
+ print result
+
+ yield sel
+
+
+
def successful_campaign_signal():
"""fire off a success_campaign signal and send notifications"""