titanium_model/
monetization.rs

1//! Monetization types for Discord's premium features.
2//!
3//! Includes entitlements, subscriptions, and SKUs.
4
5use crate::Snowflake;
6use serde::{Deserialize, Serialize};
7use serde_repr::{Deserialize_repr, Serialize_repr};
8
9/// An entitlement represents a user's access to a premium offering.
10#[derive(Debug, Clone, Deserialize, Serialize)]
11pub struct Entitlement {
12    /// ID of the entitlement.
13    pub id: Snowflake,
14
15    /// ID of the SKU.
16    pub sku_id: Snowflake,
17
18    /// ID of the parent application.
19    pub application_id: Snowflake,
20
21    /// ID of the user that is granted access.
22    #[serde(default)]
23    pub user_id: Option<Snowflake>,
24
25    /// Type of entitlement.
26    #[serde(rename = "type")]
27    pub entitlement_type: EntitlementType,
28
29    /// Whether the entitlement was deleted.
30    #[serde(default)]
31    pub deleted: bool,
32
33    /// Start date at which the entitlement is valid (ISO8601 timestamp).
34    #[serde(default)]
35    pub starts_at: Option<String>,
36
37    /// Date at which the entitlement is no longer valid (ISO8601 timestamp).
38    #[serde(default)]
39    pub ends_at: Option<String>,
40
41    /// ID of the guild that is granted access.
42    #[serde(default)]
43    pub guild_id: Option<Snowflake>,
44
45    /// Whether the entitlement has been consumed.
46    #[serde(default)]
47    pub consumed: bool,
48}
49
50/// Type of entitlement.
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
52#[repr(u8)]
53pub enum EntitlementType {
54    /// Entitlement was purchased by user.
55    Purchase = 1,
56    /// Entitlement for Discord Nitro subscription.
57    PremiumSubscription = 2,
58    /// Entitlement was gifted by developer.
59    DeveloperGift = 3,
60    /// Entitlement was purchased by a dev in application test mode.
61    TestModePurchase = 4,
62    /// Entitlement was granted when the SKU was free.
63    FreePurchase = 5,
64    /// Entitlement was gifted by another user.
65    UserGift = 6,
66    /// Entitlement was claimed by user for free as a Nitro subscriber.
67    PremiumPurchase = 7,
68    /// Entitlement was purchased as an app subscription.
69    ApplicationSubscription = 8,
70}
71
72/// A subscription represents a user's recurring purchase.
73#[derive(Debug, Clone, Deserialize, Serialize)]
74pub struct Subscription {
75    /// ID of the subscription.
76    pub id: Snowflake,
77
78    /// ID of the user who is subscribed.
79    pub user_id: Snowflake,
80
81    /// List of SKUs subscribed to.
82    pub sku_ids: Vec<Snowflake>,
83
84    /// List of entitlements granted for this subscription.
85    pub entitlement_ids: Vec<Snowflake>,
86
87    /// Start of the current subscription period (ISO8601 timestamp).
88    pub current_period_start: String,
89
90    /// End of the current subscription period (ISO8601 timestamp).
91    pub current_period_end: String,
92
93    /// Current status of the subscription.
94    pub status: SubscriptionStatus,
95
96    /// When the subscription was canceled (ISO8601 timestamp).
97    #[serde(default)]
98    pub canceled_at: Option<String>,
99
100    /// ISO3166-1 alpha-2 country code of the payment source.
101    #[serde(default)]
102    pub country: Option<String>,
103}
104
105/// Status of a subscription.
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
107#[repr(u8)]
108pub enum SubscriptionStatus {
109    /// Subscription is active and scheduled to renew.
110    Active = 0,
111    /// Subscription is active but will not renew.
112    Ending = 1,
113    /// Subscription is inactive and not being charged.
114    Inactive = 2,
115}
116
117/// A SKU (Stock Keeping Unit) represents a premium offering.
118#[derive(Debug, Clone, Deserialize, Serialize)]
119pub struct Sku {
120    /// ID of SKU.
121    pub id: Snowflake,
122
123    /// Type of SKU.
124    #[serde(rename = "type")]
125    pub sku_type: SkuType,
126
127    /// ID of the parent application.
128    pub application_id: Snowflake,
129
130    /// Customer-facing name of the premium offering.
131    pub name: String,
132
133    /// System-generated URL slug based on the SKU's name.
134    pub slug: String,
135
136    /// SKU flags as a bitfield.
137    #[serde(default)]
138    pub flags: u64,
139}
140
141/// Type of SKU.
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
143#[repr(u8)]
144pub enum SkuType {
145    /// Durable one-time purchase.
146    Durable = 2,
147    /// Consumable one-time purchase.
148    Consumable = 3,
149    /// Recurring subscription.
150    Subscription = 5,
151    /// System-generated SKU applied to a subscription.
152    SubscriptionGroup = 6,
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    #[test]
160    fn test_entitlement() {
161        let json = r#"{
162            "id": "123",
163            "sku_id": "456",
164            "application_id": "789",
165            "type": 8,
166            "deleted": false,
167            "consumed": false
168        }"#;
169
170        let entitlement: Entitlement = crate::json::from_str(json).unwrap();
171        assert_eq!(
172            entitlement.entitlement_type,
173            EntitlementType::ApplicationSubscription
174        );
175    }
176
177    #[test]
178    fn test_subscription() {
179        let json = r#"{
180            "id": "123",
181            "user_id": "456",
182            "sku_ids": ["789"],
183            "entitlement_ids": ["321"],
184            "current_period_start": "2024-01-01T00:00:00.000Z",
185            "current_period_end": "2024-02-01T00:00:00.000Z",
186            "status": 0
187        }"#;
188
189        let subscription: Subscription = crate::json::from_str(json).unwrap();
190        assert_eq!(subscription.status, SubscriptionStatus::Active);
191    }
192}