diff --git a/pinax/stripe/actions/subscriptions.py b/pinax/stripe/actions/subscriptions.py index 1a2e77853..036172b24 100644 --- a/pinax/stripe/actions/subscriptions.py +++ b/pinax/stripe/actions/subscriptions.py @@ -25,7 +25,7 @@ def cancel(subscription, at_period_end=True): return sync_subscription_from_stripe_data(subscription.customer, sub) -def create(customer, plan, quantity=None, trial_days=None, token=None, coupon=None, tax_percent=None): +def create(customer, plan, quantity=None, trial_days=None, token=None, coupon=None, tax_percent=None, metadata=None): """ Creates a subscription for the given customer @@ -58,6 +58,7 @@ def create(customer, plan, quantity=None, trial_days=None, token=None, coupon=No subscription_params["quantity"] = quantity subscription_params["coupon"] = coupon subscription_params["tax_percent"] = tax_percent + subscription_params["metadata"] = metadata resp = stripe.Subscription.create(**subscription_params) return sync_subscription_from_stripe_data(customer, resp) @@ -160,7 +161,8 @@ def sync_subscription_from_stripe_data(customer, subscription): start=utils.convert_tstamp(subscription["start"]), status=subscription["status"], trial_start=utils.convert_tstamp(subscription["trial_start"]) if subscription["trial_start"] else None, - trial_end=utils.convert_tstamp(subscription["trial_end"]) if subscription["trial_end"] else None + trial_end=utils.convert_tstamp(subscription["trial_end"]) if subscription["trial_end"] else None, + metadata=subscription["metadata"] ) sub, created = models.Subscription.objects.get_or_create( stripe_id=subscription["id"], @@ -170,7 +172,7 @@ def sync_subscription_from_stripe_data(customer, subscription): return sub -def update(subscription, plan=None, quantity=None, prorate=True, coupon=None, charge_immediately=False): +def update(subscription, plan=None, quantity=None, prorate=True, coupon=None, charge_immediately=False, metadata=None): """ Updates a subscription @@ -194,6 +196,8 @@ def update(subscription, plan=None, quantity=None, prorate=True, coupon=None, ch if charge_immediately: if stripe_subscription.trial_end is not None and utils.convert_tstamp(stripe_subscription.trial_end) > timezone.now(): stripe_subscription.trial_end = "now" + if metadata: + stripe_subscription.metadata = metadata sub = stripe_subscription.save() customer = models.Customer.objects.get(pk=subscription.customer.pk) return sync_subscription_from_stripe_data(customer, sub) diff --git a/pinax/stripe/migrations/0014_subscription_metadata.py b/pinax/stripe/migrations/0014_subscription_metadata.py new file mode 100644 index 000000000..98e0cae8c --- /dev/null +++ b/pinax/stripe/migrations/0014_subscription_metadata.py @@ -0,0 +1,19 @@ +# Generated by Django 2.0.1 on 2018-01-23 09:17 + +from django.db import migrations +import jsonfield.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('pinax_stripe', '0013_charge_outcome'), + ] + + operations = [ + migrations.AddField( + model_name='subscription', + name='metadata', + field=jsonfield.fields.JSONField(blank=True, null=True), + ), + ] diff --git a/pinax/stripe/models.py b/pinax/stripe/models.py index 5d619441d..98706d297 100644 --- a/pinax/stripe/models.py +++ b/pinax/stripe/models.py @@ -365,6 +365,7 @@ class Subscription(StripeAccountFromCustomerMixin, StripeObject): status = models.CharField(max_length=25) # trialing, active, past_due, canceled, or unpaid trial_end = models.DateTimeField(null=True, blank=True) trial_start = models.DateTimeField(null=True, blank=True) + metadata = JSONField(null=True, blank=True) @property def stripe_subscription(self): diff --git a/pinax/stripe/tests/test_actions.py b/pinax/stripe/tests/test_actions.py index 11ed7ce27..7252e7e71 100644 --- a/pinax/stripe/tests/test_actions.py +++ b/pinax/stripe/tests/test_actions.py @@ -1052,6 +1052,15 @@ def test_update_plan_charge_now(self, SyncMock): self.assertTrue(SubMock.stripe_subscription.save.called) self.assertTrue(SyncMock.called) + @patch("pinax.stripe.actions.subscriptions.sync_subscription_from_stripe_data") + def test_update_plan_metadata(self, SyncMock): + SubMock = Mock() + SubMock.customer = self.customer + subscriptions.update(SubMock, metadata={"test_value": "test_value"}) + self.assertEquals(SubMock.stripe_subscription.metadata, {"test_value": "test_value"}) + self.assertTrue(SubMock.stripe_subscription.save.called) + self.assertTrue(SyncMock.called) + @patch("pinax.stripe.actions.subscriptions.sync_subscription_from_stripe_data") def test_update_plan_charge_now_old_trial(self, SyncMock): trial_end = time.time() - 1000000.0 @@ -1104,6 +1113,7 @@ def test_subscription_create_with_connect(self, SubscriptionCreateMock): "status": "active", "trial_start": None, "trial_end": None, + "metadata": None, "plan": { "id": self.plan.stripe_id, }} @@ -1111,6 +1121,7 @@ def test_subscription_create_with_connect(self, SubscriptionCreateMock): SubscriptionCreateMock.assert_called_once_with( coupon=None, customer=self.connected_customer.stripe_id, + metadata=None, plan="the-plan", quantity=4, stripe_account="acct_xx", @@ -1135,6 +1146,7 @@ def test_retrieve_subscription_with_connect(self, CreateMock, RetrieveMock): "status": "active", "trial_start": None, "trial_end": None, + "metadata": None, "plan": { "id": self.plan.stripe_id, }} diff --git a/pinax/stripe/tests/test_event.py b/pinax/stripe/tests/test_event.py index 4a3bc8577..67c446e69 100644 --- a/pinax/stripe/tests/test_event.py +++ b/pinax/stripe/tests/test_event.py @@ -264,6 +264,7 @@ def test_customer_subscription_deleted(self, CustomerMock, EventMock, SyncMock): "ended_at": 1380317537, "trial_start": None, "trial_end": None, + "metadata": None, "canceled_at": 1380317537, "quantity": 1, "application_fee_percent": None