1use crate::account::*;
4use crate::accounting::Address;
5use crate::device::device::DeviceStruct;
6use crate::rest::common::{
7 ApiError, ApiResponse, ListRequest, PaginatedResponse,
8};
9use crate::RecordReference;
10use serde::{Deserialize, Serialize};
11
12#[cfg(feature = "openapi")]
13use utoipa::{ToSchema, IntoParams};
14
15#[derive(Debug, Deserialize)]
16#[cfg_attr(feature = "openapi", derive(ToSchema, IntoParams))]
17pub struct AccountIdQuery {
18 pub account_id: String,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24#[cfg_attr(feature = "openapi", derive(ToSchema))]
25#[serde(rename_all = "camelCase")]
26pub struct CreateAccountRequest {
27 pub name: String,
28 pub mbn: String,
29 pub domain: String,
30 pub organisation: RecordReference,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub address: Option<Address>,
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub teams: Option<TeamsAccount>,
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub environment: Option<Environment>,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub spend_cap: Option<SpendCap>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub concurrency: Option<Concurrency>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub class_of_service: Option<ClassOfService>,
43 pub cluster_settings: Cluster,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48#[cfg_attr(feature = "openapi", derive(ToSchema))]
49#[serde(rename_all = "camelCase")]
50pub struct UpdateAccountRequest {
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub name: Option<String>,
53 #[serde(skip_serializing_if = "Option::is_none")]
54 pub mbn: Option<String>,
55 #[serde(skip_serializing_if = "Option::is_none")]
56 pub domain: Option<String>,
57 #[serde(skip_serializing_if = "Option::is_none")]
58 pub organisation: Option<RecordReference>,
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub address: Option<Address>,
61 #[serde(skip_serializing_if = "Option::is_none")]
62 pub teams: Option<TeamsAccount>,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub environment: Option<Environment>,
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub spend_cap: Option<SpendCap>,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub concurrency: Option<Concurrency>,
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub class_of_service: Option<ClassOfService>,
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub cluster_settings: Option<Cluster>,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77#[cfg_attr(feature = "openapi", derive(ToSchema))]
78#[serde(rename_all = "camelCase")]
79pub struct AccountListRequest {
80 #[serde(flatten)]
81 pub common: ListRequest,
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub organisation_id: Option<String>,
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub name: Option<String>,
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub mbn: Option<String>,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub domain: Option<String>,
90}
91
92pub type AccountResponse = ApiResponse<Account>;
94pub type AccountListResponse = ApiResponse<PaginatedResponse<Account>>;
95pub type DDIResponse = ApiResponse<DDI>;
96pub type DeviceResponse = ApiResponse<DeviceStruct>;
97pub type TrunkResponse = ApiResponse<Trunk>;
98pub type HookResponse = ApiResponse<Hook>;
99pub type AssetResponse = ApiResponse<Asset>;
100pub type AddressResponse = ApiResponse<Address>;
101
102#[derive(Debug, Clone)]
104pub enum AccountErrorCode {
105 NotFound,
106 DuplicateMbn,
107 DuplicateDomain,
108 InvalidOrganisation,
109 InvalidCluster,
110 MissingRequiredField,
111}
112
113impl AccountErrorCode {
114 pub fn as_str(&self) -> &'static str {
115 match self {
116 Self::NotFound => "ACCOUNT_NOT_FOUND",
117 Self::DuplicateMbn => "DUPLICATE_MBN",
118 Self::DuplicateDomain => "DUPLICATE_DOMAIN",
119 Self::InvalidOrganisation => "INVALID_ORGANISATION",
120 Self::InvalidCluster => "INVALID_CLUSTER",
121 Self::MissingRequiredField => "MISSING_REQUIRED_FIELD",
122 }
123 }
124}
125
126impl CreateAccountRequest {
128 pub fn validate(&self) -> Result<(), ApiError> {
129 if self.name.trim().is_empty() {
130 return Err(ApiError::new(
131 AccountErrorCode::MissingRequiredField.as_str(),
132 "Account name is required",
133 )
134 .with_field("name"));
135 }
136
137 if self.mbn.trim().is_empty() {
138 return Err(ApiError::new(
139 AccountErrorCode::MissingRequiredField.as_str(),
140 "MBN is required",
141 )
142 .with_field("mbn"));
143 }
144
145 if self.domain.trim().is_empty() {
146 return Err(ApiError::new(
147 AccountErrorCode::MissingRequiredField.as_str(),
148 "Domain is required",
149 )
150 .with_field("domain"));
151 }
152
153 Ok(())
154 }
155}
156
157impl UpdateAccountRequest {
158 pub fn is_empty(&self) -> bool {
159 self.name.is_none()
160 && self.mbn.is_none()
161 && self.domain.is_none()
162 && self.organisation.is_none()
163 && self.address.is_none()
164 && self.teams.is_none()
165 && self.environment.is_none()
166 && self.spend_cap.is_none()
167 && self.concurrency.is_none()
168 && self.class_of_service.is_none()
169 && self.cluster_settings.is_none()
170 }
171}
172
173impl Default for AccountListRequest {
174 fn default() -> Self {
175 Self {
176 common: ListRequest {
177 pagination: crate::rest::common::PaginationParams::default(),
178 sort: crate::rest::common::SortParams::default(),
179 search: None,
180 time_range: None,
181 filters: None,
182 },
183 organisation_id: None,
184 name: None,
185 mbn: None,
186 domain: None,
187 }
188 }
189}
190
191impl AccountListRequest {
192 pub fn new() -> Self {
193 Self::default()
194 }
195
196 pub fn with_pagination(mut self, page: u32, page_size: u32) -> Self {
197 self.common.pagination = crate::rest::common::PaginationParams::new(page, page_size);
198 self
199 }
200
201 pub fn with_organisation_id(mut self, organisation_id: String) -> Self {
202 self.organisation_id = Some(organisation_id);
203 self
204 }
205}