1use super::PAYSTACK_BASE_URL;
6use crate::{
7 ChargeRequest, ChargeResponseData, Currency, ExportTransactionData, HttpClient,
8 PartialDebitTransactionRequest, PaystackAPIError, PaystackResult, Response, Status,
9 TransactionIdentifier, TransactionRequest, TransactionResponseData, TransactionStatusData,
10 TransactionTimelineData, TransactionTotalData,
11};
12use std::sync::Arc;
13
14#[derive(Debug, Clone)]
16pub struct TransactionEndpoints<T: HttpClient + Default> {
17 key: String,
19 base_url: String,
21 http: Arc<T>,
23}
24
25impl<T: HttpClient + Default> TransactionEndpoints<T> {
26 pub fn new(key: Arc<String>, http: Arc<T>) -> TransactionEndpoints<T> {
35 let base_url = format!("{PAYSTACK_BASE_URL}/transaction");
36 TransactionEndpoints {
37 key: key.to_string(),
38 base_url,
39 http,
40 }
41 }
42
43 pub async fn initialize_transaction(
52 &self,
53 transaction_request: TransactionRequest,
54 ) -> PaystackResult<TransactionResponseData> {
55 let url = format!("{}/initialize", self.base_url);
56 let body = serde_json::to_value(transaction_request)
57 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
58
59 let response = self
60 .http
61 .post(&url, &self.key, &body)
62 .await
63 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
64
65 let parsed_response: Response<TransactionResponseData> = serde_json::from_str(&response)
66 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
67 Ok(parsed_response)
68 }
69
70 pub async fn verify_transaction(
78 &self,
79 reference: &str,
80 ) -> PaystackResult<TransactionStatusData> {
81 let url = format!("{}/verify/{}", self.base_url, reference);
82
83 let response = self
84 .http
85 .get(&url, &self.key, None)
86 .await
87 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
88
89 let parsed_response: Response<TransactionStatusData> = serde_json::from_str(&response)
90 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
91
92 Ok(parsed_response)
93 }
94
95 pub async fn list_transactions(
104 &self,
105 per_page: Option<u32>,
106 status: Option<Status>,
107 ) -> PaystackResult<Vec<TransactionStatusData>> {
108 let url = &self.base_url;
109
110 let per_page = per_page.unwrap_or(10).to_string();
111 let status = status.unwrap_or(Status::Success).to_string();
112 let query = vec![("perPage", per_page.as_str()), ("status", status.as_str())];
113
114 let response = self
115 .http
116 .get(url, &self.key, Some(&query))
117 .await
118 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
119
120 let parsed_response: Response<Vec<TransactionStatusData>> = serde_json::from_str(&response)
121 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
122
123 Ok(parsed_response)
124 }
125
126 pub async fn fetch_transactions(
134 &self,
135 transaction_id: u64,
136 ) -> PaystackResult<TransactionStatusData> {
137 let url = format!("{}/{}", self.base_url, transaction_id);
138
139 let response = self
140 .http
141 .get(&url, &self.key, None)
142 .await
143 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
144
145 let parsed_response: Response<TransactionStatusData> = serde_json::from_str(&response)
146 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
147
148 Ok(parsed_response)
149 }
150
151 pub async fn charge_authorization(
160 &self,
161 charge_request: ChargeRequest,
162 ) -> PaystackResult<ChargeResponseData> {
163 let url = format!("{}/charge_authorization", self.base_url);
164 let body = serde_json::to_value(charge_request)
165 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
166
167 let response = self
168 .http
169 .post(&url, &self.key, &body)
170 .await
171 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
172
173 let parsed_response: Response<ChargeResponseData> =
174 serde_json::from_str(&response).map_err(|e| PaystackAPIError::Charge(e.to_string()))?;
175
176 Ok(parsed_response)
177 }
178
179 pub async fn view_transaction_timeline(
187 &self,
188 identifier: TransactionIdentifier,
189 ) -> PaystackResult<TransactionTimelineData> {
190 let url = match identifier {
193 TransactionIdentifier::Id(id) => Ok(format!("{}/timeline/{}", self.base_url, id)),
194 TransactionIdentifier::Reference(reference) => {
195 Ok(format!("{}/timeline/{}", self.base_url, &reference))
196 }
197 }?; let response = self
200 .http
201 .get(&url, &self.key, None)
202 .await
203 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
204
205 let parsed_response: Response<TransactionTimelineData> = serde_json::from_str(&response)
206 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
207
208 Ok(parsed_response)
209 }
210
211 pub async fn total_transactions(&self) -> PaystackResult<TransactionTotalData> {
216 let url = format!("{}/totals", self.base_url);
217
218 let response = self
219 .http
220 .get(&url, &self.key, None)
221 .await
222 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
223
224 let parsed_response: Response<TransactionTotalData> = serde_json::from_str(&response)
225 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
226
227 Ok(parsed_response)
228 }
229
230 pub async fn export_transaction(
240 &self,
241 status: Option<Status>,
242 currency: Option<Currency>,
243 settled: Option<bool>,
244 ) -> PaystackResult<ExportTransactionData> {
245 let url = format!("{}/export", self.base_url);
246
247 let settled = match settled {
249 Some(settled) => settled.to_string(),
250 None => String::from(""),
251 };
252
253 let status = status.unwrap_or(Status::Success).to_string();
254 let currency = currency.unwrap_or(Currency::NGN).to_string();
255
256 let query = vec![
257 ("status", status.as_str()),
258 ("currency", currency.as_str()),
259 ("settled", settled.as_str()),
260 ];
261
262 let response = self
263 .http
264 .get(&url, &self.key, Some(&query))
265 .await
266 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
267
268 let parsed_response = serde_json::from_str(&response)
269 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
270
271 Ok(parsed_response)
272 }
273
274 pub async fn partial_debit(
283 &self,
284 partial_debit_transaction_request: PartialDebitTransactionRequest,
285 ) -> PaystackResult<TransactionStatusData> {
286 let url = format!("{}/partial_debit", self.base_url);
287 let body = serde_json::to_value(partial_debit_transaction_request)
288 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
289
290 let response = self
291 .http
292 .post(&url, &self.key, &body)
293 .await
294 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
295
296 let parsed_response: Response<TransactionStatusData> = serde_json::from_str(&response)
297 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
298
299 Ok(parsed_response)
300 }
301}