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