use super::{StripePaymentProcessor, sync_plan_costs};
use crate::payments::adapters::stripe::find_customer_for_account::find_customer_for_account;
use crate::{payments::Error, pbbson::Model};
use pbbson::bson::{DateTime, doc};
use std::collections::HashMap;
use std::str::FromStr;
use stripe_checkout::CheckoutSessionMode;
use stripe_checkout::checkout_session::{
CreateCheckoutSession, CreateCheckoutSessionLineItems, CreateCheckoutSessionSubscriptionData,
};
#[allow(clippy::too_many_arguments)]
pub(super) async fn create<B: Clone + FromStr + Send + Sync + ToString>(
this: &StripePaymentProcessor<B>,
account: Model,
plan: Model,
plan_metadata_field: &str,
client_reference_id: Option<String>,
subscription_description: Option<String>,
success_url: Option<String>,
cancel_url: Option<String>,
) -> Result<Model, Error> {
let prices = sync_plan_costs::sync(this, &plan, plan_metadata_field).await?;
let line_items: Vec<_> = prices
.iter()
.map(|price| CreateCheckoutSessionLineItems {
price: Some(price.id.to_string()),
quantity: Some(1),
..Default::default()
})
.collect();
let customer = find_customer_for_account(this, &account).await?;
log::debug!("Using customer {}", customer.id);
let mut metadata = HashMap::new();
if let Ok(account_id) = account.id() {
metadata.insert("accountId".to_string(), account_id);
}
if let Ok(plan_id) = plan.id() {
metadata.insert("planId".to_string(), plan_id);
}
let mut req = CreateCheckoutSession::new()
.customer(customer.id.as_str())
.metadata(metadata)
.mode(CheckoutSessionMode::Subscription)
.line_items(line_items);
if let Some(subscription_description) = subscription_description {
let mut data = CreateCheckoutSessionSubscriptionData::new();
data.description = Some(subscription_description);
req = req.subscription_data(data);
}
if let Some(success_url) = success_url {
req = req.success_url(success_url);
}
if let Some(cancel_url) = cancel_url {
req = req.cancel_url(cancel_url);
}
if let Some(client_reference_id) = client_reference_id {
req = req.client_reference_id(client_reference_id);
}
let checkout_session = match req.send(&this.client).await {
Ok(checkout_session) => checkout_session,
Err(e) => {
log::error!(err:? = e; "Failed creating checkout session");
return Err(e.into());
}
};
log::debug!("Created checkout session {}", checkout_session.id);
let mut checkout_session_model = Model::from(doc! {
"id": checkout_session.id.as_str(),
"mode": checkout_session.mode.as_str(),
"createdAt": DateTime::from_millis(checkout_session.created * 1000),
"expiresAt": DateTime::from_millis(checkout_session.expires_at * 1000),
});
if let Some(amount_total) = checkout_session.amount_total {
checkout_session_model.insert("amountTotal", amount_total);
}
if let Some(cancel_url) = checkout_session.cancel_url {
checkout_session_model.insert("cancelUrl", cancel_url);
}
if let Some(client_reference_id) = checkout_session.client_reference_id {
checkout_session_model.insert("clientReferenceId", client_reference_id);
}
if let Some(customer) = checkout_session.customer {
checkout_session_model.insert("customer", customer.id().as_str());
}
if let Some(success_url) = checkout_session.success_url {
checkout_session_model.insert("successUrl", success_url);
}
if let Some(url) = checkout_session.url {
checkout_session_model.insert("url", url);
}
Ok(checkout_session_model)
}