1use std::collections::HashMap;
6use std::ops::Range;
7
8use reqwest::Method;
9use serde::Serialize;
10use serde_with::skip_serializing_none;
11
12use crate::entities::{Duration, Money, Price, PriceQuantity, UnitPriceOverride};
13use crate::enums::{CatalogType, CountryCodeSupported, CurrencyCode, Interval, Status, TaxMode};
14use crate::ids::{PriceID, ProductID};
15use crate::paginated::Paginated;
16use crate::nullable::Nullable;
17use crate::{Paddle, Result};
18
19#[skip_serializing_none]
21#[derive(Serialize)]
22pub struct PricesList<'a> {
23 #[serde(skip)]
24 client: &'a Paddle,
25 after: Option<PriceID>,
26 #[serde(serialize_with = "crate::comma_separated")]
27 id: Option<Vec<PriceID>>,
28 #[serde(serialize_with = "crate::comma_separated")]
29 include: Option<Vec<String>>,
30 order_by: Option<String>,
31 per_page: Option<usize>,
32 #[serde(serialize_with = "crate::comma_separated")]
33 product_id: Option<Vec<ProductID>>,
34 status: Option<Status>,
35 recurring: Option<bool>,
36 r#type: Option<CatalogType>,
37}
38
39impl<'a> PricesList<'a> {
40 pub fn new(client: &'a Paddle) -> Self {
41 Self {
42 client,
43 after: None,
44 id: None,
45 include: None,
46 order_by: None,
47 per_page: None,
48 product_id: None,
49 status: None,
50 recurring: None,
51 r#type: None,
52 }
53 }
54
55 pub fn after(&mut self, price_id: impl Into<PriceID>) -> &mut Self {
57 self.after = Some(price_id.into());
58 self
59 }
60
61 pub fn ids(&mut self, price_ids: impl IntoIterator<Item = impl Into<PriceID>>) -> &mut Self {
63 self.id = Some(price_ids.into_iter().map(Into::into).collect());
64 self
65 }
66
67 pub fn include(&mut self, includes: impl IntoIterator<Item = impl Into<String>>) -> &mut Self {
69 self.include = Some(includes.into_iter().map(Into::into).collect());
70 self
71 }
72
73 pub fn order_by_asc(&mut self, field: &str) -> &mut Self {
75 self.order_by = Some(format!("{}[ASC]", field));
76 self
77 }
78
79 pub fn order_by_desc(&mut self, field: &str) -> &mut Self {
81 self.order_by = Some(format!("{}[DESC]", field));
82 self
83 }
84
85 pub fn per_page(&mut self, entities_per_page: usize) -> &mut Self {
90 self.per_page = Some(entities_per_page);
91 self
92 }
93
94 pub fn product_ids(
96 &mut self,
97 product_ids: impl IntoIterator<Item = impl Into<ProductID>>,
98 ) -> &mut Self {
99 self.product_id = Some(product_ids.into_iter().map(Into::into).collect());
100 self
101 }
102
103 pub fn status(&mut self, status: Status) -> &mut Self {
105 self.status = Some(status);
106 self
107 }
108
109 pub fn recurring(&mut self, value: bool) -> &mut Self {
111 self.recurring = Some(value);
112 self
113 }
114
115 pub fn r#type(&mut self, catalog_type: CatalogType) -> &mut Self {
117 self.r#type = Some(catalog_type);
118 self
119 }
120
121 pub fn send(&self) -> Paginated<'_, Vec<Price>> {
123 Paginated::new(self.client, "/prices", self)
124 }
125}
126
127#[skip_serializing_none]
129#[derive(Serialize)]
130pub struct PricesCreate<'a> {
131 #[serde(skip)]
132 client: &'a Paddle,
133 description: String,
134 product_id: ProductID,
135 unit_price: Money,
136 r#type: Option<CatalogType>,
137 name: Option<String>,
138 billing_cycle: Option<Duration>,
139 trial_period: Option<Duration>,
140 tax_mode: TaxMode,
141 unit_price_overrides: Option<Vec<UnitPriceOverride>>,
142 quantity: Option<PriceQuantity>,
143 custom_data: Option<HashMap<String, String>>,
144}
145
146impl<'a> PricesCreate<'a> {
147 pub fn new(
148 client: &'a Paddle,
149 product_id: impl Into<ProductID>,
150 description: impl Into<String>,
151 amount: u64,
152 currency: CurrencyCode,
153 ) -> Self {
154 Self {
155 client,
156 description: description.into(),
157 product_id: product_id.into(),
158 unit_price: Money {
159 amount: amount.to_string(),
160 currency_code: currency,
161 },
162 r#type: None,
163 name: None,
164 billing_cycle: None,
165 trial_period: None,
166 tax_mode: TaxMode::AccountSetting,
167 unit_price_overrides: None,
168 quantity: None,
169 custom_data: None,
170 }
171 }
172
173 pub fn catalog_type(&mut self, catalog_type: CatalogType) -> &mut Self {
175 self.r#type = Some(catalog_type);
176 self
177 }
178
179 pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
181 self.name = Some(name.into());
182 self
183 }
184
185 pub fn billing_cycle(&mut self, frequency: u64, interval: Interval) -> &mut Self {
187 self.billing_cycle = Some(Duration {
188 interval,
189 frequency,
190 });
191
192 self
193 }
194
195 pub fn trial_period(&mut self, frequency: u64, interval: Interval) -> &mut Self {
197 self.trial_period = Some(Duration {
198 interval,
199 frequency,
200 });
201
202 self
203 }
204
205 pub fn tax_mode(&mut self, tax_mode: TaxMode) -> &mut Self {
208 self.tax_mode = tax_mode;
209 self
210 }
211
212 pub fn add_unit_price_override(
218 &mut self,
219 country_codes: impl IntoIterator<Item = CountryCodeSupported>,
220 amount: u64,
221 currency: CurrencyCode,
222 ) -> &mut Self {
223 if self.unit_price_overrides.is_none() {
224 self.unit_price_overrides = Some(vec![]);
225 }
226
227 self.unit_price_overrides
228 .as_mut()
229 .unwrap()
230 .push(UnitPriceOverride {
231 country_codes: country_codes.into_iter().collect(),
232 unit_price: Money {
233 amount: amount.to_string(),
234 currency_code: currency,
235 },
236 });
237
238 self
239 }
240
241 pub fn set_unit_price_overrides(&mut self, overrides: Vec<UnitPriceOverride>) -> &mut Self {
249 self.unit_price_overrides = Some(overrides);
250 self
251 }
252
253 pub fn quantity(&mut self, range: Range<u64>) -> &mut Self {
255 self.quantity = Some(PriceQuantity {
256 minimum: range.start,
257 maximum: range.end,
258 });
259 self
260 }
261
262 pub fn custom_data(&mut self, custom_data: HashMap<String, String>) -> &mut Self {
264 self.custom_data = Some(custom_data);
265 self
266 }
267
268 pub async fn send(&self) -> Result<Price> {
270 self.client.send(self, Method::POST, "/prices").await
271 }
272}
273
274#[skip_serializing_none]
276#[derive(Serialize)]
277pub struct PriceGet<'a> {
278 #[serde(skip)]
279 client: &'a Paddle,
280 #[serde(skip)]
281 price_id: PriceID,
282 #[serde(serialize_with = "crate::comma_separated")]
283 include: Option<Vec<String>>,
284}
285
286impl<'a> PriceGet<'a> {
287 pub fn new(client: &'a Paddle, price_id: impl Into<PriceID>) -> Self {
288 Self {
289 client,
290 price_id: price_id.into(),
291 include: None,
292 }
293 }
294
295 pub fn include(&mut self, entities: impl IntoIterator<Item = impl AsRef<str>>) -> &mut Self {
297 self.include = Some(
298 entities
299 .into_iter()
300 .map(|s| s.as_ref().to_string())
301 .collect(),
302 );
303 self
304 }
305
306 pub async fn send(&self) -> Result<Price> {
308 self.client
309 .send(
310 self,
311 Method::GET,
312 &format!("/prices/{}", self.price_id.as_ref()),
313 )
314 .await
315 }
316}
317
318#[derive(Serialize)]
320pub struct PriceUpdate<'a> {
321 #[serde(skip)]
322 client: &'a Paddle,
323 #[serde(skip)]
324 price_id: PriceID,
325 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
326 description: Nullable<String>,
327 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
328 r#type: Nullable<CatalogType>,
329 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
330 name: Nullable<String>,
331 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
332 billing_cycle: Nullable<Duration>,
333 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
334 trial_period: Nullable<Duration>,
335 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
336 tax_mode: Nullable<TaxMode>,
337 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
338 unit_price: Nullable<Money>,
339 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
340 unit_price_overrides: Nullable<Vec<UnitPriceOverride>>,
341 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
342 quantity: Nullable<PriceQuantity>,
343 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
344 status: Nullable<Status>,
345 #[serde(skip_serializing_if = "Nullable::is_unchanged")]
346 custom_data: Nullable<HashMap<String, String>>,
347}
348
349impl<'a> PriceUpdate<'a> {
350 pub fn new(client: &'a Paddle, price_id: impl Into<PriceID>) -> Self {
351 Self {
352 client,
353 price_id: price_id.into(),
354 description: Nullable::Unchanged,
355 r#type: Nullable::Unchanged,
356 name: Nullable::Unchanged,
357 billing_cycle: Nullable::Unchanged,
358 trial_period: Nullable::Unchanged,
359 tax_mode: Nullable::Unchanged,
360 unit_price: Nullable::Unchanged,
361 unit_price_overrides: Nullable::Unchanged,
362 quantity: Nullable::Unchanged,
363 status: Nullable::Unchanged,
364 custom_data: Nullable::Unchanged,
365 }
366 }
367
368 pub fn description(&mut self, description: impl Into<Nullable<String>>) -> &mut Self {
370 self.description = description.into();
371 self
372 }
373
374 pub fn catalog_type(&mut self, catalog_type: impl Into<Nullable<CatalogType>>) -> &mut Self {
376 self.r#type = catalog_type.into();
377 self
378 }
379
380 pub fn name(&mut self, name: impl Into<Nullable<String>>) -> &mut Self {
382 self.name = name.into();
383 self
384 }
385
386 pub fn billing_cycle(
388 &mut self,
389 billing_cycle: impl Into<Nullable<Duration>>,
390 ) -> &mut Self {
391 self.billing_cycle = billing_cycle.into();
392 self
393 }
394
395 pub fn trial_period(
397 &mut self,
398 trial_period: impl Into<Nullable<Duration>>,
399 ) -> &mut Self {
400 self.trial_period = trial_period.into();
401 self
402 }
403
404 pub fn tax_mode(&mut self, tax_mode: impl Into<Nullable<TaxMode>>) -> &mut Self {
406 self.tax_mode = tax_mode.into();
407 self
408 }
409
410 pub fn unit_price(&mut self, unit_price: impl Into<Nullable<Money>>) -> &mut Self {
412 self.unit_price = unit_price.into();
413 self
414 }
415
416 pub fn add_unit_price_override(
418 &mut self,
419 country_codes: impl IntoIterator<Item = CountryCodeSupported>,
420 amount: u64,
421 currency: CurrencyCode,
422 ) -> &mut Self {
423 if !matches!(self.unit_price_overrides, Nullable::Value(_)) {
424 self.unit_price_overrides = Nullable::Value(vec![]);
425 }
426
427 if let Nullable::Value(ref mut v) = self.unit_price_overrides {
428 v.push(UnitPriceOverride {
429 country_codes: country_codes.into_iter().collect(),
430 unit_price: Money {
431 amount: amount.to_string(),
432 currency_code: currency,
433 },
434 });
435 }
436
437 self
438 }
439
440 pub fn set_unit_price_overrides(
442 &mut self,
443 overrides: impl Into<Nullable<Vec<UnitPriceOverride>>>,
444 ) -> &mut Self {
445 self.unit_price_overrides = overrides.into();
446 self
447 }
448
449 pub fn quantity(&mut self, quantity: impl Into<Nullable<PriceQuantity>>) -> &mut Self {
451 self.quantity = quantity.into();
452 self
453 }
454
455 pub fn status(&mut self, status: impl Into<Nullable<Status>>) -> &mut Self {
457 self.status = status.into();
458 self
459 }
460
461 pub fn custom_data(
463 &mut self,
464 custom_data: impl Into<Nullable<HashMap<String, String>>>,
465 ) -> &mut Self {
466 self.custom_data = custom_data.into();
467 self
468 }
469
470 pub async fn send(&self) -> Result<Price> {
472 self.client
473 .send(
474 self,
475 Method::PATCH,
476 &format!("/prices/{}", self.price_id.as_ref()),
477 )
478 .await
479 }
480}