@@ -15,14 +15,10 @@ def create
1515 private
1616 def dispatch_stripe_event ( event )
1717 case event . type
18- when "checkout.session.completed"
19- handle_checkout_completed ( event . data . object )
20- when "customer.subscription.updated"
21- handle_subscription_updated ( event . data . object )
22- when "customer.subscription.deleted"
23- handle_subscription_deleted ( event . data . object )
24- when "invoice.payment_failed"
25- handle_payment_failed ( event . data . object )
18+ when "checkout.session.completed"
19+ sync_new_subscription ( event . data . object . subscription , plan_key : event . data . object . metadata [ "plan_key" ] ) if event . data . object . mode == "subscription"
20+ when "customer.subscription.updated" , "customer.subscription.deleted"
21+ sync_subscription ( event . data . object . id )
2622 end
2723 end
2824
@@ -36,47 +32,37 @@ def verify_webhook_signature
3632 nil
3733 end
3834
39- def handle_checkout_completed ( session )
40- return unless session . mode == "subscription"
41-
42- subscription = find_subscription_by_customer ( session . customer )
43- return unless subscription
44-
45- stripe_subscription = Stripe ::Subscription . retrieve ( session . subscription )
46-
47- subscription . update! \
48- stripe_subscription_id : stripe_subscription . id ,
49- plan_key : session . metadata [ "plan_key" ] ,
50- status : stripe_subscription . status ,
51- current_period_end : extract_current_period_end ( stripe_subscription )
35+ def sync_new_subscription ( stripe_subscription_id , plan_key :)
36+ sync_subscription ( stripe_subscription_id ) do |subscription_properties |
37+ subscription_properties [ :plan_key ] = plan_key if plan_key
38+ end
5239 end
5340
54- def handle_subscription_updated ( stripe_subscription )
41+ # Always fetch fresh subscription data from Stripe to handle out-of-order
42+ # event delivery. Not relying on payload data.
43+ def sync_subscription ( stripe_subscription_id )
44+ stripe_subscription = Stripe ::Subscription . retrieve ( stripe_subscription_id )
45+
5546 if subscription = find_subscription_by_customer ( stripe_subscription . customer )
56- subscription . update! \
47+ subscription_properties = {
48+ stripe_subscription_id : stripe_subscription . id ,
5749 status : stripe_subscription . status ,
58- current_period_end : extract_current_period_end ( stripe_subscription ) ,
50+ current_period_end : current_period_end_for ( stripe_subscription ) ,
5951 cancel_at : stripe_subscription . cancel_at ? Time . at ( stripe_subscription . cancel_at ) : nil
60- end
61- end
52+ }
6253
63- def handle_subscription_deleted ( stripe_subscription )
64- if subscription = find_subscription_by_customer ( stripe_subscription . customer )
65- subscription . update! ( status : "canceled" , stripe_subscription_id : nil )
66- end
67- end
54+ yield subscription_properties if block_given?
55+ subscription_properties [ :stripe_subscription_id ] = nil if stripe_subscription . status == "canceled"
6856
69- def handle_payment_failed ( invoice )
70- if subscription = find_subscription_by_customer ( invoice . customer )
71- subscription . update! ( status : "past_due" )
57+ subscription . update! ( subscription_properties )
7258 end
7359 end
7460
7561 def find_subscription_by_customer ( customer_id )
7662 Account ::Subscription . find_by ( stripe_customer_id : customer_id )
7763 end
7864
79- def extract_current_period_end ( stripe_subscription )
65+ def current_period_end_for ( stripe_subscription )
8066 timestamp = stripe_subscription . items . data . first &.current_period_end
8167 Time . at ( timestamp ) if timestamp
8268 end
0 commit comments