mirror of https://github.com/zulip/zulip.git
corporate: Import corporate.lib.stripe lazily.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
fcafcb24d7
commit
f0f048de69
|
@ -16,11 +16,6 @@ from django.utils.timezone import now as timezone_now
|
|||
from markupsafe import Markup
|
||||
from psycopg2.sql import Composable
|
||||
|
||||
from corporate.lib.stripe import (
|
||||
RealmBillingSession,
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
)
|
||||
from corporate.models import CustomerPlan, LicenseLedger
|
||||
from zerver.lib.pysa import mark_sanitized
|
||||
from zerver.lib.url_encoding import append_url_query_string
|
||||
|
@ -196,6 +191,8 @@ def get_remote_activity_plan_data(
|
|||
remote_realm: RemoteRealm | None = None,
|
||||
remote_server: RemoteZulipServer | None = None,
|
||||
) -> RemoteActivityPlanData:
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession, RemoteServerBillingSession
|
||||
|
||||
if plan.tier == CustomerPlan.TIER_SELF_HOSTED_LEGACY or plan.status in (
|
||||
CustomerPlan.DOWNGRADE_AT_END_OF_FREE_TRIAL,
|
||||
CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE,
|
||||
|
@ -226,6 +223,8 @@ def get_remote_activity_plan_data(
|
|||
|
||||
|
||||
def get_estimated_arr_and_rate_by_realm() -> tuple[dict[str, int], dict[str, str]]: # nocoverage
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
# NOTE: Customers without a plan might still have a discount attached to them which
|
||||
# are not included in `plan_rate`.
|
||||
annual_revenue = {}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import inspect
|
||||
from collections.abc import Callable
|
||||
from functools import wraps
|
||||
from typing import Concatenate
|
||||
from typing import TYPE_CHECKING, Concatenate
|
||||
from urllib.parse import urlencode, urljoin
|
||||
|
||||
from django.conf import settings
|
||||
|
@ -15,12 +15,14 @@ from corporate.lib.remote_billing_util import (
|
|||
get_remote_realm_and_user_from_session,
|
||||
get_remote_server_and_user_from_session,
|
||||
)
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession, RemoteServerBillingSession
|
||||
from zerver.lib.exceptions import RemoteBillingAuthenticationError
|
||||
from zerver.lib.subdomains import get_subdomain
|
||||
from zerver.lib.url_encoding import append_url_query_string
|
||||
from zilencer.models import RemoteRealm
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession, RemoteServerBillingSession
|
||||
|
||||
ParamT = ParamSpec("ParamT")
|
||||
|
||||
|
||||
|
@ -54,7 +56,9 @@ def self_hosting_management_endpoint(
|
|||
|
||||
|
||||
def authenticated_remote_realm_management_endpoint(
|
||||
view_func: Callable[Concatenate[HttpRequest, RemoteRealmBillingSession, ParamT], HttpResponse],
|
||||
view_func: Callable[
|
||||
Concatenate[HttpRequest, "RemoteRealmBillingSession", ParamT], HttpResponse
|
||||
],
|
||||
) -> Callable[Concatenate[HttpRequest, ParamT], HttpResponse]:
|
||||
@wraps(view_func)
|
||||
def _wrapped_view_func(
|
||||
|
@ -63,6 +67,8 @@ def authenticated_remote_realm_management_endpoint(
|
|||
*args: ParamT.args,
|
||||
**kwargs: ParamT.kwargs,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession
|
||||
|
||||
if not is_self_hosting_management_subdomain(request): # nocoverage
|
||||
return render(request, "404.html", status=404)
|
||||
|
||||
|
@ -160,7 +166,9 @@ def get_next_page_param_from_request_path(request: HttpRequest) -> str | None:
|
|||
|
||||
|
||||
def authenticated_remote_server_management_endpoint(
|
||||
view_func: Callable[Concatenate[HttpRequest, RemoteServerBillingSession, ParamT], HttpResponse],
|
||||
view_func: Callable[
|
||||
Concatenate[HttpRequest, "RemoteServerBillingSession", ParamT], HttpResponse
|
||||
],
|
||||
) -> Callable[Concatenate[HttpRequest, ParamT], HttpResponse]:
|
||||
@wraps(view_func)
|
||||
def _wrapped_view_func(
|
||||
|
@ -169,6 +177,8 @@ def authenticated_remote_server_management_endpoint(
|
|||
*args: ParamT.args,
|
||||
**kwargs: ParamT.kwargs,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import RemoteServerBillingSession
|
||||
|
||||
if not is_self_hosting_management_subdomain(request): # nocoverage
|
||||
return render(request, "404.html", status=404)
|
||||
|
||||
|
|
|
@ -4976,7 +4976,9 @@ class StripeWebhookEndpointTest(ZulipTestCase):
|
|||
"type": "checkout.session.completed",
|
||||
"data": {"object": {"object": "checkout.session", "id": "stripe_session_id"}},
|
||||
}
|
||||
with patch("corporate.views.webhook.handle_checkout_session_completed_event") as m:
|
||||
with patch(
|
||||
"corporate.lib.stripe_event_handler.handle_checkout_session_completed_event"
|
||||
) as m:
|
||||
result = self.client_post(
|
||||
"/stripe/webhook/",
|
||||
valid_session_event_data,
|
||||
|
@ -4998,7 +5000,7 @@ class StripeWebhookEndpointTest(ZulipTestCase):
|
|||
"data": {"object": {"object": "invoice", "id": stripe_invoice_id}},
|
||||
}
|
||||
|
||||
with patch("corporate.views.webhook.handle_invoice_paid_event") as m:
|
||||
with patch("corporate.lib.stripe_event_handler.handle_invoice_paid_event") as m:
|
||||
result = self.client_post(
|
||||
"/stripe/webhook/",
|
||||
valid_session_event_data,
|
||||
|
@ -5015,7 +5017,7 @@ class StripeWebhookEndpointTest(ZulipTestCase):
|
|||
)
|
||||
|
||||
self.assert_length(Event.objects.filter(stripe_event_id=stripe_event_id), 0)
|
||||
with patch("corporate.views.webhook.handle_invoice_paid_event") as m:
|
||||
with patch("corporate.lib.stripe_event_handler.handle_invoice_paid_event") as m:
|
||||
result = self.client_post(
|
||||
"/stripe/webhook/",
|
||||
valid_session_event_data,
|
||||
|
@ -5026,7 +5028,7 @@ class StripeWebhookEndpointTest(ZulipTestCase):
|
|||
strip_event = stripe.Event.construct_from(valid_session_event_data, stripe.api_key)
|
||||
m.assert_called_once_with(strip_event.data.object, event)
|
||||
|
||||
with patch("corporate.views.webhook.handle_invoice_paid_event") as m:
|
||||
with patch("corporate.lib.stripe_event_handler.handle_invoice_paid_event") as m:
|
||||
result = self.client_post(
|
||||
"/stripe/webhook/",
|
||||
valid_session_event_data,
|
||||
|
@ -5048,7 +5050,7 @@ class StripeWebhookEndpointTest(ZulipTestCase):
|
|||
"data": {"object": {"object": "invoice", "id": stripe_invoice_id}},
|
||||
}
|
||||
|
||||
with patch("corporate.views.webhook.handle_invoice_paid_event") as m:
|
||||
with patch("corporate.lib.stripe_event_handler.handle_invoice_paid_event") as m:
|
||||
result = self.client_post(
|
||||
"/stripe/webhook/",
|
||||
valid_invoice_paid_event_data,
|
||||
|
@ -5065,7 +5067,7 @@ class StripeWebhookEndpointTest(ZulipTestCase):
|
|||
)
|
||||
|
||||
self.assert_length(Event.objects.filter(stripe_event_id=stripe_event_id), 0)
|
||||
with patch("corporate.views.webhook.handle_invoice_paid_event") as m:
|
||||
with patch("corporate.lib.stripe_event_handler.handle_invoice_paid_event") as m:
|
||||
result = self.client_post(
|
||||
"/stripe/webhook/",
|
||||
valid_invoice_paid_event_data,
|
||||
|
@ -5076,7 +5078,7 @@ class StripeWebhookEndpointTest(ZulipTestCase):
|
|||
strip_event = stripe.Event.construct_from(valid_invoice_paid_event_data, stripe.api_key)
|
||||
m.assert_called_once_with(strip_event.data.object, event)
|
||||
|
||||
with patch("corporate.views.webhook.handle_invoice_paid_event") as m:
|
||||
with patch("corporate.lib.stripe_event_handler.handle_invoice_paid_event") as m:
|
||||
result = self.client_post(
|
||||
"/stripe/webhook/",
|
||||
valid_invoice_paid_event_data,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import logging
|
||||
from typing import Annotated, Any, Literal
|
||||
from typing import TYPE_CHECKING, Annotated, Any, Literal
|
||||
|
||||
from django.http import HttpRequest, HttpResponse, HttpResponseNotAllowed, HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
|
@ -11,14 +11,6 @@ from corporate.lib.decorator import (
|
|||
authenticated_remote_realm_management_endpoint,
|
||||
authenticated_remote_server_management_endpoint,
|
||||
)
|
||||
from corporate.lib.stripe import (
|
||||
RealmBillingSession,
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
ServerDeactivateWithExistingPlanError,
|
||||
UpdatePlanRequest,
|
||||
do_deactivate_remote_server,
|
||||
)
|
||||
from corporate.models import CustomerPlan, get_current_plan_by_customer, get_customer_by_realm
|
||||
from zerver.decorator import process_as_post, require_billing_access, zulip_login_required
|
||||
from zerver.lib.exceptions import JsonableError
|
||||
|
@ -29,6 +21,10 @@ from zerver.models import UserProfile
|
|||
from zilencer.lib.remote_counts import MissingDataError
|
||||
from zilencer.models import RemoteRealm, RemoteZulipServer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession, RemoteServerBillingSession
|
||||
|
||||
|
||||
billing_logger = logging.getLogger("corporate.stripe")
|
||||
|
||||
ALLOWED_PLANS_API_STATUS_VALUES = [
|
||||
|
@ -49,6 +45,8 @@ def billing_page(
|
|||
*,
|
||||
success_message: str = "",
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
user = request.user
|
||||
assert user.is_authenticated
|
||||
|
||||
|
@ -91,11 +89,11 @@ def billing_page(
|
|||
return render(request, "corporate/billing/billing.html", context=context)
|
||||
|
||||
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
def remote_realm_billing_page(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteRealmBillingSession,
|
||||
billing_session: "RemoteRealmBillingSession",
|
||||
*,
|
||||
success_message: str = "",
|
||||
) -> HttpResponse:
|
||||
|
@ -152,11 +150,11 @@ def remote_realm_billing_page(
|
|||
return render(request, "corporate/billing/billing.html", context=context)
|
||||
|
||||
|
||||
@authenticated_remote_server_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def remote_server_billing_page(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteServerBillingSession,
|
||||
billing_session: "RemoteServerBillingSession",
|
||||
*,
|
||||
success_message: str = "",
|
||||
) -> HttpResponse:
|
||||
|
@ -246,6 +244,8 @@ def update_plan(
|
|||
licenses_at_next_renewal: Json[int] | None = None,
|
||||
schedule: Json[int] | None = None,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import RealmBillingSession, UpdatePlanRequest
|
||||
|
||||
update_plan_request = UpdatePlanRequest(
|
||||
status=status,
|
||||
licenses=licenses,
|
||||
|
@ -257,12 +257,12 @@ def update_plan(
|
|||
return json_success(request)
|
||||
|
||||
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
@process_as_post
|
||||
@typed_endpoint
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
def update_plan_for_remote_realm(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteRealmBillingSession,
|
||||
billing_session: "RemoteRealmBillingSession",
|
||||
*,
|
||||
status: Annotated[
|
||||
Json[int], AfterValidator(lambda x: check_int_in(x, ALLOWED_PLANS_API_STATUS_VALUES))
|
||||
|
@ -272,6 +272,8 @@ def update_plan_for_remote_realm(
|
|||
licenses_at_next_renewal: Json[int] | None = None,
|
||||
schedule: Json[int] | None = None,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import UpdatePlanRequest
|
||||
|
||||
update_plan_request = UpdatePlanRequest(
|
||||
status=status,
|
||||
licenses=licenses,
|
||||
|
@ -282,12 +284,12 @@ def update_plan_for_remote_realm(
|
|||
return json_success(request)
|
||||
|
||||
|
||||
@authenticated_remote_server_management_endpoint
|
||||
@process_as_post
|
||||
@typed_endpoint
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def update_plan_for_remote_server(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteServerBillingSession,
|
||||
billing_session: "RemoteServerBillingSession",
|
||||
*,
|
||||
status: Annotated[
|
||||
Json[int], AfterValidator(lambda x: check_int_in(x, ALLOWED_PLANS_API_STATUS_VALUES))
|
||||
|
@ -297,6 +299,8 @@ def update_plan_for_remote_server(
|
|||
licenses_at_next_renewal: Json[int] | None = None,
|
||||
schedule: Json[int] | None = None,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import UpdatePlanRequest
|
||||
|
||||
update_plan_request = UpdatePlanRequest(
|
||||
status=status,
|
||||
licenses=licenses,
|
||||
|
@ -307,14 +311,19 @@ def update_plan_for_remote_server(
|
|||
return json_success(request)
|
||||
|
||||
|
||||
@authenticated_remote_server_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def remote_server_deactivate_page(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteServerBillingSession,
|
||||
billing_session: "RemoteServerBillingSession",
|
||||
*,
|
||||
confirmed: Literal[None, "true"] = None,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import (
|
||||
ServerDeactivateWithExistingPlanError,
|
||||
do_deactivate_remote_server,
|
||||
)
|
||||
|
||||
if request.method not in ["GET", "POST"]: # nocoverage
|
||||
return HttpResponseNotAllowed(["GET", "POST"])
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.shortcuts import render
|
||||
|
@ -8,17 +9,14 @@ from corporate.lib.decorator import (
|
|||
authenticated_remote_server_management_endpoint,
|
||||
self_hosting_management_endpoint,
|
||||
)
|
||||
from corporate.lib.stripe import (
|
||||
EventStatusRequest,
|
||||
RealmBillingSession,
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
)
|
||||
from zerver.decorator import require_organization_member, zulip_login_required
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.lib.typed_endpoint import typed_endpoint
|
||||
from zerver.models import UserProfile
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession, RemoteServerBillingSession
|
||||
|
||||
billing_logger = logging.getLogger("corporate.stripe")
|
||||
|
||||
|
||||
|
@ -31,6 +29,8 @@ def event_status(
|
|||
stripe_session_id: str | None = None,
|
||||
stripe_invoice_id: str | None = None,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import EventStatusRequest, RealmBillingSession
|
||||
|
||||
event_status_request = EventStatusRequest(
|
||||
stripe_session_id=stripe_session_id, stripe_invoice_id=stripe_invoice_id
|
||||
)
|
||||
|
@ -39,15 +39,17 @@ def event_status(
|
|||
return json_success(request, data)
|
||||
|
||||
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
def remote_realm_event_status(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteRealmBillingSession,
|
||||
billing_session: "RemoteRealmBillingSession",
|
||||
*,
|
||||
stripe_session_id: str | None = None,
|
||||
stripe_invoice_id: str | None = None,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import EventStatusRequest
|
||||
|
||||
event_status_request = EventStatusRequest(
|
||||
stripe_session_id=stripe_session_id, stripe_invoice_id=stripe_invoice_id
|
||||
)
|
||||
|
@ -55,15 +57,17 @@ def remote_realm_event_status(
|
|||
return json_success(request, data)
|
||||
|
||||
|
||||
@authenticated_remote_server_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def remote_server_event_status(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteServerBillingSession,
|
||||
billing_session: "RemoteServerBillingSession",
|
||||
*,
|
||||
stripe_session_id: str | None = None,
|
||||
stripe_invoice_id: str | None = None,
|
||||
) -> HttpResponse: # nocoverage
|
||||
from corporate.lib.stripe import EventStatusRequest
|
||||
|
||||
event_status_request = EventStatusRequest(
|
||||
stripe_session_id=stripe_session_id, stripe_invoice_id=stripe_invoice_id
|
||||
)
|
||||
|
|
|
@ -25,7 +25,6 @@ from corporate.lib.activity import (
|
|||
realm_support_link,
|
||||
realm_url_link,
|
||||
)
|
||||
from corporate.lib.stripe import cents_to_dollar_string
|
||||
from corporate.views.support import get_plan_type_string
|
||||
from zerver.decorator import require_server_admin
|
||||
from zerver.lib.typed_endpoint import typed_endpoint
|
||||
|
@ -92,6 +91,8 @@ def get_realm_day_counts() -> dict[str, dict[str, Markup]]:
|
|||
|
||||
|
||||
def realm_summary_table(export: bool) -> str:
|
||||
from corporate.lib.stripe import cents_to_dollar_string
|
||||
|
||||
now = timezone_now()
|
||||
|
||||
query = SQL(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from dataclasses import asdict, dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import orjson
|
||||
|
@ -13,13 +14,6 @@ from corporate.lib.decorator import (
|
|||
authenticated_remote_realm_management_endpoint,
|
||||
authenticated_remote_server_management_endpoint,
|
||||
)
|
||||
from corporate.lib.stripe import (
|
||||
RealmBillingSession,
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
get_configured_fixed_price_plan_offer,
|
||||
get_free_trial_days,
|
||||
)
|
||||
from corporate.models import CustomerPlan, get_current_plan_by_customer, get_customer_by_realm
|
||||
from zerver.context_processors import get_realm_from_request, latest_info_context
|
||||
from zerver.decorator import add_google_analytics, zulip_login_required
|
||||
|
@ -33,6 +27,9 @@ from zerver.lib.subdomains import is_subdomain_root_or_alias
|
|||
from zerver.lib.typed_endpoint import typed_endpoint
|
||||
from zerver.models import Realm
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession, RemoteServerBillingSession
|
||||
|
||||
|
||||
@add_google_analytics
|
||||
def apps_view(request: HttpRequest, platform: str | None = None) -> HttpResponse:
|
||||
|
@ -95,6 +92,8 @@ class PlansPageContext:
|
|||
|
||||
@add_google_analytics
|
||||
def plans_view(request: HttpRequest) -> HttpResponse:
|
||||
from corporate.lib.stripe import get_free_trial_days
|
||||
|
||||
realm = get_realm_from_request(request)
|
||||
context = PlansPageContext(
|
||||
is_cloud_realm=True,
|
||||
|
@ -138,8 +137,10 @@ def plans_view(request: HttpRequest) -> HttpResponse:
|
|||
@add_google_analytics
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
def remote_realm_plans_page(
|
||||
request: HttpRequest, billing_session: RemoteRealmBillingSession
|
||||
request: HttpRequest, billing_session: "RemoteRealmBillingSession"
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import get_configured_fixed_price_plan_offer, get_free_trial_days
|
||||
|
||||
customer = billing_session.get_customer()
|
||||
context = PlansPageContext(
|
||||
is_self_hosted_realm=True,
|
||||
|
@ -205,8 +206,10 @@ def remote_realm_plans_page(
|
|||
@add_google_analytics
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def remote_server_plans_page(
|
||||
request: HttpRequest, billing_session: RemoteServerBillingSession
|
||||
request: HttpRequest, billing_session: "RemoteServerBillingSession"
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import get_configured_fixed_price_plan_offer, get_free_trial_days
|
||||
|
||||
customer = billing_session.get_customer()
|
||||
context = PlansPageContext(
|
||||
is_self_hosted_realm=True,
|
||||
|
@ -377,6 +380,8 @@ def communities_view(request: HttpRequest) -> HttpResponse:
|
|||
|
||||
@zulip_login_required
|
||||
def invoices_page(request: HttpRequest) -> HttpResponseRedirect:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
user = request.user
|
||||
assert user.is_authenticated
|
||||
|
||||
|
@ -390,7 +395,7 @@ def invoices_page(request: HttpRequest) -> HttpResponseRedirect:
|
|||
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
def remote_realm_invoices_page(
|
||||
request: HttpRequest, billing_session: RemoteRealmBillingSession
|
||||
request: HttpRequest, billing_session: "RemoteRealmBillingSession"
|
||||
) -> HttpResponseRedirect:
|
||||
list_invoices_session_url = billing_session.get_past_invoices_session_url()
|
||||
return HttpResponseRedirect(list_invoices_session_url)
|
||||
|
@ -398,7 +403,7 @@ def remote_realm_invoices_page(
|
|||
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def remote_server_invoices_page(
|
||||
request: HttpRequest, billing_session: RemoteServerBillingSession
|
||||
request: HttpRequest, billing_session: "RemoteServerBillingSession"
|
||||
) -> HttpResponseRedirect:
|
||||
list_invoices_session_url = billing_session.get_past_invoices_session_url()
|
||||
return HttpResponseRedirect(list_invoices_session_url)
|
||||
|
@ -414,6 +419,8 @@ def customer_portal(
|
|||
tier: Json[int] | None = None,
|
||||
setup_payment_by_invoice: Json[bool] = False,
|
||||
) -> HttpResponseRedirect:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
user = request.user
|
||||
assert user.is_authenticated
|
||||
|
||||
|
@ -427,11 +434,11 @@ def customer_portal(
|
|||
return HttpResponseRedirect(review_billing_information_url)
|
||||
|
||||
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
def remote_realm_customer_portal(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteRealmBillingSession,
|
||||
billing_session: "RemoteRealmBillingSession",
|
||||
*,
|
||||
return_to_billing_page: Json[bool] = False,
|
||||
manual_license_management: Json[bool] = False,
|
||||
|
@ -444,11 +451,11 @@ def remote_realm_customer_portal(
|
|||
return HttpResponseRedirect(review_billing_information_url)
|
||||
|
||||
|
||||
@authenticated_remote_server_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def remote_server_customer_portal(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteServerBillingSession,
|
||||
billing_session: "RemoteServerBillingSession",
|
||||
*,
|
||||
return_to_billing_page: Json[bool] = False,
|
||||
manual_license_management: Json[bool] = False,
|
||||
|
|
|
@ -16,7 +16,6 @@ from corporate.lib.activity import (
|
|||
remote_installation_stats_link,
|
||||
remote_installation_support_link,
|
||||
)
|
||||
from corporate.lib.stripe import cents_to_dollar_string
|
||||
from zerver.decorator import require_server_admin
|
||||
from zerver.models.realms import get_org_type_display_name
|
||||
from zilencer.models import get_remote_customer_user_count
|
||||
|
@ -24,6 +23,8 @@ from zilencer.models import get_remote_customer_user_count
|
|||
|
||||
@require_server_admin
|
||||
def get_remote_server_activity(request: HttpRequest) -> HttpResponse:
|
||||
from corporate.lib.stripe import cents_to_dollar_string
|
||||
|
||||
title = "Remote servers"
|
||||
|
||||
query = SQL(
|
||||
|
|
|
@ -32,11 +32,6 @@ from corporate.lib.remote_billing_util import (
|
|||
RemoteBillingUserDict,
|
||||
get_remote_server_and_user_from_session,
|
||||
)
|
||||
from corporate.lib.stripe import (
|
||||
BILLING_SUPPORT_EMAIL,
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
)
|
||||
from corporate.models import (
|
||||
CustomerPlan,
|
||||
get_current_plan_by_customer,
|
||||
|
@ -168,6 +163,8 @@ def remote_realm_billing_finalize_login(
|
|||
This is the endpoint accessed via the billing_access_url, generated by
|
||||
remote_realm_billing_entry entry.
|
||||
"""
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession
|
||||
|
||||
if request.method not in ["GET", "POST"]:
|
||||
return HttpResponseNotAllowed(["GET", "POST"])
|
||||
tos_consent_given = tos_consent == "true"
|
||||
|
@ -375,6 +372,8 @@ def remote_realm_billing_confirm_email(
|
|||
a fully authenticated session.
|
||||
"""
|
||||
|
||||
from corporate.lib.stripe import BILLING_SUPPORT_EMAIL
|
||||
|
||||
identity_dict = get_identity_dict_from_signed_access_token(signed_billing_access_token)
|
||||
try:
|
||||
remote_server = get_remote_server_by_uuid(identity_dict["remote_server_uuid"])
|
||||
|
@ -600,6 +599,8 @@ def remote_billing_legacy_server_confirm_login(
|
|||
a fully authenticated session.
|
||||
"""
|
||||
|
||||
from corporate.lib.stripe import BILLING_SUPPORT_EMAIL
|
||||
|
||||
try:
|
||||
remote_server, remote_billing_user = get_remote_server_and_user_from_session(
|
||||
request, server_uuid=server_uuid
|
||||
|
@ -681,6 +682,8 @@ def remote_billing_legacy_server_from_login_confirmation_link(
|
|||
"""
|
||||
The user comes here via the confirmation link they received via email.
|
||||
"""
|
||||
from corporate.lib.stripe import RemoteServerBillingSession
|
||||
|
||||
if request.method not in ["GET", "POST"]:
|
||||
return HttpResponseNotAllowed(["GET", "POST"])
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from pydantic import Json
|
||||
|
@ -7,21 +8,21 @@ from corporate.lib.decorator import (
|
|||
authenticated_remote_realm_management_endpoint,
|
||||
authenticated_remote_server_management_endpoint,
|
||||
)
|
||||
from corporate.lib.stripe import (
|
||||
RealmBillingSession,
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
)
|
||||
from zerver.decorator import require_billing_access, require_organization_member
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.lib.typed_endpoint import typed_endpoint
|
||||
from zerver.models import UserProfile
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession, RemoteServerBillingSession
|
||||
|
||||
billing_logger = logging.getLogger("corporate.stripe")
|
||||
|
||||
|
||||
@require_billing_access
|
||||
def start_card_update_stripe_session(request: HttpRequest, user: UserProfile) -> HttpResponse:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
billing_session = RealmBillingSession(user)
|
||||
session_data = billing_session.create_card_update_session()
|
||||
return json_success(
|
||||
|
@ -32,7 +33,7 @@ def start_card_update_stripe_session(request: HttpRequest, user: UserProfile) ->
|
|||
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
def start_card_update_stripe_session_for_remote_realm(
|
||||
request: HttpRequest, billing_session: RemoteRealmBillingSession
|
||||
request: HttpRequest, billing_session: "RemoteRealmBillingSession"
|
||||
) -> HttpResponse: # nocoverage
|
||||
session_data = billing_session.create_card_update_session()
|
||||
return json_success(
|
||||
|
@ -43,7 +44,7 @@ def start_card_update_stripe_session_for_remote_realm(
|
|||
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def start_card_update_stripe_session_for_remote_server(
|
||||
request: HttpRequest, billing_session: RemoteServerBillingSession
|
||||
request: HttpRequest, billing_session: "RemoteServerBillingSession"
|
||||
) -> HttpResponse: # nocoverage
|
||||
session_data = billing_session.create_card_update_session()
|
||||
return json_success(
|
||||
|
@ -61,6 +62,8 @@ def start_card_update_stripe_session_for_realm_upgrade(
|
|||
manual_license_management: Json[bool] = False,
|
||||
tier: Json[int],
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
billing_session = RealmBillingSession(user)
|
||||
session_data = billing_session.create_card_update_session_for_upgrade(
|
||||
manual_license_management, tier
|
||||
|
@ -71,11 +74,11 @@ def start_card_update_stripe_session_for_realm_upgrade(
|
|||
)
|
||||
|
||||
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
def start_card_update_stripe_session_for_remote_realm_upgrade(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteRealmBillingSession,
|
||||
billing_session: "RemoteRealmBillingSession",
|
||||
*,
|
||||
manual_license_management: Json[bool] = False,
|
||||
tier: Json[int],
|
||||
|
@ -89,11 +92,11 @@ def start_card_update_stripe_session_for_remote_realm_upgrade(
|
|||
)
|
||||
|
||||
|
||||
@authenticated_remote_server_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def start_card_update_stripe_session_for_remote_server_upgrade(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteServerBillingSession,
|
||||
billing_session: "RemoteServerBillingSession",
|
||||
*,
|
||||
manual_license_management: Json[bool] = False,
|
||||
tier: Json[int],
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse
|
||||
|
@ -6,19 +8,18 @@ from corporate.lib.decorator import (
|
|||
authenticated_remote_realm_management_endpoint,
|
||||
authenticated_remote_server_management_endpoint,
|
||||
)
|
||||
from corporate.lib.stripe import (
|
||||
RealmBillingSession,
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
SponsorshipRequestForm,
|
||||
)
|
||||
from zerver.decorator import require_organization_member, zulip_login_required
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.models import UserProfile
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession, RemoteServerBillingSession
|
||||
|
||||
|
||||
@zulip_login_required
|
||||
def sponsorship_page(request: HttpRequest) -> HttpResponse:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
user = request.user
|
||||
assert user.is_authenticated
|
||||
|
||||
|
@ -33,7 +34,7 @@ def sponsorship_page(request: HttpRequest) -> HttpResponse:
|
|||
@authenticated_remote_realm_management_endpoint
|
||||
def remote_realm_sponsorship_page(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteRealmBillingSession,
|
||||
billing_session: "RemoteRealmBillingSession",
|
||||
) -> HttpResponse: # nocoverage
|
||||
context = billing_session.get_sponsorship_request_context()
|
||||
if context is None:
|
||||
|
@ -47,7 +48,7 @@ def remote_realm_sponsorship_page(
|
|||
@authenticated_remote_server_management_endpoint
|
||||
def remote_server_sponsorship_page(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteServerBillingSession,
|
||||
billing_session: "RemoteServerBillingSession",
|
||||
) -> HttpResponse: # nocoverage
|
||||
context = billing_session.get_sponsorship_request_context()
|
||||
if context is None:
|
||||
|
@ -63,6 +64,8 @@ def sponsorship(
|
|||
request: HttpRequest,
|
||||
user: UserProfile,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import RealmBillingSession, SponsorshipRequestForm
|
||||
|
||||
billing_session = RealmBillingSession(user)
|
||||
post_data = request.POST.copy()
|
||||
form = SponsorshipRequestForm(post_data)
|
||||
|
@ -73,8 +76,10 @@ def sponsorship(
|
|||
@authenticated_remote_realm_management_endpoint
|
||||
def remote_realm_sponsorship(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteRealmBillingSession,
|
||||
billing_session: "RemoteRealmBillingSession",
|
||||
) -> HttpResponse: # nocoverage
|
||||
from corporate.lib.stripe import SponsorshipRequestForm
|
||||
|
||||
post_data = request.POST.copy()
|
||||
form = SponsorshipRequestForm(post_data)
|
||||
billing_session.request_sponsorship(form)
|
||||
|
@ -84,8 +89,10 @@ def remote_realm_sponsorship(
|
|||
@authenticated_remote_server_management_endpoint
|
||||
def remote_server_sponsorship(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteServerBillingSession,
|
||||
billing_session: "RemoteServerBillingSession",
|
||||
) -> HttpResponse: # nocoverage
|
||||
from corporate.lib.stripe import SponsorshipRequestForm
|
||||
|
||||
post_data = request.POST.copy()
|
||||
form = SponsorshipRequestForm(post_data)
|
||||
billing_session.request_sponsorship(form)
|
||||
|
|
|
@ -24,26 +24,6 @@ from confirmation.models import Confirmation, confirmation_url
|
|||
from confirmation.settings import STATUS_USED
|
||||
from corporate.lib.activity import format_optional_datetime, remote_installation_stats_link
|
||||
from corporate.lib.billing_types import BillingModality
|
||||
from corporate.lib.stripe import (
|
||||
BILLING_SUPPORT_EMAIL,
|
||||
RealmBillingSession,
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
ServerDeactivateWithExistingPlanError,
|
||||
SupportRequestError,
|
||||
SupportType,
|
||||
SupportViewRequest,
|
||||
cents_to_dollar_string,
|
||||
do_deactivate_remote_server,
|
||||
do_reactivate_remote_server,
|
||||
)
|
||||
from corporate.lib.support import (
|
||||
CloudSupportData,
|
||||
RemoteSupportData,
|
||||
get_data_for_cloud_support_view,
|
||||
get_data_for_remote_support_view,
|
||||
get_realm_support_url,
|
||||
)
|
||||
from corporate.models import CustomerPlan
|
||||
from zerver.actions.create_realm import do_change_realm_subdomain
|
||||
from zerver.actions.realm_settings import (
|
||||
|
@ -118,6 +98,8 @@ class DemoRequestForm(forms.Form):
|
|||
@zulip_login_required
|
||||
@typed_endpoint_without_parameters
|
||||
def support_request(request: HttpRequest) -> HttpResponse:
|
||||
from corporate.lib.support import get_realm_support_url
|
||||
|
||||
user = request.user
|
||||
assert user.is_authenticated
|
||||
|
||||
|
@ -161,6 +143,8 @@ def support_request(request: HttpRequest) -> HttpResponse:
|
|||
|
||||
@typed_endpoint_without_parameters
|
||||
def demo_request(request: HttpRequest) -> HttpResponse:
|
||||
from corporate.lib.stripe import BILLING_SUPPORT_EMAIL
|
||||
|
||||
context = {
|
||||
"MAX_INPUT_LENGTH": DemoRequestForm.MAX_INPUT_LENGTH,
|
||||
"SORTED_ORG_TYPE_NAMES": DemoRequestForm.SORTED_ORG_TYPE_NAMES,
|
||||
|
@ -340,11 +324,15 @@ ModifyPlan = Literal[
|
|||
|
||||
RemoteServerStatus = Literal["active", "deactivated"]
|
||||
|
||||
SHARED_SUPPORT_CONTEXT = {
|
||||
|
||||
def shared_support_context() -> dict[str, object]:
|
||||
from corporate.lib.stripe import cents_to_dollar_string
|
||||
|
||||
return {
|
||||
"get_org_type_display_name": get_org_type_display_name,
|
||||
"get_plan_type_name": get_plan_type_string,
|
||||
"dollar_amount": cents_to_dollar_string,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@require_server_admin
|
||||
|
@ -370,7 +358,15 @@ def support(
|
|||
org_type: Json[NonNegativeInt] | None = None,
|
||||
max_invites: Json[NonNegativeInt] | None = None,
|
||||
) -> HttpResponse:
|
||||
context: dict[str, Any] = {**SHARED_SUPPORT_CONTEXT}
|
||||
from corporate.lib.stripe import (
|
||||
RealmBillingSession,
|
||||
SupportRequestError,
|
||||
SupportType,
|
||||
SupportViewRequest,
|
||||
)
|
||||
from corporate.lib.support import CloudSupportData, get_data_for_cloud_support_view
|
||||
|
||||
context = shared_support_context()
|
||||
|
||||
if "success_message" in request.session:
|
||||
context["success_message"] = request.session["success_message"]
|
||||
|
@ -692,7 +688,19 @@ def remote_servers_support(
|
|||
]
|
||||
| None = None,
|
||||
) -> HttpResponse:
|
||||
context: dict[str, Any] = {**SHARED_SUPPORT_CONTEXT}
|
||||
from corporate.lib.stripe import (
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
ServerDeactivateWithExistingPlanError,
|
||||
SupportRequestError,
|
||||
SupportType,
|
||||
SupportViewRequest,
|
||||
do_deactivate_remote_server,
|
||||
do_reactivate_remote_server,
|
||||
)
|
||||
from corporate.lib.support import RemoteSupportData, get_data_for_remote_support_view
|
||||
|
||||
context = shared_support_context()
|
||||
|
||||
if "success_message" in request.session:
|
||||
context["success_message"] = request.session["success_message"]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from django.conf import settings
|
||||
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
|
||||
|
@ -10,14 +11,6 @@ from corporate.lib.decorator import (
|
|||
authenticated_remote_realm_management_endpoint,
|
||||
authenticated_remote_server_management_endpoint,
|
||||
)
|
||||
from corporate.lib.stripe import (
|
||||
BillingError,
|
||||
InitialUpgradeRequest,
|
||||
RealmBillingSession,
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
UpgradeRequest,
|
||||
)
|
||||
from corporate.models import CustomerPlan
|
||||
from zerver.decorator import require_organization_member, zulip_login_required
|
||||
from zerver.lib.response import json_success
|
||||
|
@ -25,6 +18,9 @@ from zerver.lib.typed_endpoint import typed_endpoint
|
|||
from zerver.models import UserProfile
|
||||
from zilencer.lib.remote_counts import MissingDataError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from corporate.lib.stripe import RemoteRealmBillingSession, RemoteServerBillingSession
|
||||
|
||||
billing_logger = logging.getLogger("corporate.stripe")
|
||||
|
||||
|
||||
|
@ -42,6 +38,8 @@ def upgrade(
|
|||
licenses: Json[int] | None = None,
|
||||
tier: Json[int] = CustomerPlan.TIER_CLOUD_STANDARD,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import BillingError, RealmBillingSession, UpgradeRequest
|
||||
|
||||
try:
|
||||
upgrade_request = UpgradeRequest(
|
||||
billing_modality=billing_modality,
|
||||
|
@ -77,11 +75,11 @@ def upgrade(
|
|||
raise BillingError(error_description, error_message)
|
||||
|
||||
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
def remote_realm_upgrade(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteRealmBillingSession,
|
||||
billing_session: "RemoteRealmBillingSession",
|
||||
*,
|
||||
billing_modality: BillingModality,
|
||||
schedule: BillingSchedule,
|
||||
|
@ -92,6 +90,8 @@ def remote_realm_upgrade(
|
|||
remote_server_plan_start_date: str | None = None,
|
||||
tier: Json[int] = CustomerPlan.TIER_SELF_HOSTED_BUSINESS,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import BillingError, UpgradeRequest
|
||||
|
||||
try:
|
||||
upgrade_request = UpgradeRequest(
|
||||
billing_modality=billing_modality,
|
||||
|
@ -125,11 +125,11 @@ def remote_realm_upgrade(
|
|||
raise BillingError(error_description, error_message)
|
||||
|
||||
|
||||
@authenticated_remote_server_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def remote_server_upgrade(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteServerBillingSession,
|
||||
billing_session: "RemoteServerBillingSession",
|
||||
*,
|
||||
billing_modality: BillingModality,
|
||||
schedule: BillingSchedule,
|
||||
|
@ -140,6 +140,8 @@ def remote_server_upgrade(
|
|||
remote_server_plan_start_date: str | None = None,
|
||||
tier: Json[int] = CustomerPlan.TIER_SELF_HOSTED_BUSINESS,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import BillingError, UpgradeRequest
|
||||
|
||||
try:
|
||||
upgrade_request = UpgradeRequest(
|
||||
billing_modality=billing_modality,
|
||||
|
@ -182,6 +184,8 @@ def upgrade_page(
|
|||
tier: Json[int] = CustomerPlan.TIER_CLOUD_STANDARD,
|
||||
setup_payment_by_invoice: Json[bool] = False,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import InitialUpgradeRequest, RealmBillingSession
|
||||
|
||||
user = request.user
|
||||
assert user.is_authenticated
|
||||
|
||||
|
@ -207,17 +211,19 @@ def upgrade_page(
|
|||
return response
|
||||
|
||||
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_realm_management_endpoint
|
||||
def remote_realm_upgrade_page(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteRealmBillingSession,
|
||||
billing_session: "RemoteRealmBillingSession",
|
||||
*,
|
||||
manual_license_management: Json[bool] = False,
|
||||
success_message: str = "",
|
||||
tier: str = str(CustomerPlan.TIER_SELF_HOSTED_BUSINESS),
|
||||
setup_payment_by_invoice: Json[bool] = False,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import InitialUpgradeRequest
|
||||
|
||||
billing_modality = "charge_automatically"
|
||||
if setup_payment_by_invoice: # nocoverage
|
||||
billing_modality = "send_invoice"
|
||||
|
@ -240,17 +246,19 @@ def remote_realm_upgrade_page(
|
|||
return response
|
||||
|
||||
|
||||
@authenticated_remote_server_management_endpoint
|
||||
@typed_endpoint
|
||||
@authenticated_remote_server_management_endpoint
|
||||
def remote_server_upgrade_page(
|
||||
request: HttpRequest,
|
||||
billing_session: RemoteServerBillingSession,
|
||||
billing_session: "RemoteServerBillingSession",
|
||||
*,
|
||||
manual_license_management: Json[bool] = False,
|
||||
success_message: str = "",
|
||||
tier: str = str(CustomerPlan.TIER_SELF_HOSTED_BUSINESS),
|
||||
setup_payment_by_invoice: Json[bool] = False,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import InitialUpgradeRequest
|
||||
|
||||
billing_modality = "charge_automatically"
|
||||
if setup_payment_by_invoice: # nocoverage
|
||||
billing_modality = "send_invoice"
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
import json
|
||||
import logging
|
||||
|
||||
import stripe
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from corporate.lib.stripe import STRIPE_API_VERSION
|
||||
from corporate.lib.stripe_event_handler import (
|
||||
handle_checkout_session_completed_event,
|
||||
handle_invoice_paid_event,
|
||||
)
|
||||
from corporate.models import Event, Invoice, Session
|
||||
from zproject.config import get_secret
|
||||
|
||||
|
@ -20,6 +14,14 @@ billing_logger = logging.getLogger("corporate.stripe")
|
|||
|
||||
@csrf_exempt
|
||||
def stripe_webhook(request: HttpRequest) -> HttpResponse:
|
||||
import stripe
|
||||
|
||||
from corporate.lib.stripe import STRIPE_API_VERSION
|
||||
from corporate.lib.stripe_event_handler import (
|
||||
handle_checkout_session_completed_event,
|
||||
handle_invoice_paid_event,
|
||||
)
|
||||
|
||||
stripe_webhook_endpoint_secret = get_secret("stripe_webhook_endpoint_secret", "")
|
||||
if (
|
||||
stripe_webhook_endpoint_secret and not settings.TEST_SUITE
|
||||
|
|
|
@ -48,9 +48,6 @@ from zerver.models.realms import (
|
|||
from zerver.models.users import get_system_bot
|
||||
from zproject.backends import all_default_backend_names
|
||||
|
||||
if settings.CORPORATE_ENABLED:
|
||||
from corporate.lib.support import get_realm_support_url
|
||||
|
||||
|
||||
def do_change_realm_subdomain(
|
||||
realm: Realm,
|
||||
|
@ -372,6 +369,8 @@ def do_create_realm(
|
|||
|
||||
# Send a notification to the admin realm when a new organization registers.
|
||||
if settings.CORPORATE_ENABLED:
|
||||
from corporate.lib.support import get_realm_support_url
|
||||
|
||||
admin_realm = get_realm(settings.SYSTEM_BOT_REALM)
|
||||
sender = get_system_bot(settings.NOTIFICATION_BOT, admin_realm.id)
|
||||
|
||||
|
|
|
@ -62,10 +62,6 @@ from zerver.models.realm_audit_logs import AuditLogEventType
|
|||
from zerver.models.users import active_user_ids, bot_owner_user_ids, get_system_bot
|
||||
from zerver.tornado.django_api import send_event_on_commit
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
|
||||
MAX_NUM_RECENT_MESSAGES = 1000
|
||||
MAX_NUM_RECENT_UNREAD_MESSAGES = 20
|
||||
|
||||
|
@ -512,6 +508,9 @@ def do_create_user(
|
|||
email_address_visibility: int | None = None,
|
||||
add_initial_stream_subscriptions: bool = True,
|
||||
) -> UserProfile:
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
with transaction.atomic():
|
||||
user_profile = create_user(
|
||||
email=email,
|
||||
|
@ -643,6 +642,9 @@ def do_activate_mirror_dummy_user(
|
|||
parallel code path to do_create_user; e.g. it likely does not
|
||||
handle preferences or default streams properly.
|
||||
"""
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
with transaction.atomic():
|
||||
change_user_is_active(user_profile, True)
|
||||
user_profile.is_mirror_dummy = False
|
||||
|
@ -714,6 +716,8 @@ def do_reactivate_user(user_profile: UserProfile, *, acting_user: UserProfile |
|
|||
bot_owner_changed = True
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
billing_session = RealmBillingSession(user=user_profile, realm=user_profile.realm)
|
||||
billing_session.update_license_ledger_if_needed(event_time)
|
||||
|
||||
|
|
|
@ -51,9 +51,6 @@ from zerver.models.realms import get_default_max_invites_for_realm_plan_type, ge
|
|||
from zerver.models.users import active_user_ids
|
||||
from zerver.tornado.django_api import send_event_on_commit
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
|
||||
@transaction.atomic(savepoint=False)
|
||||
def do_set_realm_property(
|
||||
|
@ -516,6 +513,9 @@ def do_deactivate_realm(
|
|||
if realm.deactivated:
|
||||
return
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
with transaction.atomic():
|
||||
realm.deactivated = True
|
||||
realm.save(update_fields=["deactivated"])
|
||||
|
@ -623,6 +623,8 @@ def do_delete_all_realm_attachments(realm: Realm, *, batch_size: int = 1000) ->
|
|||
|
||||
def do_scrub_realm(realm: Realm, *, acting_user: UserProfile | None) -> None:
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
billing_session = RealmBillingSession(user=acting_user, realm=realm)
|
||||
billing_session.downgrade_now_without_creating_additional_invoices()
|
||||
|
||||
|
|
|
@ -53,9 +53,6 @@ from zerver.models.users import (
|
|||
)
|
||||
from zerver.tornado.django_api import send_event_on_commit
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
|
||||
def do_delete_user(user_profile: UserProfile, *, acting_user: UserProfile | None) -> None:
|
||||
if user_profile.realm.is_zephyr_mirror_realm:
|
||||
|
@ -324,6 +321,9 @@ def do_deactivate_user(
|
|||
if not user_profile.is_active:
|
||||
return
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
if _cascade:
|
||||
# We need to deactivate bots before the target user, to ensure
|
||||
# that a failure partway through this function cannot result
|
||||
|
@ -474,6 +474,8 @@ def do_change_user_role(
|
|||
)
|
||||
maybe_enqueue_audit_log_upload(user_profile.realm)
|
||||
if settings.BILLING_ENABLED and UserProfile.ROLE_GUEST in [old_value, value]:
|
||||
from corporate.lib.stripe import RealmBillingSession
|
||||
|
||||
billing_session = RealmBillingSession(user=user_profile, realm=user_profile.realm)
|
||||
billing_session.update_license_ledger_if_needed(timezone_now())
|
||||
|
||||
|
|
|
@ -46,10 +46,6 @@ from zerver.models.realms import (
|
|||
from zerver.models.users import get_user_by_delivery_email, is_cross_realm_bot_email
|
||||
from zproject.backends import check_password_strength, email_auth_enabled, email_belongs_to_ldap
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.registration import check_spare_licenses_available_for_registering_new_user
|
||||
from corporate.lib.stripe import LicenseLimitError
|
||||
|
||||
# We don't mark this error for translation, because it's displayed
|
||||
# only to MIT users.
|
||||
MIT_VALIDATION_ERROR = Markup(
|
||||
|
@ -302,6 +298,11 @@ class HomepageForm(forms.Form):
|
|||
email_is_not_mit_mailing_list(email)
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.registration import (
|
||||
check_spare_licenses_available_for_registering_new_user,
|
||||
)
|
||||
from corporate.lib.stripe import LicenseLimitError
|
||||
|
||||
role = self.invited_as if self.invited_as is not None else UserProfile.ROLE_MEMBER
|
||||
try:
|
||||
check_spare_licenses_available_for_registering_new_user(realm, email, role=role)
|
||||
|
|
|
@ -2372,7 +2372,7 @@ class AnalyticsBouncerTest(BouncerTestCase):
|
|||
|
||||
with (
|
||||
mock.patch(
|
||||
"zilencer.views.RemoteRealmBillingSession.get_customer", return_value=None
|
||||
"corporate.lib.stripe.RemoteRealmBillingSession.get_customer", return_value=None
|
||||
) as m,
|
||||
mock.patch(
|
||||
"corporate.lib.stripe.RemoteRealmBillingSession.current_count_for_billed_licenses",
|
||||
|
@ -2404,7 +2404,8 @@ class AnalyticsBouncerTest(BouncerTestCase):
|
|||
dummy_customer = mock.MagicMock()
|
||||
with (
|
||||
mock.patch(
|
||||
"zilencer.views.RemoteRealmBillingSession.get_customer", return_value=dummy_customer
|
||||
"corporate.lib.stripe.RemoteRealmBillingSession.get_customer",
|
||||
return_value=dummy_customer,
|
||||
),
|
||||
mock.patch("corporate.lib.stripe.get_current_plan_by_customer", return_value=None) as m,
|
||||
mock.patch(
|
||||
|
@ -2425,7 +2426,8 @@ class AnalyticsBouncerTest(BouncerTestCase):
|
|||
|
||||
with (
|
||||
mock.patch(
|
||||
"zilencer.views.RemoteRealmBillingSession.get_customer", return_value=dummy_customer
|
||||
"corporate.lib.stripe.RemoteRealmBillingSession.get_customer",
|
||||
return_value=dummy_customer,
|
||||
),
|
||||
mock.patch("corporate.lib.stripe.get_current_plan_by_customer", return_value=None),
|
||||
mock.patch(
|
||||
|
@ -2586,7 +2588,9 @@ class AnalyticsBouncerTest(BouncerTestCase):
|
|||
"corporate.lib.stripe.RemoteServerBillingSession.get_customer",
|
||||
return_value=dummy_remote_server_customer,
|
||||
),
|
||||
mock.patch("zilencer.views.RemoteServerBillingSession.sync_license_ledger_if_needed"),
|
||||
mock.patch(
|
||||
"corporate.lib.stripe.RemoteServerBillingSession.sync_license_ledger_if_needed"
|
||||
),
|
||||
mock.patch(
|
||||
"corporate.lib.stripe.get_current_plan_by_customer",
|
||||
side_effect=get_current_plan_by_customer,
|
||||
|
@ -2702,7 +2706,9 @@ class AnalyticsBouncerTest(BouncerTestCase):
|
|||
# of a deleted realm.
|
||||
with (
|
||||
self.assertLogs(logger, level="WARNING") as analytics_logger,
|
||||
mock.patch("zilencer.views.RemoteRealmBillingSession.on_paid_plan", return_value=True),
|
||||
mock.patch(
|
||||
"corporate.lib.stripe.RemoteRealmBillingSession.on_paid_plan", return_value=True
|
||||
),
|
||||
):
|
||||
# This time the logger shouldn't get triggered - because the bouncer doesn't
|
||||
# include .realm_locally_deleted realms in its response.
|
||||
|
|
|
@ -120,10 +120,6 @@ from zproject.backends import (
|
|||
password_auth_enabled,
|
||||
)
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.registration import check_spare_licenses_available_for_registering_new_user
|
||||
from corporate.lib.stripe import LicenseLimitError
|
||||
|
||||
|
||||
@typed_endpoint
|
||||
def get_prereg_key_and_redirect(
|
||||
|
@ -332,6 +328,11 @@ def registration_helper(
|
|||
return redirect_to_email_login_url(email)
|
||||
|
||||
if settings.BILLING_ENABLED:
|
||||
from corporate.lib.registration import (
|
||||
check_spare_licenses_available_for_registering_new_user,
|
||||
)
|
||||
from corporate.lib.stripe import LicenseLimitError
|
||||
|
||||
try:
|
||||
check_spare_licenses_available_for_registering_new_user(realm, email, role=role)
|
||||
except LicenseLimitError:
|
||||
|
|
|
@ -30,13 +30,6 @@ from analytics.lib.counts import (
|
|||
REMOTE_INSTALLATION_COUNT_STATS,
|
||||
do_increment_logging_stat,
|
||||
)
|
||||
from corporate.lib.stripe import (
|
||||
BILLING_SUPPORT_EMAIL,
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
do_deactivate_remote_server,
|
||||
get_push_status_for_remote_request,
|
||||
)
|
||||
from corporate.models import (
|
||||
CustomerPlan,
|
||||
get_current_plan_by_customer,
|
||||
|
@ -120,6 +113,8 @@ def deactivate_remote_server(
|
|||
request: HttpRequest,
|
||||
remote_server: RemoteZulipServer,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import RemoteServerBillingSession, do_deactivate_remote_server
|
||||
|
||||
billing_session = RemoteServerBillingSession(remote_server)
|
||||
do_deactivate_remote_server(remote_server, billing_session)
|
||||
return json_success(request)
|
||||
|
@ -538,6 +533,8 @@ def remote_server_notify_push(
|
|||
*,
|
||||
payload: JsonBodyPayload[RemoteServerNotificationPayload],
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import get_push_status_for_remote_request
|
||||
|
||||
user_id = payload.user_id
|
||||
user_uuid = payload.user_uuid
|
||||
user_identity = UserPushIdentityCompat(user_id, user_uuid)
|
||||
|
@ -844,6 +841,8 @@ def ensure_devices_set_remote_realm(
|
|||
def update_remote_realm_data_for_server(
|
||||
server: RemoteZulipServer, server_realms_info: list[RealmDataForAnalytics]
|
||||
) -> None:
|
||||
from corporate.lib.stripe import BILLING_SUPPORT_EMAIL, RemoteRealmBillingSession
|
||||
|
||||
reported_uuids = [realm.uuid for realm in server_realms_info]
|
||||
all_registered_remote_realms_for_server = list(RemoteRealm.objects.filter(server=server))
|
||||
already_registered_remote_realms = [
|
||||
|
@ -1032,6 +1031,8 @@ def get_human_user_realm_uuids(
|
|||
def handle_customer_migration_from_server_to_realm(
|
||||
server: RemoteZulipServer,
|
||||
) -> None:
|
||||
from corporate.lib.stripe import RemoteServerBillingSession
|
||||
|
||||
server_billing_session = RemoteServerBillingSession(server)
|
||||
server_customer = server_billing_session.get_customer()
|
||||
if server_customer is None:
|
||||
|
@ -1160,6 +1161,12 @@ def remote_server_post_analytics(
|
|||
merge_base: Json[str] | None = None,
|
||||
api_feature_level: Json[int] | None = None,
|
||||
) -> HttpResponse:
|
||||
from corporate.lib.stripe import (
|
||||
RemoteRealmBillingSession,
|
||||
RemoteServerBillingSession,
|
||||
get_push_status_for_remote_request,
|
||||
)
|
||||
|
||||
# Lock the server, preventing this from racing with other
|
||||
# duplicate submissions of the data
|
||||
server = RemoteZulipServer.objects.select_for_update().get(id=server.id)
|
||||
|
|
Loading…
Reference in New Issue