From cbac146ace20945e22abdea281a7ef59dd7d534b Mon Sep 17 00:00:00 2001 From: Alexander Kavanaugh Date: Tue, 28 Apr 2015 00:07:33 -0700 Subject: [PATCH 01/12] Update AUTHORS.rst --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index e5a2ab8dc1..3ee6f4e1db 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -32,3 +32,4 @@ Contributors * Martin Hill (@martinhill) * Michael Thornhill * Tobias Lorenz (@Tyrdall) +* nanvel From 669606a866dc00f4464959d5a4bae0b07fb3f4ab Mon Sep 17 00:00:00 2001 From: Michael Thornhill Date: Tue, 28 Apr 2015 17:02:36 +0100 Subject: [PATCH 02/12] return the refunded object to calling code --- djstripe/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djstripe/models.py b/djstripe/models.py index 26d34fc7e7..ce2fe969e8 100644 --- a/djstripe/models.py +++ b/djstripe/models.py @@ -878,7 +878,7 @@ def refund(self, amount=None): ).refund( amount=self.calculate_refund_amount(amount=amount) ) - Charge.sync_from_stripe_data(charge_obj) + return Charge.sync_from_stripe_data(charge_obj) @classmethod def sync_from_stripe_data(cls, data): From 4880b14b9f35cd15f069e2972e3ee6c9f0288a48 Mon Sep 17 00:00:00 2001 From: Michael Thornhill Date: Thu, 30 Apr 2015 11:18:45 +0100 Subject: [PATCH 03/12] add test to show that we get the refunded object returned when we call the refund method --- tests/test_customer.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/test_customer.py b/tests/test_customer.py index e57e2e11d4..58d5a3dc80 100644 --- a/tests/test_customer.py +++ b/tests/test_customer.py @@ -111,6 +111,38 @@ def test_refund_charge(self, RetrieveMock): self.assertEquals(charge2.refunded, True) self.assertEquals(charge2.amount_refunded, decimal.Decimal("10.00")) + @patch("stripe.Charge.retrieve") + def test_refund_charge_object_returned(self, RetrieveMock): + charge = Charge.objects.create( + stripe_id="ch_XXXXXX", + customer=self.customer, + card_last_4="4323", + card_kind="Visa", + amount=decimal.Decimal("10.00"), + paid=True, + refunded=False, + fee=decimal.Decimal("4.99"), + disputed=False + ) + RetrieveMock.return_value.refund.return_value = { + "id": "ch_XXXXXX", + "card": { + "last4": "4323", + "type": "Visa" + }, + "amount": 1000, + "paid": True, + "refunded": True, + "amount_refunded": 1000, + "fee": 499, + "dispute": None, + "created": 1363911708, + "customer": "cus_xxxxxxxxxxxxxxx" + } + charge2 = charge.refund() + self.assertEquals(charge2.refunded, True) + self.assertEquals(charge2.amount_refunded, decimal.Decimal("10.00")) + def test_calculate_refund_amount_full_refund(self): charge = Charge( stripe_id="ch_111111", From 95d28aba625b110340000abeab4d25b0198f302e Mon Sep 17 00:00:00 2001 From: Alexander Kavanaugh Date: Thu, 30 Apr 2015 10:48:08 -0700 Subject: [PATCH 04/12] Update HISTORY.rst --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index 63aab4244b..649d2bcf47 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -9,6 +9,7 @@ History * Removed the StripeSubscriptionSignupForm * Moved available currencies to the DJSTRIPE_CURRENCIES setting (Thanks @martinhill) * Allow passing of extra parameters to stripe Charge API (Thanks @mthornhill) +* charge.refund() now returns the refunded charge object (Thanks @mthornhill) * South migrations are now up to date (Thanks @Tyrdall) 0.4.0 (2015-04-05) From 801bae593e6bdcd00b643b391757660092f4c5b2 Mon Sep 17 00:00:00 2001 From: Michael Thornhill Date: Sat, 2 May 2015 15:54:17 +0100 Subject: [PATCH 05/12] add captured NullBooleanFIeld to the Charge model --- djstripe/migrations/0005_charge_captured.py | 20 ++++++++++++++++++++ djstripe/models.py | 2 ++ 2 files changed, 22 insertions(+) create mode 100644 djstripe/migrations/0005_charge_captured.py diff --git a/djstripe/migrations/0005_charge_captured.py b/djstripe/migrations/0005_charge_captured.py new file mode 100644 index 0000000000..d3fcb43a57 --- /dev/null +++ b/djstripe/migrations/0005_charge_captured.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('djstripe', '0004_auto_20150427_1609'), + ] + + operations = [ + migrations.AddField( + model_name='charge', + name='captured', + field=models.NullBooleanField(), + preserve_default=True, + ), + ] diff --git a/djstripe/models.py b/djstripe/models.py index ce2fe969e8..0323cbb58f 100644 --- a/djstripe/models.py +++ b/djstripe/models.py @@ -858,6 +858,7 @@ class Charge(StripeObject): paid = models.NullBooleanField(null=True) disputed = models.NullBooleanField(null=True) refunded = models.NullBooleanField(null=True) + captured = models.NullBooleanField(null=True) fee = models.DecimalField(decimal_places=2, max_digits=7, null=True) receipt_sent = models.BooleanField(default=False) charge_created = models.DateTimeField(null=True, blank=True) @@ -893,6 +894,7 @@ def sync_from_stripe_data(cls, data): obj.amount = (data["amount"] / decimal.Decimal("100")) obj.paid = data["paid"] obj.refunded = data["refunded"] + obj.captured = data["captured"] obj.fee = (data["fee"] / decimal.Decimal("100")) obj.disputed = data["dispute"] is not None obj.charge_created = convert_tstamp(data, "created") From 4398ef22a3776887189812b424d42cb29b8e7f37 Mon Sep 17 00:00:00 2001 From: Michael Thornhill Date: Sat, 2 May 2015 15:56:27 +0100 Subject: [PATCH 06/12] add a capture method to the Charge model --- djstripe/models.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/djstripe/models.py b/djstripe/models.py index 0323cbb58f..6e48595bfa 100644 --- a/djstripe/models.py +++ b/djstripe/models.py @@ -881,6 +881,12 @@ def refund(self, amount=None): ) return Charge.sync_from_stripe_data(charge_obj) + def capture(self): + charge_obj = stripe.Charge.retrieve( + self.stripe_id + ).capture() + return Charge.sync_from_stripe_data(charge_obj) + @classmethod def sync_from_stripe_data(cls, data): customer = Customer.objects.get(stripe_id=data["customer"]) From e9010e97f9338f05791da9c1084b7bca5212e1ef Mon Sep 17 00:00:00 2001 From: Michael Thornhill Date: Sat, 2 May 2015 15:58:45 +0100 Subject: [PATCH 07/12] add capture test --- tests/test_customer.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/test_customer.py b/tests/test_customer.py index 58d5a3dc80..1a2f54bee0 100644 --- a/tests/test_customer.py +++ b/tests/test_customer.py @@ -111,6 +111,39 @@ def test_refund_charge(self, RetrieveMock): self.assertEquals(charge2.refunded, True) self.assertEquals(charge2.amount_refunded, decimal.Decimal("10.00")) + @patch("stripe.Charge.retrieve") + def test_capture_charge(self, RetrieveMock): + charge = Charge.objects.create( + stripe_id="ch_XXXXXX", + customer=self.customer, + card_last_4="4323", + card_kind="Visa", + amount=decimal.Decimal("10.00"), + paid=True, + refunded=False, + captured=False, + fee=decimal.Decimal("4.99"), + disputed=False + ) + RetrieveMock.return_value.capture.return_value = { + "id": "ch_XXXXXX", + "card": { + "last4": "4323", + "type": "Visa" + }, + "amount": 1000, + "paid": True, + "refunded": True, + "captured": True + "amount_refunded": 1000, + "fee": 499, + "dispute": None, + "created": 1363911708, + "customer": "cus_xxxxxxxxxxxxxxx" + } + charge2 = charge.capture() + self.assertEquals(charge2.captured, True) + @patch("stripe.Charge.retrieve") def test_refund_charge_object_returned(self, RetrieveMock): charge = Charge.objects.create( From 82f9e424689ad81e28b40aef09f8f7e9b86f8931 Mon Sep 17 00:00:00 2001 From: Michael Thornhill Date: Sat, 2 May 2015 16:04:31 +0100 Subject: [PATCH 08/12] add captured to the mock objects return values --- tests/test_customer.py | 7 ++++++- tests/test_email.py | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_customer.py b/tests/test_customer.py index 1a2f54bee0..484316f823 100644 --- a/tests/test_customer.py +++ b/tests/test_customer.py @@ -66,6 +66,7 @@ def test_record_charge(self, RetrieveMock): "amount": 1000, "paid": True, "refunded": False, + "captured": True, "fee": 499, "dispute": None, "created": 1363911708, @@ -100,6 +101,7 @@ def test_refund_charge(self, RetrieveMock): "amount": 1000, "paid": True, "refunded": True, + "captured": True, "amount_refunded": 1000, "fee": 499, "dispute": None, @@ -134,7 +136,7 @@ def test_capture_charge(self, RetrieveMock): "amount": 1000, "paid": True, "refunded": True, - "captured": True + "captured": True, "amount_refunded": 1000, "fee": 499, "dispute": None, @@ -166,6 +168,7 @@ def test_refund_charge_object_returned(self, RetrieveMock): "amount": 1000, "paid": True, "refunded": True, + "captured": True, "amount_refunded": 1000, "fee": 499, "dispute": None, @@ -222,6 +225,7 @@ def test_charge_converts_dollars_into_cents(self, ChargeMock, RetrieveMock): "amount": 1000, "paid": True, "refunded": False, + "captured": True, "fee": 499, "dispute": None, "created": 1363911708, @@ -247,6 +251,7 @@ def test_charge_passes_extra_arguments(self, ChargeMock, RetrieveMock): "amount": 1000, "paid": True, "refunded": False, + "captured": True, "fee": 499, "dispute": None, "created": 1363911708, diff --git a/tests/test_email.py b/tests/test_email.py index 760f279fa6..3287994bce 100644 --- a/tests/test_email.py +++ b/tests/test_email.py @@ -35,6 +35,7 @@ def test_email_reciept_renders_amount_properly(self, ChargeMock, RetrieveMock): "amount": 40000, "paid": True, "refunded": False, + "captured": True, "fee": 499, "dispute": None, "created": 1363911708, From 3d653e59cc069d38a6d6bd8ce020cec458f012ff Mon Sep 17 00:00:00 2001 From: Michael Thornhill Date: Sat, 2 May 2015 19:39:10 +0100 Subject: [PATCH 09/12] south migration for captured NullBooleanField --- .../0007_auto__add_field_charge_captured.py | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 djstripe/south_migrations/0007_auto__add_field_charge_captured.py diff --git a/djstripe/south_migrations/0007_auto__add_field_charge_captured.py b/djstripe/south_migrations/0007_auto__add_field_charge_captured.py new file mode 100644 index 0000000000..be2b07a367 --- /dev/null +++ b/djstripe/south_migrations/0007_auto__add_field_charge_captured.py @@ -0,0 +1,222 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as 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 'Charge.captured' + db.add_column(u'djstripe_charge', 'captured', + self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Charge.captured' + db.delete_column(u'djstripe_charge', 'captured') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'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'}), + u'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'}) + }, + u'djstripe.charge': { + 'Meta': {'object_name': 'Charge'}, + 'amount': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2'}), + 'amount_refunded': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2'}), + 'captured': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'card_kind': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'card_last_4': ('django.db.models.fields.CharField', [], {'max_length': '4', 'blank': 'True'}), + 'charge_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'charges'", 'to': u"orm['djstripe.Customer']"}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'disputed': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'fee': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invoice': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'charges'", 'null': 'True', 'to': u"orm['djstripe.Invoice']"}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'paid': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'receipt_sent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'refunded': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'stripe_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}) + }, + u'djstripe.currentsubscription': { + 'Meta': {'object_name': 'CurrentSubscription'}, + 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'cancel_at_period_end': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'current_period_end': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'current_period_start': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'customer': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "u'current_subscription'", 'unique': 'True', 'null': 'True', 'to': u"orm['djstripe.Customer']"}), + 'ended_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'plan': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'quantity': ('django.db.models.fields.IntegerField', [], {}), + 'start': ('django.db.models.fields.DateTimeField', [], {}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '25'}), + 'trial_end': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'trial_start': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + u'djstripe.customer': { + 'Meta': {'object_name': 'Customer'}, + 'card_fingerprint': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'card_kind': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'card_last_4': ('django.db.models.fields.CharField', [], {'max_length': '4', 'blank': 'True'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'date_purged': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'stripe_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}), + 'subscriber': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True', 'null': 'True'}) + }, + u'djstripe.event': { + 'Meta': {'object_name': 'Event'}, + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['djstripe.Customer']", 'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kind': ('django.db.models.fields.CharField', [], {'max_length': '250'}), + 'livemode': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'processed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'stripe_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}), + 'valid': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'validated_message': ('jsonfield.fields.JSONField', [], {'null': 'True'}), + 'webhook_message': ('jsonfield.fields.JSONField', [], {}) + }, + u'djstripe.eventprocessingexception': { + 'Meta': {'object_name': 'EventProcessingException'}, + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'data': ('django.db.models.fields.TextField', [], {}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['djstripe.Event']", 'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'message': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'traceback': ('django.db.models.fields.TextField', [], {}) + }, + u'djstripe.invoice': { + 'Meta': {'ordering': "[u'-date']", 'object_name': 'Invoice'}, + 'attempted': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'attempts': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + 'charge': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'customer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'invoices'", 'to': u"orm['djstripe.Customer']"}), + 'date': ('django.db.models.fields.DateTimeField', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'paid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'period_end': ('django.db.models.fields.DateTimeField', [], {}), + 'period_start': ('django.db.models.fields.DateTimeField', [], {}), + 'stripe_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}), + 'subtotal': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'total': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}) + }, + u'djstripe.invoiceitem': { + 'Meta': {'object_name': 'InvoiceItem'}, + 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'currency': ('django.db.models.fields.CharField', [], {'max_length': '10'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invoice': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'items'", 'to': u"orm['djstripe.Invoice']"}), + 'line_type': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'period_end': ('django.db.models.fields.DateTimeField', [], {}), + 'period_start': ('django.db.models.fields.DateTimeField', [], {}), + 'plan': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'proration': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'quantity': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'stripe_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'djstripe.plan': { + 'Meta': {'object_name': 'Plan'}, + 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'currency': ('django.db.models.fields.CharField', [], {'max_length': '10'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'interval': ('django.db.models.fields.CharField', [], {'max_length': '10'}), + 'interval_count': ('django.db.models.fields.IntegerField', [], {'default': '1', 'null': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'stripe_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}), + 'trial_period_days': ('django.db.models.fields.IntegerField', [], {'null': 'True'}) + }, + u'djstripe.transfer': { + 'Meta': {'object_name': 'Transfer'}, + 'adjustment_count': ('django.db.models.fields.IntegerField', [], {}), + 'adjustment_fees': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'adjustment_gross': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'charge_count': ('django.db.models.fields.IntegerField', [], {}), + 'charge_fees': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'charge_gross': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'collected_fee_count': ('django.db.models.fields.IntegerField', [], {}), + 'collected_fee_gross': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'date': ('django.db.models.fields.DateTimeField', [], {}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'event': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'transfers'", 'to': u"orm['djstripe.Event']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'net': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'refund_count': ('django.db.models.fields.IntegerField', [], {}), + 'refund_fees': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'refund_gross': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '25'}), + 'stripe_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}), + 'validation_count': ('django.db.models.fields.IntegerField', [], {}), + 'validation_fees': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}) + }, + u'djstripe.transferchargefee': { + 'Meta': {'object_name': 'TransferChargeFee'}, + 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '7', 'decimal_places': '2'}), + 'application': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kind': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'transfer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'charge_fee_details'", 'to': u"orm['djstripe.Transfer']"}) + } + } + + complete_apps = ['djstripe'] \ No newline at end of file From c618ecc60745df6d39c8ea70c03e75e3ce4eb7d0 Mon Sep 17 00:00:00 2001 From: Michael Thornhill Date: Sat, 2 May 2015 20:11:44 +0100 Subject: [PATCH 10/12] add a docstring to the capture method on the Charge model --- djstripe/models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/djstripe/models.py b/djstripe/models.py index 6e48595bfa..028764b795 100644 --- a/djstripe/models.py +++ b/djstripe/models.py @@ -882,6 +882,11 @@ def refund(self, amount=None): return Charge.sync_from_stripe_data(charge_obj) def capture(self): + """ + Capture the payment of an existing, uncaptured, charge. This is the second half of the two-step payment flow, + where first you created a charge with the capture option set to false. + See https://stripe.com/docs/api#capture_charge + """ charge_obj = stripe.Charge.retrieve( self.stripe_id ).capture() From 82b574d542f0493eacdea90998519fcef5624c16 Mon Sep 17 00:00:00 2001 From: Alexander Kavanaugh Date: Sat, 2 May 2015 12:22:07 -0700 Subject: [PATCH 11/12] Added Michael Thornhill's contribution --- HISTORY.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index 649d2bcf47..7731a126a6 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,13 +3,14 @@ History ======= -0.5.0 (2015-04-??) +0.5.0 (2015-05-??) --------------------- * Removed the StripeSubscriptionSignupForm * Moved available currencies to the DJSTRIPE_CURRENCIES setting (Thanks @martinhill) * Allow passing of extra parameters to stripe Charge API (Thanks @mthornhill) * charge.refund() now returns the refunded charge object (Thanks @mthornhill) +* Charge model now has captured field and a capture method (Thanks @mthornhill) * South migrations are now up to date (Thanks @Tyrdall) 0.4.0 (2015-04-05) From 4280920b2f266b53755563c8601c7046d3ebda38 Mon Sep 17 00:00:00 2001 From: Alexander Kavanaugh Date: Sat, 2 May 2015 12:23:03 -0700 Subject: [PATCH 12/12] removed dup --- AUTHORS.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 3ee6f4e1db..07b5cd7a1d 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -24,7 +24,6 @@ Contributors * Thomas Parslow (@almost) * Leonid Shvechikov (@shvechikov) * sromero84 -* Mahdi Yusuf (@myusuf3) * Peter Baumgartner (@ipmb) * Vikas (@vikasgulati) * Colton Allen (@cmanallen)