Skip to main content

chip_sdk/model/
purchase.rs

1use super::client_details::ClientDetails;
2use super::enums::{Platform, ProductType, PurchaseStatus, RefundAvailability};
3use super::issuer_details::IssuerDetails;
4use super::payment_details::PaymentDetails;
5use super::purchase_details::PurchaseDetails;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9pub struct Purchase {
10    #[serde(skip_serializing_if = "Option::is_none")]
11    pub id: Option<String>,
12    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
13    pub object_type: Option<String>,
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub created_on: Option<f64>,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub updated_on: Option<f64>,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub client: Option<ClientDetails>,
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub purchase: Option<PurchaseDetails>,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub payment: Option<PaymentDetails>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub issuer_details: Option<IssuerDetails>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub transaction_data: Option<serde_json::Value>,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub status: Option<PurchaseStatus>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub status_history: Option<Vec<serde_json::Value>>,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub viewed_on: Option<f64>,
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub company_id: Option<String>,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub is_test: Option<bool>,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub user_id: Option<String>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub brand_id: Option<String>,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub billing_template_id: Option<String>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub client_id: Option<String>,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub send_receipt: Option<bool>,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub is_recurring_token: Option<bool>,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub recurring_token: Option<String>,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub skip_capture: Option<bool>,
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub force_recurring: Option<bool>,
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub reference_generated: Option<String>,
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub reference: Option<String>,
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub issued: Option<String>,
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub due: Option<f64>,
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub refund_availability: Option<RefundAvailability>,
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub refundable_amount: Option<f64>,
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub currency_conversion: Option<serde_json::Value>,
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub payment_method_whitelist: Option<Vec<String>>,
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub success_redirect: Option<String>,
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub failure_redirect: Option<String>,
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub cancel_redirect: Option<String>,
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub success_callback: Option<String>,
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub creator_agent: Option<String>,
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub platform: Option<Platform>,
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub product: Option<ProductType>,
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub created_from_ip: Option<String>,
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub invoice_url: Option<String>,
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub checkout_url: Option<String>,
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub direct_post_url: Option<String>,
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use crate::model::Product;
100
101    #[test]
102    fn serialize_purchase_for_create() {
103        let p = Purchase {
104            brand_id: Some("test-brand-id".into()),
105            client: Some(ClientDetails {
106                email: "test@test.com".into(),
107                ..Default::default()
108            }),
109            purchase: Some(PurchaseDetails {
110                products: vec![Product {
111                    name: "Test".into(),
112                    price: 100.0,
113                    ..Default::default()
114                }],
115                ..Default::default()
116            }),
117            success_redirect: Some("https://example.com/success".into()),
118            failure_redirect: Some("https://example.com/failure".into()),
119            ..Default::default()
120        };
121        let json = serde_json::to_value(&p).unwrap();
122        assert_eq!(json["brand_id"], "test-brand-id");
123        assert_eq!(json["client"]["email"], "test@test.com");
124        assert_eq!(json["purchase"]["products"][0]["name"], "Test");
125        assert!(json.get("id").is_none());
126        assert!(json.get("status").is_none());
127    }
128
129    #[test]
130    fn deserialize_purchase_response() {
131        let json = r#"{"id":"abc-123","type":"purchase","status":"created","brand_id":"brand-uuid","checkout_url":"https://gate.chip-in.asia/checkout/abc-123","is_test":true,"client":{"email":"test@test.com"},"purchase":{"products":[{"name":"Item","price":500}],"currency":"MYR"},"refund_availability":"all","platform":"api","created_on":1700000000}"#;
132        let p: Purchase = serde_json::from_str(json).unwrap();
133        assert_eq!(p.id.as_deref(), Some("abc-123"));
134        assert_eq!(p.object_type.as_deref(), Some("purchase"));
135        assert_eq!(p.status, Some(PurchaseStatus::Created));
136        assert_eq!(
137            p.checkout_url.as_deref(),
138            Some("https://gate.chip-in.asia/checkout/abc-123")
139        );
140        assert_eq!(p.refund_availability, Some(RefundAvailability::All));
141        assert_eq!(p.platform, Some(Platform::Api));
142    }
143
144    #[test]
145    fn purchase_roundtrip() {
146        let p = Purchase {
147            brand_id: Some("brand-1".into()),
148            status: Some(PurchaseStatus::Paid),
149            ..Default::default()
150        };
151        let json = serde_json::to_string(&p).unwrap();
152        let p2: Purchase = serde_json::from_str(&json).unwrap();
153        assert_eq!(p.brand_id, p2.brand_id);
154        assert_eq!(p.status, p2.status);
155    }
156}