from unittest.mock import patch
|
|
|
|
from hc.payments.models import Subscription
|
|
from hc.test import BaseTestCase
|
|
|
|
|
|
class UpdateSubscriptionTestCase(BaseTestCase):
|
|
def _setup_mock(self, mock):
|
|
""" Set up Braintree calls that the controller will use. """
|
|
|
|
mock.Subscription.create.return_value.is_success = True
|
|
mock.Subscription.create.return_value.subscription.id = "t-sub-id"
|
|
|
|
def run_update(self, plan_id="P20", nonce="fake-nonce"):
|
|
form = {"plan_id": plan_id, "nonce": nonce}
|
|
self.client.login(username="[email protected]", password="password")
|
|
return self.client.post("/pricing/update/", form, follow=True)
|
|
|
|
@patch("hc.payments.models.braintree")
|
|
def test_it_works(self, mock):
|
|
self._setup_mock(mock)
|
|
|
|
self.profile.sms_limit = 0
|
|
self.profile.sms_sent = 1
|
|
self.profile.save()
|
|
|
|
r = self.run_update()
|
|
self.assertRedirects(r, "/accounts/profile/billing/")
|
|
self.assertContains(r, "Your billing plan has been updated!")
|
|
|
|
# Subscription should be filled out:
|
|
sub = Subscription.objects.get(user=self.alice)
|
|
self.assertEqual(sub.subscription_id, "t-sub-id")
|
|
self.assertEqual(sub.plan_id, "P20")
|
|
self.assertEqual(sub.plan_name, "Business ($20 / month)")
|
|
|
|
# User's profile should have a higher limits
|
|
self.profile.refresh_from_db()
|
|
self.assertEqual(self.profile.ping_log_limit, 1000)
|
|
self.assertEqual(self.profile.check_limit, 100)
|
|
self.assertEqual(self.profile.team_limit, 9)
|
|
self.assertEqual(self.profile.sms_limit, 50)
|
|
self.assertEqual(self.profile.sms_sent, 0)
|
|
|
|
# braintree.Subscription.cancel should have not been called
|
|
# because there was no previous subscription
|
|
self.assertFalse(mock.Subscription.cancel.called)
|
|
|
|
self.assertTrue(mock.Subscription.create.called)
|
|
|
|
@patch("hc.payments.models.braintree")
|
|
def test_supporter_works(self, mock):
|
|
self._setup_mock(mock)
|
|
|
|
self.profile.sms_limit = 0
|
|
self.profile.sms_sent = 1
|
|
self.profile.save()
|
|
|
|
r = self.run_update("S5")
|
|
self.assertRedirects(r, "/accounts/profile/billing/")
|
|
|
|
# Subscription should be filled out:
|
|
sub = Subscription.objects.get(user=self.alice)
|
|
self.assertEqual(sub.subscription_id, "t-sub-id")
|
|
self.assertEqual(sub.plan_id, "S5")
|
|
self.assertEqual(sub.plan_name, "Supporter ($5 / month)")
|
|
|
|
# User's profile should have adjusted limits
|
|
self.profile.refresh_from_db()
|
|
self.assertEqual(self.profile.ping_log_limit, 1000)
|
|
self.assertEqual(self.profile.check_limit, 20)
|
|
self.assertEqual(self.profile.team_limit, 2)
|
|
self.assertEqual(self.profile.sms_limit, 5)
|
|
self.assertEqual(self.profile.sms_sent, 0)
|
|
|
|
# braintree.Subscription.cancel should have not been called
|
|
assert not mock.Subscription.cancel.called
|
|
|
|
@patch("hc.payments.models.braintree")
|
|
def test_yearly_works(self, mock):
|
|
self._setup_mock(mock)
|
|
|
|
self.profile.sms_limit = 0
|
|
self.profile.sms_sent = 1
|
|
self.profile.save()
|
|
|
|
r = self.run_update("Y192")
|
|
self.assertRedirects(r, "/accounts/profile/billing/")
|
|
|
|
# Subscription should be filled out:
|
|
sub = Subscription.objects.get(user=self.alice)
|
|
self.assertEqual(sub.subscription_id, "t-sub-id")
|
|
self.assertEqual(sub.plan_id, "Y192")
|
|
self.assertEqual(sub.plan_name, "Business ($192 / year)")
|
|
|
|
# User's profile should have a higher limits
|
|
self.profile.refresh_from_db()
|
|
self.assertEqual(self.profile.ping_log_limit, 1000)
|
|
self.assertEqual(self.profile.check_limit, 100)
|
|
self.assertEqual(self.profile.team_limit, 9)
|
|
self.assertEqual(self.profile.sms_limit, 50)
|
|
self.assertEqual(self.profile.sms_sent, 0)
|
|
|
|
# braintree.Subscription.cancel should have not been called
|
|
assert not mock.Subscription.cancel.called
|
|
|
|
@patch("hc.payments.models.braintree")
|
|
def test_plus_works(self, mock):
|
|
self._setup_mock(mock)
|
|
|
|
self.profile.sms_limit = 0
|
|
self.profile.sms_sent = 1
|
|
self.profile.save()
|
|
|
|
r = self.run_update("P80")
|
|
self.assertRedirects(r, "/accounts/profile/billing/")
|
|
|
|
# Subscription should be filled out:
|
|
sub = Subscription.objects.get(user=self.alice)
|
|
self.assertEqual(sub.subscription_id, "t-sub-id")
|
|
self.assertEqual(sub.plan_id, "P80")
|
|
self.assertEqual(sub.plan_name, "Business Plus ($80 / month)")
|
|
|
|
# User's profile should have a higher limits
|
|
self.profile.refresh_from_db()
|
|
self.assertEqual(self.profile.ping_log_limit, 1000)
|
|
self.assertEqual(self.profile.check_limit, 1000)
|
|
self.assertEqual(self.profile.team_limit, 500)
|
|
self.assertEqual(self.profile.sms_limit, 500)
|
|
self.assertEqual(self.profile.sms_sent, 0)
|
|
|
|
# braintree.Subscription.cancel should have not been called
|
|
assert not mock.Subscription.cancel.called
|
|
|
|
@patch("hc.payments.models.braintree")
|
|
def test_it_cancels(self, mock):
|
|
self._setup_mock(mock)
|
|
|
|
self.sub = Subscription(user=self.alice)
|
|
self.sub.subscription_id = "test-id"
|
|
self.sub.plan_id = "P20"
|
|
self.sub.plan_name = "Business ($20/mo)"
|
|
self.sub.save()
|
|
|
|
self.profile.sms_limit = 1
|
|
self.profile.sms_sent = 1
|
|
self.profile.save()
|
|
|
|
r = self.run_update("")
|
|
self.assertRedirects(r, "/accounts/profile/billing/")
|
|
self.assertContains(r, "Your billing plan has been updated!")
|
|
|
|
# Subscription should be cleared
|
|
sub = Subscription.objects.get(user=self.alice)
|
|
self.assertEqual(sub.subscription_id, "")
|
|
self.assertEqual(sub.plan_id, "")
|
|
self.assertEqual(sub.plan_name, "")
|
|
|
|
# User's profile should have standard limits
|
|
self.profile.refresh_from_db()
|
|
self.assertEqual(self.profile.ping_log_limit, 100)
|
|
self.assertEqual(self.profile.check_limit, 20)
|
|
self.assertEqual(self.profile.team_limit, 2)
|
|
self.assertEqual(self.profile.sms_limit, 5)
|
|
|
|
self.assertTrue(mock.Subscription.cancel.called)
|
|
|
|
def test_bad_plan_id(self):
|
|
r = self.run_update(plan_id="this-is-wrong")
|
|
self.assertEqual(r.status_code, 400)
|
|
|
|
@patch("hc.payments.models.braintree")
|
|
def test_it_cancels_previous_subscription(self, mock):
|
|
self._setup_mock(mock)
|
|
|
|
sub = Subscription(user=self.alice)
|
|
sub.subscription_id = "prev-sub"
|
|
sub.save()
|
|
|
|
r = self.run_update()
|
|
self.assertRedirects(r, "/accounts/profile/billing/")
|
|
self.assertTrue(mock.Subscription.cancel.called)
|
|
|
|
@patch("hc.payments.models.braintree")
|
|
def test_subscription_creation_failure(self, mock):
|
|
mock.Subscription.create.return_value.is_success = False
|
|
mock.Subscription.create.return_value.message = "sub failure"
|
|
|
|
r = self.run_update()
|
|
self.assertRedirects(r, "/accounts/profile/billing/")
|
|
self.assertContains(r, "sub failure")
|
|
|
|
@patch("hc.payments.models.braintree")
|
|
def test_failed_plan_change_resets_limits(self, mock):
|
|
# Initial state: the user has a subscription and a high check limit:
|
|
sub = Subscription.objects.for_user(self.alice)
|
|
sub.subscription_id = "old-sub-id"
|
|
sub.save()
|
|
|
|
self.profile.check_limit = 1000
|
|
self.profile.save()
|
|
|
|
# Simulate a subscription creation failure:
|
|
mock.Subscription.create.return_value.is_success = False
|
|
mock.Subscription.create.return_value.message = "sub failure"
|
|
|
|
r = self.run_update()
|
|
|
|
# It should cancel the current plan
|
|
self.assertTrue(mock.Subscription.cancel.called)
|
|
|
|
# It should clear out the limits:
|
|
self.profile.refresh_from_db()
|
|
self.assertEqual(self.profile.check_limit, 20)
|
|
|
|
# And it should show the error message from API:
|
|
self.assertRedirects(r, "/accounts/profile/billing/")
|
|
self.assertContains(r, "sub failure")
|
|
|
|
@patch("hc.payments.models.braintree")
|
|
def test_it_updates_payment_method(self, mock):
|
|
# Initial state: the user has a subscription and a high check limit:
|
|
sub = Subscription.objects.for_user(self.alice)
|
|
sub.plan_id = "P20"
|
|
sub.subscription_id = "old-sub-id"
|
|
sub.save()
|
|
|
|
r = self.run_update()
|
|
|
|
# It should update the existing subscription
|
|
self.assertTrue(mock.Subscription.update.called)
|
|
self.assertRedirects(r, "/accounts/profile/billing/")
|
|
self.assertContains(r, "Your payment method has been updated!")
|