1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Deserialize, Serialize)]
4#[serde(rename_all = "camelCase")]
5pub struct InitializeRequest {}
6
7#[derive(Debug, Clone, Default, Deserialize, Serialize)]
8#[serde(rename_all = "camelCase")]
9pub struct InitializeResponse {
10 pub success: bool,
11}
12
13#[derive(Debug, Deserialize, Serialize)]
14#[serde(rename_all = "camelCase")]
15pub struct GetProductsRequest {
16 pub product_ids: Vec<String>,
17 #[serde(default = "default_product_type")]
18 pub product_type: String,
19}
20
21fn default_product_type() -> String {
22 "subs".to_string()
23}
24
25#[derive(Debug, Clone, Deserialize, Serialize)]
26#[serde(rename_all = "camelCase")]
27pub struct PricingPhase {
28 pub formatted_price: String,
29 pub price_currency_code: String,
30 pub price_amount_micros: i64,
31 pub billing_period: String,
32 pub billing_cycle_count: i32,
33 pub recurrence_mode: i32,
34}
35
36#[derive(Debug, Clone, Deserialize, Serialize)]
37#[serde(rename_all = "camelCase")]
38pub struct SubscriptionOffer {
39 pub offer_token: String,
40 pub base_plan_id: String,
41 pub offer_id: Option<String>,
42 pub pricing_phases: Vec<PricingPhase>,
43}
44
45#[derive(Debug, Clone, Deserialize, Serialize)]
46#[serde(rename_all = "camelCase")]
47pub struct Product {
48 pub product_id: String,
49 pub title: String,
50 pub description: String,
51 pub product_type: String,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub formatted_price: Option<String>,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub price_currency_code: Option<String>,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub price_amount_micros: Option<i64>,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 pub subscription_offer_details: Option<Vec<SubscriptionOffer>>,
60}
61
62#[derive(Debug, Clone, Deserialize, Serialize)]
63#[serde(rename_all = "camelCase")]
64pub struct GetProductsResponse {
65 pub products: Vec<Product>,
66}
67
68#[derive(Debug, Clone, Deserialize, Serialize)]
69#[serde(rename_all = "camelCase")]
70pub struct PurchaseOptions {
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub offer_token: Option<String>,
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub obfuscated_account_id: Option<String>,
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub obfuscated_profile_id: Option<String>,
77 #[serde(skip_serializing_if = "Option::is_none")]
78 pub app_account_token: Option<String>,
79}
80
81#[derive(Debug, Deserialize, Serialize)]
82#[serde(rename_all = "camelCase")]
83pub struct PurchaseRequest {
84 pub product_id: String,
85 #[serde(default = "default_product_type")]
86 pub product_type: String,
87 #[serde(flatten)]
88 pub options: Option<PurchaseOptions>,
89}
90
91#[derive(Debug, Clone, Deserialize, Serialize)]
92#[serde(rename_all = "camelCase")]
93pub struct Purchase {
94 pub order_id: Option<String>,
95 pub package_name: String,
96 pub product_id: String,
97 pub purchase_time: i64,
98 pub purchase_token: String,
99 pub purchase_state: i32,
100 pub is_auto_renewing: bool,
101 pub is_acknowledged: bool,
102 pub original_json: String,
103 pub signature: String,
104}
105
106#[derive(Debug, Clone, Deserialize, Serialize)]
107#[serde(rename_all = "camelCase")]
108pub struct RestorePurchasesRequest {
109 #[serde(default = "default_product_type")]
110 pub product_type: String,
111}
112
113#[derive(Debug, Clone, Deserialize, Serialize)]
114#[serde(rename_all = "camelCase")]
115pub struct RestorePurchasesResponse {
116 pub purchases: Vec<Purchase>,
117}
118
119#[derive(Debug, Clone, Deserialize, Serialize)]
120#[serde(rename_all = "camelCase")]
121pub struct PurchaseHistoryRecord {
122 pub product_id: String,
123 pub purchase_time: i64,
124 pub purchase_token: String,
125 pub quantity: i32,
126 pub original_json: String,
127 pub signature: String,
128}
129
130#[derive(Debug, Clone, Deserialize, Serialize)]
131#[serde(rename_all = "camelCase")]
132pub struct GetPurchaseHistoryResponse {
133 pub history: Vec<PurchaseHistoryRecord>,
134}
135
136#[derive(Debug, Deserialize, Serialize)]
137#[serde(rename_all = "camelCase")]
138pub struct AcknowledgePurchaseRequest {
139 pub purchase_token: String,
140}
141
142#[derive(Debug, Clone, Deserialize, Serialize)]
143#[serde(rename_all = "camelCase")]
144pub struct AcknowledgePurchaseResponse {
145 pub success: bool,
146}
147
148#[derive(Debug, Clone, Copy, PartialEq)]
149pub enum PurchaseStateValue {
150 Purchased = 0,
151 Canceled = 1,
152 Pending = 2,
153}
154
155impl Serialize for PurchaseStateValue {
156 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
157 where
158 S: serde::Serializer,
159 {
160 serializer.serialize_i32(*self as i32)
161 }
162}
163
164impl<'de> Deserialize<'de> for PurchaseStateValue {
165 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
166 where
167 D: serde::Deserializer<'de>,
168 {
169 let value = i32::deserialize(deserializer)?;
170 match value {
171 0 => Ok(PurchaseStateValue::Purchased),
172 1 => Ok(PurchaseStateValue::Canceled),
173 2 => Ok(PurchaseStateValue::Pending),
174 _ => Err(serde::de::Error::custom(format!(
175 "Invalid purchase state: {value}"
176 ))),
177 }
178 }
179}
180
181#[derive(Debug, Deserialize, Serialize)]
182#[serde(rename_all = "camelCase")]
183pub struct GetProductStatusRequest {
184 pub product_id: String,
185 #[serde(default = "default_product_type")]
186 pub product_type: String,
187}
188
189#[derive(Debug, Clone, Deserialize, Serialize)]
190#[serde(rename_all = "camelCase")]
191pub struct ProductStatus {
192 pub product_id: String,
193 pub is_owned: bool,
194 #[serde(skip_serializing_if = "Option::is_none")]
195 pub purchase_state: Option<PurchaseStateValue>,
196 #[serde(skip_serializing_if = "Option::is_none")]
197 pub purchase_time: Option<i64>,
198 #[serde(skip_serializing_if = "Option::is_none")]
199 pub expiration_time: Option<i64>,
200 #[serde(skip_serializing_if = "Option::is_none")]
201 pub is_auto_renewing: Option<bool>,
202 #[serde(skip_serializing_if = "Option::is_none")]
203 pub is_acknowledged: Option<bool>,
204 #[serde(skip_serializing_if = "Option::is_none")]
205 pub purchase_token: Option<String>,
206}