stripe_shared/
product.rs

1/// Products describe the specific goods or services you offer to your customers.
2/// For example, you might offer a Standard and Premium version of your goods or service; each version would be a separate Product.
3/// They can be used in conjunction with [Prices](https://stripe.com/docs/api#prices) to configure pricing in Payment Links, Checkout, and Subscriptions.
4///
5/// Related guides: [Set up a subscription](https://stripe.com/docs/billing/subscriptions/set-up-subscription),.
6/// [share a Payment Link](https://stripe.com/docs/payment-links),
7/// [accept payments with Checkout](https://stripe.com/docs/payments/accept-a-payment#create-product-prices-upfront),.
8/// and more about [Products and Prices](https://stripe.com/docs/products-prices/overview)
9///
10/// For more details see <<https://stripe.com/docs/api/products/object>>.
11#[derive(Clone, Debug)]
12#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
13pub struct Product {
14    /// Whether the product is currently available for purchase.
15    pub active: bool,
16    /// Time at which the object was created. Measured in seconds since the Unix epoch.
17    pub created: stripe_types::Timestamp,
18    /// The ID of the [Price](https://stripe.com/docs/api/prices) object that is the default price for this product.
19    pub default_price: Option<stripe_types::Expandable<stripe_shared::Price>>,
20    /// The product's description, meant to be displayable to the customer.
21    /// Use this field to optionally store a long form explanation of the product being sold for your own rendering purposes.
22    pub description: Option<String>,
23    /// Unique identifier for the object.
24    pub id: stripe_shared::ProductId,
25    /// A list of up to 8 URLs of images for this product, meant to be displayable to the customer.
26    pub images: Vec<String>,
27    /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode.
28    pub livemode: bool,
29    /// A list of up to 15 marketing features for this product.
30    /// These are displayed in [pricing tables](https://stripe.com/docs/payments/checkout/pricing-table).
31    pub marketing_features: Vec<stripe_shared::ProductMarketingFeature>,
32    /// Set of [key-value pairs](https://stripe.com/docs/api/metadata) that you can attach to an object.
33    /// This can be useful for storing additional information about the object in a structured format.
34    pub metadata: std::collections::HashMap<String, String>,
35    /// The product's name, meant to be displayable to the customer.
36    pub name: String,
37    /// The dimensions of this product for shipping purposes.
38    pub package_dimensions: Option<stripe_shared::PackageDimensions>,
39    /// Whether this product is shipped (i.e., physical goods).
40    pub shippable: Option<bool>,
41    /// Extra information about a product which will appear on your customer's credit card statement.
42    /// In the case that multiple products are billed at once, the first statement descriptor will be used.
43    /// Only used for subscription payments.
44    pub statement_descriptor: Option<String>,
45    /// A [tax code](https://stripe.com/docs/tax/tax-categories) ID.
46    pub tax_code: Option<stripe_types::Expandable<stripe_shared::TaxCode>>,
47    /// The type of the product.
48    /// The product is either of type `good`, which is eligible for use with Orders and SKUs, or `service`, which is eligible for use with Subscriptions and Plans.
49    #[cfg_attr(feature = "deserialize", serde(rename = "type"))]
50    pub type_: stripe_shared::ProductType,
51    /// A label that represents units of this product.
52    /// When set, this will be included in customers' receipts, invoices, Checkout, and the customer portal.
53    pub unit_label: Option<String>,
54    /// Time at which the object was last updated. Measured in seconds since the Unix epoch.
55    pub updated: stripe_types::Timestamp,
56    /// A URL of a publicly-accessible webpage for this product.
57    pub url: Option<String>,
58}
59#[doc(hidden)]
60pub struct ProductBuilder {
61    active: Option<bool>,
62    created: Option<stripe_types::Timestamp>,
63    default_price: Option<Option<stripe_types::Expandable<stripe_shared::Price>>>,
64    description: Option<Option<String>>,
65    id: Option<stripe_shared::ProductId>,
66    images: Option<Vec<String>>,
67    livemode: Option<bool>,
68    marketing_features: Option<Vec<stripe_shared::ProductMarketingFeature>>,
69    metadata: Option<std::collections::HashMap<String, String>>,
70    name: Option<String>,
71    package_dimensions: Option<Option<stripe_shared::PackageDimensions>>,
72    shippable: Option<Option<bool>>,
73    statement_descriptor: Option<Option<String>>,
74    tax_code: Option<Option<stripe_types::Expandable<stripe_shared::TaxCode>>>,
75    type_: Option<stripe_shared::ProductType>,
76    unit_label: Option<Option<String>>,
77    updated: Option<stripe_types::Timestamp>,
78    url: Option<Option<String>>,
79}
80
81#[allow(
82    unused_variables,
83    irrefutable_let_patterns,
84    clippy::let_unit_value,
85    clippy::match_single_binding,
86    clippy::single_match
87)]
88const _: () = {
89    use miniserde::de::{Map, Visitor};
90    use miniserde::json::Value;
91    use miniserde::{make_place, Deserialize, Result};
92    use stripe_types::miniserde_helpers::FromValueOpt;
93    use stripe_types::{MapBuilder, ObjectDeser};
94
95    make_place!(Place);
96
97    impl Deserialize for Product {
98        fn begin(out: &mut Option<Self>) -> &mut dyn Visitor {
99            Place::new(out)
100        }
101    }
102
103    struct Builder<'a> {
104        out: &'a mut Option<Product>,
105        builder: ProductBuilder,
106    }
107
108    impl Visitor for Place<Product> {
109        fn map(&mut self) -> Result<Box<dyn Map + '_>> {
110            Ok(Box::new(Builder { out: &mut self.out, builder: ProductBuilder::deser_default() }))
111        }
112    }
113
114    impl MapBuilder for ProductBuilder {
115        type Out = Product;
116        fn key(&mut self, k: &str) -> Result<&mut dyn Visitor> {
117            Ok(match k {
118                "active" => Deserialize::begin(&mut self.active),
119                "created" => Deserialize::begin(&mut self.created),
120                "default_price" => Deserialize::begin(&mut self.default_price),
121                "description" => Deserialize::begin(&mut self.description),
122                "id" => Deserialize::begin(&mut self.id),
123                "images" => Deserialize::begin(&mut self.images),
124                "livemode" => Deserialize::begin(&mut self.livemode),
125                "marketing_features" => Deserialize::begin(&mut self.marketing_features),
126                "metadata" => Deserialize::begin(&mut self.metadata),
127                "name" => Deserialize::begin(&mut self.name),
128                "package_dimensions" => Deserialize::begin(&mut self.package_dimensions),
129                "shippable" => Deserialize::begin(&mut self.shippable),
130                "statement_descriptor" => Deserialize::begin(&mut self.statement_descriptor),
131                "tax_code" => Deserialize::begin(&mut self.tax_code),
132                "type" => Deserialize::begin(&mut self.type_),
133                "unit_label" => Deserialize::begin(&mut self.unit_label),
134                "updated" => Deserialize::begin(&mut self.updated),
135                "url" => Deserialize::begin(&mut self.url),
136
137                _ => <dyn Visitor>::ignore(),
138            })
139        }
140
141        fn deser_default() -> Self {
142            Self {
143                active: Deserialize::default(),
144                created: Deserialize::default(),
145                default_price: Deserialize::default(),
146                description: Deserialize::default(),
147                id: Deserialize::default(),
148                images: Deserialize::default(),
149                livemode: Deserialize::default(),
150                marketing_features: Deserialize::default(),
151                metadata: Deserialize::default(),
152                name: Deserialize::default(),
153                package_dimensions: Deserialize::default(),
154                shippable: Deserialize::default(),
155                statement_descriptor: Deserialize::default(),
156                tax_code: Deserialize::default(),
157                type_: Deserialize::default(),
158                unit_label: Deserialize::default(),
159                updated: Deserialize::default(),
160                url: Deserialize::default(),
161            }
162        }
163
164        fn take_out(&mut self) -> Option<Self::Out> {
165            let (
166                Some(active),
167                Some(created),
168                Some(default_price),
169                Some(description),
170                Some(id),
171                Some(images),
172                Some(livemode),
173                Some(marketing_features),
174                Some(metadata),
175                Some(name),
176                Some(package_dimensions),
177                Some(shippable),
178                Some(statement_descriptor),
179                Some(tax_code),
180                Some(type_),
181                Some(unit_label),
182                Some(updated),
183                Some(url),
184            ) = (
185                self.active,
186                self.created,
187                self.default_price.take(),
188                self.description.take(),
189                self.id.take(),
190                self.images.take(),
191                self.livemode,
192                self.marketing_features.take(),
193                self.metadata.take(),
194                self.name.take(),
195                self.package_dimensions,
196                self.shippable,
197                self.statement_descriptor.take(),
198                self.tax_code.take(),
199                self.type_,
200                self.unit_label.take(),
201                self.updated,
202                self.url.take(),
203            )
204            else {
205                return None;
206            };
207            Some(Self::Out {
208                active,
209                created,
210                default_price,
211                description,
212                id,
213                images,
214                livemode,
215                marketing_features,
216                metadata,
217                name,
218                package_dimensions,
219                shippable,
220                statement_descriptor,
221                tax_code,
222                type_,
223                unit_label,
224                updated,
225                url,
226            })
227        }
228    }
229
230    impl<'a> Map for Builder<'a> {
231        fn key(&mut self, k: &str) -> Result<&mut dyn Visitor> {
232            self.builder.key(k)
233        }
234
235        fn finish(&mut self) -> Result<()> {
236            *self.out = self.builder.take_out();
237            Ok(())
238        }
239    }
240
241    impl ObjectDeser for Product {
242        type Builder = ProductBuilder;
243    }
244
245    impl FromValueOpt for Product {
246        fn from_value(v: Value) -> Option<Self> {
247            let Value::Object(obj) = v else {
248                return None;
249            };
250            let mut b = ProductBuilder::deser_default();
251            for (k, v) in obj {
252                match k.as_str() {
253                    "active" => b.active = FromValueOpt::from_value(v),
254                    "created" => b.created = FromValueOpt::from_value(v),
255                    "default_price" => b.default_price = FromValueOpt::from_value(v),
256                    "description" => b.description = FromValueOpt::from_value(v),
257                    "id" => b.id = FromValueOpt::from_value(v),
258                    "images" => b.images = FromValueOpt::from_value(v),
259                    "livemode" => b.livemode = FromValueOpt::from_value(v),
260                    "marketing_features" => b.marketing_features = FromValueOpt::from_value(v),
261                    "metadata" => b.metadata = FromValueOpt::from_value(v),
262                    "name" => b.name = FromValueOpt::from_value(v),
263                    "package_dimensions" => b.package_dimensions = FromValueOpt::from_value(v),
264                    "shippable" => b.shippable = FromValueOpt::from_value(v),
265                    "statement_descriptor" => b.statement_descriptor = FromValueOpt::from_value(v),
266                    "tax_code" => b.tax_code = FromValueOpt::from_value(v),
267                    "type" => b.type_ = FromValueOpt::from_value(v),
268                    "unit_label" => b.unit_label = FromValueOpt::from_value(v),
269                    "updated" => b.updated = FromValueOpt::from_value(v),
270                    "url" => b.url = FromValueOpt::from_value(v),
271
272                    _ => {}
273                }
274            }
275            b.take_out()
276        }
277    }
278};
279#[cfg(feature = "serialize")]
280impl serde::Serialize for Product {
281    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
282        use serde::ser::SerializeStruct;
283        let mut s = s.serialize_struct("Product", 19)?;
284        s.serialize_field("active", &self.active)?;
285        s.serialize_field("created", &self.created)?;
286        s.serialize_field("default_price", &self.default_price)?;
287        s.serialize_field("description", &self.description)?;
288        s.serialize_field("id", &self.id)?;
289        s.serialize_field("images", &self.images)?;
290        s.serialize_field("livemode", &self.livemode)?;
291        s.serialize_field("marketing_features", &self.marketing_features)?;
292        s.serialize_field("metadata", &self.metadata)?;
293        s.serialize_field("name", &self.name)?;
294        s.serialize_field("package_dimensions", &self.package_dimensions)?;
295        s.serialize_field("shippable", &self.shippable)?;
296        s.serialize_field("statement_descriptor", &self.statement_descriptor)?;
297        s.serialize_field("tax_code", &self.tax_code)?;
298        s.serialize_field("type", &self.type_)?;
299        s.serialize_field("unit_label", &self.unit_label)?;
300        s.serialize_field("updated", &self.updated)?;
301        s.serialize_field("url", &self.url)?;
302
303        s.serialize_field("object", "product")?;
304        s.end()
305    }
306}
307impl stripe_types::Object for Product {
308    type Id = stripe_shared::ProductId;
309    fn id(&self) -> &Self::Id {
310        &self.id
311    }
312
313    fn into_id(self) -> Self::Id {
314        self.id
315    }
316}
317stripe_types::def_id!(ProductId);
318#[derive(Copy, Clone, Eq, PartialEq)]
319pub enum ProductType {
320    Good,
321    Service,
322}
323impl ProductType {
324    pub fn as_str(self) -> &'static str {
325        use ProductType::*;
326        match self {
327            Good => "good",
328            Service => "service",
329        }
330    }
331}
332
333impl std::str::FromStr for ProductType {
334    type Err = stripe_types::StripeParseError;
335    fn from_str(s: &str) -> Result<Self, Self::Err> {
336        use ProductType::*;
337        match s {
338            "good" => Ok(Good),
339            "service" => Ok(Service),
340            _ => Err(stripe_types::StripeParseError),
341        }
342    }
343}
344impl std::fmt::Display for ProductType {
345    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
346        f.write_str(self.as_str())
347    }
348}
349
350impl std::fmt::Debug for ProductType {
351    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
352        f.write_str(self.as_str())
353    }
354}
355impl serde::Serialize for ProductType {
356    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
357    where
358        S: serde::Serializer,
359    {
360        serializer.serialize_str(self.as_str())
361    }
362}
363impl miniserde::Deserialize for ProductType {
364    fn begin(out: &mut Option<Self>) -> &mut dyn miniserde::de::Visitor {
365        crate::Place::new(out)
366    }
367}
368
369impl miniserde::de::Visitor for crate::Place<ProductType> {
370    fn string(&mut self, s: &str) -> miniserde::Result<()> {
371        use std::str::FromStr;
372        self.out = Some(ProductType::from_str(s).map_err(|_| miniserde::Error)?);
373        Ok(())
374    }
375}
376
377stripe_types::impl_from_val_with_from_str!(ProductType);
378#[cfg(feature = "deserialize")]
379impl<'de> serde::Deserialize<'de> for ProductType {
380    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
381        use std::str::FromStr;
382        let s: std::borrow::Cow<'de, str> = serde::Deserialize::deserialize(deserializer)?;
383        Self::from_str(&s).map_err(|_| serde::de::Error::custom("Unknown value for ProductType"))
384    }
385}