Updates the name for the self-hosted complimentary access plan
to "Zulip Basic (complimentary)" instead of "Free (legacy plan)".
Since these plans are never billed in Stripe, we don't need to
hold to the 22 character limit for the plan name.
Adds COMPLIMENTARY_PLAN_TIERS to the CustomerPlan model so that
we start transitioning from the "legacy plan" language in the
billing system code. Adds a helper function that checks if the
plan tier is in COMPLIMENTARY_PLAN_TIERS.
Updates the sponsorship page context to use that helper function
and updates the relevant template for the updated user-facing
terminology.
Adds ability to configure a fixed-price plan and to delete a
configured fixed-price plan in the Cloud support view.
Updates the invoice processing to send reminder emails to the
billing support email for these Cloud fixed-price plans about
renewals since we now are able to configure them via our support
panel.
Updates function to get the billing session for stripe webhook
events to handle an intial upgrade for a custom generated invoice
for a fixed-price plan for a Cloud organization, which won't have
a user_id in the invoice metadata.
Includes the license counts, date and renewal information as well
as the id field, so that print debugging and displaying these
objects is easier and more useful.
This might not be the most meaningful change of phrasing, but .is_paid()
sounds like it's a check for whether the customer has already paid their
invoice. is_a_paid_plan() reflects better the meaning that it's whether
it's a plan of a "paid" type.
We send customer an invoice at the start of free trial, if customer
pays we upgrade them to the active plan at the end of free trial,
else we downgrade them and show a custom message on the upgrade
page regarding the current status.
If the remote realm registered after the legacy plan on server
ENDED, we never migrate the plan to the remote realm. So, we need
to check the server of remote realm whenever we are check remote
realm for legacy plan.
Earlier, the 'self.on_paid_plan()' check was verifying if the
billing_session/customer is on paid plan and not the plan we
are processing.
This resulted in a bug. While processing a legacy plan, a customer
switches from legacy plan to a paid plan resulting in the
'self.on_paid_plan()' check returning True.
It leads to invoicing legacy plan which shouldn't happen.
The fix is to check if the plan we are processing is paid or not
instead of the remote_realm/remote_server plan_type.
For fixed-price plans, we send a reminder email to
sales@zulip.com, 2 months before the end date, to review
the pricing and configure a new fixed-price plan accordingly.
Earlier, we were not configuring the end_date while creating
a fixed-price plan which would result in the automatic renewal
of the plan at the end of billing cycle.
Our plan is to re-evaluate the pricing when we are close to the
end date, then:
1. Schedule a new fixed-price plan with the updated or same price.
2. or Don't do anything - the plan will end on the end_date.
Now, we add an end_date of 1 year from the start date when
creating a fixed-price plan.
Instead of charging the customer using the attached payment
method and then creating the invoice, we create an invoice and
force an immediate payment for the invoice via the attached
payment method.
Now that a customer discount may require a particular plan tier to
be applied, update the billing code to check the plan tier when
getting the customer default_discount field/information for a new
plan.
For billing schedule changes and displaying billing information for
current plans, we explicitly use the discount set on the current,
active plan and do not check the customer object for these actions.
This will be used to set a required plan tier value to be used with
the default discount that is set on the Customer object or with a
fixed price set on a CustomerPlan object.
Also adds `SWITCH_PLAN_TIER_AT_PLAN_END` for `CustomerPlan`
which will be used to mark status of remote server legacy
plans which are scheduled for an upgrade.
Since Customer already stores the realm it is linked to and
customer is always created to store sponsorship request, we directly
use customer to link to the sponsorship data for the realm.