1use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct Account {
12 pub id: i64,
13 pub org_id: String,
14 pub name: String,
15 pub provider: String, pub account_id: String,
17 pub access_key: String,
18 pub secret_key: String,
19 pub region: Option<String>,
20 pub enabled: bool,
21 pub created_at: DateTime<Utc>,
22 pub updated_at: DateTime<Utc>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct Bill {
28 pub id: i64,
29 pub account_id: i64,
30 pub org_id: String,
31 pub billing_cycle: String,
32 pub amount: f64,
33 pub currency: String,
34 pub product_code: String,
35 pub product_name: Option<String>,
36 pub provider: Option<String>,
37 pub region: Option<String>,
38 pub instance_id: Option<String>,
39 pub project_id: Option<String>,
40 pub usage_amount: f64,
41 pub usage_unit: String,
42 pub deduction_amount: Option<f64>,
43 pub created_at: DateTime<Utc>,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct CostOverview {
49 pub billing_cycle: String,
50 pub total_cost: f64,
51 pub account_count: i32,
52 pub accounts: Vec<AccountCost>,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct AccountCost {
58 pub account_id: i64,
59 pub account_name: String,
60 pub provider: String,
61 pub cost: f64,
62 pub percentage: f64,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct BillingStats {
68 pub month: String,
69 pub total_cost: f64,
70 pub service_cost: f64,
71 pub discount: f64,
72 pub monthly_recurring: f64,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct ProviderConfig {
78 pub name: String,
79 pub display_name: String,
80 pub enabled: bool,
81 pub fields: Vec<ConfigField>,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct ConfigField {
87 pub name: String,
88 pub label: String,
89 pub field_type: String, pub required: bool,
91 pub options: Option<Vec<String>>,
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
96#[serde(rename_all = "lowercase")]
97pub enum Provider {
98 Aliyun,
99 TencentCloud,
100 AWS,
101 Azure,
102 Volcengine,
103 UCloud,
104 Gcp,
105 Cloudflare,
106}
107
108impl Provider {
109 pub fn as_str(&self) -> &'static str {
110 match self {
111 Provider::Aliyun => "aliyun",
112 Provider::TencentCloud => "tencentcloud",
113 Provider::AWS => "aws",
114 Provider::Azure => "azure",
115 Provider::Volcengine => "volcengine",
116 Provider::UCloud => "ucloud",
117 Provider::Gcp => "gcp",
118 Provider::Cloudflare => "cloudflare",
119 }
120 }
121
122}
123
124impl std::str::FromStr for Provider {
125 type Err = String;
126
127 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
128 match s.to_lowercase().as_str() {
129 "aliyun" => Ok(Provider::Aliyun),
130 "tencentcloud" | "tencent" => Ok(Provider::TencentCloud),
131 "aws" => Ok(Provider::AWS),
132 "azure" => Ok(Provider::Azure),
133 "volcengine" => Ok(Provider::Volcengine),
134 "ucloud" => Ok(Provider::UCloud),
135 "gcp" | "google" | "googlecloud" => Ok(Provider::Gcp),
136 "cloudflare" | "cf" => Ok(Provider::Cloudflare),
137 _ => Err(format!("unknown provider: {}", s)),
138 }
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_account_creation() {
148 let account = Account {
149 id: 1,
150 org_id: "org_123".to_string(),
151 name: "Production Account".to_string(),
152 provider: "aliyun".to_string(),
153 account_id: "1234567890".to_string(),
154 access_key: "test_key".to_string(),
155 secret_key: "test_secret".to_string(),
156 region: Some("cn-beijing".to_string()),
157 enabled: true,
158 created_at: Utc::now(),
159 updated_at: Utc::now(),
160 };
161
162 assert_eq!(account.id, 1);
163 assert_eq!(account.provider, "aliyun");
164 assert!(account.enabled);
165 }
166
167 #[test]
168 fn test_provider_enum() {
169 assert_eq!(Provider::Aliyun.as_str(), "aliyun");
170 assert_eq!("aws".parse::<Provider>().unwrap(), Provider::AWS);
171 assert_eq!("tencent".parse::<Provider>().unwrap(), Provider::TencentCloud);
172 assert!("unknown".parse::<Provider>().is_err());
173 }
174}