1use crate::{
6 get_request, post_request, ChargeBody, Currency, Error, ExportTransactionResponse,
7 InitializeTransactionBody, PartialDebitTransactionBody, PaystackResult, Status,
8 TransactionResponse, TransactionStatusListResponse, TransactionStatusResponse,
9 TransactionTimelineResponse, TransactionTotalsResponse,
10};
11use reqwest::StatusCode;
12
13#[derive(Debug, Clone)]
15pub struct TransactionEndpoints<'a> {
16 api_key: &'a str,
18}
19
20static BASE_URL: &str = "https://api.paystack.co/transaction";
21
22impl<'a> TransactionEndpoints<'a> {
23 pub fn new(key: &'a str) -> TransactionEndpoints<'a> {
25 TransactionEndpoints { api_key: key }
26 }
27
28 pub async fn initialize_transaction(
32 &self,
33 transaction_body: InitializeTransactionBody,
34 ) -> PaystackResult<TransactionResponse> {
35 let url = format!("{}/initialize", BASE_URL);
36
37 match post_request(self.api_key, &url, transaction_body).await {
38 Ok(response) => match response.status() {
39 StatusCode::OK => match response.json::<TransactionResponse>().await {
40 Ok(content) => Ok(content),
41 Err(err) => Err(Error::Transaction(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 pub async fn verify_transaction(
57 &self,
58 reference: &str,
59 ) -> PaystackResult<TransactionStatusResponse> {
60 let url = format!("{}/verify/{}", BASE_URL, reference);
61
62 match get_request(self.api_key, &url, None).await {
63 Ok(response) => match response.status() {
64 StatusCode::OK => match response.json::<TransactionStatusResponse>().await {
65 Ok(content) => Ok(content),
66 Err(err) => Err(Error::Transaction(err.to_string())),
67 },
68 _ => Err(Error::RequestNotSuccessful(
69 response.status().to_string(),
70 response.text().await?,
71 )),
72 },
73 Err(err) => Err(Error::FailedRequest(err.to_string())),
74 }
75 }
76
77 pub async fn list_transactions(
84 &self,
85 number_of_transactions: Option<u32>,
86 status: Option<Status>,
87 ) -> PaystackResult<TransactionStatusListResponse> {
88 let url = format!("{}", BASE_URL);
89
90 let per_page = number_of_transactions.unwrap_or(10).to_string();
91 let status = status.unwrap_or(Status::Success).to_string();
92 let query = vec![("perPage", per_page.as_str()), ("status", status.as_str())];
93
94 match get_request(self.api_key, &url, Some(query)).await {
95 Ok(response) => match response.status() {
96 StatusCode::OK => match response.json::<TransactionStatusListResponse>().await {
97 Ok(content) => Ok(content),
98 Err(err) => Err(Error::Transaction(err.to_string())),
99 },
100 _ => Err(Error::RequestNotSuccessful(
101 response.status().to_string(),
102 response.text().await?,
103 )),
104 },
105 Err(err) => Err(Error::FailedRequest(err.to_string())),
106 }
107 }
108
109 pub async fn fetch_transactions(
113 &self,
114 transaction_id: u32,
115 ) -> PaystackResult<TransactionStatusResponse> {
116 let url = format!("{}/{}", BASE_URL, transaction_id);
117
118 match get_request(self.api_key, &url, None).await {
119 Ok(response) => match response.status() {
120 StatusCode::OK => match response.json::<TransactionStatusResponse>().await {
121 Ok(content) => Ok(content),
122 Err(err) => Err(Error::Transaction(err.to_string())),
123 },
124 _ => Err(Error::RequestNotSuccessful(
125 response.status().to_string(),
126 response.text().await?,
127 )),
128 },
129 Err(err) => Err(Error::FailedRequest(err.to_string())),
130 }
131 }
132
133 pub async fn charge_authorization(
137 &self,
138 charge: ChargeBody,
139 ) -> PaystackResult<TransactionStatusResponse> {
140 let url = format!("{}/charge_authorization", BASE_URL);
141
142 match post_request(self.api_key, &url, charge).await {
143 Ok(response) => match response.status() {
144 StatusCode::OK => match response.json::<TransactionStatusResponse>().await {
145 Ok(content) => Ok(content),
146 Err(err) => Err(Error::Charge(err.to_string())),
147 },
148 _ => Err(Error::RequestNotSuccessful(
149 response.status().to_string(),
150 response.text().await?,
151 )),
152 },
153 Err(err) => Err(Error::FailedRequest(err.to_string())),
154 }
155 }
156
157 pub async fn view_transaction_timeline(
161 &self,
162 id: Option<u32>,
163 reference: Option<&str>,
164 ) -> PaystackResult<TransactionTimelineResponse> {
165 let url: PaystackResult<String> = match (id, reference) {
168 (Some(id), None) => Ok(format!("{}/timeline/{}", BASE_URL, id)),
169 (None, Some(reference)) => Ok(format!("{}/timeline/{}", BASE_URL, &reference)),
170 _ => {
171 return Err(Error::Transaction(
172 "Transaction Id or Reference is need to view transaction timeline".to_string(),
173 ))
174 }
175 };
176
177 let url = url.unwrap(); match get_request(self.api_key, &url, None).await {
180 Ok(response) => match response.status() {
181 StatusCode::OK => match response.json::<TransactionTimelineResponse>().await {
182 Ok(content) => Ok(content),
183 Err(err) => Err(Error::Transaction(err.to_string())),
184 },
185 _ => Err(Error::RequestNotSuccessful(
186 response.status().to_string(),
187 response.text().await?,
188 )),
189 },
190 Err(err) => Err(Error::FailedRequest(err.to_string())),
191 }
192 }
193
194 pub async fn total_transactions(&self) -> PaystackResult<TransactionTotalsResponse> {
201 let url = format!("{}/totals", BASE_URL);
202
203 match get_request(self.api_key, &url, None).await {
204 Ok(response) => match response.status() {
205 StatusCode::OK => match response.json::<TransactionTotalsResponse>().await {
206 Ok(content) => Ok(content),
207 Err(err) => Err(Error::Transaction(err.to_string())),
208 },
209 _ => Err(Error::RequestNotSuccessful(
210 response.status().to_string(),
211 response.text().await?,
212 )),
213 },
214 Err(err) => Err(Error::FailedRequest(err.to_string())),
215 }
216 }
217
218 pub async fn export_transaction(
225 &self,
226 status: Option<Status>,
227 currency: Option<Currency>,
228 settled: Option<bool>,
229 ) -> PaystackResult<ExportTransactionResponse> {
230 let url = format!("{}/export", BASE_URL);
231
232 let settled = match settled {
234 Some(settled) => settled.to_string(),
235 None => String::from(""),
236 };
237
238 let status = status.unwrap_or(Status::Success).to_string();
239 let currency = currency.unwrap_or(Currency::EMPTY).to_string();
240
241 let query = vec![
242 ("status", status.as_str()),
243 ("currency", currency.as_str()),
244 ("settled", settled.as_str()),
245 ];
246
247 match get_request(self.api_key, &url, Some(query)).await {
248 Ok(response) => match response.status() {
249 StatusCode::OK => match response.json::<ExportTransactionResponse>().await {
250 Ok(content) => Ok(content),
251 Err(err) => Err(Error::Transaction(err.to_string())),
252 },
253 _ => Err(Error::RequestNotSuccessful(
254 response.status().to_string(),
255 response.text().await?,
256 )),
257 },
258 Err(err) => Err(Error::FailedRequest(err.to_string())),
259 }
260 }
261
262 pub async fn partial_debit(
268 &self,
269 transaction_body: PartialDebitTransactionBody,
270 ) -> PaystackResult<TransactionStatusResponse> {
271 let url = format!("{}/partial_debit", BASE_URL);
272
273 match post_request(self.api_key, &url, transaction_body).await {
274 Ok(response) => match response.status() {
275 StatusCode::OK => match response.json::<TransactionStatusResponse>().await {
276 Ok(content) => Ok(content),
277 Err(err) => Err(Error::Transaction(err.to_string())),
278 },
279 _ => Err(Error::RequestNotSuccessful(
280 response.status().to_string(),
281 response.text().await?,
282 )),
283 },
284 Err(err) => Err(Error::FailedRequest(err.to_string())),
285 }
286 }
287}