def initial_upgrade(request: HttpRequest) -> HttpResponse: if not settings.BILLING_ENABLED: return render(request, "404.html") user = request.user customer = get_customer_by_realm(user.realm) if customer is not None and get_current_plan_by_customer( customer) is not None: return HttpResponseRedirect(reverse('corporate.views.billing_home')) percent_off = Decimal(0) if customer is not None and customer.default_discount is not None: percent_off = customer.default_discount seat_count = get_latest_seat_count(user.realm) signed_seat_count, salt = sign_string(str(seat_count)) context = { 'publishable_key': STRIPE_PUBLISHABLE_KEY, 'email': user.delivery_email, 'seat_count': seat_count, 'signed_seat_count': signed_seat_count, 'salt': salt, 'min_invoiced_licenses': max(seat_count, MIN_INVOICED_LICENSES), 'default_invoice_days_until_due': DEFAULT_INVOICE_DAYS_UNTIL_DUE, 'plan': "Zulip Standard", 'page_params': { 'seat_count': seat_count, 'annual_price': 8000, 'monthly_price': 800, 'percent_off': float(percent_off), }, } # type: Dict[str, Any] response = render(request, 'corporate/upgrade.html', context=context) return response
def test_notify_realm_of_new_user_in_manual_license_management( self) -> None: realm = get_realm("zulip") user_count = get_latest_seat_count(realm) self.subscribe_realm_to_monthly_plan_on_manual_license_management( realm, user_count + 5, user_count + 5) def create_new_user_and_verify_strings_in_notification_message( strings_present: Sequence[str] = [], strings_absent: Sequence[str] = []) -> None: user_no = random.randrange(100000) new_user = UserProfile.objects.create( realm=realm, full_name=f"new user {user_no}", email=f"user-{user_no}[email protected]", delivery_email=f"user-{user_no}[email protected]", ) notify_new_user(new_user) message = self.get_last_message() actual_stream = Stream.objects.get(id=message.recipient.type_id) self.assertEqual(actual_stream, realm.signup_notifications_stream) self.assertIn( f"@_**new user {user_no}|{new_user.id}** just signed up for Zulip.", message.content, ) for string_present in strings_present: self.assertIn( string_present, message.content, ) for string_absent in strings_absent: self.assertNotIn(string_absent, message.content) create_new_user_and_verify_strings_in_notification_message( strings_absent=["Your organization has"]) create_new_user_and_verify_strings_in_notification_message( strings_present=[ "Your organization has only three Zulip licenses remaining", "to allow more than three users to", ], ) create_new_user_and_verify_strings_in_notification_message( strings_present=[ "Your organization has only two Zulip licenses remaining", "to allow more than two users to", ], ) create_new_user_and_verify_strings_in_notification_message( strings_present=[ "Your organization has only one Zulip license remaining", "to allow more than one user to", ], ) create_new_user_and_verify_strings_in_notification_message( strings_present=[ "Your organization has no Zulip licenses remaining", "to allow new users to", ])
def billing_home(request: HttpRequest) -> HttpResponse: user = request.user customer = get_customer_by_realm(user.realm) if customer is None: return HttpResponseRedirect(reverse('corporate.views.initial_upgrade')) if not CustomerPlan.objects.filter(customer=customer).exists(): return HttpResponseRedirect(reverse('corporate.views.initial_upgrade')) if not user.is_realm_admin and not user.is_billing_admin: context: Dict[str, Any] = {'admin_access': False} return render(request, 'corporate/billing.html', context=context) context = { 'admin_access': True, 'has_active_plan': False, } plan = get_current_plan_by_customer(customer) if plan is not None: now = timezone_now() last_ledger_entry = make_end_of_cycle_updates_if_needed(plan, now) if last_ledger_entry is not None: plan_name = { CustomerPlan.STANDARD: 'Zulip Standard', CustomerPlan.PLUS: 'Zulip Plus', }[plan.tier] free_trial = plan.status == CustomerPlan.FREE_TRIAL downgrade_at_end_of_cycle = plan.status == CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE licenses = last_ledger_entry.licenses licenses_used = get_latest_seat_count(user.realm) # Should do this in javascript, using the user's timezone renewal_date = '{dt:%B} {dt.day}, {dt.year}'.format(dt=start_of_next_billing_cycle(plan, now)) renewal_cents = renewal_amount(plan, now) charge_automatically = plan.charge_automatically stripe_customer = stripe_get_customer(customer.stripe_customer_id) if charge_automatically: payment_method = payment_method_string(stripe_customer) else: payment_method = 'Billed by invoice' context.update({ 'plan_name': plan_name, 'has_active_plan': True, 'free_trial': free_trial, 'downgrade_at_end_of_cycle': downgrade_at_end_of_cycle, 'licenses': licenses, 'licenses_used': licenses_used, 'renewal_date': renewal_date, 'renewal_amount': '{:,.2f}'.format(renewal_cents / 100.), 'payment_method': payment_method, 'charge_automatically': charge_automatically, 'publishable_key': STRIPE_PUBLISHABLE_KEY, 'stripe_email': stripe_customer.email, 'CustomerPlan': CustomerPlan, 'onboarding': request.GET.get("onboarding") is not None, }) return render(request, 'corporate/billing.html', context=context)
def check_spare_licenses_available_for_adding_new_users( realm: Realm, number_of_users_to_add: int) -> None: plan = get_current_plan_by_realm(realm) if (plan is None or plan.automanage_licenses or plan.customer.exempt_from_from_license_number_check): return if plan.licenses() < get_latest_seat_count(realm) + number_of_users_to_add: raise LicenseLimitError()
def initial_upgrade( request: HttpRequest, onboarding: bool = REQ(default=False, json_validator=check_bool) ) -> HttpResponse: user = request.user assert user.is_authenticated if not settings.BILLING_ENABLED or user.is_guest: return render(request, "404.html", status=404) billing_page_url = reverse(billing_home) customer = get_customer_by_realm(user.realm) if customer is not None and ( get_current_plan_by_customer(customer) is not None or customer.sponsorship_pending ): if onboarding: billing_page_url = f"{billing_page_url}?onboarding=true" return HttpResponseRedirect(billing_page_url) if is_sponsored_realm(user.realm): return HttpResponseRedirect(billing_page_url) percent_off = Decimal(0) if customer is not None and customer.default_discount is not None: percent_off = customer.default_discount seat_count = get_latest_seat_count(user.realm) signed_seat_count, salt = sign_string(str(seat_count)) context: Dict[str, Any] = { "realm": user.realm, "email": user.delivery_email, "seat_count": seat_count, "signed_seat_count": signed_seat_count, "salt": salt, "min_invoiced_licenses": max(seat_count, MIN_INVOICED_LICENSES), "default_invoice_days_until_due": DEFAULT_INVOICE_DAYS_UNTIL_DUE, "plan": "Zulip Standard", "free_trial_days": settings.FREE_TRIAL_DAYS, "onboarding": onboarding, "page_params": { "seat_count": seat_count, "annual_price": 8000, "monthly_price": 800, "percent_off": float(percent_off), }, "realm_org_type": user.realm.org_type, "sorted_org_types": sorted( ( [org_type_name, org_type] for (org_type_name, org_type) in Realm.ORG_TYPES.items() if not org_type.get("hidden") ), key=lambda d: d[1]["display_order"], ), } response = render(request, "corporate/upgrade.html", context=context) return response
def billing_home(request: HttpRequest) -> HttpResponse: user = request.user customer = Customer.objects.filter(realm=user.realm).first() if customer is None: return HttpResponseRedirect(reverse('corporate.views.initial_upgrade')) if not CustomerPlan.objects.filter(customer=customer).exists(): return HttpResponseRedirect(reverse('corporate.views.initial_upgrade')) if not user.is_realm_admin and not user.is_billing_admin: context = {'admin_access': False} # type: Dict[str, Any] return render(request, 'corporate/billing.html', context=context) context = {'admin_access': True} plan_name = "Zulip Free" licenses = 0 renewal_date = '' renewal_cents = 0 payment_method = '' charge_automatically = False stripe_customer = stripe_get_customer(customer.stripe_customer_id) plan = get_current_plan(customer) if plan is not None: plan_name = { CustomerPlan.STANDARD: 'Zulip Standard', CustomerPlan.PLUS: 'Zulip Plus', }[plan.tier] now = timezone_now() last_ledger_entry = make_end_of_cycle_updates_if_needed(plan, now) if last_ledger_entry is not None: licenses = last_ledger_entry.licenses licenses_used = get_latest_seat_count(user.realm) # Should do this in javascript, using the user's timezone renewal_date = '{dt:%B} {dt.day}, {dt.year}'.format( dt=start_of_next_billing_cycle(plan, now)) renewal_cents = renewal_amount(plan, now) charge_automatically = plan.charge_automatically if charge_automatically: payment_method = payment_method_string(stripe_customer) else: payment_method = 'Billed by invoice' context.update({ 'plan_name': plan_name, 'licenses': licenses, 'licenses_used': licenses_used, 'renewal_date': renewal_date, 'renewal_amount': '{:,.2f}'.format(renewal_cents / 100.), 'payment_method': payment_method, 'charge_automatically': charge_automatically, 'publishable_key': STRIPE_PUBLISHABLE_KEY, 'stripe_email': stripe_customer.email, }) return render(request, 'corporate/billing.html', context=context)
def initial_upgrade(request: HttpRequest) -> HttpResponse: user = request.user if not settings.BILLING_ENABLED or user.is_guest: return render(request, "404.html", status=404) billing_page_url = reverse(billing_home) customer = get_customer_by_realm(user.realm) if customer is not None and ( get_current_plan_by_customer(customer) is not None or customer.sponsorship_pending ): if request.GET.get("onboarding") is not None: billing_page_url = f"{billing_page_url}?onboarding=true" return HttpResponseRedirect(billing_page_url) if user.realm.plan_type == user.realm.STANDARD_FREE: return HttpResponseRedirect(billing_page_url) percent_off = Decimal(0) if customer is not None and customer.default_discount is not None: percent_off = customer.default_discount seat_count = get_latest_seat_count(user.realm) signed_seat_count, salt = sign_string(str(seat_count)) context: Dict[str, Any] = { "realm": user.realm, "publishable_key": STRIPE_PUBLISHABLE_KEY, "email": user.delivery_email, "seat_count": seat_count, "signed_seat_count": signed_seat_count, "salt": salt, "min_invoiced_licenses": max(seat_count, MIN_INVOICED_LICENSES), "default_invoice_days_until_due": DEFAULT_INVOICE_DAYS_UNTIL_DUE, "plan": "Zulip Standard", "free_trial_days": settings.FREE_TRIAL_DAYS, "onboarding": request.GET.get("onboarding") is not None, "page_params": { "seat_count": seat_count, "annual_price": 8000, "monthly_price": 800, "percent_off": float(percent_off), }, } response = render(request, "corporate/upgrade.html", context=context) return response
def initial_upgrade(request: HttpRequest) -> HttpResponse: user = request.user if not settings.BILLING_ENABLED or user.is_guest: return render(request, "404.html", status=404) customer = get_customer_by_realm(user.realm) if customer is not None and (get_current_plan_by_customer(customer) is not None or customer.sponsorship_pending): billing_page_url = reverse('corporate.views.billing_home') if request.GET.get("onboarding") is not None: billing_page_url = f"{billing_page_url}?onboarding=true" return HttpResponseRedirect(billing_page_url) percent_off = Decimal(0) if customer is not None and customer.default_discount is not None: percent_off = customer.default_discount seat_count = get_latest_seat_count(user.realm) signed_seat_count, salt = sign_string(str(seat_count)) context: Dict[str, Any] = { 'realm': user.realm, 'publishable_key': STRIPE_PUBLISHABLE_KEY, 'email': user.delivery_email, 'seat_count': seat_count, 'signed_seat_count': signed_seat_count, 'salt': salt, 'min_invoiced_licenses': max(seat_count, MIN_INVOICED_LICENSES), 'default_invoice_days_until_due': DEFAULT_INVOICE_DAYS_UNTIL_DUE, 'plan': "Zulip Standard", "free_trial_days": settings.FREE_TRIAL_DAYS, "onboarding": request.GET.get("onboarding") is not None, 'page_params': { 'seat_count': seat_count, 'annual_price': 8000, 'monthly_price': 800, 'percent_off': float(percent_off), }, } response = render(request, 'corporate/upgrade.html', context=context) return response
def generate_licenses_low_warning_message_if_required(realm: Realm) -> Optional[str]: plan = get_current_plan_by_realm(realm) if plan is None or plan.automanage_licenses: return None licenses_remaining = plan.licenses() - get_latest_seat_count(realm) if licenses_remaining > 3: return None format_kwargs = { "billing_page_link": "/billing/#settings", "deactivate_user_help_page_link": "/help/deactivate-or-reactivate-a-user", } if licenses_remaining <= 0: return _( "Your organization has no Zulip licenses remaining and can no longer accept new users. " "Please [increase the number of licenses]({billing_page_link}) or " "[deactivate inactive users]({deactivate_user_help_page_link}) to allow new users to join." ).format(**format_kwargs) return { 1: _( "Your organization has only one Zulip license remaining. You can " "[increase the number of licenses]({billing_page_link}) or [deactivate inactive users]({deactivate_user_help_page_link}) " "to allow more than one user to join." ), 2: _( "Your organization has only two Zulip licenses remaining. You can " "[increase the number of licenses]({billing_page_link}) or [deactivate inactive users]({deactivate_user_help_page_link}) " "to allow more than two users to join." ), 3: _( "Your organization has only three Zulip licenses remaining. You can " "[increase the number of licenses]({billing_page_link}) or [deactivate inactive users]({deactivate_user_help_page_link}) " "to allow more than three users to join." ), }[licenses_remaining].format(**format_kwargs)
def billing_home(request: HttpRequest) -> HttpResponse: user = request.user assert user.is_authenticated customer = get_customer_by_realm(user.realm) context: Dict[str, Any] = { "admin_access": user.has_billing_access, "has_active_plan": False, } if user.realm.plan_type == user.realm.STANDARD_FREE: context["is_sponsored"] = True return render(request, "corporate/billing.html", context=context) if customer is None: from corporate.views.upgrade import initial_upgrade return HttpResponseRedirect(reverse(initial_upgrade)) if customer.sponsorship_pending: context["sponsorship_pending"] = True return render(request, "corporate/billing.html", context=context) if not CustomerPlan.objects.filter(customer=customer).exists(): from corporate.views.upgrade import initial_upgrade return HttpResponseRedirect(reverse(initial_upgrade)) if not user.has_billing_access: return render(request, "corporate/billing.html", context=context) plan = get_current_plan_by_customer(customer) if plan is not None: now = timezone_now() new_plan, last_ledger_entry = make_end_of_cycle_updates_if_needed( plan, now) if last_ledger_entry is not None: if new_plan is not None: # nocoverage plan = new_plan assert plan is not None # for mypy downgrade_at_end_of_cycle = plan.status == CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE switch_to_annual_at_end_of_cycle = ( plan.status == CustomerPlan.SWITCH_TO_ANNUAL_AT_END_OF_CYCLE) licenses = last_ledger_entry.licenses licenses_at_next_renewal = last_ledger_entry.licenses_at_next_renewal seat_count = get_latest_seat_count(user.realm) # Should do this in javascript, using the user's timezone renewal_date = "{dt:%B} {dt.day}, {dt.year}".format( dt=start_of_next_billing_cycle(plan, now)) renewal_cents = renewal_amount(plan, now) charge_automatically = plan.charge_automatically assert customer.stripe_customer_id is not None # for mypy stripe_customer = stripe_get_customer(customer.stripe_customer_id) if charge_automatically: payment_method = payment_method_string(stripe_customer) else: payment_method = "Billed by invoice" context.update( plan_name=plan.name, has_active_plan=True, free_trial=plan.is_free_trial(), downgrade_at_end_of_cycle=downgrade_at_end_of_cycle, automanage_licenses=plan.automanage_licenses, switch_to_annual_at_end_of_cycle= switch_to_annual_at_end_of_cycle, licenses=licenses, licenses_at_next_renewal=licenses_at_next_renewal, seat_count=seat_count, renewal_date=renewal_date, renewal_amount=cents_to_dollar_string(renewal_cents), payment_method=payment_method, charge_automatically=charge_automatically, publishable_key=STRIPE_PUBLISHABLE_KEY, stripe_email=stripe_customer.email, CustomerPlan=CustomerPlan, onboarding=request.GET.get("onboarding") is not None, ) return render(request, "corporate/billing.html", context=context)
def update_plan( request: HttpRequest, user: UserProfile, status: Optional[int] = REQ( "status", json_validator=check_int_in([ CustomerPlan.ACTIVE, CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE, CustomerPlan.SWITCH_TO_ANNUAL_AT_END_OF_CYCLE, CustomerPlan.ENDED, ]), default=None, ), licenses: Optional[int] = REQ("licenses", json_validator=check_int, default=None), licenses_at_next_renewal: Optional[int] = REQ("licenses_at_next_renewal", json_validator=check_int, default=None), ) -> HttpResponse: plan = get_current_plan_by_realm(user.realm) assert plan is not None # for mypy new_plan, last_ledger_entry = make_end_of_cycle_updates_if_needed( plan, timezone_now()) if new_plan is not None: raise JsonableError( _("Unable to update the plan. The plan has been expired and replaced with a new plan." )) if last_ledger_entry is None: raise JsonableError( _("Unable to update the plan. The plan has ended.")) if status is not None: if status == CustomerPlan.ACTIVE: assert plan.status == CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE do_change_plan_status(plan, status) elif status == CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE: assert plan.status == CustomerPlan.ACTIVE downgrade_at_the_end_of_billing_cycle(user.realm) elif status == CustomerPlan.SWITCH_TO_ANNUAL_AT_END_OF_CYCLE: assert plan.billing_schedule == CustomerPlan.MONTHLY assert plan.status == CustomerPlan.ACTIVE assert plan.fixed_price is None do_change_plan_status(plan, status) elif status == CustomerPlan.ENDED: assert plan.is_free_trial() downgrade_now_without_creating_additional_invoices(user.realm) return json_success() if licenses is not None: if plan.automanage_licenses: raise JsonableError( _("Unable to update licenses manually. Your plan is on automatic license management." )) if last_ledger_entry.licenses == licenses: raise JsonableError( _("Your plan is already on {licenses} licenses in the current billing period." ).format(licenses=licenses)) if last_ledger_entry.licenses > licenses: raise JsonableError( _("You cannot decrease the licenses in the current billing period." ).format(licenses=licenses)) validate_licenses(plan.charge_automatically, licenses, get_latest_seat_count(user.realm)) update_license_ledger_for_manual_plan(plan, timezone_now(), licenses=licenses) return json_success() if licenses_at_next_renewal is not None: if plan.automanage_licenses: raise JsonableError( _("Unable to update licenses manually. Your plan is on automatic license management." )) if last_ledger_entry.licenses_at_next_renewal == licenses_at_next_renewal: raise JsonableError( _("Your plan is already scheduled to renew with {licenses_at_next_renewal} licenses." ).format(licenses_at_next_renewal=licenses_at_next_renewal)) validate_licenses( plan.charge_automatically, licenses_at_next_renewal, get_latest_seat_count(user.realm), ) update_license_ledger_for_manual_plan( plan, timezone_now(), licenses_at_next_renewal=licenses_at_next_renewal) return json_success() raise JsonableError(_("Nothing to change."))
def support( request: HttpRequest, realm_id: Optional[int] = REQ(default=None, converter=to_non_negative_int), plan_type: Optional[int] = REQ(default=None, converter=to_non_negative_int), discount: Optional[Decimal] = REQ(default=None, converter=to_decimal), new_subdomain: Optional[str] = REQ(default=None), status: Optional[str] = REQ( default=None, str_validator=check_string_in(VALID_STATUS_VALUES)), billing_method: Optional[str] = REQ( default=None, str_validator=check_string_in(VALID_BILLING_METHODS)), sponsorship_pending: Optional[bool] = REQ(default=None, json_validator=check_bool), approve_sponsorship: Optional[bool] = REQ(default=None, json_validator=check_bool), downgrade_method: Optional[str] = REQ( default=None, str_validator=check_string_in(VALID_DOWNGRADE_METHODS)), scrub_realm: Optional[bool] = REQ(default=None, json_validator=check_bool), query: Optional[str] = REQ("q", default=None), org_type: Optional[int] = REQ(default=None, converter=to_non_negative_int), ) -> HttpResponse: context: Dict[str, Any] = {} if "success_message" in request.session: context["success_message"] = request.session["success_message"] del request.session["success_message"] if settings.BILLING_ENABLED and request.method == "POST": # We check that request.POST only has two keys in it: The # realm_id and a field to change. keys = set(request.POST.keys()) if "csrfmiddlewaretoken" in keys: keys.remove("csrfmiddlewaretoken") if len(keys) != 2: raise JsonableError(_("Invalid parameters")) realm = Realm.objects.get(id=realm_id) acting_user = request.user assert isinstance(acting_user, UserProfile) if plan_type is not None: current_plan_type = realm.plan_type do_change_plan_type(realm, plan_type, acting_user=acting_user) msg = f"Plan type of {realm.string_id} changed from {get_plan_name(current_plan_type)} to {get_plan_name(plan_type)} " context["success_message"] = msg elif org_type is not None: current_realm_type = realm.org_type do_change_realm_org_type(realm, org_type, acting_user=acting_user) msg = f"Org type of {realm.string_id} changed from {get_org_type_display_name(current_realm_type)} to {get_org_type_display_name(org_type)} " context["success_message"] = msg elif discount is not None: current_discount = get_discount_for_realm(realm) or 0 attach_discount_to_realm(realm, discount, acting_user=acting_user) context[ "success_message"] = f"Discount of {realm.string_id} changed to {discount}% from {current_discount}%." elif new_subdomain is not None: old_subdomain = realm.string_id try: check_subdomain_available(new_subdomain) except ValidationError as error: context["error_message"] = error.message else: do_change_realm_subdomain(realm, new_subdomain, acting_user=acting_user) request.session[ "success_message"] = f"Subdomain changed from {old_subdomain} to {new_subdomain}" return HttpResponseRedirect( reverse("support") + "?" + urlencode({"q": new_subdomain})) elif status is not None: if status == "active": do_send_realm_reactivation_email(realm, acting_user=acting_user) context[ "success_message"] = f"Realm reactivation email sent to admins of {realm.string_id}." elif status == "deactivated": do_deactivate_realm(realm, acting_user=acting_user) context["success_message"] = f"{realm.string_id} deactivated." elif billing_method is not None: if billing_method == "send_invoice": update_billing_method_of_current_plan( realm, charge_automatically=False, acting_user=acting_user) context[ "success_message"] = f"Billing method of {realm.string_id} updated to pay by invoice." elif billing_method == "charge_automatically": update_billing_method_of_current_plan( realm, charge_automatically=True, acting_user=acting_user) context[ "success_message"] = f"Billing method of {realm.string_id} updated to charge automatically." elif sponsorship_pending is not None: if sponsorship_pending: update_sponsorship_status(realm, True, acting_user=acting_user) context[ "success_message"] = f"{realm.string_id} marked as pending sponsorship." else: update_sponsorship_status(realm, False, acting_user=acting_user) context[ "success_message"] = f"{realm.string_id} is no longer pending sponsorship." elif approve_sponsorship: do_approve_sponsorship(realm, acting_user=acting_user) context[ "success_message"] = f"Sponsorship approved for {realm.string_id}" elif downgrade_method is not None: if downgrade_method == "downgrade_at_billing_cycle_end": downgrade_at_the_end_of_billing_cycle(realm) context[ "success_message"] = f"{realm.string_id} marked for downgrade at the end of billing cycle" elif downgrade_method == "downgrade_now_without_additional_licenses": downgrade_now_without_creating_additional_invoices(realm) context[ "success_message"] = f"{realm.string_id} downgraded without creating additional invoices" elif downgrade_method == "downgrade_now_void_open_invoices": downgrade_now_without_creating_additional_invoices(realm) voided_invoices_count = void_all_open_invoices(realm) context[ "success_message"] = f"{realm.string_id} downgraded and voided {voided_invoices_count} open invoices" elif scrub_realm: do_scrub_realm(realm, acting_user=acting_user) context["success_message"] = f"{realm.string_id} scrubbed." if query: key_words = get_invitee_emails_set(query) users = set(UserProfile.objects.filter(delivery_email__in=key_words)) realms = set(Realm.objects.filter(string_id__in=key_words)) for key_word in key_words: try: URLValidator()(key_word) parse_result = urllib.parse.urlparse(key_word) hostname = parse_result.hostname assert hostname is not None if parse_result.port: hostname = f"{hostname}:{parse_result.port}" subdomain = get_subdomain_from_hostname(hostname) try: realms.add(get_realm(subdomain)) except Realm.DoesNotExist: pass except ValidationError: users.update( UserProfile.objects.filter(full_name__iexact=key_word)) for realm in realms: realm.customer = get_customer_by_realm(realm) current_plan = get_current_plan_by_realm(realm) if current_plan is not None: new_plan, last_ledger_entry = make_end_of_cycle_updates_if_needed( current_plan, timezone_now()) if last_ledger_entry is not None: if new_plan is not None: realm.current_plan = new_plan else: realm.current_plan = current_plan realm.current_plan.licenses = last_ledger_entry.licenses realm.current_plan.licenses_used = get_latest_seat_count( realm) # full_names can have , in them users.update(UserProfile.objects.filter(full_name__iexact=query)) context["users"] = users context["realms"] = realms confirmations: List[Dict[str, Any]] = [] preregistration_users = PreregistrationUser.objects.filter( email__in=key_words) confirmations += get_confirmations( [ Confirmation.USER_REGISTRATION, Confirmation.INVITATION, Confirmation.REALM_CREATION ], preregistration_users, hostname=request.get_host(), ) multiuse_invites = MultiuseInvite.objects.filter(realm__in=realms) confirmations += get_confirmations([Confirmation.MULTIUSE_INVITE], multiuse_invites) confirmations += get_confirmations([Confirmation.REALM_REACTIVATION], [realm.id for realm in realms]) context["confirmations"] = confirmations def get_realm_owner_emails_as_string(realm: Realm) -> str: return ", ".join(realm.get_human_owner_users().order_by( "delivery_email").values_list("delivery_email", flat=True)) def get_realm_admin_emails_as_string(realm: Realm) -> str: return ", ".join( realm.get_human_admin_users(include_realm_owners=False).order_by( "delivery_email").values_list("delivery_email", flat=True)) context[ "get_realm_owner_emails_as_string"] = get_realm_owner_emails_as_string context[ "get_realm_admin_emails_as_string"] = get_realm_admin_emails_as_string context["get_discount_for_realm"] = get_discount_for_realm context["get_org_type_display_name"] = get_org_type_display_name context["realm_icon_url"] = realm_icon_url context["Confirmation"] = Confirmation context["sorted_realm_types"] = sorted(Realm.ORG_TYPES.values(), key=lambda d: d["display_order"]) return render(request, "analytics/support.html", context=context)
def billing_home(request: HttpRequest) -> HttpResponse: user = request.user customer = get_customer_by_realm(user.realm) context: Dict[str, Any] = { "admin_access": user.has_billing_access, 'has_active_plan': False, } if user.realm.plan_type == user.realm.STANDARD_FREE: context["is_sponsored"] = True return render(request, 'corporate/billing.html', context=context) if customer is None: return HttpResponseRedirect(reverse('corporate.views.initial_upgrade')) if customer.sponsorship_pending: context["sponsorship_pending"] = True return render(request, 'corporate/billing.html', context=context) if not CustomerPlan.objects.filter(customer=customer).exists(): return HttpResponseRedirect(reverse('corporate.views.initial_upgrade')) if not user.has_billing_access: return render(request, 'corporate/billing.html', context=context) plan = get_current_plan_by_customer(customer) if plan is not None: now = timezone_now() new_plan, last_ledger_entry = make_end_of_cycle_updates_if_needed( plan, now) if last_ledger_entry is not None: if new_plan is not None: # nocoverage plan = new_plan assert (plan is not None) # for mypy free_trial = plan.status == CustomerPlan.FREE_TRIAL downgrade_at_end_of_cycle = plan.status == CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE switch_to_annual_at_end_of_cycle = plan.status == CustomerPlan.SWITCH_TO_ANNUAL_AT_END_OF_CYCLE licenses = last_ledger_entry.licenses licenses_used = get_latest_seat_count(user.realm) # Should do this in javascript, using the user's timezone renewal_date = '{dt:%B} {dt.day}, {dt.year}'.format( dt=start_of_next_billing_cycle(plan, now)) renewal_cents = renewal_amount(plan, now) charge_automatically = plan.charge_automatically stripe_customer = stripe_get_customer(customer.stripe_customer_id) if charge_automatically: payment_method = payment_method_string(stripe_customer) else: payment_method = 'Billed by invoice' context.update({ 'plan_name': plan.name, 'has_active_plan': True, 'free_trial': free_trial, 'downgrade_at_end_of_cycle': downgrade_at_end_of_cycle, 'automanage_licenses': plan.automanage_licenses, 'switch_to_annual_at_end_of_cycle': switch_to_annual_at_end_of_cycle, 'licenses': licenses, 'licenses_used': licenses_used, 'renewal_date': renewal_date, 'renewal_amount': f'{renewal_cents / 100.:,.2f}', 'payment_method': payment_method, 'charge_automatically': charge_automatically, 'publishable_key': STRIPE_PUBLISHABLE_KEY, 'stripe_email': stripe_customer.email, 'CustomerPlan': CustomerPlan, 'onboarding': request.GET.get("onboarding") is not None, }) return render(request, 'corporate/billing.html', context=context)