1use std::collections::HashMap;
6
7use reqwest::Method;
8use serde::Serialize;
9use serde_with::skip_serializing_none;
10
11use crate::entities::Product;
12use crate::enums::{CatalogType, Status, TaxCategory};
13use crate::ids::ProductID;
14use crate::paginated::Paginated;
15use crate::{Paddle, Result};
16
17#[skip_serializing_none]
19#[derive(Serialize)]
20pub struct ProductsList<'a> {
21 #[serde(skip)]
22 client: &'a Paddle,
23 after: Option<ProductID>,
24 #[serde(serialize_with = "crate::comma_separated")]
25 id: Option<Vec<ProductID>>,
26 #[serde(serialize_with = "crate::comma_separated")]
27 include: Option<Vec<String>>,
28 order_by: Option<String>,
29 per_page: Option<usize>,
30 status: Option<Status>,
31 #[serde(serialize_with = "crate::comma_separated")]
32 tax_category: Option<Vec<TaxCategory>>,
33 r#type: Option<CatalogType>,
34}
35
36impl<'a> ProductsList<'a> {
37 pub fn new(client: &'a Paddle) -> Self {
38 Self {
39 client,
40 after: None,
41 id: None,
42 include: None,
43 order_by: None,
44 per_page: None,
45 status: None,
46 tax_category: None,
47 r#type: None,
48 }
49 }
50
51 pub fn after(&mut self, product_id: impl Into<ProductID>) -> &mut Self {
53 self.after = Some(product_id.into());
54 self
55 }
56
57 pub fn ids(
59 &mut self,
60 product_ids: impl IntoIterator<Item = impl Into<ProductID>>,
61 ) -> &mut Self {
62 self.id = Some(product_ids.into_iter().map(|i| i.into()).collect());
63 self
64 }
65
66 pub fn include(&mut self, entities: impl IntoIterator<Item = impl AsRef<str>>) -> &mut Self {
68 self.include = Some(
69 entities
70 .into_iter()
71 .map(|s| s.as_ref().to_string())
72 .collect(),
73 );
74 self
75 }
76
77 pub fn order_by_asc(&mut self, field: &str) -> &mut Self {
79 self.order_by = Some(format!("{}[ASC]", field));
80 self
81 }
82
83 pub fn order_by_desc(&mut self, field: &str) -> &mut Self {
85 self.order_by = Some(format!("{}[DESC]", field));
86 self
87 }
88
89 pub fn per_page(&mut self, entities_per_page: usize) -> &mut Self {
94 self.per_page = Some(entities_per_page);
95 self
96 }
97
98 pub fn status(&mut self, status: Status) -> &mut Self {
100 self.status = Some(status);
101 self
102 }
103
104 pub fn tax_category(
106 &mut self,
107 tax_categories: impl IntoIterator<Item = TaxCategory>,
108 ) -> &mut Self {
109 self.tax_category = Some(tax_categories.into_iter().collect());
110 self
111 }
112
113 pub fn catalog_type(&mut self, catalog_type: CatalogType) -> &mut Self {
115 self.r#type = Some(catalog_type);
116 self
117 }
118
119 pub fn send(&self) -> Paginated<'_, Vec<Product>> {
121 Paginated::new(self.client, "/products", self)
122 }
123}
124
125#[skip_serializing_none]
127#[derive(Serialize)]
128pub struct ProductCreate<'a> {
129 #[serde(skip)]
130 client: &'a Paddle,
131 name: String,
132 tax_category: TaxCategory,
133 description: Option<String>,
134 r#type: Option<CatalogType>,
135 image_url: Option<String>,
136 custom_data: Option<HashMap<String, String>>,
137}
138
139impl<'a> ProductCreate<'a> {
140 pub fn new(client: &'a Paddle, name: impl Into<String>, tax_category: TaxCategory) -> Self {
141 Self {
142 client,
143 name: name.into(),
144 tax_category,
145 description: None,
146 r#type: None,
147 image_url: None,
148 custom_data: None,
149 }
150 }
151
152 pub fn description(&mut self, description: impl Into<String>) -> &mut Self {
154 self.description = Some(description.into());
155 self
156 }
157
158 pub fn catalog_type(&mut self, catalog_type: CatalogType) -> &mut Self {
160 self.r#type = Some(catalog_type);
161 self
162 }
163
164 pub fn image_url(&mut self, image_url: impl Into<String>) -> &mut Self {
166 self.image_url = Some(image_url.into());
167 self
168 }
169
170 pub fn custom_data(&mut self, custom_data: HashMap<String, String>) -> &mut Self {
172 self.custom_data = Some(custom_data);
173 self
174 }
175
176 pub async fn send(&self) -> Result<Product> {
178 self.client.send(self, Method::POST, "/products").await
179 }
180}
181
182#[skip_serializing_none]
184#[derive(Serialize)]
185pub struct ProductGet<'a> {
186 #[serde(skip)]
187 client: &'a Paddle,
188 #[serde(skip)]
189 product_id: ProductID,
190 #[serde(serialize_with = "crate::comma_separated")]
191 include: Option<Vec<String>>,
192}
193
194impl<'a> ProductGet<'a> {
195 pub fn new(client: &'a Paddle, product_id: impl Into<ProductID>) -> Self {
196 Self {
197 client,
198 product_id: product_id.into(),
199 include: None,
200 }
201 }
202
203 pub fn include(&mut self, entities: impl IntoIterator<Item = impl AsRef<str>>) -> &mut Self {
205 self.include = Some(
206 entities
207 .into_iter()
208 .map(|s| s.as_ref().to_string())
209 .collect(),
210 );
211 self
212 }
213
214 pub async fn send(&self) -> Result<Product> {
216 self.client
217 .send(
218 self,
219 Method::GET,
220 &format!("/products/{}", self.product_id.as_ref()),
221 )
222 .await
223 }
224}
225
226#[skip_serializing_none]
228#[derive(Serialize)]
229pub struct ProductUpdate<'a> {
230 #[serde(skip)]
231 client: &'a Paddle,
232 #[serde(skip)]
233 product_id: ProductID,
234 name: Option<String>,
235 description: Option<String>,
236 r#type: Option<CatalogType>,
237 tax_category: Option<TaxCategory>,
238 image_url: Option<String>,
239 custom_data: Option<HashMap<String, String>>,
240 status: Option<Status>,
241}
242
243impl<'a> ProductUpdate<'a> {
244 pub fn new(client: &'a Paddle, product_id: impl Into<ProductID>) -> Self {
245 Self {
246 client,
247 product_id: product_id.into(),
248 name: None,
249 description: None,
250 r#type: None,
251 tax_category: None,
252 image_url: None,
253 custom_data: None,
254 status: None,
255 }
256 }
257
258 pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
260 self.name = Some(name.into());
261 self
262 }
263
264 pub fn description(&mut self, description: impl Into<String>) -> &mut Self {
266 self.description = Some(description.into());
267 self
268 }
269
270 pub fn catalog_type(&mut self, catalog_type: CatalogType) -> &mut Self {
272 self.r#type = Some(catalog_type);
273 self
274 }
275
276 pub fn tax_category(&mut self, tax_category: TaxCategory) -> &mut Self {
278 self.tax_category = Some(tax_category);
279 self
280 }
281
282 pub fn image_url(&mut self, image_url: impl Into<String>) -> &mut Self {
284 self.image_url = Some(image_url.into());
285 self
286 }
287
288 pub fn custom_data(&mut self, custom_data: HashMap<String, String>) -> &mut Self {
290 self.custom_data = Some(custom_data);
291 self
292 }
293
294 pub fn status(&mut self, status: Status) -> &mut Self {
296 self.status = Some(status);
297 self
298 }
299
300 pub async fn send(&self) -> Result<Product> {
302 self.client
303 .send(
304 self,
305 Method::PATCH,
306 &format!("/products/{}", self.product_id.as_ref()),
307 )
308 .await
309 }
310}