1use crate::{
6 ChargeRequest, ChargeResponseData, Currency, ExportTransactionData, HttpClient,
7 PartialDebitTransactionRequest, PaystackAPIError, PaystackResult, Response, Status,
8 TransactionIdentifier, TransactionRequest, TransactionResponseData, TransactionStatusData,
9 TransactionTimelineData, TransactionTotalData,
10};
11use std::sync::Arc;
12
13#[derive(Debug, Clone)]
15pub struct TransactionEndpoints<T: HttpClient + Default> {
16 key: String,
18 base_url: String,
20 http: Arc<T>,
22}
23
24impl<T: HttpClient + Default> TransactionEndpoints<T> {
25 pub fn new(key: Arc<String>, http: Arc<T>) -> TransactionEndpoints<T> {
27 let base_url = String::from("https://api.paystack.co/transaction");
28 TransactionEndpoints {
29 key: key.to_string(),
30 base_url,
31 http,
32 }
33 }
34
35 pub async fn initialize_transaction(
39 &self,
40 transaction_request: TransactionRequest,
41 ) -> PaystackResult<TransactionResponseData> {
42 let url = format!("{}/initialize", self.base_url);
43 let body = serde_json::to_value(transaction_request)
44 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
45
46 let response = self.http.post(&url, &self.key, &body).await;
47
48 match response {
49 Ok(response) => {
50 let parsed_response: Response<TransactionResponseData> =
51 serde_json::from_str(&response)
52 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
53 Ok(parsed_response)
54 }
55 Err(e) => {
56 Err(PaystackAPIError::Transaction(e.to_string()))
58 }
59 }
60 }
61
62 pub async fn verify_transaction(
67 &self,
68 reference: &str,
69 ) -> PaystackResult<TransactionStatusData> {
70 let url = format!("{}/verify/{}", self.base_url, reference);
71
72 let response = self.http.get(&url, &self.key, None).await;
73
74 match response {
75 Ok(response) => {
76 let parsed_response: Response<TransactionStatusData> =
77 serde_json::from_str(&response)
78 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
79
80 Ok(parsed_response)
81 }
82 Err(e) => Err(PaystackAPIError::Transaction(e.to_string())),
83 }
84 }
85
86 pub async fn list_transactions(
93 &self,
94 per_page: Option<u32>,
95 status: Option<Status>,
96 ) -> PaystackResult<Vec<TransactionStatusData>> {
97 let url = self.base_url.to_string();
98
99 let per_page = per_page.unwrap_or(10).to_string();
100 let status = status.unwrap_or(Status::Success).to_string();
101 let query = vec![("perPage", per_page.as_str()), ("status", status.as_str())];
102
103 let response = self.http.get(&url, &self.key, Some(&query)).await;
104
105 match response {
106 Ok(response) => {
107 let parsed_response: Response<Vec<TransactionStatusData>> =
108 serde_json::from_str(&response)
109 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
110
111 Ok(parsed_response)
112 }
113 Err(e) => Err(PaystackAPIError::Transaction(e.to_string())),
114 }
115 }
116
117 pub async fn fetch_transactions(
121 &self,
122 transaction_id: u64,
123 ) -> PaystackResult<TransactionStatusData> {
124 let url = format!("{}/{}", self.base_url, transaction_id);
125
126 let response = self.http.get(&url, &self.key, None).await;
127
128 match response {
129 Ok(response) => {
130 let parsed_response: Response<TransactionStatusData> =
131 serde_json::from_str(&response)
132 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
133
134 Ok(parsed_response)
135 }
136 Err(e) => Err(PaystackAPIError::Transaction(e.to_string())),
137 }
138 }
139
140 pub async fn charge_authorization(
144 &self,
145 charge_request: ChargeRequest,
146 ) -> PaystackResult<ChargeResponseData> {
147 let url = format!("{}/charge_authorization", self.base_url);
148 let body = serde_json::to_value(charge_request)
149 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
150
151 let response = self.http.post(&url, &self.key, &body).await;
152
153 match response {
154 Ok(response) => {
155 let parsed_response: Response<ChargeResponseData> = serde_json::from_str(&response)
156 .map_err(|e| PaystackAPIError::Charge(e.to_string()))?;
157
158 Ok(parsed_response)
159 }
160 Err(e) => Err(PaystackAPIError::Transaction(e.to_string())),
161 }
162 }
163
164 pub async fn view_transaction_timeline(
168 &self,
169 identifier: TransactionIdentifier,
170 ) -> PaystackResult<TransactionTimelineData> {
171 let url = match identifier {
174 TransactionIdentifier::Id(id) => Ok(format!("{}/timeline/{}", self.base_url, id)),
175 TransactionIdentifier::Reference(reference) => {
176 Ok(format!("{}/timeline/{}", self.base_url, &reference))
177 }
178 }?; let response = self.http.get(&url, &self.key, None).await;
181
182 match response {
183 Ok(response) => {
184 let parsed_response: Response<TransactionTimelineData> =
185 serde_json::from_str(&response)
186 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
187
188 Ok(parsed_response)
189 }
190 Err(e) => Err(PaystackAPIError::Transaction(e.to_string())),
191 }
192 }
193
194 pub async fn total_transactions(&self) -> PaystackResult<TransactionTotalData> {
201 let url = format!("{}/totals", self.base_url);
202
203 let response = self.http.get(&url, &self.key, None).await;
204
205 match response {
206 Ok(response) => {
207 let parsed_response: Response<TransactionTotalData> =
208 serde_json::from_str(&response)
209 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
210
211 Ok(parsed_response)
212 }
213 Err(e) => Err(PaystackAPIError::Transaction(e.to_string())),
214 }
215 }
216
217 pub async fn export_transaction(
224 &self,
225 status: Option<Status>,
226 currency: Option<Currency>,
227 settled: Option<bool>,
228 ) -> PaystackResult<ExportTransactionData> {
229 let url = format!("{}/export", self.base_url);
230
231 let settled = match settled {
233 Some(settled) => settled.to_string(),
234 None => String::from(""),
235 };
236
237 let status = status.unwrap_or(Status::Success).to_string();
238 let currency = currency.unwrap_or(Currency::NGN).to_string();
239
240 let query = vec![
241 ("status", status.as_str()),
242 ("currency", currency.as_str()),
243 ("settled", settled.as_str()),
244 ];
245
246 let response = self.http.get(&url, &self.key, Some(&query)).await;
247
248 match response {
249 Ok(response) => {
250 let parsed_response = serde_json::from_str(&response)
251 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
252
253 Ok(parsed_response)
254 }
255 Err(e) => Err(PaystackAPIError::Transaction(e.to_string())),
256 }
257 }
258
259 pub async fn partial_debit(
265 &self,
266 partial_debit_transaction_request: PartialDebitTransactionRequest,
267 ) -> PaystackResult<TransactionStatusData> {
268 let url = format!("{}/partial_debit", self.base_url);
269 let body = serde_json::to_value(partial_debit_transaction_request)
270 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
271
272 let response = self.http.post(&url, &self.key, &body).await;
273
274 match response {
275 Ok(response) => {
276 let parsed_response: Response<TransactionStatusData> =
277 serde_json::from_str(&response)
278 .map_err(|e| PaystackAPIError::Transaction(e.to_string()))?;
279
280 Ok(parsed_response)
281 }
282 Err(e) => Err(PaystackAPIError::Transaction(e.to_string())),
283 }
284 }
285}