mirror of https://github.com/zulip/zulip.git
billing: Rename seat_count to licenses where appropriate.
This commit is contained in:
parent
7ab1406962
commit
b4a28f3147
|
@ -35,7 +35,7 @@ log_to_file(logging.getLogger('stripe'), BILLING_LOG_PATH)
|
|||
|
||||
CallableT = TypeVar('CallableT', bound=Callable[..., Any])
|
||||
|
||||
MIN_INVOICED_SEAT_COUNT = 30
|
||||
MIN_INVOICED_LICENSES = 30
|
||||
DEFAULT_INVOICE_DAYS_UNTIL_DUE = 30
|
||||
|
||||
def get_seat_count(realm: Realm) -> int:
|
||||
|
|
|
@ -28,7 +28,7 @@ from corporate.lib.stripe import catch_stripe_errors, \
|
|||
do_subscribe_customer_to_plan, attach_discount_to_realm, \
|
||||
get_seat_count, extract_current_subscription, sign_string, unsign_string, \
|
||||
BillingError, StripeCardError, StripeConnectionError, stripe_get_customer, \
|
||||
DEFAULT_INVOICE_DAYS_UNTIL_DUE, MIN_INVOICED_SEAT_COUNT, do_create_customer
|
||||
DEFAULT_INVOICE_DAYS_UNTIL_DUE, MIN_INVOICED_LICENSES, do_create_customer
|
||||
from corporate.models import Customer, CustomerPlan, Plan, Coupon
|
||||
from corporate.views import payment_method_string
|
||||
import corporate.urls
|
||||
|
@ -250,7 +250,7 @@ class StripeTest(ZulipTestCase):
|
|||
'schedule': 'annual'} # type: Dict[str, Any]
|
||||
if invoice: # send_invoice
|
||||
params.update({
|
||||
'invoiced_seat_count': 123,
|
||||
'licenses': 123,
|
||||
'billing_modality': 'send_invoice'})
|
||||
else: # charge_automatically
|
||||
stripe_token = None
|
||||
|
@ -482,19 +482,19 @@ class StripeTest(ZulipTestCase):
|
|||
|
||||
def test_upgrade_with_insufficient_invoiced_seat_count(self) -> None:
|
||||
self.login(self.example_email("hamlet"))
|
||||
# Test invoicing for less than MIN_INVOICED_SEAT_COUNT
|
||||
# Test invoicing for less than MIN_INVOICED_LICENSES
|
||||
response = self.upgrade(invoice=True, talk_to_stripe=False,
|
||||
invoiced_seat_count=MIN_INVOICED_SEAT_COUNT - 1)
|
||||
self.assert_json_error_contains(response, "at least {} users.".format(MIN_INVOICED_SEAT_COUNT))
|
||||
self.assertEqual(ujson.loads(response.content)['error_description'], 'lowball seat count')
|
||||
licenses=MIN_INVOICED_LICENSES - 1)
|
||||
self.assert_json_error_contains(response, "at least {} users.".format(MIN_INVOICED_LICENSES))
|
||||
self.assertEqual(ujson.loads(response.content)['error_description'], 'not enough licenses')
|
||||
# Test invoicing for less than your user count
|
||||
with patch("corporate.views.MIN_INVOICED_SEAT_COUNT", 3):
|
||||
response = self.upgrade(invoice=True, talk_to_stripe=False, invoiced_seat_count=4)
|
||||
with patch("corporate.views.MIN_INVOICED_LICENSES", 3):
|
||||
response = self.upgrade(invoice=True, talk_to_stripe=False, licenses=4)
|
||||
self.assert_json_error_contains(response, "at least {} users.".format(self.seat_count))
|
||||
self.assertEqual(ujson.loads(response.content)['error_description'], 'lowball seat count')
|
||||
# Test not setting invoiced_seat_count
|
||||
response = self.upgrade(invoice=True, talk_to_stripe=False, invoiced_seat_count=None)
|
||||
self.assert_json_error_contains(response, "invoiced_seat_count is not an integer")
|
||||
self.assertEqual(ujson.loads(response.content)['error_description'], 'not enough licenses')
|
||||
# Test not setting licenses
|
||||
response = self.upgrade(invoice=True, talk_to_stripe=False, licenses=None)
|
||||
self.assert_json_error_contains(response, "licenses is not an integer")
|
||||
|
||||
@patch("corporate.lib.stripe.billing_logger.error")
|
||||
def test_upgrade_with_uncaught_exception(self, mock_: Mock) -> None:
|
||||
|
|
|
@ -21,7 +21,7 @@ from corporate.lib.stripe import STRIPE_PUBLISHABLE_KEY, \
|
|||
stripe_get_customer, upcoming_invoice_total, get_seat_count, \
|
||||
extract_current_subscription, process_initial_upgrade, sign_string, \
|
||||
unsign_string, BillingError, process_downgrade, do_replace_payment_source, \
|
||||
MIN_INVOICED_SEAT_COUNT, DEFAULT_INVOICE_DAYS_UNTIL_DUE
|
||||
MIN_INVOICED_LICENSES, DEFAULT_INVOICE_DAYS_UNTIL_DUE
|
||||
from corporate.models import Customer, CustomerPlan, Plan
|
||||
|
||||
billing_logger = logging.getLogger('corporate.stripe')
|
||||
|
@ -72,19 +72,20 @@ def upgrade(request: HttpRequest, user: UserProfile,
|
|||
signed_seat_count: str=REQ(validator=check_string),
|
||||
salt: str=REQ(validator=check_string),
|
||||
billing_modality: str=REQ(validator=check_string),
|
||||
invoiced_seat_count: int=REQ(validator=check_int, default=None),
|
||||
licenses: int=REQ(validator=check_int, default=None),
|
||||
stripe_token: str=REQ(validator=check_string, default=None)) -> HttpResponse:
|
||||
try:
|
||||
seat_count, billing_schedule = unsign_and_check_upgrade_parameters(
|
||||
user, schedule, signed_seat_count, salt, billing_modality)
|
||||
if billing_modality == 'send_invoice':
|
||||
min_required_seat_count = max(seat_count, MIN_INVOICED_SEAT_COUNT)
|
||||
if invoiced_seat_count < min_required_seat_count:
|
||||
min_required_licenses = max(seat_count, MIN_INVOICED_LICENSES)
|
||||
if licenses < min_required_licenses:
|
||||
raise BillingError(
|
||||
'lowball seat count',
|
||||
"You must invoice for at least %d users." % (min_required_seat_count,))
|
||||
seat_count = invoiced_seat_count
|
||||
process_initial_upgrade(user, seat_count, billing_schedule, stripe_token)
|
||||
'not enough licenses',
|
||||
"You must invoice for at least %d users." % (min_required_licenses,))
|
||||
else:
|
||||
licenses = seat_count
|
||||
process_initial_upgrade(user, licenses, billing_schedule, stripe_token)
|
||||
except BillingError as e:
|
||||
return json_error(e.message, data={'error_description': e.description})
|
||||
except Exception as e:
|
||||
|
@ -117,7 +118,7 @@ def initial_upgrade(request: HttpRequest) -> HttpResponse:
|
|||
'seat_count': seat_count,
|
||||
'signed_seat_count': signed_seat_count,
|
||||
'salt': salt,
|
||||
'min_seat_count_for_invoice': max(seat_count, MIN_INVOICED_SEAT_COUNT),
|
||||
'min_invoiced_licenses': max(seat_count, MIN_INVOICED_LICENSES),
|
||||
'default_invoice_days_until_due': DEFAULT_INVOICE_DAYS_UNTIL_DUE,
|
||||
'plan': "Zulip Standard",
|
||||
'page_params': JSONEncoderForHTML().encode({
|
||||
|
@ -159,7 +160,7 @@ def billing_home(request: HttpRequest) -> HttpResponse:
|
|||
subscription = extract_current_subscription(stripe_customer)
|
||||
if subscription:
|
||||
plan_name = PLAN_NAMES[Plan.objects.get(stripe_plan_id=subscription.plan.id).nickname]
|
||||
seat_count = subscription.quantity
|
||||
licenses = subscription.quantity
|
||||
# Need user's timezone to do this properly
|
||||
renewal_date = '{dt:%B} {dt.day}, {dt.year}'.format(
|
||||
dt=timestamp_to_datetime(subscription.current_period_end))
|
||||
|
@ -170,13 +171,13 @@ def billing_home(request: HttpRequest) -> HttpResponse:
|
|||
# yet, but keeping this code here since we will soon.
|
||||
else: # nocoverage
|
||||
plan_name = "Zulip Free"
|
||||
seat_count = 0
|
||||
licenses = 0
|
||||
renewal_date = ''
|
||||
renewal_amount = 0
|
||||
|
||||
context.update({
|
||||
'plan_name': plan_name,
|
||||
'seat_count': seat_count,
|
||||
'licenses': licenses,
|
||||
'renewal_date': renewal_date,
|
||||
'renewal_amount': '{:,.2f}'.format(renewal_amount / 100.),
|
||||
'payment_method': payment_method_string(stripe_customer),
|
||||
|
|
|
@ -113,7 +113,7 @@ $(function () {
|
|||
salt: get_form_input("autopay", "salt"),
|
||||
schedule: get_form_input("autopay", "schedule"),
|
||||
license_management: JSON.stringify(license_management),
|
||||
invoiced_seat_count: $("#" + license_management + "_license_count").val(),
|
||||
licenses: $("#" + license_management + "_license_count").val(),
|
||||
billing_modality: get_form_input("autopay", "billing_modality"),
|
||||
},
|
||||
success: function () {
|
||||
|
@ -150,7 +150,7 @@ $(function () {
|
|||
});
|
||||
|
||||
$("#invoice-button").on("click", function (e) {
|
||||
if ($("#invoiced_seat_count")[0].checkValidity() === false) {
|
||||
if ($("#invoiced_licenses")[0].checkValidity() === false) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
@ -167,7 +167,7 @@ $(function () {
|
|||
salt: get_form_input("invoice", "salt"),
|
||||
schedule: get_form_input("invoice", "schedule"),
|
||||
billing_modality: get_form_input("invoice", "billing_modality"),
|
||||
invoiced_seat_count: get_form_input("invoice", "invoiced_seat_count", false),
|
||||
licenses: get_form_input("invoice", "invoiced_licenses", false),
|
||||
},
|
||||
success: function () {
|
||||
$("#invoice-loading").hide();
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="overview">
|
||||
<p>Your current plan is <strong>{{ plan_name }}</strong></p>
|
||||
<p>You are paying for <strong>{{ seat_count }} users</strong>.</p>
|
||||
<p>You are paying for <strong>{{ licenses }} users</strong>.</p>
|
||||
<p>Your plan will renew on <strong>{{ renewal_date }}</strong> for <strong>${{ renewal_amount }}</strong>.</p>
|
||||
{% if account_charges %}
|
||||
<p>You have <strong>${{ account_charges }}</strong> in charges that will be added to your next bill.</p>
|
||||
|
|
|
@ -179,7 +179,7 @@
|
|||
Enter the number of users you would like to pay for. We'll email you an
|
||||
invoice in 1-2 hours. Invoices can be paid by ACH transfer or credit card.
|
||||
</p>
|
||||
<h4>Number of users (minimum {{ min_seat_count_for_invoice }})</h4>
|
||||
<h4>Number of users (minimum {{ min_invoiced_licenses }})</h4>
|
||||
<input pattern="\d*" oninvalid="this.setCustomValidity('Invalid input')"
|
||||
oninput="this.setCustomValidity('')" type="text" autocomplete="off"
|
||||
id="invoiced_seat_count" name="invoiced_seat_count" required/><br>
|
||||
|
|
Loading…
Reference in New Issue