Skip to content

Commit 8f38ce5

Browse files
authored
Allow organizations to delete if in odd Stripe state (#20651)
* allow cancelling if not in bad state list * test new org bill cancel checks
1 parent 6ce5d06 commit 8f38ce5

3 files changed

Lines changed: 45 additions & 21 deletions

File tree

‎tests/unit/manage/views/test_organizations.py‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1218,24 +1218,41 @@ def test_delete_organization_with_active_projects(
12181218
assert organization_service.delete_organization.calls == []
12191219
assert db_request.route_path.calls == []
12201220

1221+
@pytest.mark.parametrize(
1222+
("subscription_status", "should_cancel"),
1223+
[
1224+
("active", True),
1225+
("past_due", True),
1226+
("canceled", False),
1227+
("incomplete_expired", False),
1228+
],
1229+
)
12211230
def test_delete_organization_with_subscriptions(
12221231
self,
12231232
db_request,
12241233
pyramid_user,
1234+
billing_service,
12251235
organization_service,
12261236
user_service,
12271237
monkeypatch,
1238+
subscription_status,
1239+
should_cancel,
12281240
):
12291241
organization = OrganizationFactory.create()
12301242
stripe_customer = StripeCustomerFactory.create()
12311243
OrganizationStripeCustomerFactory.create(
12321244
organization=organization, customer=stripe_customer
12331245
)
1234-
subscription = StripeSubscriptionFactory.create(customer=stripe_customer)
1246+
subscription = StripeSubscriptionFactory.create(
1247+
customer=stripe_customer, status=subscription_status
1248+
)
12351249
OrganizationStripeSubscriptionFactory.create(
12361250
organization=organization, subscription=subscription
12371251
)
12381252

1253+
cancel_subscription = pretend.call_recorder(lambda *a, **kw: None)
1254+
monkeypatch.setattr(billing_service, "cancel_subscription", cancel_subscription)
1255+
12391256
db_request.POST = {"confirm_organization_name": organization.name}
12401257
db_request.route_path = pretend.call_recorder(
12411258
lambda *a, **kw: "/manage/organizations/"
@@ -1265,6 +1282,9 @@ def test_delete_organization_with_subscriptions(
12651282

12661283
assert isinstance(result, HTTPSeeOther)
12671284
assert result.headers["Location"] == "/manage/organizations/"
1285+
assert cancel_subscription.calls == (
1286+
[pretend.call(subscription.subscription_id)] if should_cancel else []
1287+
)
12681288
assert organization_service.delete_organization.calls == [
12691289
pretend.call(organization.id)
12701290
]

‎warehouse/locale/messages.pot‎

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎warehouse/manage/views/organizations.py‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
from warehouse.packaging.models import JournalEntry, ProjectFactory
8787
from warehouse.rate_limiting.interfaces import RateLimiterException
8888
from warehouse.subscriptions import IBillingService, ISubscriptionService
89+
from warehouse.subscriptions.models import StripeSubscriptionStatus
8990
from warehouse.subscriptions.services import MockStripeBillingService
9091
from warehouse.utils.http import is_safe_url
9192
from warehouse.utils.organization import confirm_organization
@@ -513,9 +514,12 @@ def delete_organization(self):
513514
# Get owners before deleting organization.
514515
owner_users = set(organization_owners(self.request, self.organization))
515516

516-
# Cancel any subscriptions tied to this organization.
517-
if self.organization.subscriptions:
518-
for subscription in self.organization.subscriptions:
517+
# Cancel subscriptions that are not already in a terminal state.
518+
for subscription in self.organization.subscriptions:
519+
if subscription.status not in (
520+
StripeSubscriptionStatus.Canceled.value,
521+
StripeSubscriptionStatus.IncompleteExpired.value,
522+
):
519523
self.billing_service.cancel_subscription(subscription.subscription_id)
520524

521525
self.organization_service.delete_organization(self.organization.id)

0 commit comments

Comments
 (0)