paystack/endpoints/
terminal.rs

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