square_ox/api/
customers.rs

1/*!
2Customers functionality of the [Square API](https://developer.squareup.com).
3 */
4
5use crate::client::SquareClient;
6use crate::api::{Verb, SquareAPI};
7use crate::errors::{SquareError, ListParametersBuilderError, ValidationError};
8use crate::response::SquareResponse;
9use crate::objects::{Address, Customer, enums::CustomerCreationSource, SearchQueryAttribute,
10                     TimeRange, CustomerFilter, CustomerTextFilter, CreationSource};
11
12use serde::{Deserialize, Serialize};
13use uuid::Uuid;
14use crate::builder::{Builder, ParentBuilder, Validate, Buildable};
15
16impl SquareClient {
17    pub fn customers(&self) -> Customers {
18        Customers {
19            client: &self
20        }
21    }
22}
23
24pub struct Customers<'a> {
25    client: &'a SquareClient,
26}
27
28impl<'a> Customers<'a> {
29    /// Lists customer profiles associated with a Square account.
30    /// [Open in API Reference](https://developer.squareup.com/reference/square/customers/list-customers)
31    pub async fn list(self, list_parameters: Vec<(String, String)>)
32                      -> Result<SquareResponse, SquareError> {
33        self.client.request(
34            Verb::GET,
35            SquareAPI::Customers("".to_string()),
36            None::<&Customer>,
37            Some(list_parameters),
38        ).await
39    }
40
41    /// Creates a new customer for a business.
42    /// [Open in API Reference](https://developer.squareup.com/reference/square/customers/create-customer)
43    pub async fn create(self, customer: Customer)
44                        -> Result<SquareResponse, SquareError> {
45        self.client.request(
46            Verb::POST,
47            SquareAPI::Customers("".to_string()),
48            Some(&customer),
49            None,
50        ).await
51    }
52
53    /// Searches the customer profiles associated with a Square account using a supported query filter.
54    /// [Open in API Reference](https://developer.squareup.com/reference/square/customers/search-customers)
55    pub async fn search(self, customer_search_query: CustomerSearchQuery)
56                        -> Result<SquareResponse, SquareError>{
57        self.client.request(
58            Verb::POST,
59            SquareAPI::Customers("/search".to_string()),
60            Some(&customer_search_query),
61            None,
62        ).await
63    }
64
65    /// Deletes a customer profile from a business.
66    /// [Open in API Reference](https://developer.squareup.com/reference/square/customers/delete-customer)
67    pub async fn delete(self, customer_to_delete: CustomerDelete)
68                        -> Result<SquareResponse, SquareError > {
69        self.client.request(
70            Verb::DELETE,
71            SquareAPI::Customers(format!("/{}", customer_to_delete.customer_id.unwrap())),
72            None::<&CustomerSearchQuery>,
73            customer_to_delete.version,
74        ).await
75    }
76}
77
78// -------------------------------------------------------------------------------------------------
79// CustomerListParametersBuilder implementation
80// -------------------------------------------------------------------------------------------------
81#[derive(Default)]
82pub struct CustomerListParametersBuilder {
83    cursor: Option<String>,
84    limit: Option<String>,
85    sort_field: Option<String>,
86    sort_order: Option<String>,
87}
88
89impl CustomerListParametersBuilder {
90    pub fn new() -> Self {
91        Default::default()
92    }
93
94    pub fn cursor(mut self, cursor: String) -> Self {
95        self.cursor = Some(cursor.clone());
96
97        self
98    }
99
100    pub fn limit(mut self, limit: i32) -> Self {
101        if limit < 1 || limit > 100 { return self }
102        let limit = limit.to_string();
103        self.limit = Some(limit);
104
105        self
106    }
107
108    pub fn sort_field_default(mut self) -> Self {
109        self.sort_field = Some("DEFAULT".to_string());
110
111        self
112    }
113
114    pub fn sort_field_created_at(mut self) -> Self {
115        self.sort_field = Some("CREATED_AT".to_string());
116
117        self
118    }
119
120    pub fn sort_order_desc(mut self) -> Self {
121        self.sort_order = Some("DESC".to_string());
122
123        self
124    }
125
126    pub fn sort_order_asc(mut self) -> Self {
127        self.sort_order = Some("ASC".to_string());
128
129        self
130    }
131
132    pub async fn build(mut self) -> Result<Vec<(String, String)>, ListParametersBuilderError> {
133        let mut res = Vec::new();
134        if let Some(cursor) = self.cursor.take() {
135            res.push(("cursor".to_string(), cursor))
136        }
137        if let Some(limit) = self.limit.take() {
138            res.push(("limit".to_string(), limit))
139        }
140        if let Some(sort_field) = self.sort_field.take() {
141            res.push(("sort_field".to_string(), sort_field))
142        }
143        if let Some(sort_order) = self.sort_order.take() {
144            res.push(("sort_order".to_string(), sort_order))
145        }
146
147        Ok(res)
148    }
149}
150
151// -------------------------------------------------------------------------------------------------
152// Customer builder implementation
153// -------------------------------------------------------------------------------------------------
154impl Validate for Customer {
155    fn validate(mut self) -> Result<Self, ValidationError> where Self: Sized {
156        if self.given_name.is_some() ||
157            self.family_name.is_some() ||
158            self.company_name.is_some() ||
159            self.email_address.is_some() ||
160            self.phone_number.is_some() {
161            self.idempotency_key = Some(Uuid::new_v4().to_string());
162
163            Ok(self)
164        } else {
165            Err(ValidationError)
166        }
167    }
168}
169
170impl<T: ParentBuilder> Builder<Customer, T> {
171    pub fn given_name(mut self, given_name: String) -> Self {
172        self.body.given_name = Some(given_name);
173
174        self
175    }
176
177    pub fn family_name(mut self, family_name: String) -> Self {
178        self.body.family_name = Some(family_name);
179
180        self
181    }
182
183    pub fn nickname(mut self, nickname: String) -> Self {
184        self.body.nickname = Some(nickname);
185
186        self
187    }
188
189    pub fn email_address(mut self, email_address: String) -> Self {
190        self.body.email_address = Some(email_address);
191
192        self
193    }
194
195    pub fn address_from_address(mut self, address: Address) -> Self {
196        self.body.address = Some(address);
197
198        self
199    }
200
201    pub fn birthday(mut self, birthday: String) -> Self {
202        self.body.birthday = Some(birthday);
203
204        self
205    }
206
207    pub fn phone_number(mut self, phone_number: String) -> Self {
208        self.body.phone_number = Some(phone_number);
209
210        self
211    }
212
213    pub fn note(mut self, note: String) -> Self {
214        self.body.birthday = Some(note);
215
216        self
217    }
218}
219
220// -------------------------------------------------------------------------------------------------
221// CustomerDelete builder implementation
222// -------------------------------------------------------------------------------------------------
223#[derive(Debug, Default)]
224pub struct CustomerDelete {
225    customer_id: Option<String>,
226    version: Option<Vec<(String, String)>>,
227}
228
229impl Validate for CustomerDelete {
230    fn validate(self) -> Result<Self, ValidationError> where Self: Sized {
231        if self.customer_id.is_some() {
232            Ok(self)
233        } else {
234            Err(ValidationError)
235        }
236    }
237}
238
239impl<T: ParentBuilder> Builder<CustomerDelete, T> {
240    pub fn customer_id(mut self, customer_id: String) -> Self {
241        self.body.customer_id = Some(customer_id);
242
243        self
244    }
245
246    pub fn version(mut self, version: i64) -> Self {
247        self.body.version = Some(vec![("version".to_string(), version.to_string())]);
248
249        self
250    }
251}
252
253// -------------------------------------------------------------------------------------------------
254// CustomerSearchQuery builder implementation
255// -------------------------------------------------------------------------------------------------
256#[derive(Clone, Debug, Serialize, Deserialize, Default)]
257pub struct CustomerSearchQuery {
258    #[serde(skip_serializing_if = "Option::is_none")]
259    pub cursor: Option<String>,
260    #[serde(skip_serializing_if = "Option::is_none")]
261    pub limit: Option<i64>,
262    #[serde(skip_serializing_if = "Option::is_none")]
263    pub query: Option<SearchQueryAttribute>
264}
265
266impl Validate for CustomerSearchQuery {
267    fn validate(self) -> Result<Self, ValidationError> where Self: Sized {
268        Ok(self)
269    }
270}
271
272impl<T: ParentBuilder> Builder<CustomerSearchQuery, T> {
273    pub fn cursor(mut self, cursor: String) -> Self {
274        self.body.cursor = Some(cursor);
275
276        self
277    }
278
279    pub fn limit(mut self, limit: i64) -> Self {
280        if limit < 1 || limit > 100 { return self };
281        self.body.limit = Some(limit);
282
283        self
284    }
285
286    pub fn created_at(mut self, start: String, end: String) -> Self {
287        let time_range = TimeRange {
288            start_at: Some(start),
289            end_at: Some(end),
290        };
291        let filter = CustomerFilter {
292            created_at:  Some(time_range.clone()),
293            creation_source: None,
294            email_address: None,
295            group_ids: None,
296            phone_number: None,
297            reference_id: None,
298            updated_at: None
299        };
300        let query = SearchQueryAttribute {
301            filter: Some(filter.clone()),
302            sort: None
303        };
304
305        if let Some(ref mut query) = &mut self.body.query {
306            if let Some(ref mut filter) = query.filter {
307                filter.created_at = Some(time_range);
308            } else {
309                query.filter = Some(filter);
310            }
311        } else {
312            self.body.query = Some(query);
313        }
314
315        self
316    }
317
318    pub fn updated_at(mut self, start: String, end: String) -> Self {
319        let time_range = TimeRange {
320            start_at: Some(start),
321            end_at: Some(end),
322        };
323        let filter = CustomerFilter {
324            created_at:  None,
325            creation_source: None,
326            email_address: None,
327            group_ids: None,
328            phone_number: None,
329            reference_id: None,
330            updated_at: Some(time_range.clone())
331        };
332        let query = SearchQueryAttribute {
333            filter: Some(filter.clone()),
334            sort: None
335        };
336
337        if let Some(ref mut query) = &mut self.body.query {
338            if let Some(ref mut filter) = query.filter {
339                filter.updated_at = Some(time_range);
340            } else {
341                query.filter = Some(filter);
342            }
343        } else {
344            self.body.query = Some(query);
345        }
346
347        self
348    }
349
350    pub fn exact_email_address(mut self, email: String) -> Self {
351        let email_group = CustomerTextFilter {
352            exact: Some(email.clone()),
353            fuzzy: None
354        };
355        let filter = CustomerFilter {
356            created_at:  None,
357            creation_source: None,
358            email_address: Some(email_group.clone()),
359            group_ids: None,
360            phone_number: None,
361            reference_id: None,
362            updated_at: None
363        };
364        let query = SearchQueryAttribute {
365            filter: Some(filter.clone()),
366            sort: None
367        };
368
369        if let Some(ref mut query) = &mut self.body.query {
370            if let Some(ref mut filter) = query.filter {
371                if let Some(ref mut email_group) = &mut filter.email_address {
372                    email_group.exact = Some(email);
373                } else {
374                    filter.email_address = Some(email_group)
375                }
376            } else {
377                query.filter = Some(filter);
378            }
379        } else {
380            self.body.query = Some(query);
381        }
382
383        self
384    }
385
386    pub fn fuzzy_email_address(mut self, email: String) -> Self {
387        let email_group = CustomerTextFilter {
388            exact: None,
389            fuzzy: Some(email.clone())
390        };
391        let filter = CustomerFilter {
392            created_at:  None,
393            creation_source: None,
394            email_address: Some(email_group.clone()),
395            group_ids: None,
396            phone_number: None,
397            reference_id: None,
398            updated_at: None
399        };
400        let query = SearchQueryAttribute {
401            filter: Some(filter.clone()),
402            sort: None
403        };
404
405        if let Some(ref mut query) = &mut self.body.query {
406            if let Some(ref mut filter) = query.filter {
407                if let Some(ref mut email_group) = &mut filter.email_address {
408                    email_group.fuzzy = Some(email);
409                } else {
410                    filter.email_address = Some(email_group)
411                }
412            } else {
413                query.filter = Some(filter);
414            }
415        } else {
416            self.body.query = Some(query);
417        }
418
419        self
420    }
421
422    pub fn exact_phone_number(mut self, number: String) -> Self {
423        let phone_group = CustomerTextFilter {
424            exact: Some(number.clone()),
425            fuzzy: None,
426        };
427        let filter = CustomerFilter {
428            created_at:  None,
429            creation_source: None,
430            email_address: None,
431            group_ids: None,
432            phone_number: Some(phone_group.clone()),
433            reference_id: None,
434            updated_at: None
435        };
436        let query = SearchQueryAttribute {
437            filter: Some(filter.clone()),
438            sort: None
439        };
440
441        if let Some(ref mut query) = &mut self.body.query {
442            if let Some(ref mut filter) = query.filter {
443                if let Some(ref mut phone_group) = &mut filter.phone_number {
444                    phone_group.exact = Some(number);
445                } else {
446                    filter.phone_number = Some(phone_group)
447                }
448            } else {
449                query.filter = Some(filter);
450            }
451        } else {
452            self.body.query = Some(query);
453        }
454
455        self
456    }
457
458    pub fn fuzzy_phone_number(mut self, number: String) -> Self {
459        let phone_group = CustomerTextFilter {
460            exact: None,
461            fuzzy: Some(number.clone())
462        };
463        let filter = CustomerFilter {
464            created_at:  None,
465            creation_source: None,
466            email_address: None,
467            group_ids: None,
468            phone_number: Some(phone_group.clone()),
469            reference_id: None,
470            updated_at: None
471        };
472        let query = SearchQueryAttribute {
473            filter: Some(filter.clone()),
474            sort: None
475        };
476
477        if let Some(ref mut query) = &mut self.body.query {
478            if let Some(ref mut filter) = query.filter {
479                if let Some(ref mut phone_group) = &mut filter.phone_number {
480                    phone_group.fuzzy = Some(number);
481                } else {
482                    filter.phone_number = Some(phone_group)
483                }
484            } else {
485                query.filter = Some(filter);
486            }
487        } else {
488            self.body.query = Some(query);
489        }
490
491        self
492    }
493
494    pub fn exact_reference_id(mut self, id: String) -> Self {
495        let reference_id_group = CustomerTextFilter {
496            exact: Some(id.clone()),
497            fuzzy: None,
498        };
499        let filter = CustomerFilter {
500            created_at:  None,
501            creation_source: None,
502            email_address: None,
503            group_ids: None,
504            phone_number: None,
505            reference_id: Some(reference_id_group.clone()),
506            updated_at: None
507        };
508        let query = SearchQueryAttribute {
509            filter: Some(filter.clone()),
510            sort: None
511        };
512
513        if let Some(ref mut query) = &mut self.body.query {
514            if let Some(ref mut filter) = query.filter {
515                if let Some(ref mut reference_id_group) = &mut filter.reference_id {
516                    reference_id_group.exact = Some(id);
517                } else {
518                    filter.reference_id = Some(reference_id_group)
519                }
520            } else {
521                query.filter = Some(filter);
522            }
523        } else {
524            self.body.query = Some(query);
525        }
526
527        self
528    }
529
530    pub fn fuzzy_reference_id(mut self, id: String) -> Self {
531        let reference_id_group = CustomerTextFilter {
532            exact: None,
533            fuzzy: Some(id.clone()),
534        };
535        let filter = CustomerFilter {
536            created_at:  None,
537            creation_source: None,
538            email_address: None,
539            group_ids: None,
540            phone_number: None,
541            reference_id: Some(reference_id_group.clone()),
542            updated_at: None
543        };
544        let query = SearchQueryAttribute {
545            filter: Some(filter.clone()),
546            sort: None
547        };
548
549        if let Some(ref mut query) = &mut self.body.query {
550            if let Some(ref mut filter) = query.filter {
551                if let Some(ref mut reference_id_group) = &mut filter.reference_id {
552                    reference_id_group.fuzzy = Some(id);
553                } else {
554                    filter.reference_id = Some(reference_id_group)
555                }
556            } else {
557                query.filter = Some(filter);
558            }
559        } else {
560            self.body.query = Some(query);
561        }
562
563        self
564    }
565
566    pub fn set_creation_source_exclude(mut self) -> Self {
567        let creation_source = CreationSource {
568            rule: Some("EXCLUDE".to_string()),
569            values: None
570        };
571        let filter = CustomerFilter {
572            created_at:  None,
573            creation_source: Some(creation_source.clone()),
574            email_address: None,
575            group_ids: None,
576            phone_number: None,
577            reference_id: None,
578            updated_at: None
579        };
580        let query = SearchQueryAttribute {
581            filter: Some(filter.clone()),
582            sort: None
583        };
584
585        if let Some(ref mut query) = &mut self.body.query {
586            if let Some(ref mut filter) = query.filter {
587                if let Some(ref mut creation_source) = &mut filter.creation_source {
588                    creation_source.rule = Some("EXCLUDE".to_string());
589                } else {
590                    filter.creation_source = Some(creation_source)
591                }
592            } else {
593                query.filter = Some(filter);
594            }
595        } else {
596            self.body.query = Some(query);
597        }
598
599        self
600    }
601
602    pub fn set_creation_source_include(mut self) -> Self {
603        let creation_source = CreationSource {
604            rule: Some("INCLUDE".to_string()),
605            values: None
606        };
607        let filter = CustomerFilter {
608            created_at:  None,
609            creation_source: Some(creation_source.clone()),
610            email_address: None,
611            group_ids: None,
612            phone_number: None,
613            reference_id: None,
614            updated_at: None
615        };
616        let query = SearchQueryAttribute {
617            filter: Some(filter.clone()),
618            sort: None
619        };
620
621        if let Some(ref mut query) = &mut self.body.query {
622            if let Some(ref mut filter) = query.filter {
623                if let Some(ref mut creation_source) = &mut filter.creation_source {
624                    creation_source.rule = Some("INCLUDE".to_string());
625                } else {
626                    filter.creation_source = Some(creation_source)
627                }
628            } else {
629                query.filter = Some(filter);
630            }
631        } else {
632            self.body.query = Some(query);
633        }
634
635        self
636    }
637
638    pub fn creation_source_value(mut self, value: CustomerCreationSource) -> Self {
639        let values = vec![value.clone()];
640        let creation_source = CreationSource {
641            rule: Some("INCLUDE".to_string()),
642            values: Some(values.clone())
643        };
644        let filter = CustomerFilter {
645            created_at:  None,
646            creation_source: Some(creation_source.clone()),
647            email_address: None,
648            group_ids: None,
649            phone_number: None,
650            reference_id: None,
651            updated_at: None
652        };
653        let query = SearchQueryAttribute {
654            filter: Some(filter.clone()),
655            sort: None
656        };
657
658        if let Some(ref mut query) = &mut self.body.query {
659            if let Some(ref mut filter) = &mut query.filter {
660                if let Some(ref mut creation_source) = &mut filter.creation_source {
661                    if let Some(ref mut values) = &mut creation_source.values {
662                        for val in values.iter() {
663                            if *val == value {return self}
664                        }
665                        values.push(value)
666                    } else {
667                        creation_source.values = Some(values);
668                    }
669                } else {
670                    filter.creation_source = Some(creation_source)
671                }
672            } else {
673                query.filter = Some(filter);
674            }
675        } else {
676            self.body.query = Some(query);
677        }
678
679        self
680    }
681}
682
683#[cfg(test)]
684mod test_customers {
685    use super::*;
686
687    #[tokio::test]
688    async fn test_list_parameter_builder() {
689        let sut = CustomerListParametersBuilder::new();
690        let expected =  vec![
691            ("limit".to_string(), "4".to_string()),
692            ("sort_field".to_string(), "DEFAULT".to_string())
693        ];
694        let actual =
695            sut.limit(4).limit(101).sort_field_default().build().await;
696
697        assert!(actual.is_ok());
698        assert_eq!(expected, actual.unwrap())
699    }
700
701    #[tokio::test]
702    async fn test_list_customers() {
703        use dotenv::dotenv;
704        use std::env;
705
706        dotenv().ok();
707        let access_token = env::var("ACCESS_TOKEN").expect("ACCESS_TOKEN to be set");
708        let sut = SquareClient::new(&access_token);
709
710        let input = vec![("limit".to_string(), "23".to_string()),
711             ("sort_field".to_string(), "DEFAULT".to_string())];
712
713        let result = sut.customers().list(input).await;
714
715        assert!(result.is_ok());
716        println!("{:?}", result.unwrap())
717    }
718
719    #[tokio::test]
720    async fn test_customer_builder() {
721        let expected = Customer {
722            id: None,
723            birthday: Some("1996-11-02".to_string()),
724            address: Some(Address{
725                address_line_1: Some("1234 Hillborrow Rd.".to_string()),
726                address_line_2: None,
727                address_line_3: None,
728                locality: Some("Charleston".to_string()),
729                sublocality: None,
730                administrative_district_level: Some("MA".to_string()),
731                postal_code: Some("12345".to_string()),
732                country: Some("United States".to_string())
733            }),
734            company_name: None,
735            created_at: None,
736            creation_source: None,
737            updated_at: None,
738            email_address: None,
739            family_name: Some("Ramsey".to_string()),
740            given_name: Some("Pierre".to_string()),
741            group_ids: None,
742            nickname: None,
743            note: None,
744            phone_number: Some("123-456-7890".to_string()),
745            preferences: None,
746            reference_id: None,
747            segment_ids: None,
748            tax_ids: None,
749            version: None,
750            cards: None,
751            idempotency_key: None
752        };
753
754        let address = Address{
755            address_line_1: Some("1234 Hillborrow Rd.".to_string()),
756            address_line_2: None,
757            address_line_3: None,
758            locality: Some("Charleston".to_string()),
759            sublocality: None,
760            administrative_district_level: Some("MA".to_string()),
761            postal_code: Some("12345".to_string()),
762            country: Some("United States".to_string())
763        };
764
765        let mut actual = Builder::from(Customer::default())
766            .address_from_address(address)
767            .given_name("Pierre".to_string())
768            .family_name("Ramsey".to_string())
769            .phone_number("123-456-7890".to_string())
770            .phone_number("123-456-7890".to_string())
771            .birthday("1996-11-02".to_string())
772            .build();
773
774        assert!(actual.is_ok());
775
776        actual.as_mut().unwrap().idempotency_key = None;
777
778        assert_eq!(format!("{:?}", expected), format!("{:?}", actual.unwrap()))
779    }
780
781    // #[tokio::test]
782    async fn test_create_customer() {
783        use dotenv::dotenv;
784        use std::env;
785
786        dotenv().ok();
787        let access_token = env::var("ACCESS_TOKEN").expect("ACCESS_TOKEN to be set");
788        let sut = SquareClient::new(&access_token);
789
790        let input = Builder::from(Customer::default())
791            .given_name("Boyd".to_string())
792            .nickname("the coolest".to_string())
793            .build().unwrap();
794
795        let result = sut.customers().create(input).await;
796
797        assert!(result.is_ok());
798        println!("{:?}", result.unwrap())
799    }
800
801    #[tokio::test]
802    async fn test_customer_delete_builder() {
803        let expected = CustomerDelete {
804            customer_id: Some("dew212ewfd32123ca".to_string()),
805            version: None
806        };
807
808        let actual = Builder::from(CustomerDelete::default())
809            .customer_id("dew212ewfd32123ca".to_string())
810            .build();
811
812        assert!(actual.is_ok());
813        assert_eq!(format!("{:?}", expected), format!("{:?}", actual.unwrap()))
814    }
815
816    // #[tokio::test]
817    async fn test_delete_customer() {
818        use dotenv::dotenv;
819        use std::env;
820
821        dotenv().ok();
822        let access_token = env::var("ACCESS_TOKEN").expect("ACCESS_TOKEN to be set");
823        let sut = SquareClient::new(&access_token);
824
825        let input = CustomerDelete {
826            customer_id: Some("WPGEDT7V38Y318JVGZ1G1C39W4".to_string()),
827            version: None
828        };
829
830        let res = sut.customers().delete(input).await;
831
832        assert!(res.is_ok());
833    }
834
835    #[tokio::test]
836    async fn test_customer_search_query_builder() {
837        let expected = CustomerSearchQuery {
838            cursor: None,
839            limit: Some(5),
840            query: Some(SearchQueryAttribute {
841                filter: Some(CustomerFilter {
842                    created_at: Some(TimeRange {
843                        end_at: Some("2022-01-23T20:21:54.859Z".to_string()),
844                        start_at: Some("2018-01-23T20:21:54.859Z".to_string())
845                    }),
846                    creation_source: Some(CreationSource {
847                        rule: Some("EXCLUDE".to_string()),
848                        values: Some(vec![CustomerCreationSource::Appointments,
849                                          CustomerCreationSource::Coupon])
850                    }),
851                    email_address: Some(CustomerTextFilter {
852                        exact: Some("emil.k.hofstetter@gmail.com".to_string()),
853                        fuzzy: Some("3umel.us@gmail.com".to_string())
854                    }),
855                    group_ids: None,
856                    phone_number: Some(CustomerTextFilter {
857                        exact: Some("571-694-6282".to_string()),
858                        fuzzy: Some("0176-47-85-993".to_string())
859                    }),
860                    reference_id: Some(CustomerTextFilter {
861                        exact: Some("cmiw9u209md82".to_string()),
862                        fuzzy: Some("432mi23cß2".to_string())
863                    }),
864                    updated_at: None
865                }),
866                sort: None
867            })
868        };
869
870        let actual = Builder::from(CustomerSearchQuery::default())
871            .limit(5).limit(1001).created_at(
872            "2018-01-23T20:21:54.859Z".to_string(),
873            "2022-01-23T20:21:54.859Z".to_string(),
874            ).fuzzy_email_address("3umel.us@gmail.com".to_string())
875            .exact_email_address("emil.k.hofstetter@gmail.com".to_string())
876            .exact_phone_number("571-694-6282".to_string())
877            .fuzzy_phone_number("0176-47-85-993".to_string())
878            .fuzzy_reference_id("432mi23cß2".to_string())
879            .exact_reference_id("cmiw9u209md82".to_string())
880            .creation_source_value(CustomerCreationSource::Appointments)
881            .creation_source_value(CustomerCreationSource::Coupon)
882            .creation_source_value(CustomerCreationSource::Appointments)
883            .set_creation_source_exclude()
884            .build();
885
886        assert!(actual.is_ok());
887        assert_eq!(format!("{:?}", expected), format!("{:?}", actual.unwrap()));
888    }
889
890    #[tokio::test]
891    async fn test_search_customers() {
892        use dotenv::dotenv;
893        use std::env;
894
895        dotenv().ok();
896        let access_token = env::var("ACCESS_TOKEN").expect("ACCESS_TOKEN to be set");
897        let sut = SquareClient::new(&access_token);
898
899        let input = CustomerSearchQuery {
900            cursor: None,
901            limit: None,
902            query: Some(SearchQueryAttribute {
903                filter: Some(CustomerFilter {
904                    created_at: Some(TimeRange {
905                        end_at: None,
906                        start_at: None,
907                    }),
908                    creation_source: Some(CreationSource {
909                        rule: Some("INCLUDE".to_string()),
910                        values: Some(vec![CustomerCreationSource::Appointments,
911                                          CustomerCreationSource::ThirdParty]),
912                    }),
913                    email_address: Some(CustomerTextFilter {
914                        exact: None,
915                        fuzzy: Some(".co".to_string()),
916                    }),
917                    group_ids: None,
918                    phone_number: Some(CustomerTextFilter {
919                        exact: None,
920                        fuzzy: None,
921                    }),
922                    reference_id: Some(CustomerTextFilter {
923                        exact: None,
924                        fuzzy: None,
925                    }),
926                    updated_at: None
927                }),
928                sort: None
929            })
930        };
931
932        let result = sut.customers().search(input).await;
933
934        // assert!(result.is_ok() || result.err().unwrap().get().is_some())
935        assert!(result.is_ok())
936    }
937}