1use std::str::FromStr as _;
2use std::sync::Arc;
3
4use anyhow::{Context as _, Result};
5use async_trait::async_trait;
6use serde::Serialize;
7use stripe::{CreateCustomer, Customer, CustomerId, ListCustomers, Price, PriceId, Recurring};
8
9use crate::stripe_client::{
10 CreateCustomerParams, StripeClient, StripeCustomer, StripeCustomerId, StripeMeter, StripePrice,
11 StripePriceId, StripePriceRecurring,
12};
13
14pub struct RealStripeClient {
15 client: Arc<stripe::Client>,
16}
17
18impl RealStripeClient {
19 pub fn new(client: Arc<stripe::Client>) -> Self {
20 Self { client }
21 }
22}
23
24#[async_trait]
25impl StripeClient for RealStripeClient {
26 async fn list_customers_by_email(&self, email: &str) -> Result<Vec<StripeCustomer>> {
27 let response = Customer::list(
28 &self.client,
29 &ListCustomers {
30 email: Some(email),
31 ..Default::default()
32 },
33 )
34 .await?;
35
36 Ok(response
37 .data
38 .into_iter()
39 .map(StripeCustomer::from)
40 .collect())
41 }
42
43 async fn create_customer(&self, params: CreateCustomerParams<'_>) -> Result<StripeCustomer> {
44 let customer = Customer::create(
45 &self.client,
46 CreateCustomer {
47 email: params.email,
48 ..Default::default()
49 },
50 )
51 .await?;
52
53 Ok(StripeCustomer::from(customer))
54 }
55
56 async fn list_prices(&self) -> Result<Vec<StripePrice>> {
57 let response = stripe::Price::list(
58 &self.client,
59 &stripe::ListPrices {
60 limit: Some(100),
61 ..Default::default()
62 },
63 )
64 .await?;
65
66 Ok(response.data.into_iter().map(StripePrice::from).collect())
67 }
68
69 async fn list_meters(&self) -> Result<Vec<StripeMeter>> {
70 #[derive(Serialize)]
71 struct Params {
72 #[serde(skip_serializing_if = "Option::is_none")]
73 limit: Option<u64>,
74 }
75
76 let response = self
77 .client
78 .get_query::<stripe::List<StripeMeter>, _>(
79 "/billing/meters",
80 Params { limit: Some(100) },
81 )
82 .await?;
83
84 Ok(response.data)
85 }
86}
87
88impl From<CustomerId> for StripeCustomerId {
89 fn from(value: CustomerId) -> Self {
90 Self(value.as_str().into())
91 }
92}
93
94impl TryFrom<StripeCustomerId> for CustomerId {
95 type Error = anyhow::Error;
96
97 fn try_from(value: StripeCustomerId) -> Result<Self, Self::Error> {
98 Self::from_str(value.0.as_ref()).context("failed to parse Stripe customer ID")
99 }
100}
101
102impl From<Customer> for StripeCustomer {
103 fn from(value: Customer) -> Self {
104 StripeCustomer {
105 id: value.id.into(),
106 email: value.email,
107 }
108 }
109}
110
111impl From<PriceId> for StripePriceId {
112 fn from(value: PriceId) -> Self {
113 Self(value.as_str().into())
114 }
115}
116
117impl TryFrom<StripePriceId> for PriceId {
118 type Error = anyhow::Error;
119
120 fn try_from(value: StripePriceId) -> Result<Self, Self::Error> {
121 Self::from_str(value.0.as_ref()).context("failed to parse Stripe price ID")
122 }
123}
124
125impl From<Price> for StripePrice {
126 fn from(value: Price) -> Self {
127 Self {
128 id: value.id.into(),
129 unit_amount: value.unit_amount,
130 lookup_key: value.lookup_key,
131 recurring: value.recurring.map(StripePriceRecurring::from),
132 }
133 }
134}
135
136impl From<Recurring> for StripePriceRecurring {
137 fn from(value: Recurring) -> Self {
138 Self { meter: value.meter }
139 }
140}