diff --git a/crates/component_subsystem/billing/src/stripe/http_endpoints/checkout/stripe_create_checkout_session_shared.rs b/crates/component_subsystem/billing/src/stripe/http_endpoints/checkout/stripe_create_checkout_session_shared.rs index 2f46c1528c..9cc35767bd 100644 --- a/crates/component_subsystem/billing/src/stripe/http_endpoints/checkout/stripe_create_checkout_session_shared.rs +++ b/crates/component_subsystem/billing/src/stripe/http_endpoints/checkout/stripe_create_checkout_session_shared.rs @@ -50,6 +50,38 @@ pub async fn stripe_create_checkout_session_shared( success_url, ); + /* + + Stripe webhook event type: PaymentIntentCreated + UNHANDLED STRIPE WEBHOOK EVENT TYPE: PaymentIntentCreated + + [-] 127.0.0.1:54490 "POST /stripe/webhook HTTP/1.1" 200 16 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)" 0.003373 + + Stripe webhook event type: CustomerCreated + + >>> customer.created: "cus_MPQxICCzeD8wKm", None + [-] 127.0.0.1:54492 "POST /stripe/webhook HTTP/1.1" 200 16 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)" 0.002464 + Stripe webhook event type: PaymentIntentSucceeded + + [-] 127.0.0.1:54492 "POST /stripe/webhook HTTP/1.1" 200 16 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)" 0.003981 + Stripe webhook event type: ChargeSucceeded + UNHANDLED STRIPE WEBHOOK EVENT TYPE: ChargeSucceeded + + [-] 127.0.0.1:54492 "POST /stripe/webhook HTTP/1.1" 200 16 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)" 0.002594 + Stripe webhook event type: CheckoutSessionCompleted + + >>> checkout.session.completed: Some("cus_MPQxICCzeD8wKm"), None + [-] 127.0.0.1:54492 "POST /stripe/webhook HTTP/1.1" 200 16 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)" 0.002465 + [-] 127.0.0.1:54494 "GET /stripe/checkout/success HTTP/1.1" 200 16 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0" 0.000522 + + + + */ + + + + + let mut metadata = HashMap::new(); @@ -74,6 +106,9 @@ pub async fn stripe_create_checkout_session_shared( // Payment mode: Accept one-time payments for cards, iDEAL, and more. params.mode = Some(CheckoutSessionMode::Payment); + // TODO: Should this also be on subscriptions (?) + // NB: This metadata attaches to the payment_intent entity itself. + // https://support.stripe.com/questions/using-metadata-with-checkout-sessions params.payment_intent_data = Some(CreateCheckoutSessionPaymentIntentData { metadata: metadata.clone(), ..Default::default() diff --git a/crates/component_subsystem/billing/src/stripe/http_endpoints/stripe_webhook_handler.rs b/crates/component_subsystem/billing/src/stripe/http_endpoints/stripe_webhook_handler.rs index 552a804c6c..199317e77b 100644 --- a/crates/component_subsystem/billing/src/stripe/http_endpoints/stripe_webhook_handler.rs +++ b/crates/component_subsystem/billing/src/stripe/http_endpoints/stripe_webhook_handler.rs @@ -26,6 +26,7 @@ use sqlx::MySqlPool; use std::collections::HashMap; use std::fmt; use stripe::{EventObject, EventType, PaymentIntentStatus, Webhook}; +use crate::stripe::webhook_event_handlers::payment_intent::payment_intent_succeeded_handler::payment_intent_succeeded_handler; #[derive(Serialize)] pub struct StripeWebhookSuccessResponse { @@ -217,6 +218,7 @@ pub async fn stripe_webhook_handler( EventType::PaymentIntentSucceeded => { if let EventObject::PaymentIntent(payment_intent) = webhook_payload.data.object { + let _r = payment_intent_succeeded_handler(&payment_intent)?; } } diff --git a/crates/component_subsystem/billing/src/stripe/webhook_event_handlers/mod.rs b/crates/component_subsystem/billing/src/stripe/webhook_event_handlers/mod.rs index 4706b90d40..e302702f74 100644 --- a/crates/component_subsystem/billing/src/stripe/webhook_event_handlers/mod.rs +++ b/crates/component_subsystem/billing/src/stripe/webhook_event_handlers/mod.rs @@ -4,3 +4,4 @@ pub (crate) mod checkout_session; pub (crate) mod customer; pub (crate) mod customer_subscription; pub (crate) mod invoice; +pub (crate) mod payment_intent; diff --git a/crates/component_subsystem/billing/src/stripe/webhook_event_handlers/payment_intent/mod.rs b/crates/component_subsystem/billing/src/stripe/webhook_event_handlers/payment_intent/mod.rs new file mode 100644 index 0000000000..b99953f9c5 --- /dev/null +++ b/crates/component_subsystem/billing/src/stripe/webhook_event_handlers/payment_intent/mod.rs @@ -0,0 +1 @@ +pub (crate) mod payment_intent_succeeded_handler; \ No newline at end of file diff --git a/crates/component_subsystem/billing/src/stripe/webhook_event_handlers/payment_intent/payment_intent_succeeded_handler.rs b/crates/component_subsystem/billing/src/stripe/webhook_event_handlers/payment_intent/payment_intent_succeeded_handler.rs new file mode 100644 index 0000000000..10fbcd6d63 --- /dev/null +++ b/crates/component_subsystem/billing/src/stripe/webhook_event_handlers/payment_intent/payment_intent_succeeded_handler.rs @@ -0,0 +1,27 @@ +use container_common::anyhow_result::AnyhowResult; +use crate::stripe::helpers::common_metadata_keys::METADATA_USER_TOKEN; +use crate::stripe::helpers::expand_customer_id::expand_customer_id; +use crate::stripe::webhook_event_handlers::stripe_webhook_error::StripeWebhookError; +use log::warn; +use stripe::{Invoice, PaymentIntent}; + +// Handle event type: 'payment_intent.succeeded' +pub fn payment_intent_succeeded_handler(payment_intent: &PaymentIntent) -> Result<(), StripeWebhookError> { + + let payment_intent_status = payment_intent.status; + + // NB: We'll need this to send them to the "customer portal", which is how they can modify + // or cancel their subscriptions. + let maybe_stripe_customer_id = payment_intent.customer + .as_ref() + .map(|c| expand_customer_id(c)); + + // NB: Our internal user token. + let maybe_user_token = payment_intent.metadata.get(METADATA_USER_TOKEN) + .map(|t| t.to_string()); + + warn!(">>> payment_intent.succeeded: {:?}, {:?}, {:?}", + payment_intent_status, maybe_stripe_customer_id, maybe_user_token); + + Ok(()) +}