class RestSubscriptionTest(APITestCase): """ Test the REST api for subscriptions. """ def setUp(self): self.url = reverse("rest_djstripe:subscription") self.user = get_user_model().objects.create_user( username="******", email="*****@*****.**", password="******" ) self.assertTrue(self.client.login(username="******", password="******")) @patch("djstripe.models.Customer.subscribe", autospec=True) @patch("djstripe.models.Customer.update_card", autospec=True) @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890")) def test_create_subscription(self, stripe_customer_mock, update_card_mock, subscribe_mock): self.assertEqual(0, Customer.objects.count()) data = { "plan": "test0", "stripe_token": "cake", } response = self.client.post(self.url, data) self.assertEqual(1, Customer.objects.count()) update_card_mock.assert_called_once_with(self.user.customer, "cake") subscribe_mock.assert_called_once_with(self.user.customer, "test0") self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.data, data) @patch("djstripe.models.Customer.subscribe", autospec=True) @patch("djstripe.models.Customer.update_card", autospec=True) @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890")) def test_create_subscription_exception(self, stripe_customer_mock, update_card_mock, subscribe_mock): e = Exception subscribe_mock.side_effect = e data = { "plan": "test0", "stripe_token": "cake", } response = self.client.post(self.url, data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_get_no_content_for_subscription(self): response = self.client.get(self.url) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) def test_get_subscription(self): fake_customer = Customer.objects.create( stripe_id="cus_xxx1234567890", subscriber=self.user ) CurrentSubscription.objects.create( customer=fake_customer, plan="test", quantity=1, start=timezone.now(), amount=Decimal(25.00), status="active", ) response = self.client.get(self.url) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data["plan"], "test") self.assertEqual(response.data['status'], 'active') self.assertEqual(response.data['cancel_at_period_end'], False) @patch("djstripe.models.Customer.cancel_subscription", return_value=CurrentSubscription(status=CurrentSubscription.STATUS_ACTIVE)) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=CurrentSubscription(plan="test", amount=Decimal(25.00), status="active")) @patch("djstripe.models.Customer.subscribe", autospec=True) def test_cancel_subscription(self, subscribe_mock, stripe_create_customer_mock, cancel_subscription_mock): fake_customer = Customer.objects.create( stripe_id="cus_xxx1234567890", subscriber=self.user ) CurrentSubscription.objects.create( customer=fake_customer, plan="test", quantity=1, start=timezone.now(), amount=Decimal(25.00), status="active", ) self.assertEqual(1, CurrentSubscription.objects.count()) response = self.client.delete(self.url) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) # Cancelled means flagged as cancelled, so it should still be there self.assertEqual(1, CurrentSubscription.objects.count()) cancel_subscription_mock.assert_called_once_with( at_period_end=djstripe_settings.CANCELLATION_AT_PERIOD_END ) self.assertTrue(self.user.is_authenticated()) def test_cancel_subscription_exception(self): response = self.client.delete(self.url) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_create_subscription_incorrect_data(self): self.assertEqual(0, Customer.objects.count()) data = { "foo": "bar", } response = self.client.post(self.url, data) self.assertEqual(0, Customer.objects.count()) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
class ChangePlanViewTest(TestCase): @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890_01")) def setUp(self, stripe_customer_mock): self.url = reverse("djstripe:change_plan") self.user1 = get_user_model().objects.create_user( username="******", email="*****@*****.**", password="******") self.user2 = get_user_model().objects.create_user( username="******", email="*****@*****.**", password="******") Customer.get_or_create(subscriber=self.user1) @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890")) def test_post_form_invalid(self, stripe_customer_mock): self.assertTrue(self.client.login(username="******", password="******")) response = self.client.post(self.url) self.assertEqual(200, response.status_code) self.assertIn("plan", response.context["form"].errors) self.assertIn("This field is required.", response.context["form"].errors["plan"]) @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890_02")) def test_post_new_sub_no_proration(self, stripe_customer_mock): self.assertTrue(self.client.login(username="******", password="******")) response = self.client.post(self.url, {"plan": "test0"}) self.assertEqual(200, response.status_code) self.assertIn("form", response.context) self.assertIn( "You must already be subscribed to a plan before you can change it.", response.context["form"].errors["__all__"]) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=CurrentSubscription(plan="test", amount=Decimal(25.00))) @patch("djstripe.models.Customer.subscribe", autospec=True) def test_change_sub_no_proration(self, subscribe_mock, current_subscription_mock): self.assertTrue(self.client.login(username="******", password="******")) response = self.client.post(self.url, {"plan": "test0"}) self.assertRedirects(response, reverse("djstripe:history")) subscribe_mock.assert_called_once_with(self.user1.customer, "test0") @patch("djstripe.views.PRORATION_POLICY_FOR_UPGRADES", return_value=True) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=CurrentSubscription(plan="test", amount=Decimal(25.00))) @patch("djstripe.models.Customer.subscribe", autospec=True) def test_change_sub_with_proration_downgrade(self, subscribe_mock, current_subscription_mock, proration_policy_mock): self.assertTrue(self.client.login(username="******", password="******")) response = self.client.post(self.url, {"plan": "test0"}) self.assertRedirects(response, reverse("djstripe:history")) subscribe_mock.assert_called_once_with(self.user1.customer, "test0") @patch("djstripe.views.PRORATION_POLICY_FOR_UPGRADES", return_value=True) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=CurrentSubscription(plan="test", amount=Decimal(25.00))) @patch("djstripe.models.Customer.subscribe", autospec=True) def test_change_sub_with_proration_upgrade(self, subscribe_mock, current_subscription_mock, proration_policy_mock): self.assertTrue(self.client.login(username="******", password="******")) response = self.client.post(self.url, {"plan": "test2"}) self.assertRedirects(response, reverse("djstripe:history")) subscribe_mock.assert_called_once_with(self.user1.customer, "test2", prorate=True) @patch("djstripe.views.PRORATION_POLICY_FOR_UPGRADES", return_value=True) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=CurrentSubscription(plan="test", amount=Decimal(25.00))) @patch("djstripe.models.Customer.subscribe", autospec=True) def test_change_sub_with_proration_same_plan(self, subscribe_mock, current_subscription_mock, proration_policy_mock): self.assertTrue(self.client.login(username="******", password="******")) response = self.client.post(self.url, {"plan": "test"}) self.assertRedirects(response, reverse("djstripe:history")) subscribe_mock.assert_called_once_with(self.user1.customer, "test") @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=CurrentSubscription(plan="test", amount=Decimal(25.00))) @patch("djstripe.models.Customer.subscribe", autospec=True) def test_change_sub_same_plan(self, subscribe_mock, current_subscription_mock): self.assertTrue(self.client.login(username="******", password="******")) response = self.client.post(self.url, {"plan": "test"}) self.assertRedirects(response, reverse("djstripe:history")) subscribe_mock.assert_called_once_with(self.user1.customer, "test") @patch("djstripe.models.Customer.subscribe", autospec=True) def test_change_sub_stripe_error(self, subscribe_mock): subscribe_mock.side_effect = stripe.StripeError( "No such plan: test_id_3") self.assertTrue(self.client.login(username="******", password="******")) response = self.client.post(self.url, {"plan": "test_deletion"}) self.assertEqual(200, response.status_code) self.assertIn("form", response.context) self.assertIn("No such plan: test_id_3", response.context["form"].errors["__all__"])
class EventTest(TestCase): message = { "created": 1363911708, "data": { "object": { "account_balance": 0, "active_card": None, "created": 1363911708, "delinquent": False, "description": None, "discount": None, "email": "*****@*****.**", "id": "cus_yyyyyyyyyyyyyyyyyyyy", "customer": "cus_xxxxxxxxxxxxxxx", "livemode": True, "object": "customer", "subscription": None } }, "id": "evt_xxxxxxxxxxxxx", "livemode": True, "object": "event", "pending_webhooks": 1, "type": "ping" } fake_current_subscription = CurrentSubscription(plan="test", quantity=1, start=timezone.now(), amount=Decimal(25.00)) def setUp(self): self.message["data"]["object"][ "customer"] = "cus_xxxxxxxxxxxxxxx" # Yes, this is intentional. self.user = get_user_model().objects.create_user( username="******", email="*****@*****.**") self.customer = Customer.objects.create( stripe_id=self.message["data"]["object"]["customer"], subscriber=self.user) def test_tostring(self): event = Event.objects.create(stripe_id=self.message["id"], kind="eventkind", webhook_message=self.message, validated_message=self.message, valid=True) self.assertEquals("<eventkind, stripe_id=evt_xxxxxxxxxxxxx>", str(event)) def test_link_customer_customer_created(self): msg = { "created": 1363911708, "data": { "object": { "account_balance": 0, "active_card": None, "created": 1363911708, "delinquent": False, "description": None, "discount": None, "email": "*****@*****.**", "id": "cus_xxxxxxxxxxxxxxx", "livemode": True, "object": "customer", "subscription": None } }, "id": "evt_xxxxxxxxxxxxx", "livemode": True, "object": "event", "pending_webhooks": 1, "type": "customer.created" } event = Event.objects.create( stripe_id=msg["id"], kind="customer.created", livemode=True, webhook_message=msg, validated_message=msg, valid=True, ) event.process() self.assertEquals(event.customer, self.customer) def test_link_customer_customer_updated(self): msg = { "created": 1346855599, "data": { "object": { "account_balance": 0, "active_card": { "address_city": None, "address_country": None, "address_line1": None, "address_line1_check": None, "address_line2": None, "address_state": None, "address_zip": None, "address_zip_check": None, "country": "MX", "cvc_check": "pass", "exp_month": 1, "exp_year": 2014, "fingerprint": "XXXXXXXXXXX", "last4": "7992", "name": None, "object": "card", "type": "MasterCard" }, "created": 1346855596, "delinquent": False, "description": None, "discount": None, "email": "*****@*****.**", "id": "cus_xxxxxxxxxxxxxxx", "livemode": True, "object": "customer", "subscription": None }, "previous_attributes": { "active_card": None } }, "id": "evt_xxxxxxxxxxxxx", "livemode": True, "object": "event", "pending_webhooks": 1, "type": "customer.updated" } event = Event.objects.create( stripe_id=msg["id"], kind="customer.updated", livemode=True, webhook_message=msg, validated_message=msg, valid=True, ) event.process() self.assertEquals(event.customer, self.customer) def test_link_customer_customer_deleted(self): msg = { "created": 1348286560, "data": { "object": { "account_balance": 0, "active_card": None, "created": 1348286302, "delinquent": False, "description": None, "discount": None, "email": "*****@*****.**", "id": "cus_xxxxxxxxxxxxxxx", "livemode": True, "object": "customer", "subscription": None } }, "id": "evt_xxxxxxxxxxxxx", "livemode": True, "object": "event", "pending_webhooks": 1, "type": "customer.deleted" } event = Event.objects.create( stripe_id=msg["id"], kind="customer.deleted", livemode=True, webhook_message=msg, validated_message=msg, valid=True, ) event.process() self.assertEquals(event.customer, self.customer) @patch('stripe.Event.retrieve', return_value=convert_to_fake_stripe_object({ "data": message["data"], "zebra": True, "alpha": False })) def test_validate_true(self, event_retrieve_mock): event = Event.objects.create(stripe_id=self.message["id"], kind="ping", webhook_message=self.message, validated_message=self.message) self.assertEqual(None, event.valid) event.validate() event_retrieve_mock.assert_called_once_with(self.message["id"]) self.assertEqual(True, event.valid) @patch('stripe.Event.retrieve', return_value=convert_to_fake_stripe_object({ "data": { "object": { "flavor": "chocolate" } }, "zebra": True, "alpha": False })) def test_validate_false(self, event_retrieve_mock): event = Event.objects.create(stripe_id=self.message["id"], kind="ping", webhook_message=self.message, validated_message=self.message) self.assertEqual(None, event.valid) event.validate() event_retrieve_mock.assert_called_once_with(self.message["id"]) self.assertEqual(False, event.valid) def test_process_exit_immediately(self): event = Event.objects.create(stripe_id=self.message["id"], kind="ping", webhook_message=self.message, validated_message=self.message, valid=False) event.process() self.assertFalse(event.processed) @patch('djstripe.models.Customer.objects.get') @patch('stripe.Invoice.retrieve') @patch('djstripe.models.Invoice.sync_from_stripe_data') def test_process_invoice_event(self, stripe_sync_mock, retrieve_mock, customer_get): event = Event.objects.create(stripe_id=self.message["id"], kind="invoice.created", webhook_message=self.message, validated_message=self.message, valid=True) customer_get.return_value = self.customer retrieve_mock.return_value = self.message['object'] event.process() customer_get.assert_called_once_with(stripe_id=self.customer.stripe_id) stripe_sync_mock.assert_called_once_with(self.message['object'], send_receipt=True) self.assertTrue(event.processed) @patch('djstripe.models.Customer.objects.get') @patch('stripe.Invoice.retrieve') @patch('djstripe.models.Invoice.sync_from_stripe_data') def test_process_invoice_event_ignored(self, stripe_sync_mock, retrieve_mock, customer_get): event = Event.objects.create(stripe_id=self.message["id"], kind="invoice.notanevent", webhook_message=self.message, validated_message=self.message, valid=True) customer_get.return_value = self.customer retrieve_mock.return_value = self.message['object'] event.process() self.assertFalse(stripe_sync_mock.called) self.assertTrue(event.processed) @patch('djstripe.models.Customer.objects.get') @patch('stripe.Invoice.retrieve') @patch('djstripe.models.Invoice.sync_from_stripe_data') def test_process_invoice_event_badcustomer(self, stripe_sync_mock, retrieve_mock, customer_get): event = Event.objects.create(stripe_id=self.message["id"], kind="invoice.created", webhook_message=self.message, validated_message=self.message, valid=True) customer_get.side_effect = Customer.DoesNotExist() retrieve_mock.return_value = self.message['object'] event.process() customer_get.assert_called_once_with(stripe_id=self.customer.stripe_id) stripe_sync_mock.assert_called_once_with(self.message['object'], send_receipt=True) self.assertTrue(event.processed) @patch('stripe.Charge.retrieve', return_value='hello') @patch('djstripe.models.Charge.sync_from_stripe_data') def test_process_charge_event(self, record_charge_mock, retrieve_mock): event = Event.objects.create(stripe_id=self.message["id"], kind="charge.created", webhook_message=self.message, validated_message=self.message, valid=True) event.process() self.assertEqual(event.customer, self.customer) retrieve_mock.assert_called_once_with( self.message["data"]["object"]["id"]) record_charge_mock.assert_called_once_with("hello") self.assertTrue(event.processed) @patch('djstripe.models.Customer.sync_current_subscription') def test_customer_subscription_event(self, sync_current_subscription_mock): event = Event.objects.create(stripe_id=self.message["id"], kind="customer.subscription.created", webhook_message=self.message, validated_message=self.message, valid=True) event.process() sync_current_subscription_mock.assert_called_once_with() self.assertTrue(event.processed) @patch('djstripe.models.Customer.sync_current_subscription') def test_customer_subscription_event_no_customer( self, sync_current_subscription_mock): self.message["data"]["object"]["customer"] = None event = Event.objects.create(stripe_id=self.message["id"], kind="customer.subscription.created", webhook_message=self.message, validated_message=self.message, valid=True) event.process() self.assertFalse(sync_current_subscription_mock.called) self.assertTrue(event.processed) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=fake_current_subscription) def test_customer_subscription_deleted_event(self, current_subscription_mock): event = Event.objects.create(stripe_id=self.message["id"], kind="customer.subscription.deleted", webhook_message=self.message, validated_message=self.message, valid=True) event.process() self.assertTrue(current_subscription_mock.status, CurrentSubscription.STATUS_CANCELLED) self.assertTrue(event.processed) @patch("stripe.Customer.retrieve") def test_process_customer_deleted(self, customer_retrieve_mock): msg = { "created": 1348286560, "data": { "object": { "account_balance": 0, "active_card": None, "created": 1348286302, "delinquent": False, "description": None, "discount": None, "email": "*****@*****.**", "id": "cus_xxxxxxxxxxxxxxx", "livemode": True, "object": "customer", "subscription": None } }, "id": "evt_xxxxxxxxxxxxx", "livemode": True, "object": "event", "pending_webhooks": 1, "type": "customer.deleted" } event = Event.objects.create(stripe_id=msg["id"], kind="customer.deleted", livemode=True, webhook_message=msg, validated_message=msg, valid=True) event.process() self.assertEquals(event.customer, self.customer) self.assertEquals(event.customer.subscriber, None) self.assertTrue(event.processed) def test_invalid_event_kind(self): """Should just fail silently and not do anything.""" event = Event.objects.create(stripe_id=self.message["id"], kind="fake.event.kind", webhook_message=self.message, validated_message=self.message, valid=True) event.process() self.assertTrue(event.processed) @patch('djstripe.models.EventProcessingException.log') @patch('djstripe.models.Event.send_signal', side_effect=stripe.StripeError()) def test_stripe_error(self, send_signal_mock, event_exception_log): event = Event.objects.create(stripe_id=self.message["id"], kind="fake.event.kind", webhook_message=self.message, validated_message=self.message, valid=True) event.process() self.assertTrue(event_exception_log.called) self.assertFalse(event.processed)
class ConfirmFormViewTest(TestCase): fake_stripe_customer_id = "cus_xxx1234567890" def setUp(self): self.plan = "test0" self.url = reverse("djstripe:confirm", kwargs={'plan': self.plan}) self.user = get_user_model().objects.create_user( username="******", email="*****@*****.**", password="******") self.assertTrue(self.client.login(username="******", password="******")) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=CurrentSubscription(plan="something-else")) @patch("stripe.Customer.create", return_value=PropertyMock(id=fake_stripe_customer_id)) def test_get_form_valid(self, djstripe_customer_customer_subscription_mock, stripe_create_customer_mock): response = self.client.get(self.url) self.assertEqual(200, response.status_code) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=CurrentSubscription(plan="test0")) @patch("stripe.Customer.create", return_value=PropertyMock(id=fake_stripe_customer_id)) def test_get_form_unknown(self, djstripe_customer_customer_subscription_mock, stripe_create_customer_mock): response = self.client.get( reverse("djstripe:confirm", kwargs={'plan': 'does-not-exist'})) self.assertRedirects(response, reverse("djstripe:subscribe")) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=CurrentSubscription(plan="test0")) @patch("stripe.Customer.create", return_value=PropertyMock(id=fake_stripe_customer_id)) def test_get_form_invalid(self, djstripe_customer_customer_subscription_mock, stripe_create_customer_mock): response = self.client.get(self.url) self.assertRedirects(response, reverse("djstripe:subscribe")) @patch("djstripe.models.Customer.subscribe", autospec=True) @patch("djstripe.models.Customer.update_card", autospec=True) @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890")) def test_post_valid(self, stripe_customer_mock, update_card_mock, subscribe_mock): self.assertEqual(0, Customer.objects.count()) response = self.client.post(self.url, { "plan": self.plan, "stripe_token": "cake" }) self.assertEqual(1, Customer.objects.count()) update_card_mock.assert_called_once_with(self.user.customer, "cake") subscribe_mock.assert_called_once_with(self.user.customer, self.plan) self.assertRedirects(response, reverse("djstripe:history")) @patch("djstripe.models.Customer.subscribe", autospec=True) @patch("djstripe.models.Customer.update_card", autospec=True) @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890")) def test_post_no_card(self, stripe_customer_mock, update_card_mock, subscribe_mock): update_card_mock.side_effect = stripe.StripeError( "Invalid source object:") response = self.client.post(self.url, {"plan": self.plan}) self.assertEqual(200, response.status_code) self.assertIn("form", response.context) self.assertIn("Invalid source object:", response.context["form"].errors["__all__"]) @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890")) def test_post_form_invalid(self, stripe_customer_mock): response = self.client.post(self.url) self.assertEqual(200, response.status_code) self.assertIn("plan", response.context["form"].errors) self.assertIn("This field is required.", response.context["form"].errors["plan"])
class TestCustomer(TestCase): fake_current_subscription = CurrentSubscription( plan="test_plan", quantity=1, start=timezone.now(), amount=decimal.Decimal(25.00)) def setUp(self): self.user = get_user_model().objects.create_user( username="******", email="*****@*****.**") self.customer = Customer.objects.create( subscriber=self.user, stripe_id="cus_xxxxxxxxxxxxxxx", card_fingerprint="YYYYYYYY", card_last_4="2342", card_kind="Visa") def test_tostring(self): self.assertEquals("<patrick, stripe_id=cus_xxxxxxxxxxxxxxx>", str(self.customer)) @patch("stripe.Customer.retrieve") def test_customer_purge_leaves_customer_record(self, customer_retrieve_fake): self.customer.purge() customer = Customer.objects.get(stripe_id=self.customer.stripe_id) self.assertTrue(customer.subscriber is None) self.assertTrue(customer.card_fingerprint == "") self.assertTrue(customer.card_last_4 == "") self.assertTrue(customer.card_kind == "") self.assertTrue( get_user_model().objects.filter(pk=self.user.pk).exists()) @patch("stripe.Customer.retrieve") def test_customer_delete_same_as_purge(self, customer_retrieve_fake): self.customer.delete() customer = Customer.objects.get(stripe_id=self.customer.stripe_id) self.assertTrue(customer.subscriber is None) self.assertTrue(customer.card_fingerprint == "") self.assertTrue(customer.card_last_4 == "") self.assertTrue(customer.card_kind == "") self.assertTrue( get_user_model().objects.filter(pk=self.user.pk).exists()) @patch("stripe.Customer.retrieve") def test_customer_purge_raises_customer_exception(self, customer_retrieve_mock): customer_retrieve_mock.side_effect = stripe.InvalidRequestError( "No such customer:", "blah") self.customer.purge() customer = Customer.objects.get(stripe_id=self.customer.stripe_id) self.assertTrue(customer.subscriber is None) self.assertTrue(customer.card_fingerprint == "") self.assertTrue(customer.card_last_4 == "") self.assertTrue(customer.card_kind == "") self.assertTrue( get_user_model().objects.filter(pk=self.user.pk).exists()) customer_retrieve_mock.assert_called_once_with(self.customer.stripe_id) @patch("stripe.Customer.retrieve") def test_customer_delete_raises_unexpected_exception( self, customer_retrieve_mock): customer_retrieve_mock.side_effect = stripe.InvalidRequestError( "Unexpected Exception", "blah") with self.assertRaisesMessage(stripe.InvalidRequestError, "Unexpected Exception"): self.customer.purge() customer_retrieve_mock.assert_called_once_with(self.customer.stripe_id) def test_change_charge(self): self.assertTrue(self.customer.can_charge()) @patch("stripe.Customer.retrieve") def test_cannot_charge(self, customer_retrieve_fake): self.customer.delete() self.assertFalse(self.customer.can_charge()) def test_charge_accepts_only_decimals(self): with self.assertRaises(ValueError): self.customer.charge(10) @patch("stripe.Charge.retrieve") def test_record_charge(self, charge_retrieve_mock): charge_retrieve_mock.return_value = { "id": "ch_XXXXXX", "card": { "last4": "4323", "type": "Visa" }, "amount": 1000, "paid": True, "refunded": False, "captured": True, "fee": 499, "dispute": None, "created": 1363911708, "customer": "cus_xxxxxxxxxxxxxxx" } obj = self.customer.record_charge("ch_XXXXXX") self.assertEquals(Charge.objects.get(stripe_id="ch_XXXXXX").pk, obj.pk) self.assertEquals(obj.paid, True) self.assertEquals(obj.disputed, False) self.assertEquals(obj.refunded, False) self.assertEquals(obj.amount_refunded, None) @patch("stripe.Charge.retrieve") def test_refund_charge(self, charge_retrieve_mock): 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) charge_retrieve_mock.return_value.refund.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" } charge.refund() charge2 = Charge.objects.get(stripe_id="ch_XXXXXX") self.assertEquals(charge2.refunded, True) self.assertEquals(charge2.amount_refunded, decimal.Decimal("10.00")) @patch("stripe.Charge.retrieve") def test_capture_charge(self, charge_retrieve_mock): 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) charge_retrieve_mock.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, charge_retrieve_mock): 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) charge_retrieve_mock.return_value.refund.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.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", customer=self.customer, amount=decimal.Decimal("500.00")) self.assertEquals(charge.calculate_refund_amount(), 50000) def test_calculate_refund_amount_partial_refund(self): charge = Charge(stripe_id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00")) self.assertEquals( charge.calculate_refund_amount(amount=decimal.Decimal("300.00")), 30000) def test_calculate_refund_above_max_refund(self): charge = Charge(stripe_id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00")) self.assertEquals( charge.calculate_refund_amount(amount=decimal.Decimal("600.00")), 50000) @patch("stripe.Charge.retrieve") @patch("stripe.Charge.create") def test_charge_converts_dollars_into_cents(self, charge_create_mock, charge_retrieve_mock): charge_create_mock.return_value.id = "ch_XXXXX" charge_retrieve_mock.return_value = { "id": "ch_XXXXXX", "card": { "last4": "4323", "type": "Visa" }, "amount": 1000, "paid": True, "refunded": False, "captured": True, "fee": 499, "dispute": None, "created": 1363911708, "customer": "cus_xxxxxxxxxxxxxxx" } self.customer.charge(amount=decimal.Decimal("10.00")) _, kwargs = charge_create_mock.call_args self.assertEquals(kwargs["amount"], 1000) @patch("stripe.Charge.retrieve") @patch("stripe.Charge.create") def test_charge_passes_extra_arguments(self, charge_create_mock, charge_retrieve_mock): charge_create_mock.return_value.id = "ch_XXXXX" charge_retrieve_mock.return_value = { "id": "ch_XXXXXX", "card": { "last4": "4323", "type": "Visa" }, "amount": 1000, "paid": True, "refunded": False, "captured": True, "fee": 499, "dispute": None, "created": 1363911708, "customer": "cus_xxxxxxxxxxxxxxx" } self.customer.charge(amount=decimal.Decimal("10.00"), capture=True, destination='a_stripe_client_id') _, kwargs = charge_create_mock.call_args self.assertEquals(kwargs["capture"], True) self.assertEquals(kwargs["destination"], 'a_stripe_client_id') @patch( "djstripe.models.djstripe_settings.trial_period_for_subscriber_callback", return_value="donkey") @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890")) def test_create_trial_callback(self, customer_create_mock, callback_mock): user = get_user_model().objects.create_user(username="******", email="*****@*****.**") Customer.create(user) customer_create_mock.assert_called_once_with(email=user.email) callback_mock.assert_called_once_with(user) @patch("djstripe.models.Customer.subscribe") @patch("djstripe.models.djstripe_settings.DEFAULT_PLAN", new_callable=PropertyMock, return_value="schreck") @patch( "djstripe.models.djstripe_settings.trial_period_for_subscriber_callback", return_value="donkey") @patch("stripe.Customer.create", return_value=PropertyMock(id="cus_xxx1234567890")) def test_create_default_plan(self, customer_create_mock, callback_mock, default_plan_fake, subscribe_mock): user = get_user_model().objects.create_user(username="******", email="*****@*****.**") Customer.create(user) customer_create_mock.assert_called_once_with(email=user.email) callback_mock.assert_called_once_with(user) subscribe_mock.assert_called_once_with(plan=default_plan_fake, trial_days="donkey") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock) def test_update_card(self, customer_stripe_customer_mock): customer_stripe_customer_mock.return_value = PropertyMock( active_card=PropertyMock(fingerprint="test_fingerprint", last4="1234", type="test_type", exp_month=12, exp_year=2020)) self.customer.update_card("test") self.assertEqual("test_fingerprint", self.customer.card_fingerprint) self.assertEqual("1234", self.customer.card_last_4) self.assertEqual("test_type", self.customer.card_kind) self.assertEqual(12, self.customer.card_exp_month) self.assertEqual(2020, self.customer.card_exp_year) @patch( "djstripe.models.Customer.invoices", new_callable=PropertyMock, return_value=PropertyMock( name="filter", filter=MagicMock(return_value=[ MagicMock(name="inv", retry=MagicMock(name="retry", return_value="test")) ]))) @patch("djstripe.models.Customer.sync_invoices") def test_retry_unpaid_invoices(self, sync_invoices_mock, invoices_mock): self.customer.retry_unpaid_invoices() sync_invoices_mock.assert_called_once_with() # TODO: Figure out how to assert on filter and retry mocks @patch("djstripe.models.Customer.invoices", new_callable=PropertyMock, return_value=PropertyMock( name="filter", filter=MagicMock(return_value=[ MagicMock(name="inv", retry=MagicMock( name="retry", return_value="test", side_effect=stripe.InvalidRequestError( "Invoice is already paid", "blah"))) ]))) @patch("djstripe.models.Customer.sync_invoices") def test_retry_unpaid_invoices_expected_exception(self, sync_invoices_mock, invoices_mock): try: self.customer.retry_unpaid_invoices() except: self.fail("Exception was unexpectedly raise.") @patch("djstripe.models.Customer.invoices", new_callable=PropertyMock, return_value=PropertyMock( name="filter", filter=MagicMock(return_value=[ MagicMock(name="inv", retry=MagicMock( name="retry", return_value="test", side_effect=stripe.InvalidRequestError( "This should fail!", "blah"))) ]))) @patch("djstripe.models.Customer.sync_invoices") def test_retry_unpaid_invoices_unexpected_exception( self, sync_invoices_mock, invoices_mock): with self.assertRaisesMessage(stripe.InvalidRequestError, "This should fail!"): self.customer.retry_unpaid_invoices() @patch("stripe.Invoice.create") def test_send_invoice_success(self, invoice_create_mock): return_status = self.customer.send_invoice() self.assertTrue(return_status) invoice_create_mock.assert_called_once_with( customer=self.customer.stripe_id) @patch("stripe.Invoice.create") def test_send_invoice_failure(self, invoice_create_mock): invoice_create_mock.side_effect = stripe.InvalidRequestError( "Invoice creation failed.", "blah") return_status = self.customer.send_invoice() self.assertFalse(return_status) invoice_create_mock.assert_called_once_with( customer=self.customer.stripe_id) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock) def test_sync_active_card(self, stripe_customer_mock): stripe_customer_mock.return_value = PropertyMock( active_card=PropertyMock( fingerprint="cherry", last4="4429", type="apple", exp_month=12, exp_year=2020, )) self.customer.sync() self.assertEqual("cherry", self.customer.card_fingerprint) self.assertEqual("4429", self.customer.card_last_4) self.assertEqual("apple", self.customer.card_kind) self.assertEqual(12, self.customer.card_exp_month) self.assertEqual(2020, self.customer.card_exp_year) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(active_card=None)) def test_sync_no_card(self, stripe_customer_mock): self.customer.sync() self.assertEqual("YYYYYYYY", self.customer.card_fingerprint) self.assertEqual("2342", self.customer.card_last_4) self.assertEqual("Visa", self.customer.card_kind) @patch("djstripe.models.Invoice.sync_from_stripe_data") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(invoices=MagicMock( return_value=PropertyMock(data=["apple", "orange", "pear"])))) def test_sync_invoices(self, stripe_customer_mock, sync_from_stripe_data_mock): self.customer.sync_invoices() sync_from_stripe_data_mock.assert_any_call("apple", send_receipt=False) sync_from_stripe_data_mock.assert_any_call("orange", send_receipt=False) sync_from_stripe_data_mock.assert_any_call("pear", send_receipt=False) self.assertEqual(3, sync_from_stripe_data_mock.call_count) @patch("djstripe.models.Invoice.sync_from_stripe_data") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(invoices=MagicMock( return_value=PropertyMock(data=[])))) def test_sync_invoices_none(self, stripe_customer_mock, sync_from_stripe_data_mock): self.customer.sync_invoices() self.assertFalse(sync_from_stripe_data_mock.called) @patch("djstripe.models.Customer.record_charge") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(charges=MagicMock( return_value=PropertyMock(data=[ PropertyMock(id="herbst"), PropertyMock(id="winter"), PropertyMock(id="fruehling"), PropertyMock(id="sommer") ])))) def test_sync_charges(self, stripe_customer_mock, record_charge_mock): self.customer.sync_charges() record_charge_mock.assert_any_call("herbst") record_charge_mock.assert_any_call("winter") record_charge_mock.assert_any_call("fruehling") record_charge_mock.assert_any_call("sommer") self.assertEqual(4, record_charge_mock.call_count) @patch("djstripe.models.Customer.record_charge") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(charges=MagicMock( return_value=PropertyMock(data=[])))) def test_sync_charges_none(self, stripe_customer_mock, record_charge_mock): self.customer.sync_charges() self.assertFalse(record_charge_mock.called) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(subscription=None)) def test_sync_current_subscription_no_stripe_subscription( self, stripe_customer_mock): self.assertEqual(None, self.customer.sync_current_subscription()) @patch("djstripe.models.djstripe_settings.plan_from_stripe_id", return_value="test_plan") @patch("djstripe.models.convert_tstamp", return_value=timezone.make_aware(datetime.datetime(2015, 6, 19))) @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=fake_current_subscription) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock(subscription=PropertyMock( plan=PropertyMock(id="fish", amount=5000), quantity=5, trial_start=False, trial_end=False, cancel_at_period_end=False, status="tree"))) def test_sync_current_subscription_update_no_trial( self, stripe_customer_mock, customer_subscription_mock, convert_tstamp_fake, plan_getter_mock): tz_test_time = timezone.make_aware(datetime.datetime(2015, 6, 19)) self.customer.sync_current_subscription() plan_getter_mock.assert_called_with("fish") self.assertEqual("test_plan", self.fake_current_subscription.plan) self.assertEqual(decimal.Decimal("50.00"), self.fake_current_subscription.amount) self.assertEqual("tree", self.fake_current_subscription.status) self.assertEqual(5, self.fake_current_subscription.quantity) self.assertEqual(False, self.fake_current_subscription.cancel_at_period_end) self.assertEqual(tz_test_time, self.fake_current_subscription.canceled_at) self.assertEqual(tz_test_time, self.fake_current_subscription.start) self.assertEqual(tz_test_time, self.fake_current_subscription.current_period_start) self.assertEqual(tz_test_time, self.fake_current_subscription.current_period_end) self.assertEqual(None, self.fake_current_subscription.trial_start) self.assertEqual(None, self.fake_current_subscription.trial_end) @patch("djstripe.models.Customer.send_invoice") @patch("djstripe.models.Customer.sync_current_subscription") @patch("djstripe.models.Customer.stripe_customer.update_subscription") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock()) def test_subscribe_trial_plan(self, stripe_customer_mock, update_subscription_mock, sync_subscription_mock, send_invoice_mock): trial_days = 7 # From settings self.customer.subscribe(plan="test_trial") sync_subscription_mock.assert_called_once_with() send_invoice_mock.assert_called_once_with() _, call_kwargs = update_subscription_mock.call_args self.assertIn("trial_end", call_kwargs) self.assertLess(call_kwargs["trial_end"], timezone.now() + datetime.timedelta(days=trial_days)) @patch("djstripe.models.Customer.send_invoice") @patch("djstripe.models.Customer.sync_current_subscription") @patch("djstripe.models.Customer.stripe_customer.update_subscription") @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock()) def test_subscribe_trial_days_kwarg(self, stripe_customer_mock, update_subscription_mock, sync_subscription_mock, send_invoice_mock): trial_days = 9 self.customer.subscribe(plan="test", trial_days=trial_days) sync_subscription_mock.assert_called_once_with() send_invoice_mock.assert_called_once_with() _, call_kwargs = update_subscription_mock.call_args self.assertIn("trial_end", call_kwargs) self.assertLess(call_kwargs["trial_end"], timezone.now() + datetime.timedelta(days=trial_days)) @patch("djstripe.models.Customer.send_invoice") @patch("djstripe.models.Customer.sync_current_subscription") @patch("djstripe.models.Customer.current_subscription", new_callable=PropertyMock, return_value=fake_current_subscription) @patch("djstripe.models.Customer.stripe_customer", new_callable=PropertyMock, return_value=PropertyMock()) def test_subscribe_not_charge_immediately(self, stripe_customer_mock, customer_subscription_mock, sync_subscription_mock, send_invoice_mock): self.customer.subscribe(plan="test", charge_immediately=False) sync_subscription_mock.assert_called_once_with() self.assertFalse(send_invoice_mock.called) @patch("djstripe.models.Charge.send_receipt") @patch("djstripe.models.Customer.record_charge", return_value=Charge()) @patch("stripe.Charge.create", return_value={"id": "test_charge_id"}) def test_charge_not_send_receipt(self, charge_create_mock, record_charge_mock, send_receipt_mock): self.customer.charge(amount=decimal.Decimal("50.00"), send_receipt=False) self.assertTrue(charge_create_mock.called) record_charge_mock.assert_called_once_with("test_charge_id") self.assertFalse(send_receipt_mock.called) @patch("stripe.InvoiceItem.create") def test_add_invoice_item(self, invoice_item_create_mock): self.customer.add_invoice_item(amount=decimal.Decimal("50.00"), currency="eur", invoice_id=77, description="test") invoice_item_create_mock.assert_called_once_with( amount=5000, currency="eur", invoice=77, description="test", customer=self.customer.stripe_id) def test_add_invoice_item_bad_decimal(self): with self.assertRaisesMessage( ValueError, "You must supply a decimal value representing dollars."): self.customer.add_invoice_item(amount=5000)