diff --git a/crates/service/plugins/billing_artcraft/src/endpoints/checkout/stripe_artcraft_create_credits_pack_checkout_handler.rs b/crates/service/plugins/billing_artcraft/src/endpoints/checkout/stripe_artcraft_create_credits_pack_checkout_handler.rs index 2ad1023fb5..c63b19eb2a 100644 --- a/crates/service/plugins/billing_artcraft/src/endpoints/checkout/stripe_artcraft_create_credits_pack_checkout_handler.rs +++ b/crates/service/plugins/billing_artcraft/src/endpoints/checkout/stripe_artcraft_create_credits_pack_checkout_handler.rs @@ -18,7 +18,7 @@ use sqlx::MySqlPool; use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; -use stripe_checkout::checkout_session::{CreateCheckoutSession, CreateCheckoutSessionAutomaticTax, CreateCheckoutSessionLineItems, CreateCheckoutSessionLineItemsAdjustableQuantity, CreateCheckoutSessionPaymentIntentData, CreateCheckoutSessionSubscriptionData}; +use stripe_checkout::checkout_session::{CreateCheckoutSession, CreateCheckoutSessionAutomaticTax, CreateCheckoutSessionLineItems, CreateCheckoutSessionLineItemsAdjustableQuantity, CreateCheckoutSessionPaymentIntentData, CreateCheckoutSessionSavedPaymentMethodOptions, CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters, CreateCheckoutSessionSavedPaymentMethodOptionsPaymentMethodSave, CreateCheckoutSessionSubscriptionData}; use stripe_checkout::CheckoutSessionMode; use stripe_core::CustomerId; use user_traits_component::traits::internal_session_cache_purge::InternalSessionCachePurge; @@ -86,7 +86,7 @@ pub async fn stripe_artcraft_create_credits_pack_checkout_handler( error!("Error looking up user's ({}) existing subscription: {:?}", &user_metadata.user_token_typed, err); CommonWebError::ServerError // NB: This was probably *our* fault. })?; - + let maybe_existing_stripe_customer_id = maybe_subscription.as_ref() .map(|sub| sub.stripe_customer_id.as_str()); @@ -150,9 +150,9 @@ pub async fn stripe_artcraft_create_credits_pack_checkout_handler( ..Default::default() } ]) - .allow_promotion_codes(true) + .allow_promotion_codes(true)// Allow promo codes / coupons .automatic_tax(CreateCheckoutSessionAutomaticTax { - enabled: true, + enabled: true, // This will ask for the customer's location liability: None, }) .metadata(metadata.clone()) @@ -166,6 +166,24 @@ pub async fn stripe_artcraft_create_credits_pack_checkout_handler( match CustomerId::from_str(existing_stripe_customer_id) { Ok(customer_id) => { checkout_builder = checkout_builder.customer(customer_id); + + // Stripe won't let us use `saved_payment_method_options` without an existing customer, + // at least for one-off payments. Subscriptions allow this to be set. + // If we try to set this without a customer, the checkout session will blow up. + checkout_builder = checkout_builder + .saved_payment_method_options(CreateCheckoutSessionSavedPaymentMethodOptions { + // The user can choose to tick a checkbox that saves their card for redisplay later. + payment_method_save: Some(CreateCheckoutSessionSavedPaymentMethodOptionsPaymentMethodSave::Enabled), + // Without any items, we do not get card redisplay. + // All three values seems to enable redisplay. + // I haven't tested individual enum values. + // The user can choose to tick a checkbox that saves their card for redisplay later. + allow_redisplay_filters: Some(vec![ + CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters::Always, + CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters::Limited, + CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters::Unspecified, + ]) + }); } Err(err) => { // NB: Don't block checkout. diff --git a/crates/service/plugins/billing_artcraft/src/endpoints/checkout/stripe_artcraft_create_subscription_checkout_handler.rs b/crates/service/plugins/billing_artcraft/src/endpoints/checkout/stripe_artcraft_create_subscription_checkout_handler.rs index 4a0c5ebbe2..1ab83c5e05 100644 --- a/crates/service/plugins/billing_artcraft/src/endpoints/checkout/stripe_artcraft_create_subscription_checkout_handler.rs +++ b/crates/service/plugins/billing_artcraft/src/endpoints/checkout/stripe_artcraft_create_subscription_checkout_handler.rs @@ -16,7 +16,7 @@ use sqlx::MySqlPool; use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; -use stripe_checkout::checkout_session::{CreateCheckoutSession, CreateCheckoutSessionAutomaticTax, CreateCheckoutSessionLineItems, CreateCheckoutSessionSubscriptionData}; +use stripe_checkout::checkout_session::{CreateCheckoutSession, CreateCheckoutSessionAutomaticTax, CreateCheckoutSessionLineItems, CreateCheckoutSessionSavedPaymentMethodOptions, CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters, CreateCheckoutSessionSavedPaymentMethodOptionsPaymentMethodSave, CreateCheckoutSessionSubscriptionData}; use stripe_checkout::CheckoutSessionMode; use stripe_core::CustomerId; use user_traits_component::traits::internal_session_cache_purge::InternalSessionCachePurge; @@ -170,16 +170,26 @@ pub async fn stripe_artcraft_create_subscription_session_handler( ..Default::default() } ]) - .allow_promotion_codes(true) + .saved_payment_method_options(CreateCheckoutSessionSavedPaymentMethodOptions { + allow_redisplay_filters: Some(vec![ + CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters::Always, + CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters::Limited, + CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters::Unspecified, + ]), + // The user can choose to tick a checkbox that saves their card for redisplay later. + payment_method_save: Some(CreateCheckoutSessionSavedPaymentMethodOptionsPaymentMethodSave::Enabled), + }) + .allow_promotion_codes(true) // Allow promo codes / coupons .automatic_tax(CreateCheckoutSessionAutomaticTax { - enabled: true, + enabled: true, // This will ask for the customer's location liability: None, }) .metadata(metadata.clone()) .subscription_data(CreateCheckoutSessionSubscriptionData { metadata: Some(metadata), ..Default::default() - }); + }) + ; // NB: This works, but it feels really weird to have the customer's old email shown in a // completely immutable state in the stripe checkout form.