diff --git a/README.md b/README.md index 88ac937..3005d38 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ You can see the code shown in each 101 episode by video by viewing the correspon 3. [Build notifications into Checkout](https://www.youtube.com/watch?v=EaX444Fe2Tk): Add a webhook handler to your Checkout integration so you know when you've gotten paid and can fulfill the order. [PR](https://github.com/stripe-samples/checkout-foundations-ruby/pull/1) 4. [Build a customer order confirmation page with Checkout](https://www.youtube.com/watch?v=COeMEHKbECw): Use the Checkout Session ID to look up order information after the customer has completed their purchase to display on the success page. Allow your customers to return to their Checkout session from the cancel page. [PR](https://github.com/stripe-samples/checkout-foundations-ruby/pull/2) 5. Add support for adjustable quantities: Let your customer adjust their order during Checkout. Display the total price and quantities for each line item purchased on the success page. [PR](https://github.com/stripe-samples/checkout-foundations-ruby/pull/3) +6. Recover abandoned carts: Configure Checkout to generate a new session when the original session is abandoned by the customer and expires. Collect consent to send promotional emails and listen for session expired events to know when to reach out to encourage a customer to complete their purchase. [PR](https://github.com/stripe-samples/checkout-foundations-ruby/pull/4) ## Get support diff --git a/server.rb b/server.rb index 5520c05..3aca4f9 100644 --- a/server.rb +++ b/server.rb @@ -48,6 +48,16 @@ mode: 'payment', success_url: YOUR_DOMAIN + '/success.html?session_id={CHECKOUT_SESSION_ID}', cancel_url: YOUR_DOMAIN + '/cancel.html?session_id={CHECKOUT_SESSION_ID}', + consent_collection: { + promotions: 'auto' + }, + after_expiration: { + recovery: { + enabled: true, + allow_promotion_codes: true + } + }, + expires_at: Time.now.to_i + (3600 * 2), # configure to expire after 2 hours }) redirect session.url, 303 end @@ -98,6 +108,10 @@ if checkout_session.payment_status == 'paid' fulfill_order(checkout_session) end + + unless checkout_session.recovered_from.nil? + log_recovered_cart(checkout_session) + end when 'checkout.session.async_payment_succeeded' checkout_session = event.data.object @@ -108,6 +122,12 @@ # Send an email to the customer asking them to retry their order email_customer_about_failed_payment(checkout_session) + when 'checkout.session.expired' + checkout_session = event.data.object + if checkout_session&.consent && + checkout_session.consent&.promotions == 'opt_in' + email_customer_about_abandoned_cart(checkout_session) + end else puts "unhandled event type: #{event.type}" end @@ -129,3 +149,16 @@ def email_customer_about_failed_payment(checkout_session) # TODO: fill in with your own logic puts "Emailing customer about payment failure for: #{checkout_session.inspect}" end + +def email_customer_about_abandoned_cart(checkout_session) + # TODO: fill in with your own logic + return if checkout_session.customer_details.email.nil? + + puts "Recovery email to send to customer: + #{checkout_session.after_expiration.recovery.url}" +end + +def log_recovered_cart(checkout_session) + # TODO fill in with your own logic + puts "#{checkout_session.id} recovered from #{checkout_session.recovered_from}" +end