snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 15:05:30 +05:00
commit 64898b2c79
8999 changed files with 1757358 additions and 0 deletions

View File

@@ -0,0 +1,654 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "billing" %}
{% block title %}
<title>{{ _("Billing") }} | Zulip</title>
{% endblock %}
{% block portico_content %}
<div id="billing-page" class="register-account flex full-page" data-billing-base-url="{{ billing_base_url }}">
<div class="center-block new-style">
{% if admin_access and has_active_plan %}
{% if is_sponsorship_pending %}
<div class="alert alert-success billing-page-success" id="billing-sponsorship-pending-message-top">
This organization has requested sponsorship for a
{% if is_self_hosted_billing and sponsorship_plan_name != "Community" %}
discounted
{% endif %}
<a href="{{ billing_base_url }}/plans/">{{ sponsorship_plan_name }}</a> plan.<br/><a href="mailto:support@zulip.com">Contact Zulip support</a> with any questions or updates.
</div>
{% endif %}
{% if success_message %}
<div class="alert alert-success billing-page-success" id="billing-success-message-top">
{% if complimentary_access_next_plan_name and "PLAN_NAME" in success_message %}
Your organization will be upgraded to {{ complimentary_access_next_plan_name }} on {{ complimentary_access_plan_end_date }}.
{% else %}
{{ success_message.replace("PLAN_NAME", plan_name) }}
{% endif %}
</div>
{% endif %}
<div class="pitch">
<h1>
Zulip
{% if is_self_hosted_billing %}
{% else %}
Cloud
{% endif %}
billing for {{ org_name }}
</h1>
</div>
<div class="alert alert-danger" id="error-message-box"></div>
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}" />
<div class="white-box">
<div id="billing-page-details">
<div class="input-box billing-page-field">
<h2 class="billing-section-title">Your plan</h2>
<div class="billing-section-content">
{% if free_trial or downgrade_at_end_of_free_trial %}
<a href="{{ billing_base_url }}/plans/">
{{ plan_name }} <i>(free trial)</i>
</a>
{% elif complimentary_access_plan %}
<a href="{{ billing_base_url }}/plans/">
{{ plan_name.replace(" (complimentary)", "") -}}
</a>
<i>(complimentary access)</i>
{% else %}
<a href="{{ billing_base_url }}/plans/">
{{ plan_name }}
</a>
{% endif %}
</div>
</div>
{% if complimentary_access_plan %}
<div class="input-box billing-page-field" id="complimentary-access-end-notice-wrapper">
<div id="complimentary-access-end-notice" class="not-editable-realm-field">
<i>Your complimentary access to Zulip Basic ends on {{ complimentary_access_plan_end_date }}.</i>
</div>
</div>
{% endif %}
<div class="input-box billing-page-field org-billing-frequency-wrapper"
data-current-billing-frequency="{{ billing_frequency }}"
{%if free_trial %}data-free-trial="true"{% endif %}
{%if downgrade_at_end_of_cycle %}data-downgrade-eoc="true"{% endif %}
{%if switch_to_monthly_at_end_of_cycle %}data-switch-to-monthly-eoc="true"{% endif %}
{%if switch_to_annual_at_end_of_cycle %}data-switch-to-annual-eoc="true"{% endif %}>
<h2 class="billing-section-title">Billing frequency</h2>
{% if downgrade_at_end_of_free_trial or downgrade_at_end_of_cycle or complimentary_access_plan or fixed_price_plan or (free_trial and not charge_automatically) %}
<div class="billing-section-content">
{{ billing_frequency }}
</div>
{% elif switch_to_annual_at_end_of_cycle %}
<select name="schedule" id="org-billing-frequency-annual" class="billing-frequency-select billing-section-content">
<option value="Monthly">Monthly</option>
<option value="Annual" selected>Annual</option>
</select>
<div class="billing-frequency-message not-editable-realm-field">
Your plan will switch to annual billing on {{ renewal_date }}.
</div>
{%elif switch_to_monthly_at_end_of_cycle %}
<select name="schedule" id="org-billing-frequency-monthly" class="billing-frequency-select billing-section-content">
<option value="Monthly" selected>Monthly</option>
<option value="Annual">Annual</option>
</select>
<div class="billing-frequency-message not-editable-realm-field">
Your plan will switch to monthly billing on {{ renewal_date }}.
</div>
{% else %}
<select name="schedule" id="org-billing-frequency-default" class="billing-frequency-select billing-section-content">
<option value="Monthly" {% if billing_frequency == "Monthly" %}selected{% endif %}>Monthly</option>
<option value="Annual" {% if billing_frequency == "Annual" %}selected{% endif %}>Annual</option>
</select>
{% endif %}
<button id="org-billing-frequency-confirm-button" class="hide">
<span class="billing-button-text">Update</span>
<object class="loader billing-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
<div id="org-billing-frequency-change-error" class="alert alert-danger billing-page-error"></div>
</div>
{% if complimentary_access_plan or fixed_price_plan %}
{% elif automanage_licenses %}
<div class="input-box billing-page-field">
<h2 class="billing-section-title">
Number of licenses
{% if is_self_hosted_billing %}
<a href="/help/self-hosted-billing#how-does-automatic-license-management-work" target="_blank" rel="noopener noreferrer">
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
{% else %}
<a href="/help/zulip-cloud-billing#how-does-automatic-license-management-work" target="_blank" rel="noopener noreferrer">
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
{% endif %}
</h2>
<div class="billing-section-content">
{{ licenses }}
<br />
Licenses are managed
<a href="/help/self-hosted-billing#how-does-automatic-license-management-work">automatically</a>.
You can
<a class="toggle-license-management" type="button">switch</a>
to manual license management.
</div>
</div>
{% else %}
{% if not (free_trial or downgrade_at_end_of_free_trial) %}
<div class="input-box billing-page-field input-box-number">
<h2 class="billing-section-title">
Number of licenses for current billing period
{% if is_self_hosted_billing %}
<a href="/help/self-hosted-billing#how-does-manual-license-management-work" target="_blank" rel="noopener noreferrer">
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
{% else %}
<a href="/help/zulip-cloud-billing#how-does-manual-license-management-work" target="_blank" rel="noopener noreferrer">
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
{% endif %}
</h2>
<div class="number-input-with-label">
<form id="current-license-change-form">
<input type="number" name="licenses" autocomplete="off" id="current-manual-license-count" class="short-width-number-input billing-section-content" data-original-value="{{ licenses }}" value="{{ licenses }}" {%if not exempt_from_license_number_check %}min="{{ seat_count }}"{% endif %} required/>
</form>
<span class="licence-count-in-use">licenses ({{ seat_count }} in use)</span>
<button id="current-manual-license-count-update-button" class="license-count-update-button hide">
<span class="billing-button-text">Update</span>
<object class="loader billing-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
</div>
<div id="current-license-change-error" class="alert alert-danger billing-page-error"></div>
<div class="not-editable-realm-field billing-page-license-management-description">
Licenses are managed
<a href="/help/self-hosted-billing#how-does-manual-license-management-work">manually</a>.
You can
<a class="toggle-license-management" type="button">switch</a>
to automatic license management.
</div>
</div>
{% endif %}
{% if not (downgrade_at_end_of_cycle or downgrade_at_end_of_free_trial) %}
<div class="input-box billing-page-field input-box-number">
<h2 class="billing-section-title">
Number of licenses for next billing period
{% if is_self_hosted_billing %}
<a href="/help/self-hosted-billing#how-does-manual-license-management-work" target="_blank" rel="noopener noreferrer">
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
{% else %}
<a href="/help/zulip-cloud-billing#how-does-manual-license-management-work" target="_blank" rel="noopener noreferrer">
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
{% endif %}
</h2>
<div class="number-input-with-label">
<form id="next-license-change-form">
<input type="number" name="licenses_at_next_renewal" autocomplete="off" id="next-manual-license-count" class="short-width-number-input billing-section-content" data-original-value="{{ licenses_at_next_renewal }}" value="{{ licenses_at_next_renewal }}" {%if not exempt_from_license_number_check %}min="{{ seat_count }}"{% endif %} required/>
</form>
<span class="licence-count-in-use">licenses ({{ seat_count }} in use)</span>
<button id="next-manual-license-count-update-button" class="license-count-update-button hide">
<span class="billing-button-text">Update</span>
<object class="loader billing-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
</div>
<div id="next-license-change-error" class="alert alert-danger billing-page-error"></div>
</div>
{% endif %}
{% endif %}
<form id="toggle-license-management-form">
<input name="toggle_license_management" type="hidden" value="true" />
</form>
<div id="toggle-license-management-error" class="alert alert-danger"></div>
<div class="input-box billing-page-field">
<h2 class="billing-section-title">Billing contact</h2>
<div class="billing-section-content">
<a href="mailto:{{ stripe_email }}">{{ stripe_email }}</a>
</div>
</div>
<div id="cardchange-error" class="alert alert-danger"></div>
<div class="input-box billing-page-field">
<h2 class="billing-section-title">Payment method</h2>
<div class="billing-section-content">
{{ payment_method }}
</div>
{% if charge_automatically %}
<div class="user-stripe-card-update input-box billing-page-field">
<button class="user-stripe-card-update-button" id="update-card-button">
<span class="billing-button-text">Update card</span>
<object class="loader billing-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
</div>
{% endif %}
<br />
<div class="stripe-customer-billing-portal not-editable-realm-field">
<a href="{{ billing_base_url }}/customer_portal/?return_to_billing_page=true">View and update</a> billing information that will be displayed on your next invoice and receipt.
</div>
</div>
<div class="input-box billing-page-field">
<div class="next-payment-info not-editable-realm-field">
{% if renewal_amount %}
{% if downgrade_at_end_of_cycle %}
{% if is_self_hosted_billing %}
Your organization will be downgraded to the <strong>Free</strong> plan at the end of the
current billing period ({{ renewal_date }}). You will lose access to the
<a href="{{ billing_base_url }}/plans/#self-hosted-plan-comparison">benefits</a>
of your current plan. For organizations with more than 10 users, this
includes losing access to the
<a href="https://zulip.readthedocs.io/en/stable/production/mobile-push-notifications.html">Mobile Push Notification Service</a>.
{% else %}
Your organization will be downgraded to <strong>Zulip Cloud Free</strong> at the end of the current billing
period (<strong>{{ renewal_date }}</strong>). You will lose access to unlimited search history and
<a href="{{ billing_base_url }}/plans/">other features</a> of your current plan.
{% endif %}
{% elif downgrade_at_end_of_free_trial %}
{% if is_self_hosted_billing %}
Your organization will be downgraded to the <strong>Free</strong> plan at the end of the free trial
({{ renewal_date }}). You will lose access to the
<a href="{{ billing_base_url }}/plans/#self-hosted-plan-comparison">benefits</a>
of your current plan. For organizations with more than 10 users, this
includes losing access to the
<a href="https://zulip.readthedocs.io/en/stable/production/mobile-push-notifications.html">Mobile Push Notification Service</a>.
{% else %}
Your organization will be downgraded to <strong>Zulip Cloud Free</strong> at the end of the free trial
(<strong>{{ renewal_date }}</strong>). You will lose access to unlimited search history and
<a href="{{ billing_base_url }}/plans/">other features</a> of your current plan.
{% endif %}
{% else %}
{% if fixed_price_plan %}
This is a fixed-price plan.
{% endif %}
{% if charge_automatically %}
{% if complimentary_access_plan %}
Your plan will automatically upgrade to {{ complimentary_access_next_plan_name }} on {{ complimentary_access_plan_end_date }}.
{% else %}
Your plan will automatically renew on <strong>{{ renewal_date }}</strong>.
{% endif %}
{% else %}
{% if free_trial %}
{% if has_paid_invoice_for_free_trial %}
You have no outstanding invoices. Your next plan renewal date is <b>{{ free_trial_next_renewal_date_after_invoice_paid }}</b>. An invoice will be sent to <b>{{ stripe_email }}</b> on the same day.
{% else %}
To ensure continuous access to {{ plan_name }}, please pay your <a href="{{ billing_base_url }}/invoices/">invoice</a> before the end of your trial.
Your free trial ends on <br /><strong>{{ renewal_date }}</strong>.
{% endif %}
{% else %}
Next invoice will be sent on <strong>{{ renewal_date }}</strong>.
{% endif %}
{% endif %}
<br />
{% if free_trial and not charge_automatically %}
{% else %}
<div class="input-box billing-page-field">
<h2 class="billing-section-title">Expected next charge</h2>
{% if not fixed_price_plan %}
<div class="billing-section-content">
${{ pre_discount_renewal_cents }} (${{ price_per_license }} x {{ licenses_at_next_renewal }} {{ 'user' if licenses_at_next_renewal == 1 else 'users' }} x
{% if switch_to_annual_at_end_of_cycle %}
12 months
{%- elif switch_to_monthly_at_end_of_cycle %}
1 month
{%- else %}
{{ "1 month" if billing_frequency == "Monthly" else "12 months" }}
{%- endif -%})
{% if discounted_months_left != 0 %}
<br />
<span class="flat-discount-minus-sign">−</span>
<span class="flat-discount-separator">${{ flat_discount }}/month off</span> <i class="billing-page-discount">({{ discounted_months_left }} {{ "month" if discounted_months_left == 1 else "months" }} remaining)</i>
{% endif %}
{% if discount_percent %}
<br />
<i class="billing-page-discount">Includes: {{ discount_percent }}% discount</i>
{% endif %}
</div>
{% endif %}
</div>
<h1>${{ renewal_amount }}</h1>
{% endif %}
{% if not fixed_price_plan and using_min_licenses_for_plan %}
<i>Minimum purchase for this plan: {{ min_licenses_for_plan }} licenses</i>
{% endif %}
{% endif %}
{% elif fixed_price_plan %}
This is a fixed-price plan. Your plan ends on <strong>{{ renewal_date }}</strong>.
You will be contacted by Zulip Sales a couple of months before <strong>{{renewal_date}}</strong> to discuss plan renewal.
{% else %}
Your plan ends on <strong>{{ renewal_date }}</strong>, and does not renew.
{% endif %}
</div>
</div>
<div class="input-box billing-page-field">
<h2 class="billing-section-title">Invoices</h2>
<div class="billing-section-content">
<a href="{{ billing_base_url }}/invoices/">
View invoices
</a>
</div>
</div>
{% if free_trial and not charge_automatically %}
<!--
We don't show cancel plan button for free trial with invoice payments to avoid confusion about the current status.
Plan automatically downgrades anyway if user fails to pay the invoice.
-->
{% else %}
<div id="planchange-error" class="alert alert-danger"></div>
<div id="planchange-input-section">
{% if free_trial and not downgrade_at_end_of_free_trial %}
<div class="end-free-trial plan-toggle-action input-box billing-page-field" id="end-free-trial">
<button class="end-free-trial-button plan-toggle-action-button">
<span class="billing-button-text">Cancel plan</span>
<object class="loader billing-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
</div>
{% elif downgrade_at_end_of_cycle or downgrade_at_end_of_free_trial %}
<div class="reactivate-current-plan plan-toggle-action input-box billing-page-field" id="reactivate-subscription">
<button class="reactivate-current-plan-button plan-toggle-action-button">
<span class="billing-button-text">
{% if downgrade_at_end_of_free_trial %}
Cancel downgrade
{% else %}
Reactivate subscription
{% endif %}
</span>
<object class="loader billing-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
</div>
{% elif complimentary_access_plan %}
<div class="plan-toggle-action input-box billing-page-field" id="cancel-complimentary-access-upgrade">
<button class="plan-toggle-action-button">
<span class="billing-button-text">Cancel upgrade</span>
<object class="loader billing-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
</div>
{% else %}
<div class="cancel-current-plan plan-toggle-action input-box billing-page-field" id="cancel-subscription">
<button class="plan-toggle-action-button {% if is_self_hosted_billing %}cancel-current-self-hosted-plan-button{% else %}cancel-current-cloud-plan-button{% endif %}">
<span class="billing-button-text">Cancel plan</span>
<object class="loader billing-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
</div>
{% endif %}
</div>
<form id="planchange-form">
{% if free_trial %}
<input name="status" type="hidden" value="{{ CustomerPlan.DOWNGRADE_AT_END_OF_FREE_TRIAL }}" />
{% elif downgrade_at_end_of_free_trial %}
<input name="status" type="hidden" value="{{ CustomerPlan.FREE_TRIAL }}" />
{% elif downgrade_at_end_of_cycle or complimentary_access_plan %}
<input name="status" type="hidden" value="{{ CustomerPlan.ACTIVE }}" />
{% else %}
<input name="status" type="hidden" value="{{ CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE }}" />
{% endif %}
</form>
{% endif %}
</div>
</div>
<hr />
<div class="support-link">
<p>
To make changes to your plan or view your billing history <a href="mailto:support@zulip.com">contact Zulip support</a>.
</p>
</div>
{% else %}
<!-- For sponsored or sponsorship pending organizations we redirect to /sponsorship page. -->
<!-- For organizations on free plan we redirect to /plans page. -->
<div class="billing-status-page">
<div class="pitch">
<h1>Zulip Cloud billing for {{ org_name }}</h1>
</div>
<div class="white-box">
<p>
You do not have permission to view this page.
</p>
</div>
</div>
{% endif %}
</div>
</div>
<div id="confirm-end-free-trial" class="micromodal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="confirm-end-free-trial-label">
<header class="modal__header">
<div class="modal__header-content">
<h1 id="confirm-end-free-trial-label" class="modal__title dialog_heading">
Downgrade {{ org_name }} to
{% if is_self_hosted_billing %}
Free plan?
{% else %}
Zulip Cloud Free?
{% endif %}
</h1>
</div>
<button type="button" class="modal__close" aria-label="{{ _('Close modal') }}" tabindex="0" data-micromodal-close>
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
</header>
<main class="modal__content">
<p>
{% if is_self_hosted_billing %}
Your organization will be downgraded to the <strong>Free</strong> plan at the
end of your free trial ({{ renewal_date }}). You will lose access to the
<a href="{{ billing_base_url }}/plans/#self-hosted-plan-comparison">benefits</a>
of your current plan. For organizations with more than 10 users, this
includes losing access to the
<a href="https://zulip.readthedocs.io/en/stable/production/mobile-push-notifications.html">Mobile Push Notification Service</a>.
{% else %}
Your organization will be downgraded to <strong>Zulip Cloud Free</strong> at the end of your free trial
({{ renewal_date }}). You will lose access to unlimited search history and
<a href="{{ billing_base_url }}/plans/">other features</a>
of your current plan. Are you sure you want to continue?
{% endif %}
</p>
</main>
<footer class="modal__footer">
<button class="modal__button dialog_exit_button" aria-label="{{ '(Close this dialog window)' }}" data-micromodal-close>{{ _('Never mind') }}</button>
<button class="modal__button dialog_submit_button">
<span>{{ _('Downgrade') }}</span>
</button>
</footer>
</div>
</div>
</div>
<div id="confirm-licenses-modal-increase" class="micromodal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="confirm-licenses-modal-increase-label">
<header class="modal__header">
<div class="modal__header-content">
<h1 id="confirm-licenses-modal-increase-label" class="modal__title dialog_heading">
Confirm adding licenses
</h1>
</div>
<button type="button" class="modal__close" aria-label="{{ _('Close modal') }}" tabindex="0" data-micromodal-close>
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
</header>
<main class="modal__content">
<p>
Are you sure you want to increase the number of licenses from
<b><span class="current_license_count_holder"></span></b> to
<b><span class="new_license_count_holder"></span></b>?
</p>
<p>
{% if payment_method == "Invoice" %}
You will receive an invoice for
{% else %}
You will be charged for
{% endif %}
<b><span class="difference_license_count_holder"></span></b> additional licenses.
</p>
</main>
<footer class="modal__footer">
<button class="modal__button dialog_exit_button" aria-label="{{ '(Close this dialog window)' }}" data-micromodal-close>{{ _('Cancel') }}</button>
<button class="modal__button dialog_submit_button">
<span>{{ _('Confirm') }}</span>
</button>
</footer>
</div>
</div>
</div>
<div id="confirm-licenses-modal-decrease" class="micromodal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="confirm-licenses-modal-decrease-label">
<header class="modal__header">
<div class="modal__header-content">
<h1 id="confirm-licenses-modal-decrease-label" class="modal__title dialog_heading">
Confirm decreasing licenses
</h1>
</div>
<button type="button" class="modal__close" aria-label="{{ _('Close modal') }}" tabindex="0" data-micromodal-close>
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
</header>
<main class="modal__content">
<p>
Are you sure you want to decrease the number of licenses from
<b><span class="current_license_count_holder"></span></b> to
<b><span class="new_license_count_holder"></span></b>?
</p>
<p>
Your organization will be limited to at most
<b><span class="new_license_count_holder"></span></b> users.
</p>
</main>
<footer class="modal__footer">
<button class="modal__button dialog_exit_button" aria-label="{{ '(Close this dialog window)' }}" data-micromodal-close>{{ _('Cancel') }}</button>
<button class="modal__button dialog_submit_button">
<span>{{ _('Confirm') }}</span>
</button>
</footer>
</div>
</div>
</div>
<div id="confirm-cancel-cloud-subscription-modal" class="micromodal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="confirm-cancel-cloud-subscription-modal-label">
<header class="modal__header">
<div class="modal__header-content">
<h1 id="confirm-cancel-cloud-subscription-modal-label" class="modal__title dialog_heading">
Downgrade {{ org_name }} to Zulip Cloud Free?
</h1>
</div>
<button type="button" class="modal__close" aria-label="{{ _('Close modal') }}" tabindex="0" data-micromodal-close>
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
</header>
<main class="modal__content">
<p>
Your organization will be downgraded to <strong>Zulip Cloud Free</strong> at the end of the current billing
period ({{ renewal_date }}). You will lose access to unlimited search history and
<a href="{{ billing_base_url }}/plans/">other features</a>
of your current plan. Are you sure you want to continue?
</p>
</main>
<footer class="modal__footer">
<button class="modal__button dialog_exit_button" aria-label="{{ '(Close this dialog window)' }}" data-micromodal-close>{{ _('Never mind') }}</button>
<button class="modal__button dialog_submit_button">
<span>{{ _('Downgrade') }}</span>
</button>
</footer>
</div>
</div>
</div>
<div id="confirm-cancel-self-hosted-subscription-modal" class="micromodal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="confirm-cancel-self-hosted-subscription-modal-label">
<header class="modal__header">
<div class="modal__header-content">
<h1 id="confirm-cancel-self-hosted-subscription-modal-label" class="modal__title dialog_heading">
Downgrade {{ org_name }} to the Free plan?
</h1>
</div>
<button type="button" class="modal__close" aria-label="{{ _('Close modal') }}" tabindex="0" data-micromodal-close>
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
</header>
<main class="modal__content">
<p>
Your organization will be downgraded to the <strong>Free</strong> plan at the end of the
current billing period ({{ renewal_date }}). You will lose access to the
<a href="{{ billing_base_url }}/plans/#self-hosted-plan-comparison">benefits</a>
of your current plan. For organizations with more than 10 users, this
includes losing access to the
<a href="https://zulip.readthedocs.io/en/stable/production/mobile-push-notifications.html">Mobile Push Notification Service</a>.
</p>
</main>
<footer class="modal__footer">
<button class="modal__button dialog_exit_button" aria-label="{{ '(Close this dialog window)' }}" data-micromodal-close>{{ _('Never mind') }}</button>
<button class="modal__button dialog_submit_button">
<span>{{ _('Downgrade') }}</span>
</button>
</footer>
</div>
</div>
</div>
<div id="confirm-cancel-complimentary-access-upgrade-modal" class="micromodal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="confirm-cancel-complimentary-access-upgrade-modal-label">
<header class="modal__header">
<div class="modal__header-content">
<h1 id="confirm-cancel-complimentary-access-upgrade-modal-label" class="modal__title dialog_heading">
Cancel scheduled upgrade of {{ org_name }}?
</h1>
</div>
<button type="button" class="modal__close" aria-label="{{ _('Close modal') }}" tabindex="0" data-micromodal-close>
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
</header>
<main class="modal__content">
<p>
Your organization will be not be upgraded to <strong>{{ complimentary_access_next_plan_name }}</strong>
on {{ complimentary_access_plan_end_date }}. If your organization has more than
10 users at that time, you will lose access to the
<a href="https://zulip.readthedocs.io/en/stable/production/mobile-push-notifications.html">Mobile Push Notification Service</a>.
You will also not receive the <a href="{{ billing_base_url }}/plans/#self-hosted-plan-comparison">other benefits</a>
of the {{ complimentary_access_next_plan_name }} plan. Are you sure you want to continue?
</p>
</main>
<footer class="modal__footer">
<button class="modal__button dialog_exit_button" aria-label="{{ '(Close this dialog window)' }}" data-micromodal-close>{{ _('Never mind') }}</button>
<button class="modal__button dialog_submit_button">
<span>{{ _('Cancel upgrade') }}</span>
</button>
</footer>
</div>
</div>
</div>
<div id="confirm-toggle-license-management-modal" class="micromodal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="confirm-toggle-license-management-modal-label">
<header class="modal__header">
<div class="modal__header-content">
<h1 id="confirm-toggle-license-management-modal-label" class="modal__title dialog_heading">
Confirm switching to
{% if automanage_licenses %}
manual
{% else %}
automatic
{% endif %}
license management
</h1>
<div class="modal__subtitle">
Are you sure you want to switch to
<a href="/help/self-hosted-billing#how-does-automatic-license-management-work">
{% if automanage_licenses %}
manual
{% else %}
automatic
{% endif %}
license management
</a>?
</div>
</div>
<button type="button" class="modal__close" aria-label="{{ _('Close modal') }}" tabindex="0" data-micromodal-close>
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
</header>
<footer class="modal__footer">
<button class="modal__button dialog_exit_button" aria-label="{{ '(Close this dialog window)' }}" data-micromodal-close>{{ _('Never mind') }}</button>
<button class="modal__button dialog_submit_button">
<span>{{ _('Confirm') }}</span>
</button>
</footer>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,31 @@
{% extends "zerver/portico.html" %}
{% block title %}
<title>Not available for demo organizations | Zulip</title>
{% endblock %}
{% block portico_content %}
<div class="app portico-page">
<div class="app-main portico-page-container center-block flex full-page account-creation new-style">
<div class="inline-block">
<div class="get-started">
<h1>Not available for demo organizations</h1>
</div>
<div class="white-box">
<p>
{% if upgrade_request %}
Demo organizations cannot be directly upgraded to a paid plan.
{% elif sponsorship_request %}
Demo organizations cannot apply for sponsorship.
{% endif %}
Please start by
<a href="/help/demo-organizations#convert-a-demo-organization-to-a-permanent-organization">
converting your demo organization
</a>
to a permanent Zulip Cloud organization.
</p>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,53 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "billing-event-status" %}
{% block title %}
<title>{{ _("Billing status") }} | Zulip</title>
{% endblock %}
{% block customhead %}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{% endblock %}
{% block content %}
<div class="app portico-page">
<div class="billing-upgrade-page">
<div class="hero small-hero"></div>
<div class="page-content">
<div class="main">
<br />
<div id="data" data-stripe-session-id="{{ stripe_session_id}}" data-stripe-invoice-id="{{ stripe_invoice_id }}" data-billing-base-url="{{ billing_base_url }}"></div>
<div class="alert alert-success" id="webhook-success"></div>
<div class="alert alert-danger" id="webhook-error"></div>
<div id="webhook-loading">
<div class="zulip-loading-logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 773.12 773.12">
<circle cx="386.56" cy="386.56" r="386.56"/>
<path d="M566.66 527.25c0 33.03-24.23 60.05-53.84 60.05H260.29c-29.61 0-53.84-27.02-53.84-60.05 0-20.22 9.09-38.2 22.93-49.09l134.37-120c2.5-2.14 5.74 1.31 3.94 4.19l-49.29 98.69c-1.38 2.76.41 6.16 3.25 6.16h191.18c29.61 0 53.83 27.03 53.83 60.05zm0-281.39c0 20.22-9.09 38.2-22.93 49.09l-134.37 120c-2.5 2.14-5.74-1.31-3.94-4.19l49.29-98.69c1.38-2.76-.41-6.16-3.25-6.16H260.29c-29.61 0-53.84-27.02-53.84-60.05s24.23-60.05 53.84-60.05h252.54c29.61 0 53.83 27.02 53.83 60.05z"/>
</svg>
</div>
<div id="webhook_loading_indicator"></div>
</div>
<form id="restartsession-form">
<input type="hidden" name="stripe_invoice_id" value="{{ stripe_invoice_id }}" />
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}" />
</form>
<div class="alert alert-success" id="restartsession-success">Redirecting to Stripe Checkout</div>
<div class="alert alert-danger" id="restartsession-error"></div>
<div id="restartsession-loading">
<div class="zulip-loading-logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 773.12 773.12">
<circle cx="386.56" cy="386.56" r="386.56"/>
<path d="M566.66 527.25c0 33.03-24.23 60.05-53.84 60.05H260.29c-29.61 0-53.84-27.02-53.84-60.05 0-20.22 9.09-38.2 22.93-49.09l134.37-120c2.5-2.14 5.74 1.31 3.94 4.19l-49.29 98.69c-1.38 2.76.41 6.16 3.25 6.16h191.18c29.61 0 53.83 27.03 53.83 60.05zm0-281.39c0 20.22-9.09 38.2-22.93 49.09l-134.37 120c-2.5 2.14-5.74-1.31-3.94-4.19l49.29-98.69c1.38-2.76-.41-6.16-3.25-6.16H260.29c-29.61 0-53.84-27.02-53.84-60.05s24.23-60.05 53.84-60.05h252.54c29.61 0 53.83 27.02 53.83 60.05z"/>
</svg>
</div>
<div id="restartsession_loading_indicator"></div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,56 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "billing_auth" %}
{% set PAGE_TITLE = "Authenticate server for Zulip plan management" %}
{% block portico_content %}
<div id="server-login-page" class="register-account flex full-page">
<div class="center-block new-style">
<div class="pitch">
<h1>Authenticate server<br/>for Zulip plan management</h1>
</div>
<div class="white-box">
<div id="server-login-page-details">
{% if error_message %}
<div id="server-login-error" class="alert alert-danger">{{ error_message }}</div>
{% endif %}
<div id="server-login-input-section">
<form id="server-login-form" method="post" action="/serverlogin/">
{{ csrf_input }}
{% if next_page %}
<input type="hidden" name="next_page" value="{{ next_page }}" />
{% endif %}
<div id="server-login-form-title" class="input-box server-login-form">
<div class="not-editable-realm-field">
To access plan management for a Zulip
server, first enter <a href="https://zulip.readthedocs.io/en/stable/production/mobile-push-notifications.html#plan-management-for-an-entire-zulip-server">your server's credentials</a>.
</div>
</div>
<div class="input-box server-login-form-field">
<label for="zulip-org-id" class="inline-block label-title">
zulip_org_id
</label>
<input id="zulip-org-id" name="zulip_org_id" class="required" type="text"/>
<div class="alert alert-danger server-login-form-field-error zulip_org_id-error"></div>
</div>
<div class="input-box server-login-form-field">
<label for="password" class="inline-block label-title">zulip_org_key</label>
<input id="password" name="zulip_org_key" class="required" type="password"/>
<div class="alert alert-danger server-login-form-field-error zulip_org_key-error"></div>
</div>
<div id="server-login-page-button-container">
<button type="submit" id="server-login-button" class="stripe-button-el invoice-button">
<span class="server-login-button-text">Continue</span>
<img class="loader remote-billing-button-loader" src="{{ static('images/loading/loader-white.svg') }}" alt="" />
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,52 @@
{% extends "zerver/portico_signup.html" %}
{% set entrypoint = "billing_auth" %}
{% block title %}
{% if remote_server_hostname %}
<title>Enter log in email | Zulip</title>
{% else %}
<title>Enter email | Zulip</title>
{% endif %}
{% endblock %}
{% block portico_content %}
<div class="register-account flex full-page" id="remote-billing-confirm-email">
<div class="center-block new-style">
<div class="pitch">
{% if remote_server_hostname %}
<h1>Enter log in email</h1>
{% else %}
<h1>Enter email</h1>
{% endif %}
</div>
<div class="white-box">
<form id="remote-billing-confirm-email-form" method="post" action="{{ action_url }}">
{{ csrf_input }}
{% if next_page %}
<input type="hidden" name="next_page" value="{{ next_page }}" />
{% endif %}
<div class="input-box server-login-form-field" id="remote-billing-confirm-email-intro">
<div class="not-editable-realm-field">
{% if remote_server_hostname %}
Enter the email address of the person who is logging in to manage plans and billing for this server (yourself or someone else). They will receive an email from Zulip with a log in link.
{% else %}
Enter the email address you want to use for Zulip plan management. You will receive a one-time confirmation email.
{% endif %}
</div>
</div>
<div class="input-box server-login-form-field">
<label for="email" class="inline-block label-title">Email</label>
<input id="email" name="email" type="email" class="required" {% if email %}value="{{ email }}"{% endif %} />
<div id="server-login-form-email-error" class="alert alert-danger server-login-form-field-error email-error"></div>
</div>
<div class="upgrade-button-container">
<button type="submit" id="remote-billing-confirm-email-button" class="stripe-button-el invoice-button">
<span class="server-login-button-text">Continue</span>
<img class="loader remote-billing-button-loader" src="{{ static('images/loading/loader-white.svg') }}" alt="" />
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,41 @@
{% extends "zerver/portico_signup.html" %}
{% set entrypoint = "billing_auth" %}
{% block title %}
{% if remote_server_hostname %}
<title>Log in link sent | Zulip</title>
{% else %}
<title>Confirm your email address | Zulip</title>
{% endif %}
{% endblock %}
{% block portico_content %}
<div class="app portico-page">
<div class="app-main portico-page-container center-block flex full-page account-creation account-email-confirm-container new-style">
<div class="inline-block">
<div class="get-started">
{% if remote_server_hostname %}
<h1>Log in link sent</h1>
{% else %}
<h1>Confirm your email address</h1>
{% endif %}
</div>
<div class="white-box">
{% if remote_server_hostname %}
<p>We have sent <span class="user_email semi-bold">{{ email }}</span> a log in link for Zulip plan management. This link will expire in 24 hours.</p>
{% else %}
<p>To finish logging in, check your email account (<span class="user_email semi-bold">{{ email }}</span>) for a confirmation email from Zulip.</p>
{% endif %}
{% include 'zerver/dev_env_email_access_details.html' %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block customhead %}
{{ super() }}
{% endblock %}

View File

@@ -0,0 +1,81 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "billing_auth" %}
{% block title %}
<title>
{% if next_page and next_page == "deactivate" %}
Log in to deactivate registration for {{ host }} | Zulip
{% else %}
Log in to Zulip plan management for {{ host }} | Zulip
{% endif %}
</title>
{% endblock %}
{% block portico_content %}
<div id="remote-billing-confirm-login-page" class="register-account flex full-page">
<div class="center-block new-style">
<div class="pitch">
{% if next_page and next_page == "deactivate" %}
<h1>Log in to deactivate registration for<br/>{{ host }}</h1>
{% else %}
<h1>Log in to Zulip plan management for<br/>{{ host }}</h1>
{% endif %}
</div>
<div class="white-box">
<form id="remote-billing-confirm-login-form" method="post" action="{{ action_url }}">
{{ csrf_input }}
<div class="input-box remote-billing-confirm-login-form-field">
<label for="full_name" class="inline-block label-title">Name</label>
{% if not user_full_name %}
<input id="full_name" name="full_name" class="required" type="text" />
<div id="remote-billing-confirm-login-form-full_name-error" class="alert alert-danger remote-billing-confirm-login-form-field-error full_name-error"></div>
{% else %}
<div class="not-editable-realm-field">
{{ user_full_name }}
</div>
{% endif %}
</div>
<div class="input-box remote-billing-confirm-login-form-field">
<label for="user-email" class="inline-block label-title">
Email
</label>
<div id="user-email" class="not-editable-realm-field">
{{ user_email }}
</div>
</div>
<!-- user_full_name is not present only when user first logs in which also perfect to set email preferences -->
{% if (not user_full_name) and (not (next_page and next_page == "deactivate")) %}
<div class="input-group remote-billing-confirm-email-subscription-form-field">
<label for="enable-major-release-emails" class="checkbox">
<input id="enable-major-release-emails" name="enable_major_release_emails" type="checkbox" value="true" checked="checked" />
<span class="rendered-checkbox"></span>
Sign me up for emails about <strong>major Zulip releases</strong> and other big announcements (a few times a year)
</label>
<label for="enable-maintenance-release-emails" class="checkbox">
<input id="enable-maintenance-release-emails" name="enable_maintenance_release_emails" type="checkbox" value="true" checked="checked" />
<span class="rendered-checkbox"></span>
Sign me up for emails about <strong>all Zulip releases</strong>, including security and maintenance releases (recommended for server administrators)
</label>
</div>
{% endif %}
{% if tos_consent_needed %}
<div class="input-group terms-of-service remote-billing-confirm-login-form-field" id="remote-billing-confirm-login-tos-wrapper">
<label for="remote-billing-confirm-login-tos" class="checkbox">
<input id="remote-billing-confirm-login-tos" name="tos_consent" class="required" type="checkbox" value="true" />
<span class="rendered-checkbox"></span>
I agree to the <a href="{{ root_domain_url }}/policies/terms" target="_blank" rel="noopener noreferrer">Terms of Service</a>.
</label>
<div id="remote-billing-confirm-login-form-tos_consent-error" class="alert alert-danger remote-billing-confirm-login-form-field-error tos_consent-error"></div>
</div>
{% endif %}
<div class="upgrade-button-container">
<button type="submit" id="remote-billing-confirm-login-button" class="stripe-button-el invoice-button">
<span class="remote-billing-confirm-login-button-text">Continue</span>
<img class="loader remote-billing-button-loader" src="{{ static('images/loading/loader-white.svg') }}" alt="" />
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,55 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "billing_auth" %}
{% block title %}
<title>{{ _("Deactivate server registration?") }} | Zulip</title>
{% endblock %}
{% block portico_content %}
<div id="server-deactivate-page" class="register-account account-deactivation flex full-page">
<div class="new-style">
<div class="pitch">
<h1>
Deactivate registration for<br />{{ server_hostname }}?
</h1>
</div>
<div class="white-box">
<div id="server-deactivate-details">
{% if show_existing_plan_error %}
<div id="server-deactivate-error" class="alert alert-danger">
Could not deactivate registration. You must first
<a href="https://zulip.com/help/self-hosted-billing#cancel-paid-plan">cancel</a>
all paid plans associated with this server, including scheduled plan upgrades.
</div>
{% endif %}
<form id="server-deactivate-form" method="post" action="{{ action_url }}">
{{ csrf_input }}
<div id="server-deactivate-form-top-description" class="input-box server-deactivate-form-field">
<div class="not-editable-realm-field">
You are about to deactivate this server's
registration with
the <a href="https://zulip.readthedocs.io/en/stable/production/mobile-push-notifications.html">Zulip
Mobile Push Notification Service</a>. This
will disable delivery of mobile push
notifications for all organizations hosted
on <b>{{ server_hostname }}</b>.
</div>
</div>
<input type="hidden" name="confirmed" value="true" />
<div class="upgrade-button-container">
<button type="submit" id="server-deactivate-button" class="stripe-button-el invoice-button">
<span class="server-deactivate-button-text">Deactivate registration</span>
<img class="loader remote-billing-button-loader" src="{{ static('images/loading/loader-white.svg') }}" alt="" />
</button>
</div>
</form>
<div class="input-box upgrade-page-field">
<div class="support-link not-editable-realm-field">
Questions? Contact <a href="mailto:support@zulip.com">support@zulip.com</a>.
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,32 @@
{% extends "zerver/portico_signup.html" %}
{% set entrypoint = "billing_auth" %}
{% block title %}
<title>Server registration deactivated | Zulip</title>
{% endblock %}
{% block portico_content %}
<div class="register-account flex full-page" id="account-deactivated-success-page">
<div class="center-block new-style">
<div class="pitch">
<h1>
Registration deactivated for<br />{{ server_hostname }}
</h1>
</div>
<div class="white-box">
<div id="account-deactivated-success-page-details">
<div class="input-box account-deactivated-success-page-field" id="account-deactivated-success-page-top-message">
<div class="not-editable-realm-field">
Your server's registration has been deactivated.
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block customhead %}
{{ super() }}
{% endblock %}

View File

@@ -0,0 +1,30 @@
{% extends "zerver/portico_error_pages/portico_error_page.html" %}
{% block title %}
<title>{{ _("Plan management not available") }} | Zulip</title>
{% endblock %}
{% block error_page_content %}
<img src="{{ static('images/errors/400art.svg') }}" alt=""/>
<div class="errorbox">
<div class="errorcontent">
<h1 class="lead">{{ _("Plan management not available") }}</h1>
<p>
{% trans %} Plan management is not available for this
organization, because your Zulip server is already on a
{{ server_plan_name }} plan, which covers all
organizations on this server. See the <b>Server-level billing</b> tab of the
<a href="https://zulip.com/help/self-hosted-billing#log-in-to-billing-management">log
in instructions</a> to administer the plan for your
Zulip server.
{% endtrans %}
</p>
<p>
{% trans %} To move the plan from the server to this
organization, or for other questions, <a href="mailto:{{
support_email }}">contact support</a>.
{% endtrans %}
</p>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,26 @@
{% extends "zerver/portico_error_pages/portico_error_page.html" %}
{% block title %}
<title>{{ _("Plan management not available") }} | Zulip</title>
{% endblock %}
{% block error_page_content %}
<img src="{{ static('images/errors/400art.svg') }}" alt=""/>
<div class="errorbox">
<div class="errorcontent">
<h1 class="lead">{{ _("Plan management not available") }}</h1>
<p>
{% trans %}
Plan management for this server is not available because at least one organization
hosted on this server already has an active plan.
{% endtrans %}
</p>
<p>
{% trans %}
<a href="https://zulip.com/help/self-hosted-billing#manage-billing">Log in</a> to plan management for your
organization instead, or <a href='mailto:{{ support_email }}'>contact support</a> with any questions.
{% endtrans %}
</p>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,19 @@
{% extends "zerver/portico_error_pages/portico_error_page.html" %}
{% block title %}
<title>{{ _("Rate limit exceeded") }} | Zulip</title>
{% endblock %}
{% block error_page_content %}
<img src="{{ static('images/errors/500art.svg') }}" alt=""/>
<div class="errorbox">
<div class="errorcontent">
<h1 class="lead">{{ _("Rate limit exceeded.") }}</h1>
<p>
{% trans %}Your server has exceeded the limit for how
often this action can be performed.{% endtrans %}
{% trans %}You can try again in {{retry_after_string}}.{% endtrans %}
</p>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,42 @@
{% extends "zerver/portico.html" %}
{% block title %}
<title>Required metadata missing | Zulip</title>
{% endblock %}
{% block portico_content %}
<div class="center-block flex full-page account-creation new-style">
<div class="inline-block">
<div class="get-started">
<h1>Error: Server not uploading basic metadata</h1>
</div>
<div class="white-box">
<p>
Managing your Zulip plan requires your server to upload
up-to-date
<a
href="https://zulip.readthedocs.io/en/latest/production/mobile-push-notifications.html#uploading-basic-metadata">basic
metadata</a>. This data is not being uploaded successfully.
</p>
{% if remote_realm_session %}
<p>
If your Zulip server's administrator is not able to fix this, <a
href="mailto:support@zulip.com">contact Zulip support</a>.
</p>
{% elif supports_remote_realms %}
<p>
If your Zulip server's administrator is not able to fix this, <a
href="mailto:support@zulip.com">contact Zulip support</a>.
</p>
{% else %}
<p>
Your Zulip server's administrator can fix this issue by <a
href="https://zulip.readthedocs.io/en/stable/production/upgrade.html">upgrading</a>
the server to Zulip 8.0+, or <a href="https://zulip.readthedocs.io/en/stable/production/mobile-push-notifications.html#uploading-usage-statistics">enabling the
<code>SUBMIT_USAGE_STATISTICS</code> setting</a>.
</p>
{% endif %}
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,188 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "sponsorship" %}
{% block title %}
<title>
{% if is_sponsored or is_sponsorship_pending %}
Zulip
{% if is_remotely_hosted %}
{% else %}
Cloud
{% endif %}
billing for {{ org_name }}
{% else %}
Request Zulip
{% if is_remotely_hosted %}
{% else %}
Cloud
{% endif %} sponsorship
{% endif %}
</title>
{% endblock %}
{% block portico_content %}
{% if is_sponsored or is_sponsorship_pending %}
<div class="register-account flex full-page sponsorship-status-page">
<div class="center-block new-style">
<div class="alert alert-success sponsorship-page-success" id="sponsorship-status-success-message-top">
{% if is_sponsored %}
Zulip is sponsoring a free <a href="{{ billing_base_url }}/plans/">{{ sponsorship_plan_name }}</a> plan for this organization. 🎉
{% else %}
This organization has requested sponsorship for a
{% if is_remotely_hosted and sponsorship_plan_name != "Community" %}
discounted
{% endif %}
<a href="{{ billing_base_url }}/plans/">{{ sponsorship_plan_name }}</a> plan.<br/><a href="mailto:support@zulip.com">Contact Zulip support</a> with any questions or updates.
{% endif %}
</div>
<div class="pitch">
<h1>
Zulip
{% if is_remotely_hosted %}
{% else %}
Cloud
{% endif %}
billing for {{ org_name }}
</h1>
</div>
<div class="white-box">
<div id="sponsorship-status-page-details">
<div class="input-box sponsorship-form-field">
<label for="sponsored-org-current-plan" class="inline-block label-title">Your plan</label>
<div id="sponsored-org-current-plan" class="not-editable-realm-field">
{% if is_sponsored %}
<a href="{{ billing_base_url }}/plans/">{{ sponsorship_plan_name }}</a>
{% elif complimentary_access %}
<a href="{{ billing_base_url }}/plans/">Zulip Basic</a> <i>(complimentary access)</i>
{% else %}
<a href="{{ billing_base_url }}/plans/">{{ plan_name }}</a>
{% endif %}
</div>
</div>
</div>
</div>
{% if is_sponsored %}
<hr />
<div class="support-link">
<p>
To make changes to your plan or view your billing history <a href="mailto:support@zulip.com">contact Zulip support</a>.
</p>
</div>
{% endif %}
</div>
</div>
{% else %}
<div class="register-account flex full-page sponsorship-page">
<div class="center-block new-style">
<div class="pitch">
<h1>
Request Zulip
{% if is_remotely_hosted %}
{% else %}
Cloud
{% endif %} sponsorship
</h1>
</div>
<div class="white-box">
<div id="sponsorship-error" class="alert alert-danger"></div>
<div id="sponsorship-input-section">
<form id="sponsorship-form" method="post" data-billing-base-url="{{ billing_base_url }}" data-is-remotely-hosted="{{ is_remotely_hosted }}">
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}" />
<div class="input-box sponsorship-form-field">
<label for="org-name" class="inline-block label-title">Organization</label>
<div id="org-name" class="not-editable-realm-field">{{ org_name }}</div>
</div>
<div class="input-box sponsorship-form-field">
<div class="inline-block relative">
<select name="organization_type" id="organization-type" class="sponsorship-form-select">
{% for org_type in sorted_org_types %}
{% if not org_type[1].hidden %}
<option data-string-value="{{ org_type[0] }}"
{% if org_type[1].id == realm_org_type %}selected{% endif %}
value="{{ org_type[1].id }}">
{{ _(org_type[1].name) }}
</option>
{% endif %}
{% endfor %}
</select>
</div>
<label for="organization_type" class="inline-block label-title">
Organization type
{% if is_remotely_hosted %}
<a href="/help/self-hosted-billing#free-community-plan" target="_blank" rel="noopener noreferrer">
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
</a>
{% endif %}
</label>
</div>
<p id="sponsorship-discount-details"></p>
{% if is_remotely_hosted %}
<div class="input-box sponsorship-form-field">
<div class="inline-block relative">
<select name="requested_plan" id="organization-requested-plan" class="sponsorship-form-select">
<option value="Community" selected>
Community
</option>
<option value="Basic">
Basic (discounted)
</option>
<option value="Business">
Business (discounted)
</option>
</select>
</div>
<label for="organization-requested-plan" class="inline-block label-title">Requested plan</label>
</div>
{% endif %}
<div class="input-box sponsorship-form-field">
<label for="org-website" class="inline-block
label-title">Organization website (if any)</label>
<input id="org-website" name="website" type="text"/>
<div id="sponsorship-org-website-error" class="alert alert-danger sponsorship-field-error"></div>
</div>
<div class="input-box sponsorship-form-field">
<label for="description" class="inline-block
label-title">Description of your organization</label>
<textarea id="description" name="description" cols="100" rows="5"></textarea>
<div id="sponsorship-description-error" class="alert alert-danger sponsorship-field-error"></div>
</div>
<div class="input-box sponsorship-form-field">
<label for="plan-to-use-zulip" class="inline-block
label-title">How do you plan to use Zulip?</label>
<textarea id="plan-to-use-zulip" name="plan_to_use_zulip" cols="100" rows="2"></textarea>
<div id="sponsorship-plan-to-use-zulip-error" class="alert alert-danger sponsorship-field-error"></div>
</div>
<div class="input-box sponsorship-form-field">
<label for="expected-total-users" class="inline-block label-title">Expected number of users (approximate range)</label>
<input id="expected-total-users" name="expected_total_users" type="text" />
<div id="sponsorship-expected-total-users-error" class="alert alert-danger sponsorship-field-error"></div>
</div>
<div class="input-box sponsorship-form-field">
<label for="paid-users-count" class="inline-block label-title">How many paid staff does your organization have?</label>
<input id="paid-users-count" name="paid_users_count" type="text"/>
<div id="sponsorship-paid-users-count-error" class="alert alert-danger sponsorship-field-error"></div>
</div>
<div class="input-box sponsorship-form-field">
<label for="paid-users-description" class="inline-block
label-title">Description of paid staff (if any)</label>
<textarea id="paid-users-description" name="paid_users_description" cols="100" rows="2"></textarea>
<div id="sponsorship-paid-users-description-error" class="alert alert-danger sponsorship-field-error"></div>
</div>
<div class="upgrade-button-container">
<button type="submit" id="sponsorship-button" class="stripe-button-el invoice-button">
<span class="sponsorship-button-text">Submit</span>
<object class="loader sponsorship-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,365 @@
{% extends "zerver/portico.html" %}
{% set entrypoint = "upgrade" %}
{% block title %}
<title>{{ _("Upgrade") }} | Zulip</title>
{% endblock %}
{% block portico_content %}
<div id="upgrade-page" class="register-account flex full-page">
<div class="center-block new-style">
{% if is_self_hosting_management_page and is_sponsorship_pending %}
<div class="alert alert-success billing-page-success" id="upgrade-page-sponsorship-pending-message-top">
This organization has requested sponsorship for a
{% if sponsorship_plan_name == "Business" %}
discounted
{% endif %}
<a href="{{ page_params.billing_base_url }}/plans/">{{ sponsorship_plan_name }}</a> plan.<br/><a href="mailto:support@zulip.com">Contact Zulip support</a> with any questions or updates.
</div>
{% endif %}
{% if success_message %}
<div class="alert alert-success billing-page-success" id="upgrade-success-message-top">
{{ success_message }}
</div>
{% endif %}
<div class="pitch">
<h1>
{% if page_params.free_trial_days %}
Start free trial of
{% else %}
Upgrade {{ customer_name }} to
{% endif %}
<a href="{{ page_params.billing_base_url }}/plans/">
{{ plan }}
</a>
</h1>
</div>
<div class="white-box">
<div id="upgrade-page-details">
{% if pay_by_invoice_payments_page %}
<div class="input-box top-of-page-notice upgrade-page-field">
<div class="not-editable-realm-field">
{% if is_free_trial_invoice_expired_notice %}
Your free trial of {{ free_trial_invoice_expired_notice_page_plan_name }} has expired.
<a href="{{ pay_by_invoice_payments_page }}" target="_blank" rel="noopener noreferrer">An invoice</a>
for ${{ scheduled_upgrade_invoice_amount_due }} has been sent to <b>{{ stripe_email }}</b>.
To reactivate your {{ free_trial_invoice_expired_notice_page_plan_name }} plan, please pay the amount due.
Once the invoice has been paid, reload this page to see billing details.
{% else %}
<a href="{{ pay_by_invoice_payments_page }}" target="_blank" rel="noopener noreferrer">An invoice</a>
{% if fixed_price_plan %}
for $<span class="due-today-price"></span>
{% endif %}
{% if scheduled_upgrade_invoice_amount_due %}
for ${{ scheduled_upgrade_invoice_amount_due }}
{% endif %}
has been sent to <b>{{ stripe_email }}</b>.
To complete the plan upgrade process, please pay the amount due. Once the invoice has been paid, reload this page to see billing details.
{% endif %}
</div>
</div>
{% else %}
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}" />
<form id="autopay-form">
<input type="hidden" name="seat_count" value="{{ seat_count }}" />
<input type="hidden" name="signed_seat_count" value="{{ signed_seat_count }}" />
<input type="hidden" name="salt" value="{{ salt }}" />
{% if page_params.setup_payment_by_invoice %}
<input type="hidden" name="billing_modality" value="send_invoice" />
{% else %}
<input type="hidden" name="billing_modality" value="charge_automatically" />
{% endif %}
<input type="hidden" name="tier" value="{{ page_params.tier }}" />
<div id="free-trial-top-banner" class="input-box upgrade-page-field">
{% if page_params.free_trial_days %}
<div class="not-editable-realm-field">
{% if page_params.setup_payment_by_invoice %}
An invoice will immediately be sent to <b>{{ stripe_email }}</b>. To ensure continuous access to Zulip Basic,
please pay your invoice before your free trial ends on {{ free_trial_end_date }}.
{% else %}
Add a credit card to start your <b>{{ page_params.free_trial_days }}-day free trial</b> of
{{ plan }}. Your card will not be charged if you
cancel in the first {{ page_params.free_trial_days }} days.
{% endif %}
</div>
{% endif %}
</div>
{% if page_params.free_trial_days and not page_params.setup_payment_by_invoice %}
<input type="hidden" name="schedule" value="monthly" />
{% else %}
<div class="input-box upgrade-page-field">
<select name="schedule" id="payment-schedule-select">
{% if fixed_price_plan %}
<option value="monthly">Pay monthly</option>
<option value="annual">Pay annually</option>
{% else %}
<option value="monthly" id="autopay_monthly_price"></option>
<option value="annual" id="autopay_annual_price_per_month"></option>
{% endif %}
</select>
<label for="payment-schedule-select">Payment schedule</label>
</div>
{% endif %}
{% if complimentary_access_plan_end_date %}
<div class="input-box upgrade-page-field">
<select name="remote_server_plan_start_date" id="remote-server-plan-start-date-select">
<option value="billing_cycle_end_date">{{ complimentary_access_plan_end_date }}</option>
<option value="today">Today</option>
</select>
<label for="remote-server-plan-start-date-select">Plan start date</label>
</div>
{% endif %}
{% if manual_license_management %}
<div class="input-box upgrade-page-field" id="upgrade-manual-license-count-wrapper">
<label for="licenses" class="inline-block label-title">Number of licenses {% if not exempt_from_license_number_check %}(minimum {{ seat_count }}){% endif %}</label>
<input type="number" name="licenses" autocomplete="off" {% if not exempt_from_license_number_check %}min="{{ seat_count }}" value="{{ seat_count }}"{% endif %} autocomplete="off" id="manual_license_count" required/>
<div id="upgrade-licenses-change-error" class="alert alert-danger upgrade-page-error"></div>
</div>
<input type="hidden" name="license_management" value="manual" />
{% else %}
<input type="hidden" name="license_management" value="automatic" />
{% endif %}
{% if complimentary_access_plan_end_date %}
<div class="input-box upgrade-page-field" id="due-today-for-future-update-wrapper">
<label for="due-today-for-future-update" class="inline-block label-title">
Due today
</label>
<div id="due-today-for-future-update" class="not-editable-realm-field">
<h1>$0</h1>
</div>
</div>
{% endif %}
<div class="input-box upgrade-page-field">
<label for="due-today" class="inline-block label-title">
{% if complimentary_access_plan_end_date %}
<span id="due-today-remote-server-title">
Due {{ complimentary_access_plan_end_date }}
</span>
{% endif %}
<span id="due-today-title">
Due
{% if page_params.free_trial_days %}
on {{ free_trial_end_date }}
{% else %}
today
{% endif %}
</span>
</label>
<div id="due-today" class="not-editable-realm-field">
{% if fixed_price_plan %}
<h1>$<span class="due-today-price"></span></h1>
{% else %}
$<span id="pre-discount-renewal-cents"></span>
($<span class="due-today-unit-price"></span> x
{% if not manual_license_management %}
{{ seat_count }}
{% else %}
<span class="due-today-license-count">{{ seat_count }}</span>
{% endif %}
<span class="due-today-license-count-user-plural">
{{ 'user' if seat_count == 1 else 'users' }}
</span> x
<span class="due-today-duration"></span>)
{% if page_params.flat_discounted_months > 0 %}
<br/>
<span class="flat-discount-minus-sign">−</span>
<span class="flat-discount-separator">$<span class="flat-discounted-price"></span>/month off</span> <i class="billing-page-discount">({{ page_params.flat_discounted_months }} {{ "month" if page_params.flat_discounted_months == 1 else "months" }} remaining)</i>
{% else %}
<br/>
<i class="billing-page-discount hide">Includes: <span class="billing-page-selected-schedule-discount"></span>% discount</i>
{% endif %}
<h1>$<span class="due-today-price"></span></h1>
{% if page_params.free_trial_days and not manual_license_management %}
<i>Your actual bill will depend on the number of
active users in your organization.</i>
{% endif %}
{% if not manual_license_management and using_min_licenses_for_plan %}
<i>Minimum purchase for this plan: {{ min_licenses_for_plan }} licenses</i>
{% endif %}
{% endif %}
</div>
</div>
{% if page_params.free_trial_days %}
{% else %}
<div id="license-management-details" class="input-box upgrade-page-field license-management-section">
{% if fixed_price_plan %}
<p class="not-editable-realm-field">
This is a fixed-price plan. You will be contacted by Zulip Sales a couple of months before the plan ends to discuss plan renewal.
</p>
{% elif not manual_license_management %}
<p class="not-editable-realm-field">
Your subscription will renew automatically. Your bill will vary based on the number of active users in your organization.
You can also <a href="{{ page_params.billing_base_url }}/upgrade/?manual_license_management=true&tier={{ page_params.tier }}">purchase a fixed number of licenses</a> instead.
{% if is_self_hosting_management_page %}
See <a href="/help/self-hosted-billing#how-does-manual-license-management-work" target="_blank" rel="noopener noreferrer">here</a> for details.
{% else %}
See <a href="/help/zulip-cloud-billing#how-does-manual-license-management-work" target="_blank" rel="noopener noreferrer">here</a> for details.
{% endif %}
</p>
<input type="hidden" name="licenses" id="automatic_license_count" value="{{ seat_count }}" />
{% else %}
<p class="not-editable-realm-field">
Your subscription will renew automatically. You will be able to manage the number of licenses on your organization's billing page.
{% if not page_params.setup_payment_by_invoice %}
You can also <a href="{{ page_params.billing_base_url }}/upgrade/?tier={{ page_params.tier }}">choose automatic license management</a> instead.
{% if is_self_hosting_management_page %}
See <a href="/help/self-hosted-billing#how-does-automatic-license-management-work" target="_blank" rel="noopener noreferrer">here</a> for details.
{% else %}
See <a href="/help/zulip-cloud-billing#how-does-automatic-license-management-work" target="_blank" rel="noopener noreferrer">here</a> for details.
{% endif %}
{% else %}
{% if is_self_hosting_management_page %}
See <a href="/help/self-hosted-billing#how-does-manual-license-management-work" target="_blank" rel="noopener noreferrer">here</a> for details.
{% else %}
See <a href="/help/zulip-cloud-billing#how-does-manual-license-management-work" target="_blank" rel="noopener noreferrer">here</a> for details.
{% endif %}
{% endif %}
</p>
{% endif %}
</div>
{% endif %}
<div {% if page_params.setup_payment_by_invoice %} id="update-invoice-billing-info" {% elif payment_method %} id="upgrade-payment-info"{% endif %}>
{% if page_params.setup_payment_by_invoice %}
{% elif payment_method %}
<div class="input-box upgrade-page-field" id="upgrade-payment-method-wrapper">
<label for="customer-payment-method-for-upgrade" class="inline-block label-title">Payment method</label>
<div id="customer-payment-method-for-upgrade" class="not-editable-realm-field">
{{ payment_method }}
</div>
</div>
{% endif %}
<div id="upgrade-payment-method-container" class="upgrade-add-card-container input-box upgrade-page-field">
<button id="upgrade-add-card-button" {% if page_params.setup_payment_by_invoice %}class="update-billing-information-button"{% elif payment_method %}class="update-card-button"{% endif %}>
<span id="upgrade-add-card-button-text">
{% if page_params.setup_payment_by_invoice %}
Update billing information
{% elif payment_method %}
Update card
{% else %}
Add card
{% endif %}
</span>
<object class="loader upgrade-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
{% if not fixed_price_plan %}
<span class="not-editable-realm-field" id="upgrade-payment-by-invoice-container">
{% if page_params.setup_payment_by_invoice %}
or <a href="{{ page_params.billing_base_url }}/upgrade/?tier={{ page_params.tier }}">pay by card</a>
{% else %}
or <a href="{{ page_params.billing_base_url }}/upgrade/?manual_license_management=true&tier={{ page_params.tier }}&setup_payment_by_invoice=true" id="upgrade-payment-by-invoice-link" data-tippy-content="Requires purchasing a fixed number of licenses" data-tippy-placement="right">pay by invoice</a>
{% endif %}
</span>
{% endif %}
</div>
{% if not page_params.free_trial_days and payment_method %}
<div class="stripe-billing-information not-editable-realm-field">
{% if not manual_license_management %}
<a href="{{ page_params.billing_base_url }}/customer_portal/?tier={{ page_params.tier }}">View and update</a> billing information that will be displayed on your invoice and receipt.
{% else %}
<a href="{{ page_params.billing_base_url }}/customer_portal/?manual_license_management=true&tier={{ page_params.tier }}">View and update</a> billing information that will be displayed on your invoice and receipt.
{% endif %}
</div>
{% endif %}
<div id="upgrade-cardchange-error" class="alert alert-danger upgrade-page-error"></div>
</div>
<div class="upgrade-button-container input-box upgrade-page-field" >
<button id="org-upgrade-button" {% if not page_params.setup_payment_by_invoice and not payment_method %}disabled{% endif %}>
<span id="org-upgrade-button-text">
{% if complimentary_access_plan_end_date %}
<span id="org-future-upgrade-button-text-remote-server">
Schedule upgrade to {{ plan }}
</span>
{% endif %}
<span id="org-today-upgrade-button-text">
{% if page_params.free_trial_days %}
Start {{ page_params.free_trial_days }}-day free trial
{% elif page_params.setup_payment_by_invoice %}
Send invoice
{% else %}
Purchase {{ plan }}
{% endif %}
</span>
</span>
<object class="loader upgrade-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
</button>
<div id="autopay-error" class="alert alert-danger upgrade-page-error hide"></div>
</div>
</form>
<form id="upgrade-cardchange-form">
{% if manual_license_management %}
<input type="hidden" name="manual_license_management" value="true" />
{% endif %}
<input type="hidden" name="tier" value="{{ page_params.tier }}" />
</form>
{% endif %}
<div class="input-box upgrade-page-field">
<div class="support-link not-editable-realm-field">
{% if pay_by_invoice_payments_page %}
If you have questions or need to make any changes, please contact <a href="mailto:sales@zulip.com">sales@zulip.com</a>.
{% else %}
Questions? Contact <a href="mailto:sales@zulip.com">sales@zulip.com</a>.
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
{% if page_params.setup_payment_by_invoice %}
<div id="confirm-send-invoice-modal" class="micromodal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1">
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="confirm-send-invoice-modal-label">
<header class="modal__header">
<div class="modal__header-content">
<h1 id="confirm-send-invoice-modal-label" class="modal__title dialog_heading">
{% if page_params.free_trial_days %}
Start free trial for {{ plan }}
{% else %}
Send invoice for {{ plan }}
{% endif %}
</h1>
</div>
<button type="button" class="modal__close" aria-label="{{ _('Close modal') }}" tabindex="0" data-micromodal-close>
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
</header>
<main class="modal__content">
<p>
Please be sure to
<a href="{{ page_params.billing_base_url }}/customer_portal/?manual_license_management=true&tier={{ page_params.tier }}&setup_payment_by_invoice=true" target="_blank" rel="noopener noreferrer">configure</a>
your billing details if you have not done so already. This information will appear on your invoice and receipt.
<br />
{% if page_params.free_trial_days %}
<br />
Starting free trial will immediately send an invoice to <b>{{ stripe_email }}</b>.
This is your last chance to update the billing information on your invoice.
{% else %}
Your invoice will be sent to <b>{{ stripe_email }}</b>.
{% endif %}
</p>
</main>
<footer class="modal__footer">
<button class="modal__button dialog_exit_button" aria-label="{{ '(Close this dialog window)' }}" data-micromodal-close>{{ _('Cancel') }}</button>
<button class="modal__button dialog_submit_button">
<span>
{% if page_params.free_trial_days %}
{{ _('Send invoice and start free trial') }}
{% else %}
{{ _('Send invoice') }}
{% endif %}
</span>
</button>
</footer>
</div>
</div>
</div>
{% endif %}
{% endblock %}