Commit Graph

532 Commits

Author SHA1 Message Date
Lauryn Menard 391c52639f support: Show discount information on remote support views.
In commit 7203661d99, we removed the default_discount field on the
Customer model, but we didn't update the remote support views for
this change.

Adds a has_discount boolean to the SponsorshipData that's used in
the support views for headers, and updates the discount information
on a deactivated remote realm to show any pre-existing discounted
prices.
2024-08-15 09:51:35 -07:00
Alex Vandiver 8e1582d82e support: Reject attempts to approve sponsorship for deactivated orgs. 2024-08-13 20:29:02 -07:00
Anders Kaseorg 05e54a0af2 ruff: Fix E721 Use `isinstance()` for isinstance checks.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-08-01 16:46:58 -07:00
Anders Kaseorg 818bad300e corporate: Set assume_scheme="https" for django.forms.URLField.
The previous default of "http" is deprecated and will change to
"https" in Django 6.0.

https://docs.djangoproject.com/en/5.0/releases/5.0/#id2
https://docs.djangoproject.com/en/5.0/ref/forms/fields/#django.forms.URLField.assume_scheme

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-07-16 13:40:59 -07:00
Anders Kaseorg 1e9b6445a9 ruff: Fix PLR6104 Use `+=` to perform an augmented assignment directly.
This is a preview rule, not yet enabled by default.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-07-14 13:49:51 -07:00
Anders Kaseorg 48202389b8 ruff: Bump target-version from py38 to py310.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-07-13 22:28:22 -07:00
Anders Kaseorg 3f29bc42b1 ruff: Fix B905 `zip()` without an explicit `strict=` parameter.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-07-13 22:28:22 -07:00
Anders Kaseorg 1464009fae ruff: Fix UP038 Use `X | Y` in `isinstance` call instead of `(X, Y)`.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-07-13 22:28:22 -07:00
Anders Kaseorg 0fa5e7f629 ruff: Fix UP035 Import from `collections.abc`, `typing` instead.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-07-13 22:28:22 -07:00
Anders Kaseorg 531b34cb4c ruff: Fix UP007 Use `X | Y` for type annotations.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-07-13 22:28:22 -07:00
Anders Kaseorg e08a24e47f ruff: Fix UP006 Use `list` instead of `List` for type annotation.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2024-07-13 22:28:22 -07:00
Lauryn Menard 1969698cf6 stripe: Use comma for collection method Literal values. 2024-06-10 16:10:42 -07:00
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