billing: Use UserProfile.is_billing_admin instead of Customer.billing_user.

This commit is contained in:
Vishnu Ks 2018-08-22 11:19:48 +05:30 committed by Tim Abbott
parent 6f57cd4d23
commit dcb7b15069
5 changed files with 33 additions and 7 deletions

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.14 on 2018-08-22 05:45
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('zerver', '0186_userprofile_starred_message_counts'),
]
operations = [
migrations.AddField(
model_name='userprofile',
name='is_billing_admin',
field=models.BooleanField(db_index=True, default=False),
),
]

View File

@ -690,6 +690,7 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
is_active = models.BooleanField(default=True, db_index=True) # type: bool is_active = models.BooleanField(default=True, db_index=True) # type: bool
is_realm_admin = models.BooleanField(default=False, db_index=True) # type: bool is_realm_admin = models.BooleanField(default=False, db_index=True) # type: bool
is_billing_admin = models.BooleanField(default=False, db_index=True) # type: bool
# Guest users are limited users without default access to public streams (etc.) # Guest users are limited users without default access to public streams (etc.)
is_guest = models.BooleanField(default=False, db_index=True) # type: bool is_guest = models.BooleanField(default=False, db_index=True) # type: bool

View File

@ -168,6 +168,8 @@ def do_create_customer(user: UserProfile, stripe_token: Optional[str]=None,
realm=realm, realm=realm,
stripe_customer_id=stripe_customer.id, stripe_customer_id=stripe_customer.id,
billing_user=user) billing_user=user)
user.is_billing_admin = True
user.save(update_fields=["is_billing_admin"])
return stripe_customer return stripe_customer
@catch_stripe_errors @catch_stripe_errors
@ -190,7 +192,7 @@ def do_replace_coupon(user: UserProfile, coupon: Coupon) -> stripe.Customer:
return stripe_customer.save() return stripe_customer.save()
@catch_stripe_errors @catch_stripe_errors
def do_subscribe_customer_to_plan(stripe_customer: stripe.Customer, stripe_plan_id: str, def do_subscribe_customer_to_plan(user: UserProfile, stripe_customer: stripe.Customer, stripe_plan_id: str,
seat_count: int, tax_percent: float) -> None: seat_count: int, tax_percent: float) -> None:
if extract_current_subscription(stripe_customer) is not None: if extract_current_subscription(stripe_customer) is not None:
# Most likely due to two people in the org going to the billing page, # Most likely due to two people in the org going to the billing page,
@ -227,7 +229,7 @@ def do_subscribe_customer_to_plan(stripe_customer: stripe.Customer, stripe_plan_
customer.realm.save(update_fields=['has_seat_based_plan']) customer.realm.save(update_fields=['has_seat_based_plan'])
RealmAuditLog.objects.create( RealmAuditLog.objects.create(
realm=customer.realm, realm=customer.realm,
acting_user=customer.billing_user, acting_user=user,
event_type=RealmAuditLog.STRIPE_PLAN_CHANGED, event_type=RealmAuditLog.STRIPE_PLAN_CHANGED,
event_time=timestamp_to_datetime(stripe_subscription.created), event_time=timestamp_to_datetime(stripe_subscription.created),
extra_data=ujson.dumps({'plan': stripe_plan_id, 'quantity': seat_count})) extra_data=ujson.dumps({'plan': stripe_plan_id, 'quantity': seat_count}))
@ -248,6 +250,7 @@ def process_initial_upgrade(user: UserProfile, plan: Plan, seat_count: int, stri
else: else:
stripe_customer = do_replace_payment_source(user, stripe_token) stripe_customer = do_replace_payment_source(user, stripe_token)
do_subscribe_customer_to_plan( do_subscribe_customer_to_plan(
user=user,
stripe_customer=stripe_customer, stripe_customer=stripe_customer,
stripe_plan_id=plan.stripe_plan_id, stripe_plan_id=plan.stripe_plan_id,
seat_count=seat_count, seat_count=seat_count,

View File

@ -177,11 +177,11 @@ class StripeTest(ZulipTestCase):
# Check that the non-admin hamlet can still access /billing # Check that the non-admin hamlet can still access /billing
response = self.client_get("/billing/") response = self.client_get("/billing/")
self.assert_in_success_response(["for billing history or to make changes"], response) self.assert_in_success_response(["for billing history or to make changes"], response)
# Check admins can access billing, even though they are not the billing_user # Check admins can access billing, even though they are not a billing admin
self.login(self.example_email('iago')) self.login(self.example_email('iago'))
response = self.client_get("/billing/") response = self.client_get("/billing/")
self.assert_in_success_response(["for billing history or to make changes"], response) self.assert_in_success_response(["for billing history or to make changes"], response)
# Check that non-admin, non-billing_user does not have access # Check that a non-admin, non-billing admin user does not have access
self.login(self.example_email("cordelia")) self.login(self.example_email("cordelia"))
response = self.client_get("/billing/") response = self.client_get("/billing/")
self.assert_in_success_response(["You must be an organization administrator"], response) self.assert_in_success_response(["You must be an organization administrator"], response)
@ -310,7 +310,7 @@ class StripeTest(ZulipTestCase):
@mock.patch("stripe.Invoice.upcoming", side_effect=mock_upcoming_invoice) @mock.patch("stripe.Invoice.upcoming", side_effect=mock_upcoming_invoice)
def test_billing_home(self, mock_upcoming_invoice: mock.Mock, def test_billing_home(self, mock_upcoming_invoice: mock.Mock,
mock_customer_with_subscription: mock.Mock) -> None: mock_customer_with_subscription: mock.Mock) -> None:
user = self.example_user("hamlet") user = self.example_user("iago")
self.login(user.email) self.login(user.email)
# No Customer yet; check that we are redirected to /upgrade # No Customer yet; check that we are redirected to /upgrade
response = self.client_get("/billing/") response = self.client_get("/billing/")
@ -320,6 +320,7 @@ class StripeTest(ZulipTestCase):
Customer.objects.create( Customer.objects.create(
realm=user.realm, stripe_customer_id=self.stripe_customer_id, billing_user=user, realm=user.realm, stripe_customer_id=self.stripe_customer_id, billing_user=user,
has_billing_relationship=True) has_billing_relationship=True)
response = self.client_get("/billing/") response = self.client_get("/billing/")
self.assert_not_in_success_response(['We can also bill by invoice'], response) self.assert_not_in_success_response(['We can also bill by invoice'], response)
for substring in ['Your plan will renew on', '$%s.00' % (80 * self.quantity,), for substring in ['Your plan will renew on', '$%s.00' % (80 * self.quantity,),
@ -350,7 +351,8 @@ class StripeTest(ZulipTestCase):
def test_subscribe_customer_to_second_plan(self) -> None: def test_subscribe_customer_to_second_plan(self) -> None:
with self.assertRaisesRegex(BillingError, 'subscribing with existing subscription'): with self.assertRaisesRegex(BillingError, 'subscribing with existing subscription'):
do_subscribe_customer_to_plan(mock_customer_with_subscription(), do_subscribe_customer_to_plan(self.example_user("iago"),
mock_customer_with_subscription(),
self.stripe_plan_id, self.quantity, 0) self.stripe_plan_id, self.quantity, 0)
def test_sign_string(self) -> None: def test_sign_string(self) -> None:

View File

@ -236,7 +236,7 @@ def billing_home(request: HttpRequest) -> HttpResponse:
if not customer.has_billing_relationship: if not customer.has_billing_relationship:
return HttpResponseRedirect(reverse('zilencer.views.initial_upgrade')) return HttpResponseRedirect(reverse('zilencer.views.initial_upgrade'))
if not user.is_realm_admin and not user == customer.billing_user: if not user.is_realm_admin and not user.is_billing_admin:
context = {'admin_access': False} # type: Dict[str, Any] context = {'admin_access': False} # type: Dict[str, Any]
return render(request, 'zilencer/billing.html', context=context) return render(request, 'zilencer/billing.html', context=context)
context = {'admin_access': True} context = {'admin_access': True}