Skip to content

Commit f42d6d9

Browse files
huntcsgampagent
andcommitted
fix(billing): trust embedded team reactivation decision
Amp-Thread-ID: https://ampcode.com/threads/T-01a025d0-71f9-77da-8f57-3f8f9560dac1 Co-authored-by: Amp <amp@ampcode.com>
1 parent 282f35b commit f42d6d9

2 files changed

Lines changed: 40 additions & 9 deletions

File tree

src/platform/workspace/composables/useSubscriptionCheckout.test.ts

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,6 +1589,33 @@ describe('useSubscriptionCheckout', () => {
15891589
)
15901590
})
15911591

1592+
it('uses the backend reactivation decision when cached team status is cancelled', async () => {
1593+
mockSubscription.value = { isCancelled: true }
1594+
mockPreviewSubscribe.mockResolvedValueOnce({
1595+
allowed: true,
1596+
transition_type: 'new_subscription',
1597+
is_immediate: true,
1598+
requires_reactivation_confirmation: false
1599+
})
1600+
const checkout = await setup()
1601+
1602+
await checkout.handleSubscribeTeamClick({
1603+
stop: {
1604+
id: 'team_700',
1605+
usd: 700,
1606+
credits: 147_700,
1607+
discountedUsd: 665
1608+
},
1609+
billingCycle: 'monthly',
1610+
isChange: false
1611+
})
1612+
1613+
expect(checkout.checkoutStep.value).toBe('preview')
1614+
expect(checkout.previewVariant.value).toBe('team-new')
1615+
expect(checkout.reactivationRequired.value).toBe(false)
1616+
expect(mockToastAdd).not.toHaveBeenCalled()
1617+
})
1618+
15921619
it('bounces a cancelled subscriber back to pricing when the preview request fails', async () => {
15931620
mockSubscription.value = { isCancelled: true }
15941621
mockPreviewSubscribe.mockRejectedValueOnce(new Error('not supported'))
@@ -2004,14 +2031,15 @@ describe('useSubscriptionCheckout', () => {
20042031
expect(checkout.checkoutStep.value).toBe('success')
20052032
})
20062033

2007-
// Regression guard: confirmReactivation must come from the disclosure
2008-
// banner's own confirm action, never be re-derived from
2009-
// subscription.isCancelled. A path with no banner (team-new fallback)
2010-
// always calls in with confirmReactivation=false, so a cancelled
2011-
// subscription must block the request rather than silently send it and
2012-
// let the BE reject it with no way for the user to consent.
20132034
it('blocks the team subscribe and shows an error for a cancelled subscription with no confirmation', async () => {
20142035
mockSubscription.value = { isCancelled: true }
2036+
mockPreviewSubscribe.mockResolvedValueOnce({
2037+
allowed: true,
2038+
transition_type: 'upgrade',
2039+
is_immediate: true,
2040+
requires_reactivation_confirmation: true,
2041+
current_plan: { period_end: '2026-08-29T00:00:00Z' }
2042+
})
20152043
const checkout = await setup()
20162044
await checkout.handleSubscribeTeamClick({
20172045
stop: {
@@ -2141,7 +2169,8 @@ describe('useSubscriptionCheckout', () => {
21412169
transition_type: 'upgrade',
21422170
is_immediate: true,
21432171
cost_today_cents: 105_000,
2144-
requires_reactivation_confirmation: true
2172+
requires_reactivation_confirmation: true,
2173+
current_plan: { period_end: '2026-08-29T00:00:00Z' }
21452174
})
21462175
await checkout.handleSubscribeTeamClick({
21472176
stop: {
@@ -2399,7 +2428,8 @@ describe('useSubscriptionCheckout', () => {
23992428
transition_type: 'upgrade',
24002429
is_immediate: true,
24012430
cost_today_cents: 105_000,
2402-
requires_reactivation_confirmation: true
2431+
requires_reactivation_confirmation: true,
2432+
current_plan: { period_end: '2026-08-29T00:00:00Z' }
24032433
})
24042434
await checkout.handleSubscribeTeamClick({
24052435
stop: {

src/platform/workspace/composables/useSubscriptionCheckout.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,8 @@ export function useSubscriptionCheckout(
826826

827827
if (
828828
response?.allowed &&
829-
(!isSubscriptionCancelled() || isReactivationCapablePreview(response))
829+
(response.requires_reactivation_confirmation === false ||
830+
isReactivationCapablePreview(response))
830831
) {
831832
installPreview(response)
832833
checkoutStep.value = 'preview'

0 commit comments

Comments
 (0)