paystack/endpoints/
terminal.rs

1//! Terminal
2//! ========
3//! The Terminal API allows you to build delightful in-person payment experiences.
4
5use crate::{
6    get_request, post_request, put_request, Error, FetchEventStatusResponse, FetchTerminalResponse,
7    FetchTerminalStatusResponse, PaystackResult, SendEventBody, SendEventResponse,
8    TerminalResponseWithNoData, UpdateTerminalBody,
9};
10use reqwest::StatusCode;
11use serde::Serialize;
12
13/// A Struct to hold all the functions of the terminal API route
14#[derive(Debug, Clone)]
15pub struct TerminalEndpoints<'a> {
16    api_key: &'a str,
17}
18
19static BASE_URL: &str = "https://api.paystack.co/terminal";
20
21impl<'a> TerminalEndpoints<'a> {
22    /// Constructor for the terminal object
23    pub fn new(key: &'a str) -> TerminalEndpoints<'a> {
24        TerminalEndpoints { api_key: key }
25    }
26
27    /// Send an event from your application to the Paystack Terminal
28    ///
29    /// It takes a SendEventBody type as its parameter
30    pub async fn send_event(
31        &self,
32        terminal_id: &str,
33        event_body: SendEventBody,
34    ) -> PaystackResult<SendEventResponse> {
35        let url = format!("{}/{}/event", BASE_URL, terminal_id);
36
37        match post_request(self.api_key, &url, event_body).await {
38            Ok(response) => match response.status() {
39                StatusCode::OK => match response.json::<SendEventResponse>().await {
40                    Ok(content) => Ok(content),
41                    Err(err) => Err(Error::Terminal(err.to_string())),
42                },
43                _ => Err(Error::RequestNotSuccessful(
44                    response.status().to_string(),
45                    response.text().await?,
46                )),
47            },
48            Err(err) => Err(Error::FailedRequest(err.to_string())),
49        }
50    }
51
52    /// Check the status of an event sent to the Terminal
53    ///
54    /// - terminal_id: The ID of the Terminal the event was sent to.
55    /// - event_id: The ID of the event that was sent to the Terminal.
56    pub async fn fetch_event_status(
57        &self,
58        terminal_id: &str,
59        event_id: &str,
60    ) -> PaystackResult<FetchEventStatusResponse> {
61        let url = format!("{}/{}/event/{}", BASE_URL, terminal_id, event_id);
62
63        match get_request(self.api_key, &url, None).await {
64            Ok(response) => match response.status() {
65                StatusCode::OK => match response.json::<FetchEventStatusResponse>().await {
66                    Ok(content) => Ok(content),
67                    Err(err) => Err(Error::Terminal(err.to_string())),
68                },
69                _ => Err(Error::RequestNotSuccessful(
70                    response.status().to_string(),
71                    response.text().await?,
72                )),
73            },
74            Err(err) => Err(Error::FailedRequest(err.to_string())),
75        }
76    }
77
78    /// Check the availability of a Terminal before sending an event to it
79    ///
80    /// - terminal_id: The ID of the Terminal you want to check
81    pub async fn fetch_terminal_status(
82        &self,
83        terminal_id: &str,
84    ) -> PaystackResult<FetchTerminalStatusResponse> {
85        let url = format!("{}/{}/presence", BASE_URL, terminal_id);
86
87        match get_request(self.api_key, &url, None).await {
88            Ok(response) => match response.status() {
89                StatusCode::OK => match response.json::<FetchTerminalStatusResponse>().await {
90                    Ok(content) => Ok(content),
91                    Err(err) => Err(Error::Terminal(err.to_string())),
92                },
93                _ => Err(Error::RequestNotSuccessful(
94                    response.status().to_string(),
95                    response.text().await?,
96                )),
97            },
98            Err(err) => Err(Error::FailedRequest(err.to_string())),
99        }
100    }
101
102    /// Get the details of a Terminal
103    ///
104    ///- terminal_id: The ID of the Terminal the event was sent to.
105    pub async fn fetch_terminal(&self, terminal_id: &str) -> PaystackResult<FetchTerminalResponse> {
106        let url = format!("{}/{}", BASE_URL, terminal_id);
107
108        match get_request(self.api_key, &url, None).await {
109            Ok(response) => match response.status() {
110                StatusCode::OK => match response.json::<FetchTerminalResponse>().await {
111                    Ok(content) => Ok(content),
112                    Err(err) => Err(Error::Terminal(err.to_string())),
113                },
114                _ => Err(Error::RequestNotSuccessful(
115                    response.status().to_string(),
116                    response.text().await?,
117                )),
118            },
119            Err(err) => Err(Error::FailedRequest(err.to_string())),
120        }
121    }
122
123    /// Update the details of a Terminal
124    pub async fn update_terminal(
125        &self,
126        terminal_id: &str,
127        update_terminal_body: UpdateTerminalBody,
128    ) -> PaystackResult<TerminalResponseWithNoData> {
129        let url = format!("{}/{}", BASE_URL, terminal_id);
130
131        match put_request(self.api_key, &url, update_terminal_body).await {
132            Ok(response) => match response.status() {
133                StatusCode::OK => match response.json::<TerminalResponseWithNoData>().await {
134                    Ok(content) => Ok(content),
135                    Err(err) => Err(Error::Terminal(err.to_string())),
136                },
137                _ => Err(Error::RequestNotSuccessful(
138                    response.status().to_string(),
139                    response.text().await?,
140                )),
141            },
142            Err(err) => Err(Error::FailedRequest(err.to_string())),
143        }
144    }
145
146    /// Activate your debug device by linking it to your integration.
147    ///
148    /// - serial_number: Device Serial Number.
149    pub async fn commission_terminal(
150        &self,
151        serial_number: &str,
152    ) -> PaystackResult<TerminalResponseWithNoData> {
153        let url = format!("{}/commission_device", BASE_URL);
154
155        let commission_body = Body {
156            serial_number: serial_number.to_string(),
157        };
158
159        match post_request(self.api_key, &url, commission_body).await {
160            Ok(response) => match response.status() {
161                StatusCode::OK => match response.json::<TerminalResponseWithNoData>().await {
162                    Ok(content) => Ok(content),
163                    Err(err) => Err(Error::Terminal(err.to_string())),
164                },
165                _ => Err(Error::RequestNotSuccessful(
166                    response.status().to_string(),
167                    response.text().await?,
168                )),
169            },
170            Err(err) => Err(Error::FailedRequest(err.to_string())),
171        }
172    }
173
174    /// Unlink your debug device from your integration
175    ///
176    /// - serial_number: Device Serial Number.
177    pub async fn decommission_terminal(
178        &self,
179        serial_number: &str,
180    ) -> PaystackResult<TerminalResponseWithNoData> {
181        let url = format!("{}/decommission_device", BASE_URL);
182
183        let decommission_body = Body {
184            serial_number: serial_number.to_string(),
185        };
186
187        match post_request(self.api_key, &url, decommission_body).await {
188            Ok(response) => match response.status() {
189                StatusCode::OK => match response.json::<TerminalResponseWithNoData>().await {
190                    Ok(content) => Ok(content),
191                    Err(err) => Err(Error::Terminal(err.to_string())),
192                },
193                _ => Err(Error::RequestNotSuccessful(
194                    response.status().to_string(),
195                    response.text().await?,
196                )),
197            },
198            Err(err) => Err(Error::FailedRequest(err.to_string())),
199        }
200    }
201}
202
203/// creating body here because it is redundant to create a dedicated type for this.
204/// This body is used for the commission and decommission route.
205#[derive(Serialize, Clone, Debug)]
206struct Body {
207    serial_number: String,
208}