paystack/models/
transaction.rs

1//! Transactions Models
2//! ====================
3
4use derive_builder::Builder;
5use serde::{Deserialize, Serialize};
6
7use crate::{Authorization, Channel, Currency, CustomerResponseData};
8
9/// This struct is used to create a transaction body for creating a transaction using the Paystack API.
10/// This struct is built using the `TransactionRequestBuilder` struct.
11#[derive(Clone, Default, Debug, Serialize, Builder)]
12pub struct TransactionRequest {
13    /// Amount should be in the subunit of the supported currency
14    pub amount: String,
15    /// Customer's email address
16    pub email: String,
17    // optional parameters from here on
18    /// The transaction currency. Defaults to your integration currency.
19    #[builder(setter(strip_option), default)]
20    pub currency: Option<Currency>,
21    /// Unique transaction reference. Only `-`, `.`, `=` and alphanumeric characters allowed.
22    #[builder(setter(strip_option), default)]
23    pub reference: Option<String>,
24    /// Fully qualified url, e.g. https://example.com/ . Use this to override the callback url provided on the dashboard for this transaction
25    #[builder(setter(strip_option), default)]
26    pub callback_url: Option<String>,
27    /// If transaction is to create a subscription to a predefined plan, provide plan code here. This would invalidate the value provided in `amount`
28    #[builder(setter(strip_option), default)]
29    pub plan: Option<String>,
30    /// Number of times to charge customer during subscription to plan
31    #[builder(setter(strip_option), default)]
32    pub invoice_limit: Option<u8>,
33    /// Stringified JSON object of custom data. Kindly check the Metadata page for more information.
34    #[builder(setter(strip_option), default)]
35    pub metadata: Option<String>,
36    /// An array of payment channels to control what channels you want to make available to the user to make a payment with.
37    #[builder(setter(strip_option), default)]
38    pub channel: Option<Vec<Channel>>,
39    /// The split code of the transaction split. e.g. `SPL_98WF13Eb3w`
40    #[builder(setter(strip_option), default)]
41    pub split_code: Option<String>,
42    /// The code for the subaccount that owns the payment. e.g. `ACCT_8f4s1eq7ml6rlzj`
43    #[builder(setter(strip_option), default)]
44    pub subaccount: Option<String>,
45    /// An amount used to override the split configuration for a single split payment.
46    /// If set, the amount specified goes to the main account regardless of the split configuration.
47    #[builder(setter(strip_option), default)]
48    pub transaction_charge: Option<String>,
49    /// Use this param to indicate who bears the transaction charges. Allowed values are: `account` or `subaccount` (defaults to `account`).
50    #[builder(setter(strip_option), default)]
51    pub bearer: Option<String>,
52}
53
54/// This struct is used to create a partial debit transaction body for creating a partial debit using the Paystack API.
55/// This struct should be created using the `PartialDebitTransactionRequestBuilder`
56/// The derive Builder allows for the automatic creation of the BuilderPattern
57#[derive(Debug, Clone, Serialize, Default, Builder)]
58pub struct PartialDebitTransactionRequest {
59    /// Authorization Code
60    authorization_code: String,
61    /// Specify the currency you want to debit. Allowed values are NGN or GHS.
62    currency: Currency,
63    /// Amount should be in the subunit of the supported currency
64    amount: String,
65    /// Customer's email address (attached to the authorization code)
66    email: String,
67    /// Unique transaction reference. Only `-`, `.`, `=` and alphanumeric characters allowed.
68    #[builder(default)]
69    reference: Option<String>,
70    /// Minimum amount to charge
71    #[builder(default)]
72    at_least: Option<String>,
73}
74
75/// This struct represents the data of the transaction response.
76#[derive(Deserialize, Debug, Clone, Default)]
77pub struct TransactionResponseData {
78    /// Generated URL to authorize the transaction.
79    pub authorization_url: String,
80    /// Access code of the transaction.
81    pub access_code: String,
82    /// Reference of the transaction.
83    pub reference: String,
84}
85
86/// This struct represents the data of the transaction status response.
87#[derive(Deserialize, Serialize, Debug, Clone, Default)]
88pub struct TransactionStatusData {
89    /// Id of the Transaction
90    pub id: u64,
91    /// Status of the Transaction. It can be `success`, `abandoned` or `failed`
92    pub status: String,
93    /// Reference of the Transaction
94    pub reference: String,
95    /// Amount of the transaction in the lowest denomination of the currency e.g. Kobo for NGN and cent for USD.
96    pub amount: u32,
97    /// Message from the transaction.
98    pub message: Option<String>,
99    /// Response from the payment gateway.
100    pub gateway_response: String,
101    /// Time the Transaction was completed.
102    pub paid_at: Option<String>,
103    /// Time the Transaction was created.
104    pub created_at: String,
105    /// Transaction channel. It can be `card` or `bank`.
106    pub channel: String,
107    /// Currency code of the Transaction e.g. `NGN for Nigerian Naira` and `USD for US Dollar`.
108    pub currency: String,
109    /// IP address of the computers the Transaction has passed through.
110    pub ip_address: Option<String>,
111    /// Meta data associated with the Transaction.
112    pub metadata: Option<String>,
113    /// Transaction fees to override the default fees specified in the integration.
114    pub fees: Option<i32>,
115    /// Transaction customer data.
116    pub customer: CustomerResponseData,
117    /// Transaction authorization data.
118    pub authorization: Authorization,
119}
120
121/// This struct represents the transaction timeline data.
122#[derive(Deserialize, Serialize, Debug, Clone, Default)]
123pub struct TransactionTimelineData {
124    /// Time spent in carrying out the transaction in ms.
125    pub time_spent: Option<u32>,
126    /// Number of attempts for the transaction.
127    pub attempts: Option<u32>,
128    /// Authentication use for the transaction.
129    pub authentication: Option<String>,
130    /// Number of errors for the transaction.
131    pub errors: Option<u32>,
132    /// Success status of the transaction.
133    pub success: Option<bool>,
134    /// If transaction was carried out with mobile.
135    pub mobile: Option<bool>,
136    /// Transaction inputs i.e. messages associated with the transaction.
137    pub input: Option<String>,
138    /// Transaction channel.
139    pub channel: Option<String>,
140    /// Transaction history.
141    pub history: Option<Vec<TransactionHistoryResponse>>,
142}
143
144/// This struct represents the transaction history data
145#[derive(Deserialize, Serialize, Debug, Clone)]
146pub struct TransactionHistoryResponse {
147    /// Transaction action.
148    #[serde(rename = "type")]
149    pub action_type: String,
150    /// Description of the action.
151    pub message: String,
152    /// Time action was taken in ms.
153    pub time: u32,
154}
155
156/// Transaction total data.
157#[derive(Debug, Deserialize, Serialize, Default)]
158pub struct TransactionTotalData {
159    /// Total number of transactions in the integration.
160    pub total_transactions: Option<u32>,
161    /// Total of unique number of customers in the integration.
162    pub unique_customers: Option<u32>,
163    /// Total volume of transaction in the integration.
164    pub total_volume: Option<u32>,
165    /// Total volume of transaction broken down by currency.
166    pub total_volume_by_currency: Option<Vec<VolumeByCurrency>>,
167    /// Total volume of pending transfers.
168    pub pending_transfers: Option<u32>,
169    /// Total volume of pending transfer broken down by currency.
170    pub pending_transfers_by_currency: Option<Vec<VolumeByCurrency>>,
171}
172
173/// Transaction volume by currency.
174#[derive(Debug, Deserialize, Serialize, Default)]
175pub struct VolumeByCurrency {
176    /// Currency code.
177    pub currency: String,
178    /// Amount in the lowest denomination of the currency.
179    pub amount: u32,
180}
181
182/// Export transaction response data.
183#[derive(Debug, Serialize, Deserialize, Default)]
184pub struct ExportTransactionData {
185    /// Path to download the exported transaction file.
186    pub path: String,
187}
188
189/// Transaction identifier.
190///
191/// It can either be a transaction reference or a transaction ID
192pub enum TransactionIdentifier {
193    Id(u64),
194    Reference(String),
195}
196
197#[cfg(test)]
198mod test {
199    use super::*;
200    use std::error::Error;
201
202    #[test]
203    fn can_create_transaction_body_with_builder() -> Result<(), Box<dyn Error>> {
204        let transaction = TransactionRequestBuilder::default()
205            .amount(String::from("10000"))
206            .email(String::from("email@example.com"))
207            .currency(Currency::NGN)
208            .build()?;
209
210        assert_eq!(transaction.email, "email@example.com");
211        assert_eq!(transaction.amount, "10000");
212        assert_eq!(transaction.currency, Some(Currency::NGN));
213        assert_eq!(transaction.bearer, None);
214
215        Ok(())
216    }
217
218    #[test]
219    fn cannot_create_transaction_body_without_compulsory_field() -> Result<(), Box<dyn Error>> {
220        let transaction = TransactionRequestBuilder::default()
221            .currency(Currency::GHS)
222            .build();
223
224        assert!(transaction.is_err());
225
226        Ok(())
227    }
228}