Merge pull request #3 from Gluejar/relaunch_ry

A first pass at storing Stripe Customer data in relaunch branch
pull/1/head
eshellman 2012-09-17 11:33:54 -07:00
commit 1f1737c328
5 changed files with 244 additions and 13 deletions

View File

@ -50,9 +50,10 @@ from regluit.frontend.forms import getManageCampaignForm, DonateForm, CampaignAd
from regluit.frontend.forms import EbookForm, CustomPremiumForm, EditManagersForm, EditionForm, PledgeCancelForm from regluit.frontend.forms import EbookForm, CustomPremiumForm, EditManagersForm, EditionForm, PledgeCancelForm
from regluit.frontend.forms import getTransferCreditForm, CCForm from regluit.frontend.forms import getTransferCreditForm, CCForm
from regluit.payment.manager import PaymentManager from regluit.payment.manager import PaymentManager
from regluit.payment.models import Transaction 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 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_TYPE_AUTHORIZATION, PAYMENT_TYPE_INSTANT
from regluit.payment.parameters import PAYMENT_HOST_STRIPE
from regluit.payment.credit import credit_transaction from regluit.payment.credit import credit_transaction
from regluit.core import goodreads from regluit.core import goodreads
from tastypie.models import ApiKey from tastypie.models import ApiKey
@ -772,7 +773,12 @@ class FundPledgeView(FormView):
if retain_cc_info: if retain_cc_info:
# create customer and charge id and then charge the customer # create customer and charge id and then charge the customer
customer = sc.create_customer(card=stripe_token, description="test customer", email="test@unglue.it") 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)
account.user = self.request.user
account.save()
charge = sc.create_charge(preapproval_amount, customer=customer, description="${0} for test / retain cc".format(preapproval_amount)) charge = sc.create_charge(preapproval_amount, customer=customer, description="${0} for test / retain cc".format(preapproval_amount))
else: else:

View File

@ -0,0 +1,201 @@
# -*- coding: 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 model 'Account'
db.create_table('payment_account', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('host', self.gf('django.db.models.fields.CharField')(default='none', max_length=32)),
('account_id', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True)),
))
db.send_create_signal('payment', ['Account'])
def backwards(self, orm):
# Deleting model 'Account'
db.delete_table('payment_account')
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': ('ckeditor.fields.RichTextField', [], {'null': 'True'}),
'details': ('ckeditor.fields.RichTextField', [], {'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'},
'cover_image': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': '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', 'blank': 'True'}),
'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
'unglued': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'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.work': {
'Meta': {'ordering': "['title']", 'object_name': 'Work'},
'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'}),
'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.account': {
'Meta': {'object_name': 'Account'},
'account_id': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
'host': ('django.db.models.fields.CharField', [], {'default': "'none'", 'max_length': '32'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'})
},
'payment.credit': {
'Meta': {'object_name': 'Credit'},
'balance': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '14', 'decimal_places': '2'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_activity': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'pledged': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '14', 'decimal_places': '2'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'credit'", 'unique': 'True', 'to': "orm['auth.User']"})
},
'payment.creditlog': {
'Meta': {'object_name': 'CreditLog'},
'action': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
'amount': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '14', 'decimal_places': '2'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'sent': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'})
},
'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.sent': {
'Meta': {'object_name': 'Sent'},
'amount': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '14', 'decimal_places': '2'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'})
},
'payment.transaction': {
'Meta': {'object_name': 'Transaction'},
'ack_dedication': ('django.db.models.fields.CharField', [], {'max_length': '140', 'null': 'True'}),
'ack_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
'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': "'none'", 'max_length': '32'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': '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'}),
'type': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'})
}
}
complete_apps = ['payment']

View File

@ -12,6 +12,10 @@ import urllib
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# in fitting stripe -- here are possible fields to fit in with Transaction
# c.id, c.amount, c.amount_refunded, c.currency, c.description, datetime.fromtimestamp(c.created, tz=utc), c.paid,
# c.fee, c.disputed, c.amount_refunded, c.failure_message,
# c.card.fingerprint, c.card.type, c.card.last4, c.card.exp_month, c.card.exp_year
class Transaction(models.Model): class Transaction(models.Model):
@ -278,6 +282,21 @@ class Sent(models.Model):
amount = models.DecimalField(default=Decimal('0.00'), max_digits=14, decimal_places=2) # max 999,999,999,999.99 amount = models.DecimalField(default=Decimal('0.00'), max_digits=14, decimal_places=2) # max 999,999,999,999.99
timestamp = models.DateTimeField(auto_now=True) timestamp = models.DateTimeField(auto_now=True)
class Account(models.Model):
"""holds references to accounts at third party payment gateways, especially for representing credit cards"""
# the following fields from stripe Customer might be relevant to Account -- we need to pick good selection
# c.id, c.description, c.email, datetime.fromtimestamp(c.created, tz=utc), c.account_balance, c.delinquent,
# c.active_card.fingerprint, c.active_card.type, c.active_card.last4, c.active_card.exp_month, c.active_card.exp_year,
# c.active_card.country
# host: the payment processor. Named after the payment module that hosts the payment processing functions
host = models.CharField(default=PAYMENT_HOST_NONE, max_length=32, null=False)
account_id = models.CharField(max_length=128, null=True)
# associated User
user = models.ForeignKey(User, null=True)
from django.db.models.signals import post_save, post_delete from django.db.models.signals import post_save, post_delete
import regluit.payment.manager import regluit.payment.manager

View File

@ -5,9 +5,10 @@ PAYMENT_TYPE_AUTHORIZATION = 2
PAYMENT_HOST_NONE = "none" PAYMENT_HOST_NONE = "none"
PAYMENT_HOST_PAYPAL = "paypal" PAYMENT_HOST_PAYPAL = "paypal"
PAYMENT_HOST_AMAZON = "amazon" PAYMENT_HOST_AMAZON = "amazon"
PAYMENT_HOST_STRIPE = "stripe"
PAYMENT_HOST_TEST = "test" PAYMENT_HOST_TEST = "test"
PAYMENT_HOST_CREDIT = "credit" PAYMENT_HOST_CREDIT = "credit"
PAYMENT_HOST_STRIPE = "stripe"
EXECUTE_TYPE_NONE = 0 EXECUTE_TYPE_NONE = 0
EXECUTE_TYPE_CHAINED_INSTANT = 1 EXECUTE_TYPE_CHAINED_INSTANT = 1

View File

@ -205,7 +205,6 @@ class StripeClient(object):
class PledgeScenarioTest(TestCase): class PledgeScenarioTest(TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
print "in setUp"
cls._sc = StripeClient(api_key=STRIPE_SK) cls._sc = StripeClient(api_key=STRIPE_SK)
# valid card # valid card
@ -219,8 +218,11 @@ class PledgeScenarioTest(TestCase):
def test_charge_good_cust(self): 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, description="$10 for good cust")
print charge.id self.assertEqual(type(charge.id), str)
# print out all the pieces of Customer and Charge objects
print dir(charge)
print dir(self._good_cust)
def test_error_creating_customer_with_declined_card(self): def test_error_creating_customer_with_declined_card(self):
# should get a CardError upon attempt to create Customer with this card # should get a CardError upon attempt to create Customer with this card
@ -231,21 +233,23 @@ class PledgeScenarioTest(TestCase):
# expect the card to be declined -- and for us to get CardError # expect the card to be declined -- and for us to get CardError
self.assertRaises(stripe.CardError, self._sc.create_charge, 10, self.assertRaises(stripe.CardError, self._sc.create_charge, 10,
customer = self._cust_bad_card, description="$10 for bad cust") customer = self._cust_bad_card, description="$10 for bad cust")
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
# clean up stuff we create in test # clean up stuff we create in test -- right now list current objects
print "in tearDown"
cls._good_cust.delete() #cls._good_cust.delete()
print "list of customers" print "list of customers"
print [(i, c.id, c.description, datetime.fromtimestamp(c.created, tz=utc), c.account_balance) for(i, c) in enumerate(cls._sc.customer.all()["data"])] print [(i, c.id, c.description, c.email, datetime.fromtimestamp(c.created, tz=utc), c.account_balance, c.delinquent, c.active_card.fingerprint, c.active_card.type, c.active_card.last4, c.active_card.exp_month, c.active_card.exp_year, c.active_card.country) for(i, c) in enumerate(cls._sc.customer.all()["data"])]
print "list of charges" print "list of charges"
print [(i, c.id, c.amount, c.currency, c.description, datetime.fromtimestamp(c.created, tz=utc), c.paid, c.fee, c.disputed, c.amount_refunded, c.failure_message, c.card.fingerprint, c.card.last4) for (i, c) in enumerate(cls._sc.charge.all()['data'])] print [(i, c.id, c.amount, c.amount_refunded, c.currency, c.description, datetime.fromtimestamp(c.created, tz=utc), c.paid, c.fee, c.disputed, c.amount_refunded, c.failure_message, c.card.fingerprint, c.card.type, c.card.last4, c.card.exp_month, c.card.exp_year) for (i, c) in enumerate(cls._sc.charge.all()['data'])]
# can retrieve events since a certain time # can retrieve events since a certain time?
print "list of events", cls._sc.event.all() print "list of events", cls._sc.event.all()
# [(i, e.id, e.type, e.created, e.pending_webhooks, e.data) for (i,e) in enumerate(s.event.all()['data'])] print [(i, e.id, e.type, e.created, e.pending_webhooks, e.data) for (i,e) in enumerate(cls._sc.event.all()['data'])]
def suite(): def suite():