mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	server_deactivate: Show error message for server on active plan.
This commit is contained in:
		@@ -424,6 +424,14 @@ class StripeConnectionError(BillingError):
 | 
				
			|||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ServerDeactivateWithExistingPlanError(BillingError):  # nocoverage
 | 
				
			||||||
 | 
					    def __init__(self) -> None:
 | 
				
			||||||
 | 
					        super().__init__(
 | 
				
			||||||
 | 
					            "server deactivation with existing plan",
 | 
				
			||||||
 | 
					            "",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UpgradeWithExistingPlanError(BillingError):
 | 
					class UpgradeWithExistingPlanError(BillingError):
 | 
				
			||||||
    def __init__(self) -> None:
 | 
					    def __init__(self) -> None:
 | 
				
			||||||
        super().__init__(
 | 
					        super().__init__(
 | 
				
			||||||
@@ -3853,10 +3861,9 @@ def do_change_remote_server_plan_type(remote_server: RemoteZulipServer, plan_typ
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@transaction.atomic
 | 
					@transaction.atomic
 | 
				
			||||||
def do_deactivate_remote_server(remote_server: RemoteZulipServer) -> None:
 | 
					def do_deactivate_remote_server(
 | 
				
			||||||
    # TODO: This should also ensure that the server doesn't have an active plan,
 | 
					    remote_server: RemoteZulipServer, billing_session: RemoteServerBillingSession
 | 
				
			||||||
    # and deactivate it otherwise. (Like do_deactivate_realm does.)
 | 
					) -> None:
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if remote_server.deactivated:
 | 
					    if remote_server.deactivated:
 | 
				
			||||||
        billing_logger.warning(
 | 
					        billing_logger.warning(
 | 
				
			||||||
            "Cannot deactivate remote server with ID %d, server has already been deactivated.",
 | 
					            "Cannot deactivate remote server with ID %d, server has already been deactivated.",
 | 
				
			||||||
@@ -3864,6 +3871,36 @@ def do_deactivate_remote_server(remote_server: RemoteZulipServer) -> None:
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    server_plans_to_consider = CustomerPlan.objects.filter(
 | 
				
			||||||
 | 
					        customer__remote_server=remote_server
 | 
				
			||||||
 | 
					    ).exclude(status=CustomerPlan.ENDED)
 | 
				
			||||||
 | 
					    realm_plans_to_consider = CustomerPlan.objects.filter(
 | 
				
			||||||
 | 
					        customer__remote_realm__server=remote_server
 | 
				
			||||||
 | 
					    ).exclude(status=CustomerPlan.ENDED)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for possible_plan in list(server_plans_to_consider) + list(realm_plans_to_consider):
 | 
				
			||||||
 | 
					        if possible_plan.tier in [
 | 
				
			||||||
 | 
					            CustomerPlan.TIER_SELF_HOSTED_BASE,
 | 
				
			||||||
 | 
					            CustomerPlan.TIER_SELF_HOSTED_LEGACY,
 | 
				
			||||||
 | 
					            CustomerPlan.TIER_SELF_HOSTED_COMMUNITY,
 | 
				
			||||||
 | 
					        ]:  # nocoverage
 | 
				
			||||||
 | 
					            # No action required for free plans.
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if possible_plan.status in [
 | 
				
			||||||
 | 
					            CustomerPlan.DOWNGRADE_AT_END_OF_FREE_TRIAL,
 | 
				
			||||||
 | 
					            CustomerPlan.DOWNGRADE_AT_END_OF_CYCLE,
 | 
				
			||||||
 | 
					        ]:  # nocoverage
 | 
				
			||||||
 | 
					            # No action required for plans scheduled to downgrade
 | 
				
			||||||
 | 
					            # automatically.
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # This customer has some sort of paid plan; ask the customer
 | 
				
			||||||
 | 
					        # to downgrade their paid plan so that they get the
 | 
				
			||||||
 | 
					        # communication in that flow, and then they can come back and
 | 
				
			||||||
 | 
					        # deactivate their server.
 | 
				
			||||||
 | 
					        raise ServerDeactivateWithExistingPlanError  # nocoverage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    remote_server.deactivated = True
 | 
					    remote_server.deactivated = True
 | 
				
			||||||
    remote_server.save(update_fields=["deactivated"])
 | 
					    remote_server.save(update_fields=["deactivated"])
 | 
				
			||||||
    RemoteZulipServerAuditLog.objects.create(
 | 
					    RemoteZulipServerAuditLog.objects.create(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4604,7 +4604,8 @@ class BillingHelpersTest(ZulipTestCase):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertFalse(remote_server.deactivated)
 | 
					        self.assertFalse(remote_server.deactivated)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        do_deactivate_remote_server(remote_server)
 | 
					        billing_session = RemoteServerBillingSession(remote_server)
 | 
				
			||||||
 | 
					        do_deactivate_remote_server(remote_server, billing_session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        remote_server = RemoteZulipServer.objects.get(uuid=server_uuid)
 | 
					        remote_server = RemoteZulipServer.objects.get(uuid=server_uuid)
 | 
				
			||||||
        remote_realm_audit_log = RemoteZulipServerAuditLog.objects.filter(
 | 
					        remote_realm_audit_log = RemoteZulipServerAuditLog.objects.filter(
 | 
				
			||||||
@@ -4615,7 +4616,7 @@ class BillingHelpersTest(ZulipTestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # Try to deactivate a remote server that is already deactivated
 | 
					        # Try to deactivate a remote server that is already deactivated
 | 
				
			||||||
        with self.assertLogs("corporate.stripe", "WARN") as warning_log:
 | 
					        with self.assertLogs("corporate.stripe", "WARN") as warning_log:
 | 
				
			||||||
            do_deactivate_remote_server(remote_server)
 | 
					            do_deactivate_remote_server(remote_server, billing_session)
 | 
				
			||||||
            self.assertEqual(
 | 
					            self.assertEqual(
 | 
				
			||||||
                warning_log.output,
 | 
					                warning_log.output,
 | 
				
			||||||
                [
 | 
					                [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ from corporate.lib.stripe import (
 | 
				
			|||||||
    RealmBillingSession,
 | 
					    RealmBillingSession,
 | 
				
			||||||
    RemoteRealmBillingSession,
 | 
					    RemoteRealmBillingSession,
 | 
				
			||||||
    RemoteServerBillingSession,
 | 
					    RemoteServerBillingSession,
 | 
				
			||||||
 | 
					    ServerDeactivateWithExistingPlanError,
 | 
				
			||||||
    UpdatePlanRequest,
 | 
					    UpdatePlanRequest,
 | 
				
			||||||
    do_deactivate_remote_server,
 | 
					    do_deactivate_remote_server,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -300,11 +301,11 @@ def remote_server_deactivate_page(
 | 
				
			|||||||
        return HttpResponseNotAllowed(["GET", "POST"])
 | 
					        return HttpResponseNotAllowed(["GET", "POST"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    remote_server = billing_session.remote_server
 | 
					    remote_server = billing_session.remote_server
 | 
				
			||||||
 | 
					    context = {
 | 
				
			||||||
 | 
					        "server_hostname": remote_server.hostname,
 | 
				
			||||||
 | 
					        "action_url": reverse(remote_server_deactivate_page, args=[str(remote_server.uuid)]),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if request.method == "GET":
 | 
					    if request.method == "GET":
 | 
				
			||||||
        context = {
 | 
					 | 
				
			||||||
            "server_hostname": remote_server.hostname,
 | 
					 | 
				
			||||||
            "action_url": reverse(remote_server_deactivate_page, args=[str(remote_server.uuid)]),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return render(request, "corporate/remote_billing_server_deactivate.html", context=context)
 | 
					        return render(request, "corporate/remote_billing_server_deactivate.html", context=context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert request.method == "POST"
 | 
					    assert request.method == "POST"
 | 
				
			||||||
@@ -312,7 +313,12 @@ def remote_server_deactivate_page(
 | 
				
			|||||||
        # Should be impossible if the user is using the UI.
 | 
					        # Should be impossible if the user is using the UI.
 | 
				
			||||||
        raise JsonableError(_("Parameter 'confirmed' is required"))
 | 
					        raise JsonableError(_("Parameter 'confirmed' is required"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    do_deactivate_remote_server(remote_server)
 | 
					    try:
 | 
				
			||||||
 | 
					        do_deactivate_remote_server(remote_server, billing_session)
 | 
				
			||||||
 | 
					    except ServerDeactivateWithExistingPlanError:  # nocoverage
 | 
				
			||||||
 | 
					        context["show_existing_plan_error"] = "true"
 | 
				
			||||||
 | 
					        return render(request, "corporate/remote_billing_server_deactivate.html", context=context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return render(
 | 
					    return render(
 | 
				
			||||||
        request,
 | 
					        request,
 | 
				
			||||||
        "corporate/remote_billing_server_deactivated_success.html",
 | 
					        "corporate/remote_billing_server_deactivated_success.html",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,13 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div class="white-box">
 | 
					        <div class="white-box">
 | 
				
			||||||
            <div id="server-deactivate-details">
 | 
					            <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 }}">
 | 
					                <form id="server-deactivate-form" method="post" action="{{ action_url }}">
 | 
				
			||||||
                    {{ csrf_input }}
 | 
					                    {{ csrf_input }}
 | 
				
			||||||
                    <div id="server-deactivate-form-top-description" class="input-box server-deactivate-form-field no-validation">
 | 
					                    <div id="server-deactivate-form-top-description" class="input-box server-deactivate-form-field no-validation">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -669,6 +669,7 @@ input[name="licenses"] {
 | 
				
			|||||||
    text-align: left;
 | 
					    text-align: left;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#server-deactivate-error,
 | 
				
			||||||
#server-login-error,
 | 
					#server-login-error,
 | 
				
			||||||
#autopay-error {
 | 
					#autopay-error {
 | 
				
			||||||
    font-weight: 400;
 | 
					    font-weight: 400;
 | 
				
			||||||
@@ -697,6 +698,7 @@ input[name="licenses"] {
 | 
				
			|||||||
    top: 5px;
 | 
					    top: 5px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#server-deactivate-error,
 | 
				
			||||||
#server-login-error {
 | 
					#server-login-error {
 | 
				
			||||||
    text-align: left;
 | 
					    text-align: left;
 | 
				
			||||||
    margin: 0 auto;
 | 
					    margin: 0 auto;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -479,6 +479,7 @@ html {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    .alert {
 | 
					    .alert {
 | 
				
			||||||
        &:not(
 | 
					        &:not(
 | 
				
			||||||
 | 
					                #server-deactivate-error,
 | 
				
			||||||
                #server-login-error,
 | 
					                #server-login-error,
 | 
				
			||||||
                .alert-info,
 | 
					                .alert-info,
 | 
				
			||||||
                .billing-page-success,
 | 
					                .billing-page-success,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -92,7 +92,8 @@ def deactivate_remote_server(
 | 
				
			|||||||
    request: HttpRequest,
 | 
					    request: HttpRequest,
 | 
				
			||||||
    remote_server: RemoteZulipServer,
 | 
					    remote_server: RemoteZulipServer,
 | 
				
			||||||
) -> HttpResponse:
 | 
					) -> HttpResponse:
 | 
				
			||||||
    do_deactivate_remote_server(remote_server)
 | 
					    billing_session = RemoteServerBillingSession(remote_server)
 | 
				
			||||||
 | 
					    do_deactivate_remote_server(remote_server, billing_session)
 | 
				
			||||||
    return json_success(request)
 | 
					    return json_success(request)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user