paystack/endpoints/
terminal.rs

1//! Terminal
2//! ========
3//! The Terminal API allows you to build delightful in-person payment experiences.
4
5use std::{marker::PhantomData, sync::Arc};
6
7use crate::{
8    EventRequest, FetchEventStatusResponseData, FetchTerminalStatusResponseData, HttpClient,
9    PaystackAPIError, PaystackResult, Response, SendEventResponseData, TerminalData,
10    UpdateTerminalRequest,
11};
12
13/// A struct to hold all the functions of the terminal API endpoint
14#[derive(Debug, Clone)]
15pub struct TerminalEndpoints<T: HttpClient + Default> {
16    /// Paystack API Key
17    key: String,
18    /// Base URL for the transaction route
19    base_url: String,
20    /// Http client for the route
21    http: Arc<T>,
22}
23
24impl<T: HttpClient + Default> TerminalEndpoints<T> {
25    /// Constructor
26    pub fn new(key: Arc<String>, http: Arc<T>) -> TerminalEndpoints<T> {
27        let base_url = String::from("https://api.paystack.co/terminal");
28        TerminalEndpoints {
29            key: key.to_string(),
30            base_url,
31            http,
32        }
33    }
34
35    /// Send an event from your application to the Paystack Terminal
36    ///
37    /// Takes in the following:
38    ///     - `terminal_id`: The ID of the Terminal the event should be sent to.
39    ///     - `EventRequest`: A struct containing the information of the event to send to the terminal. It is created with the `EventRequestBuilder`.
40    pub async fn send_event(
41        &self,
42        terminal_id: String,
43        event_request: EventRequest,
44    ) -> PaystackResult<SendEventResponseData> {
45        let url = format!("{}/{}/event", self.base_url, terminal_id);
46        let body = serde_json::to_value(event_request)
47            .map_err(|e| PaystackAPIError::Terminal(e.to_string()))?;
48
49        let response = self.http.post(&url, &self.key, &body).await;
50
51        match response {
52            Ok(response) => {
53                let parsed_response: Response<SendEventResponseData> =
54                    serde_json::from_str(&response)
55                        .map_err(|e| PaystackAPIError::Terminal(e.to_string()))?;
56
57                Ok(parsed_response)
58            }
59            Err(e) => Err(PaystackAPIError::Terminal(e.to_string())),
60        }
61    }
62
63    /// Check the status of an event sent to the Paystack Terminal
64    ///
65    /// Takes in the following:
66    ///     - `terminal_id`: The ID of the Terminal the event was sent to.
67    ///     - `event_id`: The ID of the event that was sent to the Terminal.
68    pub async fn fetch_event_status(
69        &self,
70        terminal_id: String,
71        event_id: String,
72    ) -> PaystackResult<FetchEventStatusResponseData> {
73        let url = format!("{}/{}/event/{}", self.base_url, terminal_id, event_id);
74
75        let response = self.http.get(&url, &self.key, None).await;
76
77        match response {
78            Ok(response) => {
79                let parsed_response: Response<FetchEventStatusResponseData> =
80                    serde_json::from_str(&response)
81                        .map_err(|e| PaystackAPIError::Terminal(e.to_string()))?;
82
83                Ok(parsed_response)
84            }
85            Err(e) => Err(PaystackAPIError::Terminal(e.to_string())),
86        }
87    }
88
89    /// Check the availiability of a Terminal before sending an event to it
90    ///
91    /// Takes in the following:
92    ///     - `terminal_id`: The ID of the Terminal you want to check.
93    pub async fn fetch_terminal_status(
94        &self,
95        terminal_id: String,
96    ) -> PaystackResult<FetchTerminalStatusResponseData> {
97        let url = format!("{}/{}/presence", self.base_url, terminal_id);
98
99        let response = self.http.get(&url, &self.key, None).await;
100
101        match response {
102            Ok(response) => {
103                let parsed_response: Response<FetchTerminalStatusResponseData> =
104                    serde_json::from_str(&response)
105                        .map_err(|e| PaystackAPIError::Terminal(e.to_string()))?;
106
107                Ok(parsed_response)
108            }
109            Err(e) => Err(PaystackAPIError::Terminal(e.to_string())),
110        }
111    }
112
113    /// List the Terminals available on your integration
114    ///
115    /// Takes in the following:
116    ///     - `per_page`: Specify how many records you want retrieved. Defaults to a value of 50
117    pub async fn list_terminals(&self, per_page: Option<i32>) -> PaystackResult<Vec<TerminalData>> {
118        let url = format!("{}", self.base_url);
119        let per_page = per_page.unwrap_or(50).to_string();
120        let query = vec![("perPage", per_page.as_str())];
121
122        let response = self.http.get(&url, &self.key, Some(&query)).await;
123
124        match response {
125            Ok(response) => {
126                let parsed_response: Response<Vec<TerminalData>> = serde_json::from_str(&response)
127                    .map_err(|e| PaystackAPIError::Terminal(e.to_string()))?;
128
129                Ok(parsed_response)
130            }
131            Err(e) => Err(PaystackAPIError::Terminal(e.to_string())),
132        }
133    }
134
135    /// Get the details of a Terminal
136    ///
137    /// Takes in the following:
138    ///     - `terminal_id`: The ID of the Terminal the event was sent to.
139    pub async fn fetch_terminal(&self, terminal_id: String) -> PaystackResult<TerminalData> {
140        let url = format!("{}/{}", self.base_url, terminal_id);
141
142        let response = self.http.get(&url, &self.key, None).await;
143
144        match response {
145            Ok(response) => {
146                let parsed_response: Response<TerminalData> = serde_json::from_str(&response)
147                    .map_err(|e| PaystackAPIError::Terminal(e.to_string()))?;
148
149                Ok(parsed_response)
150            }
151            Err(e) => Err(PaystackAPIError::Terminal(e.to_string())),
152        }
153    }
154
155    /// Update the details of a Terminal.
156    ///
157    /// Takes in the following:
158    ///     - `terminal_id`: The ID of the Terminal you want to update.
159    ///     - `UpdateTerminalRequest`: Contains the datails to be updated in the terminal. Should be constructed using the `UpdateTerminalRequestBuilder`
160    ///
161    /// NB: The generic for the result here is a `String`, because there is no data field in the response from the API.
162    /// The string will be ignored because the underlying `data` field in the `response` is an `Option`.
163    pub async fn update_terminal(
164        &self,
165        terminal_id: String,
166        update_request: UpdateTerminalRequest,
167    ) -> PaystackResult<PhantomData<String>> {
168        let url = format!("{}/{}", self.base_url, terminal_id);
169        let body = serde_json::to_value(update_request)
170            .map_err(|e| PaystackAPIError::Terminal(e.to_string()))?;
171
172        let response = self.http.put(&url, &self.key, &body).await;
173
174        match response {
175            Ok(response) => {
176                let parsed_response: Response<PhantomData<String>> =
177                    serde_json::from_str(&response)
178                        .map_err(|e| PaystackAPIError::Terminal(e.to_string()))?;
179
180                Ok(parsed_response)
181            }
182            Err(e) => Err(PaystackAPIError::Terminal(e.to_string())),
183        }
184    }
185
186    /// Activate your debug device by linking it to your integration
187    ///
188    /// Take in the following:
189    ///     - `serial_number`: The device serial number
190    /// NB: The generic for the result here is a `String`, because there is no data field in the response from the API.
191    /// The string will be ignored because the underlying `data` field in the `response` is an `Option`.
192    pub async fn commission_terminal(
193        &self,
194        serial_number: String,
195    ) -> PaystackResult<PhantomData<String>> {
196        let url = format!("{}/commission_device", self.base_url);
197        let body = serde_json::json!({
198            "serial_number": serial_number
199        });
200
201        let response = self.http.post(&url, &self.key, &body).await;
202
203        match response {
204            Ok(response) => {
205                let parsed_response: Response<PhantomData<String>> =
206                    serde_json::from_str(&response)
207                        .map_err(|e| PaystackAPIError::Terminal(e.to_string()))?;
208
209                Ok(parsed_response)
210            }
211            Err(e) => Err(PaystackAPIError::Terminal(e.to_string())),
212        }
213    }
214
215    /// Unlink your debug device from your integration
216    ///
217    /// Take in the following:
218    ///     - `serial_number`: The device serial number
219    /// NB: The generic for the result here is a `String`, because there is no data field in the response from the API.
220    /// The string will be ignored because the underlying `data` field in the `response` is an `Option`.
221    pub async fn decommission_terminal(
222        &self,
223        serial_number: String,
224    ) -> PaystackResult<PhantomData<String>> {
225        let url = format!("{}/decommission_device", self.base_url);
226        let body = serde_json::json!({
227            "serial_number": serial_number
228        });
229
230        let response = self.http.post(&url, &self.key, &body).await;
231
232        match response {
233            Ok(response) => {
234                let parsed_response: Response<PhantomData<String>> =
235                    serde_json::from_str(&response)
236                        .map_err(|e| PaystackAPIError::Terminal(e.to_string()))?;
237
238                Ok(parsed_response)
239            }
240            Err(e) => Err(PaystackAPIError::Terminal(e.to_string())),
241        }
242    }
243}