reauth_types/
subscription.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8#[serde(rename_all = "snake_case")]
9pub enum SubscriptionStatus {
10 Active,
11 PastDue,
12 Canceled,
13 Trialing,
14 Incomplete,
15 IncompleteExpired,
16 Unpaid,
17 Paused,
18 #[default]
19 None,
20 #[serde(other)]
24 Unknown,
25}
26
27impl SubscriptionStatus {
28 pub fn is_active(&self) -> bool {
30 matches!(self, Self::Active | Self::Trialing)
31 }
32
33 pub fn is_grace_period(&self) -> bool {
35 matches!(self, Self::PastDue)
36 }
37
38 pub fn has_access(&self) -> bool {
40 matches!(self, Self::Active | Self::Trialing | Self::PastDue)
41 }
42}
43
44impl std::fmt::Display for SubscriptionStatus {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 let s = match self {
47 Self::Active => "active",
48 Self::PastDue => "past_due",
49 Self::Canceled => "canceled",
50 Self::Trialing => "trialing",
51 Self::Incomplete => "incomplete",
52 Self::IncompleteExpired => "incomplete_expired",
53 Self::Unpaid => "unpaid",
54 Self::Paused => "paused",
55 Self::None => "none",
56 Self::Unknown => "unknown",
57 };
58 write!(f, "{}", s)
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_serde_roundtrip() {
68 let status = SubscriptionStatus::Active;
69 let json = serde_json::to_string(&status).unwrap();
70 assert_eq!(json, r#""active""#);
71
72 let parsed: SubscriptionStatus = serde_json::from_str(&json).unwrap();
73 assert_eq!(parsed, status);
74 }
75
76 #[test]
77 fn test_snake_case_serialization() {
78 let status = SubscriptionStatus::PastDue;
79 let json = serde_json::to_string(&status).unwrap();
80 assert_eq!(json, r#""past_due""#);
81 }
82
83 #[test]
84 fn test_is_active() {
85 assert!(SubscriptionStatus::Active.is_active());
86 assert!(SubscriptionStatus::Trialing.is_active());
87 assert!(!SubscriptionStatus::Canceled.is_active());
88 assert!(!SubscriptionStatus::None.is_active());
89 }
90
91 #[test]
92 fn test_has_access() {
93 assert!(SubscriptionStatus::Active.has_access());
94 assert!(SubscriptionStatus::Trialing.has_access());
95 assert!(SubscriptionStatus::PastDue.has_access());
96 assert!(!SubscriptionStatus::Canceled.has_access());
97 assert!(!SubscriptionStatus::None.has_access());
98 }
99
100 #[test]
101 fn test_unknown_status_deserialization() {
102 let parsed: SubscriptionStatus = serde_json::from_str(r#""some_future_status""#).unwrap();
103 assert_eq!(parsed, SubscriptionStatus::Unknown);
104 assert!(!parsed.is_active());
105 assert!(!parsed.has_access());
106 assert!(!parsed.is_grace_period());
107 }
108
109 #[test]
110 fn test_unknown_status_round_trip_is_lossy() {
111 let parsed: SubscriptionStatus = serde_json::from_str(r#""grandfathered""#).unwrap();
112 assert_eq!(parsed, SubscriptionStatus::Unknown);
113 let re_serialized = serde_json::to_string(&parsed).unwrap();
114 assert_eq!(re_serialized, r#""unknown""#);
115 }
116}