Commit Graph

520 Commits

Author SHA1 Message Date
Lauryn Menard 4fcf7945b0 support: Show annual revenue for active fixed price plans.
In the activity and support views, we want to see the annual
revenue for fixed price plans. While on billing pages, we do
not display this information as these plans are renegotiated
annually.

Adds get_annual_recurring_revenue_for_support_data function
to BillingSession class, so that we can get the fixed price
plan data for these views without changing the logic for
what is displayed on the billing pages.
2024-05-22 15:57:59 -07:00
Lauryn Menard 37afad038c support: Add link to stripe customer dashboard.
Adds a link to the stripe customer dashboard if the Customer
object for an active plan has a stripe_customer_id. If there
is no stripe ID to link to, then the icon is shown without
a link, which is the case for remote server/realm sponsorships
and legacy plans.
2024-05-22 11:32:46 -07:00
Anders Kaseorg b545abe1e2 typos: Fix typos caught by mwic.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-05-20 13:55:00 -07:00
Aman Agrawal 7203661d99 support: Set discounted price instead percentage for customers.
This allows us to set the price of a plan exactly as discussed with
the customer.
2024-05-16 02:18:43 -07:00
Vector73 8ab526a25a models: Replace realm.uri with realm.url.
In #23380, we are changing all occurrences of uri with url in order to
follow the latest URL standard. Previous PRs #25038 and #25045 has
replaced the occurences of uri that has no direct relation with realm.

This commit changes just the model property, which has no API
compatibility concerns.
2024-05-08 11:12:43 -07:00
Anders Kaseorg 31c7b2bfd7 stripe: Add assertions to fix errors flagged by mypy 1.10.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-04-30 13:58:24 -07:00
Anders Kaseorg b195dc5a89 stripe: Add missing stripe_customer_id assertions.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-04-30 13:58:24 -07:00
Anders Kaseorg 7b2a4304fc stripe: Stringify invoice metadata.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-04-30 13:58:24 -07:00
Anders Kaseorg 385cd038b0 stripe: Pass ids, not objects, to pagination API.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-04-30 13:58:24 -07:00
Anders Kaseorg 9ca64b21f3 stripe: Properly convert Period object to CreateParamsPeriod dict.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-04-30 13:58:24 -07:00
Anders Kaseorg 228ade86be stripe: Use absent days_until_due rather than invalid None.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-04-30 13:58:24 -07:00
Anders Kaseorg 0af62519a1 stripe: Isolate ignored error for undocumented Invoice.list usage.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-04-30 13:58:24 -07:00
Anders Kaseorg e7a3d743d1 stripe: Use more specific type annotations.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-04-30 13:58:24 -07:00
Aman Agrawal 7d1f858273 stripe: Ensure required_plan_tier is set before setting discount. 2024-04-29 17:11:11 -07:00
Aman Agrawal 2d824e85cc stripe: Remove invalid comment.
We use `error_description` in upgrade.ts to determine if the error was
related to customer's card. Doesn't seem like there is any harm
in doing so since we are explicitly handling "stripe.CardError" and
raising these errors with "card error" description.
2024-04-22 09:20:17 -07:00
Aman Agrawal 42bbeb6247 stripe: Change pricing for plus plan.
This also now allows user to upgrade to plus plan from pricing page.

Note that since we don't pass customer_plan on pages like self-hosting
and for/business, `Current plan` status is not displayed on these pages.
2024-04-19 09:57:43 -07:00
Prakhar Pratyush 14415dfa90 invoice_paid_event: Verify invoice before activating fixed-price plan.
Earlier, we were not verifying that the invoice which got paid is
for the fixed-price plan.

That could result in a bug where another support invoice with
collection_method = "send_invoice" got paid while a fixed-price
plam is already configured. The fixed-price plan would be falsely
activated.

This commit verifies the invoice before activating the fixed-price
plan.
2024-04-16 09:49:04 -07:00
Mateusz Mandera 4a2a9176c2 realms: Add caching to the get_seat_count calculation for upload limit.
For simiplicty's sake, we can avoid trying to do cache invalidation in
the variety of events that can cause the seat count to change - since
having an up to 1 day delay between users being added and the upload
limit going up is quite reasonable.
2024-04-15 15:08:56 -07:00
Mateusz Mandera 4eacd25ad5 stripe: Rename CustomerPlan.is_paid.
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.
2024-04-15 15:08:56 -07:00
Aman Agrawal 8a807949df stripe: Disable free trial for customer with any plan in the past. 2024-04-11 21:57:33 -07:00
Aman Agrawal ed2de77895 stripe: Send invoice to customer at the start of free trial.
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.
2024-04-11 21:57:33 -07:00
Aman Agrawal 8715ead8bc stripe: Regenerate stripe fixtures with fixed tests.
Tests were broken since #29221 and #28875 didn't account for
other tests failing due to changed stripe data. Also, there
was a bug where we were not fetching the correct setup intent
and stripe session for the current test, it was fixed by narrowing
the fetch to the current customer.

Also, we now run `invoice_plans` in a `while` loop until
`next_invoice_date` is greater than the provided event_time. It
makes sense to generate all the invoices for a customer that
needs to paid by them when `invoice_plans_as_needed` is called
for a `event_time`.
2024-04-11 21:57:33 -07:00
Aman Agrawal a2e0c84a7e stripe: Remove unused parameter. 2024-04-11 21:57:33 -07:00
Prakhar Pratyush e3f8c62e34 registration: Send a group DM to admins when no spare licenses left.
Earlier, when adding a new user failed due to no spare licenses
available, a message was sent to the "New user announcements"
stream.

We plan to disable the stream by default as a part of improving
onboarding experience.

Now, we send a group DM to admins when adding a new user fails
due to no spare licenses available. It makes it independent of
the "New user announcements" setting. These warning messages
are important and shouldn't be missed.
2024-04-03 12:28:05 -07:00
Aman Agrawal b86e37a979 stripe: Add period information for generated invoices.
Invoices need to have period to avoid charges being marked as
point-in-time revenue rather than monthly revenue.
2024-03-30 14:56:12 -07:00
Prakhar Pratyush a0cec2c378 stripe: Skip invoice overdue mail for free plans with no next plan.
Earlier, if a free plan (say legacy plan) with no next plan scheduled
was invoiced, we used to send an invoice overdue email if the last
audit log update is stale.

Actually, we don't need this data as the invoice step is just going
to downgrade the current plan. We should not wait for customer to
start uploading data in this case. Skip the email sending step and
invoice the plan to downgrade.
2024-03-28 09:29:23 -07:00
Mateusz Mandera c3caa3ecc8 stripe: Rename @error_handler decorator.
This decorator, among other things, transforms the "event" argument
passed when calling the decorated functions into actually passing
event.content_object.

So e.g. despite having a (before the decorator is applied) signature:

```
def handle_invoice_paid_event(stripe_invoice: stripe.Invoice, invoice: Invoice) -> None:
```

these are called passing an `Event` in the second arg when calling
`handle_invoice_paid_event`:

```
handle_invoice_paid_event(stripe_invoice, event)
```

I found that kind of confusing because the @error_handler decorator
didn't sound like something that would intervene in the arguments like
that. So it feels helpful to rename it something with a less modest
name, that makes it sound like it does more than just pure
error-handling.
2024-03-28 09:10:09 -07:00
Anders Kaseorg a1a341f0ae ruff: Fix UP032 Use f-string instead of `format` call.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-03-21 08:59:17 -07:00
Lauryn Menard 373671080d remote-support: Include billing entity name in internal billing notice.
Adds a line to the top of the internal_billing_notice email with
the billing entity's display name.

Makes sure all internal_billng_notice email subjects also include
the billing entity's display name.

Makes small updates to the notice text for some cases.
2024-03-20 11:58:15 -07:00
Prakhar Pratyush c9d25b2a95 stripe: Redirect to /plans if plans downgraded on /billing page visit.
When a customer with plan's status 'DOWNGRADE_AT_END_OF_FREE_TRIAL'
visits /billing page on the free-trial end date before the invoice
cron runs, the 'make_end_of_cycle_updates_if_needed' downgrades the
plan.

Earlier, when such a customer visited /billing page in this time window
it resulted in an assertion error.

This commit fixes the incorrect behaviour by redirecting to '/plans'
page in such cases.
2024-03-19 09:25:07 -07:00
Prakhar Pratyush 421400c651 corporate: Fix 'get_next_billing_cycle' for scheduled fixed-price plan.
No renewal ledger entry exists for a scheduled fixed-price plan.

Earlier, when a customer with scheduled fixed-price plan
visited the billing page, the 'get_next_billing_cycle' function
raised an assertion error as no renewal ledger entry exists.

We don't need the ledger entry to determine the next billing
cycle in this case, so we move the code block which determines
the last_renewal time within the else conditional i.e. where it
is needed.

The scheduled plan has NEVER_STARTED status and the
next_invoice_date set to end date of the current plan.
We use this info to determine the next billing cycle.
2024-03-15 12:31:57 -07:00
Aman Agrawal 26a92f5d66 stripe: Add more context to some comments. 2024-03-15 08:39:46 -07:00
Aman Agrawal bddc271e84 stripe: Keep remote realm and server type_of_plan_tier_change in sync.
Ideally they should never be different here.
2024-03-15 08:38:46 -07:00
Aman Agrawal e10f81197f upgrade: Fix allowed free trails for ended legacy plans on server.
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.
2024-03-15 08:38:46 -07:00
Aman Agrawal b26326815a billing: Adjust strings on billing page for invoice payment method. 2024-03-14 16:43:52 -07:00
Aman Agrawal caba57fe1e stripe: Bill manually managed licenses monthly for additional licenses.
Regardless of plan renewal schedule, we try to invoice all plans
monthly with some exceptions like free trial and fixed price plans,
which help us charge users for additional licenses used during
the previous month.
2024-03-14 16:43:52 -07:00
Aman Agrawal c84b9cbc97 upgrade: Allow payment by invoice. 2024-03-14 16:43:52 -07:00
Aman Agrawal b1ea8f3c1c stripe: Change plan type immediately after creating a live plan.
Minor refactor that makes sense to do.
2024-03-14 16:43:52 -07:00
Aman Agrawal 2788ed893a stripe: Remove completed TODO. 2024-03-14 16:43:52 -07:00
Aman Agrawal 4b93b08674 stripe: Remove unused parameter. 2024-03-14 16:43:52 -07:00
Lauryn Menard 8f5b8dbf1a stripe: Remove unused do_change_remote_server_plan_type.
This was implemented instead as part of the BillingSession class
with the do_change_plan_type method.
2024-03-12 11:19:29 -07:00
Lauryn Menard 4d470a52f8 remote-support: Highlight if audit log data is stale or current.
Includes has_stale_audit_log boolean in the remote support view
data so that we can style the last audit log data for the remote
server to visually highlight if it is stale or current.
2024-03-08 09:40:43 -08:00
Lauryn Menard 4e1e490b40 cloud-support: Display most recent sponsorship request information.
Refactors the Cloud support view to pass in any sponsorship or
discount information about the Customer object for the realm,
which allows us to display any information submitted in a
sponsorship request.
2024-03-08 09:40:43 -08:00
Prakhar Pratyush 7e9212a1a0 corporate: Use 'next_invoice_date' as the event_time in invoice_plan.
Earlier, we were using 'timezone_now' (the time cron job runs)
as the event_time while invoicing plans in 'invoice_plan'.
This is not accurate as it will lead to invoicing ledger entries
created after 'next_invoice_date' and before 'timezone_now'.

We should only invoice the ledger entries created till
next_invoice_date. It should be independent of the time
at which cron job runs.

This commit updates the logic to use next_invoice_date
as the event_time while invoicing via cron.
2024-03-08 09:25:46 -08:00
Prakhar Pratyush bd969de208 stripe: Don't invoice fixed-price plans for additional licenses.
Earlier, the code block to calculate additional licenses charge
raised assertion error when processing a fixed-price plan.

The code block shouldn't be executed for fixed-price plans as
we don't charge customers on fixed-price plans for additional
licenses.
2024-03-07 09:54:34 -08:00
Prakhar Pratyush 5085d58bc7 corporate: Fix to check if the plan we are processing is paid or not.
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.
2024-03-07 09:54:34 -08:00
Prakhar Pratyush 01516ef512 invoice_plan: Don't test an Optional value using implicit truthiness. 2024-03-07 09:54:34 -08:00
Prakhar Pratyush a513489f38 corporate: Fix invoicing of plans on free-trial with changed schedule.
Earlier, the 'next_invoice_date', 'invoiced_through', and
'invoicing_status' fields in 'do_change_schedule_after_free_trial'
were not set correctly.

It resulted in invoicing the ENDED plan and the ledger we create
in this function.

Multiple invoices were created depending on the number of times the
billing frequency was changed for customers who started free-trial
& changed their billing frequency.

This commit sets those fields correctly leading to create only one
invoice.
2024-03-01 10:47:55 -08:00
Anders Kaseorg 570f3dd447 python: Reformat with Ruff formatter.
https://docs.astral.sh/ruff/formatter/

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-02-29 17:07:16 -08:00
Prakhar Pratyush 5d58a39087 stripe: Use a common email template for internal billing notices.
This is a prep commit which replaces the 'invoice_overdue'
and 'reminder_to_review_plan' email templates with
'internal_billing_notice'.

This will help us to use the same template as we plan to
send an email to sales when a remote realm with paid plan
attached is locally deleted.
2024-02-29 12:50:23 -08:00