@@ -503,24 +503,37 @@ export async function handleInvoicePaymentSucceeded(event: Stripe.Event) {
503503 wasBlocked = row . length > 0 ? ! ! row [ 0 ] . blocked : false
504504 }
505505
506- if ( isOrgPlan ( sub . plan ) ) {
507- await unblockOrgMembers ( sub . referenceId , 'payment_failed' )
508- } else {
509- // Only unblock users blocked for payment_failed, not disputes
510- await db
511- . update ( userStats )
512- . set ( { billingBlocked : false , billingBlockedReason : null } )
513- . where (
514- and (
515- eq ( userStats . userId , sub . referenceId ) ,
516- eq ( userStats . billingBlockedReason , 'payment_failed' )
506+ // For proration invoices (mid-cycle upgrades/seat changes), only unblock if real money
507+ // was collected. A $0 credit invoice from a downgrade should not unblock a user who
508+ // was blocked for a different failed payment.
509+ const isProrationInvoice = invoice . billing_reason === 'subscription_update'
510+ const shouldUnblock = ! isProrationInvoice || ( invoice . amount_paid ?? 0 ) > 0
511+
512+ if ( shouldUnblock ) {
513+ if ( isOrgPlan ( sub . plan ) ) {
514+ await unblockOrgMembers ( sub . referenceId , 'payment_failed' )
515+ } else {
516+ await db
517+ . update ( userStats )
518+ . set ( { billingBlocked : false , billingBlockedReason : null } )
519+ . where (
520+ and (
521+ eq ( userStats . userId , sub . referenceId ) ,
522+ eq ( userStats . billingBlockedReason , 'payment_failed' )
523+ )
517524 )
518- )
525+ }
526+ } else {
527+ logger . info ( 'Skipping unblock for zero-amount proration invoice' , {
528+ invoiceId : invoice . id ,
529+ billingReason : invoice . billing_reason ,
530+ amountPaid : invoice . amount_paid ,
531+ } )
519532 }
520533
521- // Only reset usage for cycle renewals — proration invoices (subscription_update) should
522- // unblock the user but not wipe their accumulated usage mid-cycle.
523- if ( wasBlocked && invoice . billing_reason !== 'subscription_update' ) {
534+ // Only reset usage for cycle renewals — proration invoices should not wipe
535+ // accumulated usage mid-cycle.
536+ if ( wasBlocked && ! isProrationInvoice ) {
524537 await resetUsageForSubscription ( { plan : sub . plan , referenceId : sub . referenceId } )
525538 }
526539 } catch ( error ) {
0 commit comments