1use std::collections::HashMap;
6
7use chrono::{DateTime, Utc};
8use reqwest::Method;
9use serde::Serialize;
10use serde_with::skip_serializing_none;
11
12use crate::entities::{
13 AddressPreview, BillingDetails, TimePeriod, Transaction, TransactionCheckout,
14 TransactionItemNonCatalogPrice,
15};
16use crate::enums::{CollectionMode, CurrencyCode, TransactionOrigin, TransactionStatus};
17use crate::ids::{
18 AddressID, BusinessID, CustomerID, DiscountID, PriceID, SubscriptionID, TransactionID,
19};
20use crate::paginated::Paginated;
21use crate::{Paddle, Result};
22
23#[allow(non_snake_case)]
24#[skip_serializing_none]
25#[derive(Serialize, Default)]
26struct DateAtFilter {
27 LT: Option<DateTime<Utc>>,
28 LTE: Option<DateTime<Utc>>,
29 GT: Option<DateTime<Utc>>,
30 GTE: Option<DateTime<Utc>>,
31}
32
33#[derive(Serialize)]
34#[serde(untagged)]
35enum DateAt {
36 Exact(DateTime<Utc>),
37 Filter(DateAtFilter),
38}
39
40#[skip_serializing_none]
42#[derive(Serialize)]
43pub struct TransactionsList<'a> {
44 #[serde(skip)]
45 client: &'a Paddle,
46 after: Option<TransactionID>,
47 billed_at: Option<DateAt>,
48 collection_mode: Option<CollectionMode>,
49 created_at: Option<DateAt>,
50 #[serde(serialize_with = "crate::comma_separated")]
51 customer_id: Option<Vec<CustomerID>>,
52 #[serde(serialize_with = "crate::comma_separated")]
53 id: Option<Vec<TransactionID>>,
54 #[serde(serialize_with = "crate::comma_separated")]
55 include: Option<Vec<String>>,
56 #[serde(serialize_with = "crate::comma_separated")]
57 invoice_number: Option<Vec<String>>,
58 #[serde(serialize_with = "crate::comma_separated_enum")]
59 origin: Option<Vec<TransactionOrigin>>,
60 order_by: Option<String>,
61 #[serde(serialize_with = "crate::comma_separated_enum")]
62 status: Option<Vec<TransactionStatus>>,
63 #[serde(serialize_with = "crate::comma_separated")]
64 subscription_id: Option<Vec<SubscriptionID>>,
65 per_page: Option<usize>,
66 updated_at: Option<DateAt>,
67}
68
69impl<'a> TransactionsList<'a> {
70 pub fn new(client: &'a Paddle) -> Self {
71 Self {
72 client,
73 after: None,
74 billed_at: None,
75 collection_mode: None,
76 created_at: None,
77 customer_id: None,
78 id: None,
79 include: None,
80 invoice_number: None,
81 origin: None,
82 order_by: None,
83 status: None,
84 subscription_id: None,
85 per_page: None,
86 updated_at: None,
87 }
88 }
89
90 pub fn after(&mut self, transaction_id: impl Into<TransactionID>) -> &mut Self {
92 self.after = Some(transaction_id.into());
93 self
94 }
95
96 pub fn billed_at(&mut self, date: DateTime<Utc>) -> &mut Self {
98 self.billed_at = Some(DateAt::Exact(date));
99 self
100 }
101
102 pub fn billed_at_lt(&mut self, date: DateTime<Utc>) -> &mut Self {
104 self.billed_at = Some(DateAt::Filter(DateAtFilter {
105 LT: Some(date),
106 ..Default::default()
107 }));
108
109 self
110 }
111
112 pub fn billed_at_lte(&mut self, date: DateTime<Utc>) -> &mut Self {
114 self.billed_at = Some(DateAt::Filter(DateAtFilter {
115 LTE: Some(date),
116 ..Default::default()
117 }));
118
119 self
120 }
121
122 pub fn billed_at_gt(&mut self, date: DateTime<Utc>) -> &mut Self {
124 self.billed_at = Some(DateAt::Filter(DateAtFilter {
125 GT: Some(date),
126 ..Default::default()
127 }));
128
129 self
130 }
131
132 pub fn billed_at_gte(&mut self, date: DateTime<Utc>) -> &mut Self {
134 self.billed_at = Some(DateAt::Filter(DateAtFilter {
135 GTE: Some(date),
136 ..Default::default()
137 }));
138
139 self
140 }
141
142 pub fn collection_mode(&mut self, mode: CollectionMode) -> &mut Self {
144 self.collection_mode = Some(mode);
145 self
146 }
147
148 pub fn created_at(&mut self, date: DateTime<Utc>) -> &mut Self {
150 self.created_at = Some(DateAt::Exact(date));
151 self
152 }
153
154 pub fn created_at_lt(&mut self, date: DateTime<Utc>) -> &mut Self {
156 self.created_at = Some(DateAt::Filter(DateAtFilter {
157 LT: Some(date),
158 ..Default::default()
159 }));
160
161 self
162 }
163
164 pub fn created_at_lte(&mut self, date: DateTime<Utc>) -> &mut Self {
166 self.created_at = Some(DateAt::Filter(DateAtFilter {
167 LTE: Some(date),
168 ..Default::default()
169 }));
170
171 self
172 }
173
174 pub fn created_at_gt(&mut self, date: DateTime<Utc>) -> &mut Self {
176 self.created_at = Some(DateAt::Filter(DateAtFilter {
177 GT: Some(date),
178 ..Default::default()
179 }));
180
181 self
182 }
183
184 pub fn created_at_gte(&mut self, date: DateTime<Utc>) -> &mut Self {
186 self.created_at = Some(DateAt::Filter(DateAtFilter {
187 GTE: Some(date),
188 ..Default::default()
189 }));
190
191 self
192 }
193
194 pub fn customer_id(
196 &mut self,
197 customer_ids: impl IntoIterator<Item = impl Into<CustomerID>>,
198 ) -> &mut Self {
199 self.customer_id = Some(customer_ids.into_iter().map(Into::into).collect());
200 self
201 }
202
203 pub fn id(&mut self, ids: impl IntoIterator<Item = impl Into<TransactionID>>) -> &mut Self {
205 self.id = Some(ids.into_iter().map(Into::into).collect());
206 self
207 }
208
209 pub fn include(&mut self, entities: impl IntoIterator<Item = impl AsRef<str>>) -> &mut Self {
222 self.include = Some(
223 entities
224 .into_iter()
225 .map(|s| s.as_ref().to_string())
226 .collect(),
227 );
228 self
229 }
230
231 pub fn invoice_numbers(
233 &mut self,
234 numbers: impl IntoIterator<Item = impl AsRef<str>>,
235 ) -> &mut Self {
236 self.invoice_number = Some(
237 numbers
238 .into_iter()
239 .map(|s| s.as_ref().to_string())
240 .collect(),
241 );
242 self
243 }
244
245 pub fn origin(&mut self, origins: impl IntoIterator<Item = TransactionOrigin>) -> &mut Self {
247 self.origin = Some(origins.into_iter().collect());
248 self
249 }
250
251 pub fn order_by_asc(&mut self, field: &str) -> &mut Self {
253 self.order_by = Some(format!("{}[ASC]", field));
254 self
255 }
256
257 pub fn order_by_desc(&mut self, field: &str) -> &mut Self {
259 self.order_by = Some(format!("{}[DESC]", field));
260 self
261 }
262
263 pub fn status(&mut self, statuses: impl IntoIterator<Item = TransactionStatus>) -> &mut Self {
265 self.status = Some(statuses.into_iter().collect());
266 self
267 }
268
269 pub fn subscription_ids(
271 &mut self,
272 subscription_ids: impl IntoIterator<Item = impl Into<SubscriptionID>>,
273 ) -> &mut Self {
274 self.subscription_id = Some(subscription_ids.into_iter().map(Into::into).collect());
275 self
276 }
277
278 pub fn per_page(&mut self, entities_per_page: usize) -> &mut Self {
283 self.per_page = Some(entities_per_page);
284 self
285 }
286
287 pub fn updated_at(&mut self, date: DateTime<Utc>) -> &mut Self {
289 self.updated_at = Some(DateAt::Exact(date));
290 self
291 }
292
293 pub fn updated_at_lt(&mut self, date: DateTime<Utc>) -> &mut Self {
295 self.updated_at = Some(DateAt::Filter(DateAtFilter {
296 LT: Some(date),
297 ..Default::default()
298 }));
299
300 self
301 }
302
303 pub fn updated_at_lte(&mut self, date: DateTime<Utc>) -> &mut Self {
305 self.updated_at = Some(DateAt::Filter(DateAtFilter {
306 LTE: Some(date),
307 ..Default::default()
308 }));
309
310 self
311 }
312
313 pub fn updated_at_gt(&mut self, date: DateTime<Utc>) -> &mut Self {
315 self.updated_at = Some(DateAt::Filter(DateAtFilter {
316 GT: Some(date),
317 ..Default::default()
318 }));
319
320 self
321 }
322
323 pub fn updated_at_gte(&mut self, date: DateTime<Utc>) -> &mut Self {
325 self.updated_at = Some(DateAt::Filter(DateAtFilter {
326 GTE: Some(date),
327 ..Default::default()
328 }));
329
330 self
331 }
332
333 pub fn send(&self) -> Paginated<Vec<Transaction>> {
335 Paginated::new(self.client, "/transactions", self)
336 }
337}
338
339#[derive(Serialize)]
340#[serde(untagged)]
341#[allow(clippy::large_enum_variant)]
342pub enum TransactionItem {
343 CatalogItem {
344 price_id: PriceID,
345 quantity: u32,
346 },
347 NonCatalogItem {
348 price: TransactionItemNonCatalogPrice,
349 quantity: u32,
350 },
351}
352
353#[skip_serializing_none]
355#[derive(Serialize)]
356pub struct TransactionCreate<'a> {
357 #[serde(skip)]
358 client: &'a Paddle,
359 #[serde(skip)]
360 include: Option<Vec<String>>,
361 items: Vec<TransactionItem>,
362 status: Option<TransactionStatus>,
363 customer_id: Option<CustomerID>,
364 address_id: Option<AddressID>,
365 business_id: Option<BusinessID>,
366 custom_data: Option<HashMap<String, String>>,
367 currency_code: Option<CurrencyCode>,
368 collection_mode: Option<CollectionMode>,
369 discount_id: Option<DiscountID>,
370 billing_details: Option<BillingDetails>,
371 billing_period: Option<TimePeriod>,
372 checkout: Option<TransactionCheckout>,
373}
374
375impl<'a> TransactionCreate<'a> {
376 pub fn new(client: &'a Paddle) -> Self {
377 Self {
378 client,
379 include: None,
380 items: Vec::default(),
381 status: None,
382 customer_id: None,
383 address_id: None,
384 business_id: None,
385 custom_data: None,
386 currency_code: None,
387 collection_mode: None,
388 discount_id: None,
389 billing_details: None,
390 billing_period: None,
391 checkout: None,
392 }
393 }
394
395 pub fn include(&mut self, includes: impl IntoIterator<Item = impl Into<String>>) -> &mut Self {
407 self.include = Some(includes.into_iter().map(Into::into).collect());
408 self
409 }
410
411 pub fn append_catalog_item(
417 &mut self,
418 price_id: impl Into<PriceID>,
419 quantity: u32,
420 ) -> &mut Self {
421 self.items.push(TransactionItem::CatalogItem {
422 price_id: price_id.into(),
423 quantity,
424 });
425
426 self
427 }
428
429 pub fn append_non_catalog_item(
433 &mut self,
434 price: TransactionItemNonCatalogPrice,
435 quantity: u32,
436 ) -> &mut Self {
437 self.items
438 .push(TransactionItem::NonCatalogItem { price, quantity });
439 self
440 }
441
442 pub fn status(&mut self, status: TransactionStatus) -> &mut Self {
448 self.status = Some(status);
449 self
450 }
451
452 pub fn customer_id(&mut self, customer_id: impl Into<CustomerID>) -> &mut Self {
456 self.customer_id = Some(customer_id.into());
457 self
458 }
459
460 pub fn address_id(&mut self, address_id: impl Into<AddressID>) -> &mut Self {
464 self.address_id = Some(address_id.into());
465 self
466 }
467
468 pub fn business_id(&mut self, business_id: impl Into<BusinessID>) -> &mut Self {
472 self.business_id = Some(business_id.into());
473 self
474 }
475
476 pub fn custom_data(&mut self, custom_data: HashMap<String, String>) -> &mut Self {
478 self.custom_data = Some(custom_data);
479 self
480 }
481
482 pub fn currency_code(&mut self, currency_code: CurrencyCode) -> &mut Self {
484 self.currency_code = Some(currency_code);
485 self
486 }
487
488 pub fn collection_mode(&mut self, mode: CollectionMode) -> &mut Self {
490 self.collection_mode = Some(mode);
491 self
492 }
493
494 pub fn discount_id(&mut self, discount_id: impl Into<DiscountID>) -> &mut Self {
496 self.discount_id = Some(discount_id.into());
497 self
498 }
499
500 pub fn billing_details(&mut self, billing_details: BillingDetails) -> &mut Self {
502 self.billing_details = Some(billing_details);
503 self
504 }
505
506 pub fn billing_period(&mut self, billing_period: TimePeriod) -> &mut Self {
508 self.billing_period = Some(billing_period);
509 self
510 }
511
512 pub fn checkout_url(&mut self, url: String) -> &mut Self {
519 self.checkout = Some(TransactionCheckout { url: Some(url) });
520 self
521 }
522
523 pub async fn send(&self) -> Result<Transaction> {
525 let url = if let Some(include) = self.include.as_ref() {
526 &format!("/transactions?include={}", include.join(","))
527 } else {
528 "/transactions"
529 };
530
531 self.client.send(self, Method::POST, url).await
532 }
533}
534
535#[skip_serializing_none]
537#[derive(Serialize)]
538pub struct TransactionGet<'a> {
539 #[serde(skip)]
540 client: &'a Paddle,
541 #[serde(skip)]
542 transaction_id: TransactionID,
543 #[serde(serialize_with = "crate::comma_separated")]
544 include: Option<Vec<String>>,
545}
546
547impl<'a> TransactionGet<'a> {
548 pub fn new(client: &'a Paddle, transaction_id: impl Into<TransactionID>) -> Self {
549 Self {
550 client,
551 transaction_id: transaction_id.into(),
552 include: None,
553 }
554 }
555
556 pub fn include(&mut self, entities: impl IntoIterator<Item = impl AsRef<str>>) -> &mut Self {
568 self.include = Some(
569 entities
570 .into_iter()
571 .map(|s| s.as_ref().to_string())
572 .collect(),
573 );
574 self
575 }
576
577 pub async fn send(&self) -> Result<Transaction> {
579 self.client
580 .send(
581 self,
582 Method::GET,
583 &format!("/transactions/{}", self.transaction_id.as_ref()),
584 )
585 .await
586 }
587}
588
589#[skip_serializing_none]
591#[derive(Serialize)]
592pub struct TransactionUpdate<'a> {
593 #[serde(skip)]
594 client: &'a Paddle,
595 #[serde(skip)]
596 transaction_id: TransactionID,
597 #[serde(skip)]
598 include: Option<Vec<String>>,
599 status: Option<TransactionStatus>,
600 customer_id: Option<CustomerID>,
601 address_id: Option<AddressID>,
602 business_id: Option<BusinessID>,
603 custom_data: Option<HashMap<String, String>>,
604 currency_code: Option<CurrencyCode>,
605 collection_mode: Option<CollectionMode>,
606 discount_id: Option<DiscountID>,
607 billing_details: Option<BillingDetails>,
608 billing_period: Option<TimePeriod>,
609 items: Option<Vec<TransactionItem>>,
610 checkout: Option<TransactionCheckout>,
611}
612
613impl<'a> TransactionUpdate<'a> {
614 pub fn new(client: &'a Paddle, transaction_id: impl Into<TransactionID>) -> Self {
615 Self {
616 client,
617 transaction_id: transaction_id.into(),
618 include: None,
619 status: None,
620 customer_id: None,
621 address_id: None,
622 business_id: None,
623 custom_data: None,
624 currency_code: None,
625 collection_mode: None,
626 discount_id: None,
627 billing_details: None,
628 billing_period: None,
629 items: None,
630 checkout: None,
631 }
632 }
633
634 pub fn include(&mut self, entities: impl IntoIterator<Item = impl AsRef<str>>) -> &mut Self {
646 self.include = Some(
647 entities
648 .into_iter()
649 .map(|s| s.as_ref().to_string())
650 .collect(),
651 );
652 self
653 }
654
655 pub fn status(&mut self, status: TransactionStatus) -> &mut Self {
659 self.status = Some(status);
660 self
661 }
662
663 pub fn customer_id(&mut self, customer_id: impl Into<CustomerID>) -> &mut Self {
665 self.customer_id = Some(customer_id.into());
666 self
667 }
668
669 pub fn address_id(&mut self, address_id: impl Into<AddressID>) -> &mut Self {
671 self.address_id = Some(address_id.into());
672 self
673 }
674
675 pub fn business_id(&mut self, business_id: impl Into<BusinessID>) -> &mut Self {
677 self.business_id = Some(business_id.into());
678 self
679 }
680
681 pub fn custom_data(&mut self, custom_data: HashMap<String, String>) -> &mut Self {
683 self.custom_data = Some(custom_data);
684 self
685 }
686
687 pub fn currency_code(&mut self, currency_code: CurrencyCode) -> &mut Self {
689 self.currency_code = Some(currency_code);
690 self
691 }
692
693 pub fn collection_mode(&mut self, mode: CollectionMode) -> &mut Self {
695 self.collection_mode = Some(mode);
696 self
697 }
698
699 pub fn discount_id(&mut self, discount_id: impl Into<DiscountID>) -> &mut Self {
701 self.discount_id = Some(discount_id.into());
702 self
703 }
704
705 pub fn billing_details(&mut self, billing_details: BillingDetails) -> &mut Self {
707 self.billing_details = Some(billing_details);
708 self
709 }
710
711 pub fn billing_period(&mut self, billing_period: TimePeriod) -> &mut Self {
713 self.billing_period = Some(billing_period);
714 self
715 }
716
717 pub fn items(&mut self, items: impl IntoIterator<Item = TransactionItem>) -> &mut Self {
718 self.items = Some(items.into_iter().collect());
719 self
720 }
721
722 pub fn checkout_url(&mut self, url: String) -> &mut Self {
729 self.checkout = Some(TransactionCheckout { url: Some(url) });
730 self
731 }
732
733 pub async fn send(&self) -> Result<Transaction> {
735 let mut url = format!("/transactions/{}", self.transaction_id.as_ref());
736
737 if let Some(include) = self.include.as_ref() {
738 url.push_str(&format!("?include={}", include.join(",")));
739 }
740
741 self.client.send(self, Method::PATCH, &url).await
742 }
743}
744
745#[skip_serializing_none]
747#[derive(Serialize)]
748pub struct TransactionPreview<'a> {
749 #[serde(skip)]
750 client: &'a Paddle,
751 items: Vec<TransactionItem>,
752 address: Option<AddressPreview>,
753 customer_ip_address: Option<String>,
754 address_id: Option<AddressID>,
755 business_id: Option<BusinessID>,
756 customer_id: Option<CustomerID>,
757 currency_code: Option<CurrencyCode>,
758 discount_id: Option<DiscountID>,
759 ignore_trials: bool,
760}
761
762impl<'a> TransactionPreview<'a> {
763 pub fn new(client: &'a Paddle) -> Self {
764 Self {
765 client,
766 items: Vec::default(),
767 address: None,
768 customer_ip_address: None,
769 address_id: None,
770 business_id: None,
771 customer_id: None,
772 currency_code: None,
773 discount_id: None,
774 ignore_trials: false,
775 }
776 }
777
778 pub fn append_catalog_item(
784 &mut self,
785 price_id: impl Into<PriceID>,
786 quantity: u32,
787 ) -> &mut Self {
788 self.items.push(TransactionItem::CatalogItem {
789 price_id: price_id.into(),
790 quantity,
791 });
792
793 self
794 }
795
796 pub fn append_non_catalog_item(
800 &mut self,
801 price: TransactionItemNonCatalogPrice,
802 quantity: u32,
803 ) -> &mut Self {
804 self.items
805 .push(TransactionItem::NonCatalogItem { price, quantity });
806 self
807 }
808
809 pub fn address(&mut self, address: AddressPreview) -> &mut Self {
811 self.address = Some(address);
812 self
813 }
814
815 pub fn customer_ip_address(&mut self, ip: String) -> &mut Self {
817 self.customer_ip_address = Some(ip);
818 self
819 }
820
821 pub fn address_id(&mut self, address_id: impl Into<AddressID>) -> &mut Self {
823 self.address_id = Some(address_id.into());
824 self
825 }
826
827 pub fn business_id(&mut self, business_id: impl Into<BusinessID>) -> &mut Self {
829 self.business_id = Some(business_id.into());
830 self
831 }
832
833 pub fn customer_id(&mut self, customer_id: impl Into<CustomerID>) -> &mut Self {
835 self.customer_id = Some(customer_id.into());
836 self
837 }
838
839 pub fn currency_code(&mut self, currency_code: CurrencyCode) -> &mut Self {
841 self.currency_code = Some(currency_code);
842 self
843 }
844
845 pub fn discount_id(&mut self, discount_id: impl Into<DiscountID>) -> &mut Self {
847 self.discount_id = Some(discount_id.into());
848 self
849 }
850
851 pub fn ignore_trials(&mut self, ignore_trials: bool) -> &mut Self {
855 self.ignore_trials = ignore_trials;
856 self
857 }
858
859 pub async fn send(&self) -> Result<crate::entities::TransactionPreview> {
861 self.client
862 .send(self, Method::POST, "/transactions/preview")
863 .await
864 }
865}
866
867#[derive(Serialize)]
868struct RevisedCustomer {
869 name: String,
870}
871
872#[derive(Serialize, Default)]
873#[skip_serializing_none]
874struct RevisedBusiness {
875 name: Option<String>,
876 tax_identifier: Option<String>,
877}
878
879#[derive(Serialize, Default)]
880#[skip_serializing_none]
881struct RevisedAddress {
882 first_line: Option<String>,
883 second_line: Option<String>,
884 city: Option<String>,
885 region: Option<String>,
886}
887
888#[skip_serializing_none]
889#[derive(Serialize)]
890pub struct TransactionRevise<'a> {
891 #[serde(skip)]
892 client: &'a Paddle,
893 #[serde(skip)]
894 transaction_id: TransactionID,
895 customer: Option<RevisedCustomer>,
896 business: Option<RevisedBusiness>,
897 address: Option<RevisedAddress>,
898}
899
900impl<'a> TransactionRevise<'a> {
901 pub fn new(client: &'a Paddle, transaction_id: impl Into<TransactionID>) -> Self {
902 Self {
903 client,
904 transaction_id: transaction_id.into(),
905 customer: None,
906 business: None,
907 address: None,
908 }
909 }
910
911 pub fn customer_name(&mut self, name: impl Into<String>) -> &mut Self {
913 self.customer = Some(RevisedCustomer { name: name.into() });
914 self
915 }
916
917 pub fn business_name(&mut self, name: impl Into<String>) -> &mut Self {
919 self.business.get_or_insert_default().name = Some(name.into());
920 self
921 }
922
923 pub fn business_tax_identifier(&mut self, tax_identifier: impl Into<String>) -> &mut Self {
929 self.business.get_or_insert_default().tax_identifier = Some(tax_identifier.into());
930 self
931 }
932
933 pub fn address_first_line(&mut self, first_line: impl Into<String>) -> &mut Self {
935 self.address.get_or_insert_default().first_line = Some(first_line.into());
936 self
937 }
938
939 pub fn address_second_line(&mut self, second_line: impl Into<String>) -> &mut Self {
941 self.address.get_or_insert_default().second_line = Some(second_line.into());
942 self
943 }
944
945 pub fn address_city(&mut self, city: impl Into<String>) -> &mut Self {
947 self.address.get_or_insert_default().city = Some(city.into());
948 self
949 }
950
951 pub fn address_region(&mut self, region: impl Into<String>) -> &mut Self {
953 self.address.get_or_insert_default().region = Some(region.into());
954 self
955 }
956
957 pub async fn send(&self) -> Result<Transaction> {
959 let url = format!("/transactions/{}/revise", self.transaction_id.as_ref());
960
961 self.client.send(self, Method::POST, &url).await
962 }
963}