1#![allow(unused_imports)]
15use async_trait::async_trait;
16use derive_builder::Builder;
17use reqwest;
18use rust_decimal::prelude::*;
19use serde::{Deserialize, Serialize};
20use serde_json::{Value, json};
21use std::collections::BTreeMap;
22
23use crate::common::{
24 config::ConfigurationRestApi,
25 models::{ParamBuildError, RestApiResponse},
26 utils::send_request,
27};
28use crate::fiat::rest_api::models;
29
30const HAS_TIME_UNIT: bool = false;
31
32#[async_trait]
33pub trait Api: Send + Sync {
34 async fn deposit(
35 &self,
36 params: DepositParams,
37 ) -> anyhow::Result<RestApiResponse<models::DepositResponse>>;
38 async fn fiat_withdraw(
39 &self,
40 params: FiatWithdrawParams,
41 ) -> anyhow::Result<RestApiResponse<models::FiatWithdrawResponse>>;
42 async fn get_fiat_deposit_withdraw_history(
43 &self,
44 params: GetFiatDepositWithdrawHistoryParams,
45 ) -> anyhow::Result<RestApiResponse<models::GetFiatDepositWithdrawHistoryResponse>>;
46 async fn get_fiat_payments_history(
47 &self,
48 params: GetFiatPaymentsHistoryParams,
49 ) -> anyhow::Result<RestApiResponse<models::GetFiatPaymentsHistoryResponse>>;
50 async fn get_order_detail(
51 &self,
52 params: GetOrderDetailParams,
53 ) -> anyhow::Result<RestApiResponse<models::GetOrderDetailResponse>>;
54}
55
56#[derive(Debug, Clone)]
57pub struct ApiClient {
58 configuration: ConfigurationRestApi,
59}
60
61impl ApiClient {
62 pub fn new(configuration: ConfigurationRestApi) -> Self {
63 Self { configuration }
64 }
65}
66
67#[allow(non_camel_case_types)]
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub enum DepositApiPaymentMethodEnum {
70 #[serde(rename = "pix")]
71 Pix,
72}
73
74impl DepositApiPaymentMethodEnum {
75 #[must_use]
76 pub fn as_str(&self) -> &'static str {
77 match self {
78 Self::Pix => "pix",
79 }
80 }
81}
82
83impl std::str::FromStr for DepositApiPaymentMethodEnum {
84 type Err = Box<dyn std::error::Error + Send + Sync>;
85
86 fn from_str(s: &str) -> Result<Self, Self::Err> {
87 match s {
88 "pix" => Ok(Self::Pix),
89 other => Err(format!("invalid DepositApiPaymentMethodEnum: {}", other).into()),
90 }
91 }
92}
93
94#[allow(non_camel_case_types)]
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub enum FiatWithdrawApiPaymentMethodEnum {
97 #[serde(rename = "bank_transfer")]
98 BankTransfer,
99}
100
101impl FiatWithdrawApiPaymentMethodEnum {
102 #[must_use]
103 pub fn as_str(&self) -> &'static str {
104 match self {
105 Self::BankTransfer => "bank_transfer",
106 }
107 }
108}
109
110impl std::str::FromStr for FiatWithdrawApiPaymentMethodEnum {
111 type Err = Box<dyn std::error::Error + Send + Sync>;
112
113 fn from_str(s: &str) -> Result<Self, Self::Err> {
114 match s {
115 "bank_transfer" => Ok(Self::BankTransfer),
116 other => Err(format!("invalid FiatWithdrawApiPaymentMethodEnum: {}", other).into()),
117 }
118 }
119}
120
121#[derive(Clone, Debug, Builder, Deserialize)]
126#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
127pub struct DepositParams {
128 #[builder(setter(into))]
133 #[serde(rename = "currency")]
134 pub currency: String,
135 #[builder(setter(into))]
139 #[serde(rename = "apiPaymentMethod")]
140 pub api_payment_method: DepositApiPaymentMethodEnum,
141 #[builder(setter(into))]
145 #[serde(rename = "amount")]
146 pub amount: String,
147 #[builder(setter(into), default)]
151 #[serde(rename = "recvWindow", default)]
152 pub recv_window: Option<i64>,
153 #[builder(setter(into), default)]
158 #[serde(rename = "ext", default)]
159 pub ext: Option<serde_json::Value>,
160}
161
162impl DepositParams {
163 #[must_use]
172 pub fn builder(
173 currency: String,
174 api_payment_method: DepositApiPaymentMethodEnum,
175 amount: String,
176 ) -> DepositParamsBuilder {
177 DepositParamsBuilder::default()
178 .currency(currency)
179 .api_payment_method(api_payment_method)
180 .amount(amount)
181 }
182}
183#[derive(Clone, Debug, Builder, Deserialize)]
188#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
189pub struct FiatWithdrawParams {
190 #[builder(setter(into))]
194 #[serde(rename = "currency")]
195 pub currency: String,
196 #[builder(setter(into))]
200 #[serde(rename = "apiPaymentMethod")]
201 pub api_payment_method: FiatWithdrawApiPaymentMethodEnum,
202 #[builder(setter(into))]
206 #[serde(rename = "amount")]
207 pub amount: i64,
208 #[builder(setter(into))]
213 #[serde(rename = "accountInfo")]
214 pub account_info: models::FiatWithdrawRequestAccountInfo,
215 #[builder(setter(into), default)]
219 #[serde(rename = "recvWindow", default)]
220 pub recv_window: Option<i64>,
221 #[builder(setter(into), default)]
226 #[serde(rename = "ext", default)]
227 pub ext: Option<serde_json::Value>,
228}
229
230impl FiatWithdrawParams {
231 #[must_use]
241 pub fn builder(
242 currency: String,
243 api_payment_method: FiatWithdrawApiPaymentMethodEnum,
244 amount: i64,
245 account_info: models::FiatWithdrawRequestAccountInfo,
246 ) -> FiatWithdrawParamsBuilder {
247 FiatWithdrawParamsBuilder::default()
248 .currency(currency)
249 .api_payment_method(api_payment_method)
250 .amount(amount)
251 .account_info(account_info)
252 }
253}
254#[derive(Clone, Debug, Builder, Deserialize)]
259#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
260pub struct GetFiatDepositWithdrawHistoryParams {
261 #[builder(setter(into))]
265 #[serde(rename = "transactionType")]
266 pub transaction_type: String,
267 #[builder(setter(into), default)]
272 #[serde(rename = "beginTime", default)]
273 pub begin_time: Option<i64>,
274 #[builder(setter(into), default)]
279 #[serde(rename = "endTime", default)]
280 pub end_time: Option<i64>,
281 #[builder(setter(into), default)]
286 #[serde(rename = "page", default)]
287 pub page: Option<i64>,
288 #[builder(setter(into), default)]
293 #[serde(rename = "rows", default)]
294 pub rows: Option<i64>,
295 #[builder(setter(into), default)]
300 #[serde(rename = "recvWindow", default)]
301 pub recv_window: Option<i64>,
302}
303
304impl GetFiatDepositWithdrawHistoryParams {
305 #[must_use]
312 pub fn builder(transaction_type: String) -> GetFiatDepositWithdrawHistoryParamsBuilder {
313 GetFiatDepositWithdrawHistoryParamsBuilder::default().transaction_type(transaction_type)
314 }
315}
316#[derive(Clone, Debug, Builder, Deserialize)]
321#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
322pub struct GetFiatPaymentsHistoryParams {
323 #[builder(setter(into))]
327 #[serde(rename = "transactionType")]
328 pub transaction_type: String,
329 #[builder(setter(into), default)]
334 #[serde(rename = "beginTime", default)]
335 pub begin_time: Option<i64>,
336 #[builder(setter(into), default)]
341 #[serde(rename = "endTime", default)]
342 pub end_time: Option<i64>,
343 #[builder(setter(into), default)]
348 #[serde(rename = "page", default)]
349 pub page: Option<i64>,
350 #[builder(setter(into), default)]
355 #[serde(rename = "rows", default)]
356 pub rows: Option<i64>,
357 #[builder(setter(into), default)]
362 #[serde(rename = "recvWindow", default)]
363 pub recv_window: Option<i64>,
364}
365
366impl GetFiatPaymentsHistoryParams {
367 #[must_use]
374 pub fn builder(transaction_type: String) -> GetFiatPaymentsHistoryParamsBuilder {
375 GetFiatPaymentsHistoryParamsBuilder::default().transaction_type(transaction_type)
376 }
377}
378#[derive(Clone, Debug, Builder, Deserialize)]
383#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
384pub struct GetOrderDetailParams {
385 #[builder(setter(into))]
389 #[serde(rename = "orderNo")]
390 pub order_no: String,
391 #[builder(setter(into), default)]
396 #[serde(rename = "recvWindow", default)]
397 pub recv_window: Option<i64>,
398}
399
400impl GetOrderDetailParams {
401 #[must_use]
408 pub fn builder(order_no: String) -> GetOrderDetailParamsBuilder {
409 GetOrderDetailParamsBuilder::default().order_no(order_no)
410 }
411}
412
413#[async_trait]
414impl Api for ApiClient {
415 async fn deposit(
416 &self,
417 params: DepositParams,
418 ) -> anyhow::Result<RestApiResponse<models::DepositResponse>> {
419 let DepositParams {
420 currency,
421 api_payment_method,
422 amount,
423 recv_window,
424 ext,
425 } = params;
426
427 let mut query_params = BTreeMap::new();
428 let mut body_params = BTreeMap::new();
429
430 if let Some(rw) = recv_window {
431 query_params.insert("recvWindow".to_string(), json!(rw));
432 }
433
434 body_params.insert("currency".to_string(), json!(currency));
435
436 body_params.insert("apiPaymentMethod".to_string(), json!(api_payment_method));
437
438 body_params.insert("amount".to_string(), json!(amount));
439
440 if let Some(rw) = ext {
441 body_params.insert("ext".to_string(), json!(rw));
442 }
443
444 send_request::<models::DepositResponse>(
445 &self.configuration,
446 "/sapi/v1/fiat/deposit",
447 reqwest::Method::POST,
448 query_params,
449 body_params,
450 if HAS_TIME_UNIT {
451 self.configuration.time_unit
452 } else {
453 None
454 },
455 true,
456 )
457 .await
458 }
459
460 async fn fiat_withdraw(
461 &self,
462 params: FiatWithdrawParams,
463 ) -> anyhow::Result<RestApiResponse<models::FiatWithdrawResponse>> {
464 let FiatWithdrawParams {
465 currency,
466 api_payment_method,
467 amount,
468 account_info,
469 recv_window,
470 ext,
471 } = params;
472
473 let mut query_params = BTreeMap::new();
474 let mut body_params = BTreeMap::new();
475
476 if let Some(rw) = recv_window {
477 query_params.insert("recvWindow".to_string(), json!(rw));
478 }
479
480 body_params.insert("currency".to_string(), json!(currency));
481
482 body_params.insert("apiPaymentMethod".to_string(), json!(api_payment_method));
483
484 body_params.insert("amount".to_string(), json!(amount));
485
486 body_params.insert("accountInfo".to_string(), json!(account_info));
487
488 if let Some(rw) = ext {
489 body_params.insert("ext".to_string(), json!(rw));
490 }
491
492 send_request::<models::FiatWithdrawResponse>(
493 &self.configuration,
494 "/sapi/v2/fiat/withdraw",
495 reqwest::Method::POST,
496 query_params,
497 body_params,
498 if HAS_TIME_UNIT {
499 self.configuration.time_unit
500 } else {
501 None
502 },
503 true,
504 )
505 .await
506 }
507
508 async fn get_fiat_deposit_withdraw_history(
509 &self,
510 params: GetFiatDepositWithdrawHistoryParams,
511 ) -> anyhow::Result<RestApiResponse<models::GetFiatDepositWithdrawHistoryResponse>> {
512 let GetFiatDepositWithdrawHistoryParams {
513 transaction_type,
514 begin_time,
515 end_time,
516 page,
517 rows,
518 recv_window,
519 } = params;
520
521 let mut query_params = BTreeMap::new();
522 let body_params = BTreeMap::new();
523
524 query_params.insert("transactionType".to_string(), json!(transaction_type));
525
526 if let Some(rw) = begin_time {
527 query_params.insert("beginTime".to_string(), json!(rw));
528 }
529
530 if let Some(rw) = end_time {
531 query_params.insert("endTime".to_string(), json!(rw));
532 }
533
534 if let Some(rw) = page {
535 query_params.insert("page".to_string(), json!(rw));
536 }
537
538 if let Some(rw) = rows {
539 query_params.insert("rows".to_string(), json!(rw));
540 }
541
542 if let Some(rw) = recv_window {
543 query_params.insert("recvWindow".to_string(), json!(rw));
544 }
545
546 send_request::<models::GetFiatDepositWithdrawHistoryResponse>(
547 &self.configuration,
548 "/sapi/v1/fiat/orders",
549 reqwest::Method::GET,
550 query_params,
551 body_params,
552 if HAS_TIME_UNIT {
553 self.configuration.time_unit
554 } else {
555 None
556 },
557 true,
558 )
559 .await
560 }
561
562 async fn get_fiat_payments_history(
563 &self,
564 params: GetFiatPaymentsHistoryParams,
565 ) -> anyhow::Result<RestApiResponse<models::GetFiatPaymentsHistoryResponse>> {
566 let GetFiatPaymentsHistoryParams {
567 transaction_type,
568 begin_time,
569 end_time,
570 page,
571 rows,
572 recv_window,
573 } = params;
574
575 let mut query_params = BTreeMap::new();
576 let body_params = BTreeMap::new();
577
578 query_params.insert("transactionType".to_string(), json!(transaction_type));
579
580 if let Some(rw) = begin_time {
581 query_params.insert("beginTime".to_string(), json!(rw));
582 }
583
584 if let Some(rw) = end_time {
585 query_params.insert("endTime".to_string(), json!(rw));
586 }
587
588 if let Some(rw) = page {
589 query_params.insert("page".to_string(), json!(rw));
590 }
591
592 if let Some(rw) = rows {
593 query_params.insert("rows".to_string(), json!(rw));
594 }
595
596 if let Some(rw) = recv_window {
597 query_params.insert("recvWindow".to_string(), json!(rw));
598 }
599
600 send_request::<models::GetFiatPaymentsHistoryResponse>(
601 &self.configuration,
602 "/sapi/v1/fiat/payments",
603 reqwest::Method::GET,
604 query_params,
605 body_params,
606 if HAS_TIME_UNIT {
607 self.configuration.time_unit
608 } else {
609 None
610 },
611 true,
612 )
613 .await
614 }
615
616 async fn get_order_detail(
617 &self,
618 params: GetOrderDetailParams,
619 ) -> anyhow::Result<RestApiResponse<models::GetOrderDetailResponse>> {
620 let GetOrderDetailParams {
621 order_no,
622 recv_window,
623 } = params;
624
625 let mut query_params = BTreeMap::new();
626 let body_params = BTreeMap::new();
627
628 query_params.insert("orderNo".to_string(), json!(order_no));
629
630 if let Some(rw) = recv_window {
631 query_params.insert("recvWindow".to_string(), json!(rw));
632 }
633
634 send_request::<models::GetOrderDetailResponse>(
635 &self.configuration,
636 "/sapi/v1/fiat/get-order-detail",
637 reqwest::Method::GET,
638 query_params,
639 body_params,
640 if HAS_TIME_UNIT {
641 self.configuration.time_unit
642 } else {
643 None
644 },
645 true,
646 )
647 .await
648 }
649}
650
651#[cfg(all(test, feature = "fiat"))]
652mod tests {
653 use super::*;
654 use crate::TOKIO_SHARED_RT;
655 use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
656 use async_trait::async_trait;
657 use std::collections::HashMap;
658
659 struct DummyRestApiResponse<T> {
660 inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
661 status: u16,
662 headers: HashMap<String, String>,
663 rate_limits: Option<Vec<RestApiRateLimit>>,
664 }
665
666 impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
667 fn from(dummy: DummyRestApiResponse<T>) -> Self {
668 Self {
669 data_fn: dummy.inner,
670 status: dummy.status,
671 headers: dummy.headers,
672 rate_limits: dummy.rate_limits,
673 }
674 }
675 }
676
677 struct MockApiClient {
678 force_error: bool,
679 }
680
681 #[async_trait]
682 impl Api for MockApiClient {
683 async fn deposit(
684 &self,
685 _params: DepositParams,
686 ) -> anyhow::Result<RestApiResponse<models::DepositResponse>> {
687 if self.force_error {
688 return Err(ConnectorError::ConnectorClientError {
689 msg: "ResponseError".to_string(),
690 code: None,
691 }
692 .into());
693 }
694
695 let resp_json: Value = serde_json::from_str(
696 r#"{"code":"000000","message":"success","data":{"orderId":"04595xxxxxxxxx37"}}"#,
697 )
698 .unwrap_or_else(|_| serde_json::json!({}));
699 let dummy_response: models::DepositResponse = serde_json::from_value(resp_json.clone())
700 .expect("should parse into models::DepositResponse");
701
702 let dummy = DummyRestApiResponse {
703 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
704 status: 200,
705 headers: HashMap::new(),
706 rate_limits: None,
707 };
708
709 Ok(dummy.into())
710 }
711
712 async fn fiat_withdraw(
713 &self,
714 _params: FiatWithdrawParams,
715 ) -> anyhow::Result<RestApiResponse<models::FiatWithdrawResponse>> {
716 if self.force_error {
717 return Err(ConnectorError::ConnectorClientError {
718 msg: "ResponseError".to_string(),
719 code: None,
720 }
721 .into());
722 }
723
724 let resp_json: Value = serde_json::from_str(
725 r#"{"code":"000000","message":"success","data":{"orderId":"04595xxxxxxxxx37"}}"#,
726 )
727 .unwrap_or_else(|_| serde_json::json!({}));
728 let dummy_response: models::FiatWithdrawResponse =
729 serde_json::from_value(resp_json.clone())
730 .expect("should parse into models::FiatWithdrawResponse");
731
732 let dummy = DummyRestApiResponse {
733 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
734 status: 200,
735 headers: HashMap::new(),
736 rate_limits: None,
737 };
738
739 Ok(dummy.into())
740 }
741
742 async fn get_fiat_deposit_withdraw_history(
743 &self,
744 _params: GetFiatDepositWithdrawHistoryParams,
745 ) -> anyhow::Result<RestApiResponse<models::GetFiatDepositWithdrawHistoryResponse>>
746 {
747 if self.force_error {
748 return Err(ConnectorError::ConnectorClientError {
749 msg: "ResponseError".to_string(),
750 code: None,
751 }
752 .into());
753 }
754
755 let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"orderNo":"7d76d611-0568-4f43-afb6-24cac7767365","fiatCurrency":"BRL","indicatedAmount":"10.00","amount":"10.00","totalFee":"0.00","method":"BankAccount","status":"Expired","createTime":1626144956000,"updateTime":1626400907000}],"total":1,"success":true}"#).unwrap_or_else(|_| serde_json::json!({}));
756 let dummy_response: models::GetFiatDepositWithdrawHistoryResponse =
757 serde_json::from_value(resp_json.clone())
758 .expect("should parse into models::GetFiatDepositWithdrawHistoryResponse");
759
760 let dummy = DummyRestApiResponse {
761 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
762 status: 200,
763 headers: HashMap::new(),
764 rate_limits: None,
765 };
766
767 Ok(dummy.into())
768 }
769
770 async fn get_fiat_payments_history(
771 &self,
772 _params: GetFiatPaymentsHistoryParams,
773 ) -> anyhow::Result<RestApiResponse<models::GetFiatPaymentsHistoryResponse>> {
774 if self.force_error {
775 return Err(ConnectorError::ConnectorClientError {
776 msg: "ResponseError".to_string(),
777 code: None,
778 }
779 .into());
780 }
781
782 let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"orderNo":"353fca443f06466db0c4dc89f94f027a","sourceAmount":"20.0","fiatCurrency":"EUR","obtainAmount":"4.462","cryptoCurrency":"LUNA","totalFee":"0.2","price":"4.437472","status":"Failed","paymentMethod":"Credit Card","createTime":1624529919000,"updateTime":1624529919000}],"total":1,"success":true}"#).unwrap_or_else(|_| serde_json::json!({}));
783 let dummy_response: models::GetFiatPaymentsHistoryResponse =
784 serde_json::from_value(resp_json.clone())
785 .expect("should parse into models::GetFiatPaymentsHistoryResponse");
786
787 let dummy = DummyRestApiResponse {
788 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
789 status: 200,
790 headers: HashMap::new(),
791 rate_limits: None,
792 };
793
794 Ok(dummy.into())
795 }
796
797 async fn get_order_detail(
798 &self,
799 _params: GetOrderDetailParams,
800 ) -> anyhow::Result<RestApiResponse<models::GetOrderDetailResponse>> {
801 if self.force_error {
802 return Err(ConnectorError::ConnectorClientError {
803 msg: "ResponseError".to_string(),
804 code: None,
805 }
806 .into());
807 }
808
809 let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"orderId":"036752*678","orderStatus":"ORDER_INITIAL","amount":"4.33","fee":"0.43","fiatCurrency":"***","errorCode":"","errorMessage":"","ext":{}}}"#).unwrap_or_else(|_| serde_json::json!({}));
810 let dummy_response: models::GetOrderDetailResponse =
811 serde_json::from_value(resp_json.clone())
812 .expect("should parse into models::GetOrderDetailResponse");
813
814 let dummy = DummyRestApiResponse {
815 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
816 status: 200,
817 headers: HashMap::new(),
818 rate_limits: None,
819 };
820
821 Ok(dummy.into())
822 }
823 }
824
825 #[test]
826 fn deposit_required_params_success() {
827 TOKIO_SHARED_RT.block_on(async {
828 let client = MockApiClient { force_error: false };
829
830 let params = DepositParams::builder(
831 "currency_example".to_string(),
832 DepositApiPaymentMethodEnum::Pix,
833 "amount_example".to_string(),
834 )
835 .build()
836 .unwrap();
837
838 let resp_json: Value = serde_json::from_str(
839 r#"{"code":"000000","message":"success","data":{"orderId":"04595xxxxxxxxx37"}}"#,
840 )
841 .unwrap_or_else(|_| serde_json::json!({}));
842 let expected_response: models::DepositResponse =
843 serde_json::from_value(resp_json.clone())
844 .expect("should parse into models::DepositResponse");
845
846 let resp = client.deposit(params).await.expect("Expected a response");
847 let data_future = resp.data();
848 let actual_response = data_future.await.unwrap();
849 assert_eq!(actual_response, expected_response);
850 });
851 }
852
853 #[test]
854 fn deposit_optional_params_success() {
855 TOKIO_SHARED_RT.block_on(async {
856 let client = MockApiClient { force_error: false };
857
858 let params = DepositParams::builder(
859 "currency_example".to_string(),
860 DepositApiPaymentMethodEnum::Pix,
861 "amount_example".to_string(),
862 )
863 .recv_window(5000)
864 .ext(serde_json::Value::Object(Default::default()))
865 .build()
866 .unwrap();
867
868 let resp_json: Value = serde_json::from_str(
869 r#"{"code":"000000","message":"success","data":{"orderId":"04595xxxxxxxxx37"}}"#,
870 )
871 .unwrap_or_else(|_| serde_json::json!({}));
872 let expected_response: models::DepositResponse =
873 serde_json::from_value(resp_json.clone())
874 .expect("should parse into models::DepositResponse");
875
876 let resp = client.deposit(params).await.expect("Expected a response");
877 let data_future = resp.data();
878 let actual_response = data_future.await.unwrap();
879 assert_eq!(actual_response, expected_response);
880 });
881 }
882
883 #[test]
884 fn deposit_response_error() {
885 TOKIO_SHARED_RT.block_on(async {
886 let client = MockApiClient { force_error: true };
887
888 let params = DepositParams::builder(
889 "currency_example".to_string(),
890 DepositApiPaymentMethodEnum::Pix,
891 "amount_example".to_string(),
892 )
893 .build()
894 .unwrap();
895
896 match client.deposit(params).await {
897 Ok(_) => panic!("Expected an error"),
898 Err(err) => {
899 assert_eq!(err.to_string(), "Connector client error: ResponseError");
900 }
901 }
902 });
903 }
904
905 #[test]
906 fn fiat_withdraw_required_params_success() {
907 TOKIO_SHARED_RT.block_on(async {
908 let client = MockApiClient { force_error: false };
909
910 let params = FiatWithdrawParams::builder(
911 "currency_example".to_string(),
912 FiatWithdrawApiPaymentMethodEnum::BankTransfer,
913 789,
914 models::FiatWithdrawRequestAccountInfo::default(),
915 )
916 .build()
917 .unwrap();
918
919 let resp_json: Value = serde_json::from_str(
920 r#"{"code":"000000","message":"success","data":{"orderId":"04595xxxxxxxxx37"}}"#,
921 )
922 .unwrap_or_else(|_| serde_json::json!({}));
923 let expected_response: models::FiatWithdrawResponse =
924 serde_json::from_value(resp_json.clone())
925 .expect("should parse into models::FiatWithdrawResponse");
926
927 let resp = client
928 .fiat_withdraw(params)
929 .await
930 .expect("Expected a response");
931 let data_future = resp.data();
932 let actual_response = data_future.await.unwrap();
933 assert_eq!(actual_response, expected_response);
934 });
935 }
936
937 #[test]
938 fn fiat_withdraw_optional_params_success() {
939 TOKIO_SHARED_RT.block_on(async {
940 let client = MockApiClient { force_error: false };
941
942 let params = FiatWithdrawParams::builder(
943 "currency_example".to_string(),
944 FiatWithdrawApiPaymentMethodEnum::BankTransfer,
945 789,
946 models::FiatWithdrawRequestAccountInfo::default(),
947 )
948 .recv_window(5000)
949 .ext(serde_json::Value::Object(Default::default()))
950 .build()
951 .unwrap();
952
953 let resp_json: Value = serde_json::from_str(
954 r#"{"code":"000000","message":"success","data":{"orderId":"04595xxxxxxxxx37"}}"#,
955 )
956 .unwrap_or_else(|_| serde_json::json!({}));
957 let expected_response: models::FiatWithdrawResponse =
958 serde_json::from_value(resp_json.clone())
959 .expect("should parse into models::FiatWithdrawResponse");
960
961 let resp = client
962 .fiat_withdraw(params)
963 .await
964 .expect("Expected a response");
965 let data_future = resp.data();
966 let actual_response = data_future.await.unwrap();
967 assert_eq!(actual_response, expected_response);
968 });
969 }
970
971 #[test]
972 fn fiat_withdraw_response_error() {
973 TOKIO_SHARED_RT.block_on(async {
974 let client = MockApiClient { force_error: true };
975
976 let params = FiatWithdrawParams::builder(
977 "currency_example".to_string(),
978 FiatWithdrawApiPaymentMethodEnum::BankTransfer,
979 789,
980 models::FiatWithdrawRequestAccountInfo::default(),
981 )
982 .build()
983 .unwrap();
984
985 match client.fiat_withdraw(params).await {
986 Ok(_) => panic!("Expected an error"),
987 Err(err) => {
988 assert_eq!(err.to_string(), "Connector client error: ResponseError");
989 }
990 }
991 });
992 }
993
994 #[test]
995 fn get_fiat_deposit_withdraw_history_required_params_success() {
996 TOKIO_SHARED_RT.block_on(async {
997 let client = MockApiClient { force_error: false };
998
999 let params = GetFiatDepositWithdrawHistoryParams::builder("0".to_string(),).build().unwrap();
1000
1001 let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"orderNo":"7d76d611-0568-4f43-afb6-24cac7767365","fiatCurrency":"BRL","indicatedAmount":"10.00","amount":"10.00","totalFee":"0.00","method":"BankAccount","status":"Expired","createTime":1626144956000,"updateTime":1626400907000}],"total":1,"success":true}"#).unwrap_or_else(|_| serde_json::json!({}));
1002 let expected_response : models::GetFiatDepositWithdrawHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFiatDepositWithdrawHistoryResponse");
1003
1004 let resp = client.get_fiat_deposit_withdraw_history(params).await.expect("Expected a response");
1005 let data_future = resp.data();
1006 let actual_response = data_future.await.unwrap();
1007 assert_eq!(actual_response, expected_response);
1008 });
1009 }
1010
1011 #[test]
1012 fn get_fiat_deposit_withdraw_history_optional_params_success() {
1013 TOKIO_SHARED_RT.block_on(async {
1014 let client = MockApiClient { force_error: false };
1015
1016 let params = GetFiatDepositWithdrawHistoryParams::builder("0".to_string(),).begin_time(1641782889000).end_time(1641782889000).page(1).rows(100).recv_window(5000).build().unwrap();
1017
1018 let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"orderNo":"7d76d611-0568-4f43-afb6-24cac7767365","fiatCurrency":"BRL","indicatedAmount":"10.00","amount":"10.00","totalFee":"0.00","method":"BankAccount","status":"Expired","createTime":1626144956000,"updateTime":1626400907000}],"total":1,"success":true}"#).unwrap_or_else(|_| serde_json::json!({}));
1019 let expected_response : models::GetFiatDepositWithdrawHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFiatDepositWithdrawHistoryResponse");
1020
1021 let resp = client.get_fiat_deposit_withdraw_history(params).await.expect("Expected a response");
1022 let data_future = resp.data();
1023 let actual_response = data_future.await.unwrap();
1024 assert_eq!(actual_response, expected_response);
1025 });
1026 }
1027
1028 #[test]
1029 fn get_fiat_deposit_withdraw_history_response_error() {
1030 TOKIO_SHARED_RT.block_on(async {
1031 let client = MockApiClient { force_error: true };
1032
1033 let params = GetFiatDepositWithdrawHistoryParams::builder("0".to_string())
1034 .build()
1035 .unwrap();
1036
1037 match client.get_fiat_deposit_withdraw_history(params).await {
1038 Ok(_) => panic!("Expected an error"),
1039 Err(err) => {
1040 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1041 }
1042 }
1043 });
1044 }
1045
1046 #[test]
1047 fn get_fiat_payments_history_required_params_success() {
1048 TOKIO_SHARED_RT.block_on(async {
1049 let client = MockApiClient { force_error: false };
1050
1051 let params = GetFiatPaymentsHistoryParams::builder("0".to_string(),).build().unwrap();
1052
1053 let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"orderNo":"353fca443f06466db0c4dc89f94f027a","sourceAmount":"20.0","fiatCurrency":"EUR","obtainAmount":"4.462","cryptoCurrency":"LUNA","totalFee":"0.2","price":"4.437472","status":"Failed","paymentMethod":"Credit Card","createTime":1624529919000,"updateTime":1624529919000}],"total":1,"success":true}"#).unwrap_or_else(|_| serde_json::json!({}));
1054 let expected_response : models::GetFiatPaymentsHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFiatPaymentsHistoryResponse");
1055
1056 let resp = client.get_fiat_payments_history(params).await.expect("Expected a response");
1057 let data_future = resp.data();
1058 let actual_response = data_future.await.unwrap();
1059 assert_eq!(actual_response, expected_response);
1060 });
1061 }
1062
1063 #[test]
1064 fn get_fiat_payments_history_optional_params_success() {
1065 TOKIO_SHARED_RT.block_on(async {
1066 let client = MockApiClient { force_error: false };
1067
1068 let params = GetFiatPaymentsHistoryParams::builder("0".to_string(),).begin_time(1641782889000).end_time(1641782889000).page(1).rows(100).recv_window(5000).build().unwrap();
1069
1070 let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":[{"orderNo":"353fca443f06466db0c4dc89f94f027a","sourceAmount":"20.0","fiatCurrency":"EUR","obtainAmount":"4.462","cryptoCurrency":"LUNA","totalFee":"0.2","price":"4.437472","status":"Failed","paymentMethod":"Credit Card","createTime":1624529919000,"updateTime":1624529919000}],"total":1,"success":true}"#).unwrap_or_else(|_| serde_json::json!({}));
1071 let expected_response : models::GetFiatPaymentsHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetFiatPaymentsHistoryResponse");
1072
1073 let resp = client.get_fiat_payments_history(params).await.expect("Expected a response");
1074 let data_future = resp.data();
1075 let actual_response = data_future.await.unwrap();
1076 assert_eq!(actual_response, expected_response);
1077 });
1078 }
1079
1080 #[test]
1081 fn get_fiat_payments_history_response_error() {
1082 TOKIO_SHARED_RT.block_on(async {
1083 let client = MockApiClient { force_error: true };
1084
1085 let params = GetFiatPaymentsHistoryParams::builder("0".to_string())
1086 .build()
1087 .unwrap();
1088
1089 match client.get_fiat_payments_history(params).await {
1090 Ok(_) => panic!("Expected an error"),
1091 Err(err) => {
1092 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1093 }
1094 }
1095 });
1096 }
1097
1098 #[test]
1099 fn get_order_detail_required_params_success() {
1100 TOKIO_SHARED_RT.block_on(async {
1101 let client = MockApiClient { force_error: false };
1102
1103 let params = GetOrderDetailParams::builder("036752*678".to_string(),).build().unwrap();
1104
1105 let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"orderId":"036752*678","orderStatus":"ORDER_INITIAL","amount":"4.33","fee":"0.43","fiatCurrency":"***","errorCode":"","errorMessage":"","ext":{}}}"#).unwrap_or_else(|_| serde_json::json!({}));
1106 let expected_response : models::GetOrderDetailResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetOrderDetailResponse");
1107
1108 let resp = client.get_order_detail(params).await.expect("Expected a response");
1109 let data_future = resp.data();
1110 let actual_response = data_future.await.unwrap();
1111 assert_eq!(actual_response, expected_response);
1112 });
1113 }
1114
1115 #[test]
1116 fn get_order_detail_optional_params_success() {
1117 TOKIO_SHARED_RT.block_on(async {
1118 let client = MockApiClient { force_error: false };
1119
1120 let params = GetOrderDetailParams::builder("036752*678".to_string(),).recv_window(5000).build().unwrap();
1121
1122 let resp_json: Value = serde_json::from_str(r#"{"code":"000000","message":"success","data":{"orderId":"036752*678","orderStatus":"ORDER_INITIAL","amount":"4.33","fee":"0.43","fiatCurrency":"***","errorCode":"","errorMessage":"","ext":{}}}"#).unwrap_or_else(|_| serde_json::json!({}));
1123 let expected_response : models::GetOrderDetailResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetOrderDetailResponse");
1124
1125 let resp = client.get_order_detail(params).await.expect("Expected a response");
1126 let data_future = resp.data();
1127 let actual_response = data_future.await.unwrap();
1128 assert_eq!(actual_response, expected_response);
1129 });
1130 }
1131
1132 #[test]
1133 fn get_order_detail_response_error() {
1134 TOKIO_SHARED_RT.block_on(async {
1135 let client = MockApiClient { force_error: true };
1136
1137 let params = GetOrderDetailParams::builder("036752*678".to_string())
1138 .build()
1139 .unwrap();
1140
1141 match client.get_order_detail(params).await {
1142 Ok(_) => panic!("Expected an error"),
1143 Err(err) => {
1144 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1145 }
1146 }
1147 });
1148 }
1149}