paystack/models/
virtual_terminal_models.rs

1use std::fmt;
2
3use derive_builder::Builder;
4use serde::{Deserialize, Serialize};
5
6use crate::Domain;
7
8use super::Currency;
9
10#[derive(Debug, Serialize, Deserialize, Clone, Builder, Default)]
11pub struct VirtualTerminalRequestData {
12    /// Name of the virtual terminal
13    pub name: String,
14    /// An array of objects containing the notification recipients for payments to the Virtual Terminal.
15    /// Create with the `DestinationRequestDataBuilder` struct.
16    pub destinations: Vec<DestinationRequest>,
17    /// Stringified JSON object of custom data.
18    /// Kindly check the Paystack API Metadata page for more information
19    #[builder(setter(strip_option), default)]
20    pub metadata: Option<String>,
21    /// The transaction currency for the Virtual Terminal. Defaults to your integration currency
22    #[builder(setter(strip_option), default)]
23    pub currency: Option<Vec<Currency>>,
24    /// An array of objects representing custom fields to display on the form.
25    /// Create with `CustomFieldBuilder` struct.
26    #[builder(setter(strip_option), default)]
27    pub custom_field: Option<Vec<CustomField>>,
28}
29
30#[derive(Debug, Serialize, Deserialize, Clone, Builder, Default)]
31pub struct DestinationRequest {
32    /// The Whatsapp phone number to send notifications to.
33    pub target: String,
34    /// A descriptive label
35    pub name: String,
36}
37
38#[derive(Debug, Serialize, Deserialize, Clone, Builder, Default)]
39pub struct CustomField {
40    /// What will be displayed on the Virtual Terminal page
41    pub display_name: String,
42    /// Parameter for referencing the custom field programmatically
43    pub variable_name: String,
44}
45
46#[derive(Debug, Deserialize, Serialize, Clone, Default)]
47#[serde(rename_all = "camelCase")]
48pub struct VirtualTerminalResponseData {
49    pub id: u64,
50    pub name: String,
51    pub integration: u64,
52    pub domain: Domain,
53    pub code: String,
54    pub payment_methods: Option<Vec<String>>,
55    pub active: bool,
56    pub metadata: Option<String>,
57    pub connect_account_id: Option<String>,
58    pub destinations: Option<Vec<DestinationResponse>>,
59    pub currency: Option<String>,
60    pub created_at: Option<String>,
61}
62
63#[derive(Debug, Deserialize, Clone, Serialize, Default)]
64pub struct DestinationResponse {
65    pub integration: Option<u32>,
66    pub target: Option<String>,
67    pub name: Option<String>,
68    #[serde(rename = "type")]
69    pub destination_type: Option<String>,
70    pub id: Option<u32>,
71    #[serde(rename = "createdAt")]
72    pub created_at: Option<String>,
73    #[serde(rename = "updatedAt")]
74    pub updated_at: Option<String>,
75}
76
77#[derive(Debug, Serialize, Deserialize, Clone)]
78pub enum VirtualTerminalStatus {
79    Active,
80    Inactive,
81}
82
83impl fmt::Display for VirtualTerminalStatus {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        let lowercase_string = match self {
86            VirtualTerminalStatus::Active => "active",
87            VirtualTerminalStatus::Inactive => "inactive",
88        };
89        write!(f, "{lowercase_string}")
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn create_virtual_terminal_request() {
99        let destinations = vec![
100            DestinationRequestBuilder::default()
101                .target("Whatsapp-phone-number".to_string())
102                .name("Test-name".to_string())
103                .build()
104                .expect("unable to build destination request"),
105            DestinationRequestBuilder::default()
106                .target("Whatsapp-phone-number-2".to_string())
107                .name("Test-name-2".to_string())
108                .build()
109                .expect("unable to build destination request"),
110        ];
111        let currencies = vec![Currency::NGN, Currency::USD];
112        let custom_field = vec![
113            CustomFieldBuilder::default()
114                .display_name("display-name".to_string())
115                .variable_name("variable-name".to_string())
116                .build()
117                .expect("unable to build custome field"),
118            CustomFieldBuilder::default()
119                .display_name("display-name-2".to_string())
120                .variable_name("variable-name-2".to_string())
121                .build()
122                .expect("unable to build custome field"),
123        ];
124
125        let request = VirtualTerminalRequestDataBuilder::default()
126            .name("Some name".to_string())
127            .destinations(destinations)
128            .currency(currencies)
129            .custom_field(custom_field)
130            .build()
131            .expect("unable to build virtual terminal request");
132
133        assert_eq!(request.name, "Some name");
134        assert!(!request.destinations.is_empty());
135        assert!(request.currency.is_some());
136        assert!(request.custom_field.is_some());
137        assert!(request.metadata.is_none());
138    }
139
140    #[test]
141    fn cannot_create_virtual_terminal_request_without_compulsory_field() {
142        let request = VirtualTerminalRequestDataBuilder::default()
143            .currency(vec![Currency::GHS, Currency::NGN])
144            .build();
145
146        assert!(request.is_err());
147    }
148}