open_lark/service/contact/v3/
department.rs

1use crate::{
2    core::{
3        api_req::ApiRequest, api_resp::ApiResponseTrait, config::Config,
4        constants::AccessTokenType, endpoints::EndpointBuilder, http::Transport,
5    },
6    service::contact::models::*,
7};
8use serde::{Deserialize, Serialize};
9
10/// 部门管理服务
11///
12/// 提供完整的部门管理功能,包括:
13/// - 创建、修改、删除部门
14/// - 获取部门信息(单个/批量)
15/// - 获取子部门列表
16/// - 获取父部门信息
17/// - 搜索部门
18pub struct DepartmentService {
19    config: Config,
20}
21
22impl DepartmentService {
23    pub fn new(config: Config) -> Self {
24        Self { config }
25    }
26
27    /// 创建部门
28    pub async fn create(
29        &self,
30        req: &CreateDepartmentRequest,
31    ) -> crate::core::SDKResult<CreateDepartmentResponse> {
32        let api_req = ApiRequest {
33            http_method: reqwest::Method::POST,
34            api_path: crate::core::endpoints::contact::CONTACT_V3_DEPARTMENTS.to_string(),
35            supported_access_token_types: vec![AccessTokenType::Tenant],
36            body: serde_json::to_vec(req)?,
37            ..Default::default()
38        };
39
40        let resp =
41            Transport::<CreateDepartmentResponse>::request(api_req, &self.config, None).await?;
42        Ok(resp.data.unwrap_or_default())
43    }
44
45    /// 修改部门部分信息
46    pub async fn patch(
47        &self,
48        department_id: &str,
49        req: &PatchDepartmentRequest,
50    ) -> crate::core::SDKResult<PatchDepartmentResponse> {
51        let api_req = ApiRequest {
52            http_method: reqwest::Method::PATCH,
53            api_path: EndpointBuilder::replace_param(
54                crate::core::endpoints::contact::CONTACT_V3_DEPARTMENT_GET,
55                "department_id",
56                department_id,
57            ),
58            supported_access_token_types: vec![AccessTokenType::Tenant],
59            body: serde_json::to_vec(req)?,
60            ..Default::default()
61        };
62
63        let resp =
64            Transport::<PatchDepartmentResponse>::request(api_req, &self.config, None).await?;
65        Ok(resp.data.unwrap_or_default())
66    }
67
68    /// 更新部门所有信息
69    pub async fn update(
70        &self,
71        department_id: &str,
72        req: &UpdateDepartmentRequest,
73    ) -> crate::core::SDKResult<UpdateDepartmentResponse> {
74        let api_req = ApiRequest {
75            http_method: reqwest::Method::PUT,
76            api_path: EndpointBuilder::replace_param(
77                crate::core::endpoints::contact::CONTACT_V3_DEPARTMENT_GET,
78                "department_id",
79                department_id,
80            ),
81            supported_access_token_types: vec![AccessTokenType::Tenant],
82            body: serde_json::to_vec(req)?,
83            ..Default::default()
84        };
85
86        let resp =
87            Transport::<UpdateDepartmentResponse>::request(api_req, &self.config, None).await?;
88        Ok(resp.data.unwrap_or_default())
89    }
90
91    /// 更新部门 ID
92    pub async fn update_department_id(
93        &self,
94        department_id: &str,
95        req: &UpdateDepartmentIdRequest,
96    ) -> crate::core::SDKResult<UpdateDepartmentIdResponse> {
97        let api_req = ApiRequest {
98            http_method: reqwest::Method::PATCH,
99            api_path: EndpointBuilder::replace_param(
100                crate::core::endpoints::contact::CONTACT_V3_DEPARTMENT_UPDATE_ID,
101                "department_id",
102                department_id,
103            ),
104            supported_access_token_types: vec![AccessTokenType::Tenant],
105            body: serde_json::to_vec(req)?,
106            ..Default::default()
107        };
108
109        let resp =
110            Transport::<UpdateDepartmentIdResponse>::request(api_req, &self.config, None).await?;
111        Ok(resp.data.unwrap_or_default())
112    }
113
114    /// 获取单个部门信息
115    pub async fn get(
116        &self,
117        department_id: &str,
118        _req: &GetDepartmentRequest,
119    ) -> crate::core::SDKResult<GetDepartmentResponse> {
120        let api_req = ApiRequest {
121            http_method: reqwest::Method::GET,
122            api_path: EndpointBuilder::replace_param(
123                crate::core::endpoints::contact::CONTACT_V3_DEPARTMENT_GET,
124                "department_id",
125                department_id,
126            ),
127            supported_access_token_types: vec![AccessTokenType::Tenant, AccessTokenType::User],
128            body: Vec::new(),
129            query_params: std::collections::HashMap::new(),
130            ..Default::default()
131        };
132
133        let resp = Transport::<GetDepartmentResponse>::request(api_req, &self.config, None).await?;
134        Ok(resp.data.unwrap_or_default())
135    }
136
137    /// 批量获取部门信息
138    pub async fn batch(
139        &self,
140        req: &BatchGetDepartmentsRequest,
141    ) -> crate::core::SDKResult<BatchGetDepartmentsResponse> {
142        let api_req = ApiRequest {
143            http_method: reqwest::Method::POST,
144            api_path: crate::core::endpoints::contact::CONTACT_V3_DEPARTMENTS_BATCH.to_string(),
145            supported_access_token_types: vec![AccessTokenType::Tenant],
146            body: serde_json::to_vec(req)?,
147            ..Default::default()
148        };
149
150        let resp =
151            Transport::<BatchGetDepartmentsResponse>::request(api_req, &self.config, None).await?;
152        Ok(resp.data.unwrap_or_default())
153    }
154
155    /// 获取子部门列表
156    pub async fn children(
157        &self,
158        _req: &GetChildrenDepartmentsRequest,
159    ) -> crate::core::SDKResult<GetChildrenDepartmentsResponse> {
160        let api_req = ApiRequest {
161            http_method: reqwest::Method::GET,
162            api_path: crate::core::endpoints::contact::CONTACT_V3_DEPARTMENTS_CHILDREN.to_string(),
163            supported_access_token_types: vec![AccessTokenType::Tenant, AccessTokenType::User],
164            body: Vec::new(),
165            query_params: std::collections::HashMap::new(),
166            ..Default::default()
167        };
168
169        let resp =
170            Transport::<GetChildrenDepartmentsResponse>::request(api_req, &self.config, None)
171                .await?;
172        Ok(resp.data.unwrap_or_default())
173    }
174
175    /// 获取父部门信息
176    pub async fn parent(
177        &self,
178        _req: &GetParentDepartmentRequest,
179    ) -> crate::core::SDKResult<GetParentDepartmentResponse> {
180        let api_req = ApiRequest {
181            http_method: reqwest::Method::GET,
182            api_path: crate::core::endpoints::contact::CONTACT_V3_DEPARTMENTS_PARENT.to_string(),
183            supported_access_token_types: vec![AccessTokenType::Tenant, AccessTokenType::User],
184            body: Vec::new(),
185            query_params: std::collections::HashMap::new(),
186            ..Default::default()
187        };
188
189        let resp =
190            Transport::<GetParentDepartmentResponse>::request(api_req, &self.config, None).await?;
191        Ok(resp.data.unwrap_or_default())
192    }
193
194    /// 搜索部门
195    pub async fn search(
196        &self,
197        req: &SearchDepartmentsRequest,
198    ) -> crate::core::SDKResult<SearchDepartmentsResponse> {
199        let api_req = ApiRequest {
200            http_method: reqwest::Method::POST,
201            api_path: crate::core::endpoints::contact::CONTACT_V3_DEPARTMENTS_SEARCH.to_string(),
202            supported_access_token_types: vec![AccessTokenType::Tenant, AccessTokenType::User],
203            body: serde_json::to_vec(req)?,
204            ..Default::default()
205        };
206
207        let resp =
208            Transport::<SearchDepartmentsResponse>::request(api_req, &self.config, None).await?;
209        Ok(resp.data.unwrap_or_default())
210    }
211
212    /// 删除部门
213    pub async fn delete(
214        &self,
215        department_id: &str,
216        _req: &DeleteDepartmentRequest,
217    ) -> crate::core::SDKResult<DeleteDepartmentResponse> {
218        let api_req = ApiRequest {
219            http_method: reqwest::Method::DELETE,
220            api_path: EndpointBuilder::replace_param(
221                crate::core::endpoints::contact::CONTACT_V3_DEPARTMENT_GET,
222                "department_id",
223                department_id,
224            ),
225            supported_access_token_types: vec![AccessTokenType::Tenant],
226            body: Vec::new(),
227            query_params: std::collections::HashMap::new(),
228            ..Default::default()
229        };
230
231        let resp =
232            Transport::<DeleteDepartmentResponse>::request(api_req, &self.config, None).await?;
233        Ok(resp.data.unwrap_or_default())
234    }
235}
236
237// 请求/响应结构体定义
238
239/// 创建部门请求
240#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct CreateDepartmentRequest {
242    /// 部门信息
243    pub department: Department,
244    /// 用户 ID 类型
245    #[serde(skip_serializing_if = "Option::is_none")]
246    pub user_id_type: Option<String>,
247    /// 部门 ID 类型
248    #[serde(skip_serializing_if = "Option::is_none")]
249    pub department_id_type: Option<String>,
250    /// 客户端令牌
251    #[serde(skip_serializing_if = "Option::is_none")]
252    pub client_token: Option<String>,
253}
254
255/// 创建部门响应
256#[derive(Debug, Clone, Serialize, Deserialize, Default)]
257pub struct CreateDepartmentResponse {
258    /// 部门信息
259    pub department: Department,
260}
261
262impl ApiResponseTrait for CreateDepartmentResponse {
263    fn data_format() -> crate::core::api_resp::ResponseFormat {
264        crate::core::api_resp::ResponseFormat::Data
265    }
266}
267
268/// 修改部门请求
269#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct PatchDepartmentRequest {
271    /// 部门信息
272    pub department: Department,
273    /// 用户 ID 类型
274    #[serde(skip_serializing_if = "Option::is_none")]
275    pub user_id_type: Option<String>,
276    /// 部门 ID 类型
277    #[serde(skip_serializing_if = "Option::is_none")]
278    pub department_id_type: Option<String>,
279}
280
281/// 修改部门响应
282#[derive(Debug, Clone, Serialize, Deserialize, Default)]
283pub struct PatchDepartmentResponse {
284    /// 部门信息
285    pub department: Department,
286}
287
288impl ApiResponseTrait for PatchDepartmentResponse {
289    fn data_format() -> crate::core::api_resp::ResponseFormat {
290        crate::core::api_resp::ResponseFormat::Data
291    }
292}
293
294/// 更新部门请求
295#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct UpdateDepartmentRequest {
297    /// 部门信息
298    pub department: Department,
299    /// 用户 ID 类型
300    #[serde(skip_serializing_if = "Option::is_none")]
301    pub user_id_type: Option<String>,
302    /// 部门 ID 类型
303    #[serde(skip_serializing_if = "Option::is_none")]
304    pub department_id_type: Option<String>,
305}
306
307/// 更新部门响应
308#[derive(Debug, Clone, Serialize, Deserialize, Default)]
309pub struct UpdateDepartmentResponse {
310    /// 部门信息
311    pub department: Department,
312}
313
314impl ApiResponseTrait for UpdateDepartmentResponse {
315    fn data_format() -> crate::core::api_resp::ResponseFormat {
316        crate::core::api_resp::ResponseFormat::Data
317    }
318}
319
320/// 更新部门ID请求
321#[derive(Debug, Clone, Serialize, Deserialize)]
322pub struct UpdateDepartmentIdRequest {
323    /// 新的部门ID
324    pub new_department_id: String,
325    /// 部门 ID 类型
326    #[serde(skip_serializing_if = "Option::is_none")]
327    pub department_id_type: Option<String>,
328}
329
330/// 更新部门ID响应
331#[derive(Debug, Clone, Serialize, Deserialize, Default)]
332pub struct UpdateDepartmentIdResponse {}
333
334impl ApiResponseTrait for UpdateDepartmentIdResponse {
335    fn data_format() -> crate::core::api_resp::ResponseFormat {
336        crate::core::api_resp::ResponseFormat::Data
337    }
338}
339
340/// 获取部门请求
341#[derive(Debug, Clone, Default, Serialize, Deserialize)]
342pub struct GetDepartmentRequest {
343    /// 用户 ID 类型
344    #[serde(skip_serializing_if = "Option::is_none")]
345    pub user_id_type: Option<String>,
346    /// 部门 ID 类型
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub department_id_type: Option<String>,
349}
350
351/// 获取部门响应
352#[derive(Debug, Clone, Serialize, Deserialize, Default)]
353pub struct GetDepartmentResponse {
354    /// 部门信息
355    pub department: Department,
356}
357
358impl ApiResponseTrait for GetDepartmentResponse {
359    fn data_format() -> crate::core::api_resp::ResponseFormat {
360        crate::core::api_resp::ResponseFormat::Data
361    }
362}
363
364/// 批量获取部门请求
365#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct BatchGetDepartmentsRequest {
367    /// 部门ID列表
368    pub department_ids: Vec<String>,
369    /// 用户 ID 类型
370    #[serde(skip_serializing_if = "Option::is_none")]
371    pub user_id_type: Option<String>,
372    /// 部门 ID 类型
373    #[serde(skip_serializing_if = "Option::is_none")]
374    pub department_id_type: Option<String>,
375}
376
377/// 批量获取部门响应
378#[derive(Debug, Clone, Serialize, Deserialize, Default)]
379pub struct BatchGetDepartmentsResponse {
380    /// 部门列表
381    pub items: Vec<Department>,
382}
383
384impl ApiResponseTrait for BatchGetDepartmentsResponse {
385    fn data_format() -> crate::core::api_resp::ResponseFormat {
386        crate::core::api_resp::ResponseFormat::Data
387    }
388}
389
390/// 获取子部门列表请求
391#[derive(Debug, Clone, Default, Serialize, Deserialize)]
392pub struct GetChildrenDepartmentsRequest {
393    /// 父部门ID
394    #[serde(skip_serializing_if = "Option::is_none")]
395    pub parent_department_id: Option<String>,
396    /// 用户 ID 类型
397    #[serde(skip_serializing_if = "Option::is_none")]
398    pub user_id_type: Option<String>,
399    /// 部门 ID 类型
400    #[serde(skip_serializing_if = "Option::is_none")]
401    pub department_id_type: Option<String>,
402    /// 是否递归获取
403    #[serde(skip_serializing_if = "Option::is_none")]
404    pub fetch_child: Option<bool>,
405    /// 分页大小
406    #[serde(skip_serializing_if = "Option::is_none")]
407    pub page_size: Option<i32>,
408    /// 分页标记
409    #[serde(skip_serializing_if = "Option::is_none")]
410    pub page_token: Option<String>,
411}
412
413/// 获取子部门列表响应
414#[derive(Debug, Clone, Serialize, Deserialize, Default)]
415pub struct GetChildrenDepartmentsResponse {
416    /// 部门列表
417    pub items: Vec<Department>,
418    /// 是否还有更多项目
419    #[serde(skip_serializing_if = "Option::is_none")]
420    pub has_more: Option<bool>,
421    /// 分页标记
422    #[serde(skip_serializing_if = "Option::is_none")]
423    pub page_token: Option<String>,
424}
425
426impl ApiResponseTrait for GetChildrenDepartmentsResponse {
427    fn data_format() -> crate::core::api_resp::ResponseFormat {
428        crate::core::api_resp::ResponseFormat::Data
429    }
430}
431
432/// 获取父部门请求
433#[derive(Debug, Clone, Default, Serialize, Deserialize)]
434pub struct GetParentDepartmentRequest {
435    /// 部门ID
436    #[serde(skip_serializing_if = "Option::is_none")]
437    pub department_id: Option<String>,
438    /// 用户 ID 类型
439    #[serde(skip_serializing_if = "Option::is_none")]
440    pub user_id_type: Option<String>,
441    /// 部门 ID 类型
442    #[serde(skip_serializing_if = "Option::is_none")]
443    pub department_id_type: Option<String>,
444}
445
446/// 获取父部门响应
447#[derive(Debug, Clone, Serialize, Deserialize, Default)]
448pub struct GetParentDepartmentResponse {
449    /// 部门列表
450    pub items: Vec<Department>,
451}
452
453impl ApiResponseTrait for GetParentDepartmentResponse {
454    fn data_format() -> crate::core::api_resp::ResponseFormat {
455        crate::core::api_resp::ResponseFormat::Data
456    }
457}
458
459/// 搜索部门请求
460#[derive(Debug, Clone, Serialize, Deserialize)]
461pub struct SearchDepartmentsRequest {
462    /// 搜索关键词
463    pub query: String,
464    /// 分页大小
465    #[serde(skip_serializing_if = "Option::is_none")]
466    pub page_size: Option<i32>,
467    /// 分页标记
468    #[serde(skip_serializing_if = "Option::is_none")]
469    pub page_token: Option<String>,
470    /// 用户 ID 类型
471    #[serde(skip_serializing_if = "Option::is_none")]
472    pub user_id_type: Option<String>,
473    /// 部门 ID 类型
474    #[serde(skip_serializing_if = "Option::is_none")]
475    pub department_id_type: Option<String>,
476}
477
478/// 搜索部门响应
479#[derive(Debug, Clone, Serialize, Deserialize, Default)]
480pub struct SearchDepartmentsResponse {
481    /// 部门列表
482    pub items: Vec<Department>,
483    /// 是否还有更多项目
484    #[serde(skip_serializing_if = "Option::is_none")]
485    pub has_more: Option<bool>,
486    /// 分页标记
487    #[serde(skip_serializing_if = "Option::is_none")]
488    pub page_token: Option<String>,
489}
490
491impl ApiResponseTrait for SearchDepartmentsResponse {
492    fn data_format() -> crate::core::api_resp::ResponseFormat {
493        crate::core::api_resp::ResponseFormat::Data
494    }
495}
496
497/// 删除部门请求
498#[derive(Debug, Clone, Default, Serialize, Deserialize)]
499pub struct DeleteDepartmentRequest {
500    /// 部门 ID 类型
501    #[serde(skip_serializing_if = "Option::is_none")]
502    pub department_id_type: Option<String>,
503}
504
505/// 删除部门响应
506#[derive(Debug, Clone, Serialize, Deserialize, Default)]
507pub struct DeleteDepartmentResponse {}
508
509impl ApiResponseTrait for DeleteDepartmentResponse {
510    fn data_format() -> crate::core::api_resp::ResponseFormat {
511        crate::core::api_resp::ResponseFormat::Data
512    }
513}
514
515#[cfg(test)]
516mod tests {
517    use super::*;
518    use crate::core::config::Config;
519    use crate::service::contact::models::Department;
520
521    #[test]
522    fn test_department_service_creation() {
523        let config = Config::default();
524        let service = DepartmentService::new(config.clone());
525
526        assert_eq!(service.config.app_id, config.app_id);
527        assert_eq!(service.config.app_secret, config.app_secret);
528    }
529
530    #[test]
531    fn test_department_service_with_custom_config() {
532        let config = Config::builder()
533            .app_id("dept_test_app")
534            .app_secret("dept_test_secret")
535            .build();
536
537        let service = DepartmentService::new(config.clone());
538
539        assert_eq!(service.config.app_id, "dept_test_app");
540        assert_eq!(service.config.app_secret, "dept_test_secret");
541    }
542
543    #[test]
544    fn test_create_department_request_construction() {
545        let department = Department {
546            department_id: Some("dept_123".to_string()),
547            name: Some("Engineering".to_string()),
548            ..Default::default()
549        };
550
551        let request = CreateDepartmentRequest {
552            department,
553            user_id_type: Some("user_id".to_string()),
554            department_id_type: Some("open_id".to_string()),
555            client_token: Some("token_123".to_string()),
556        };
557
558        assert_eq!(
559            request.department.department_id,
560            Some("dept_123".to_string())
561        );
562        assert_eq!(request.department.name, Some("Engineering".to_string()));
563        assert_eq!(request.user_id_type, Some("user_id".to_string()));
564        assert_eq!(request.department_id_type, Some("open_id".to_string()));
565        assert_eq!(request.client_token, Some("token_123".to_string()));
566    }
567
568    #[test]
569    fn test_create_department_request_with_none_values() {
570        let department = Department {
571            name: Some("HR".to_string()),
572            ..Default::default()
573        };
574
575        let request = CreateDepartmentRequest {
576            department,
577            user_id_type: None,
578            department_id_type: None,
579            client_token: None,
580        };
581
582        assert_eq!(request.department.name, Some("HR".to_string()));
583        assert_eq!(request.user_id_type, None);
584        assert_eq!(request.department_id_type, None);
585        assert_eq!(request.client_token, None);
586    }
587
588    #[test]
589    fn test_patch_department_request_construction() {
590        let department = Department {
591            department_id: Some("dept_456".to_string()),
592            name: Some("Marketing".to_string()),
593            ..Default::default()
594        };
595
596        let request = PatchDepartmentRequest {
597            department,
598            user_id_type: Some("union_id".to_string()),
599            department_id_type: Some("department_id".to_string()),
600        };
601
602        assert_eq!(
603            request.department.department_id,
604            Some("dept_456".to_string())
605        );
606        assert_eq!(request.department.name, Some("Marketing".to_string()));
607        assert_eq!(request.user_id_type, Some("union_id".to_string()));
608        assert_eq!(
609            request.department_id_type,
610            Some("department_id".to_string())
611        );
612    }
613
614    #[test]
615    fn test_update_department_request_construction() {
616        let department = Department {
617            department_id: Some("dept_789".to_string()),
618            name: Some("Sales".to_string()),
619            ..Default::default()
620        };
621
622        let request = UpdateDepartmentRequest {
623            department,
624            user_id_type: Some("open_id".to_string()),
625            department_id_type: Some("open_id".to_string()),
626        };
627
628        assert_eq!(
629            request.department.department_id,
630            Some("dept_789".to_string())
631        );
632        assert_eq!(request.department.name, Some("Sales".to_string()));
633        assert_eq!(request.user_id_type, Some("open_id".to_string()));
634        assert_eq!(request.department_id_type, Some("open_id".to_string()));
635    }
636
637    #[test]
638    fn test_update_department_id_request_construction() {
639        let request = UpdateDepartmentIdRequest {
640            new_department_id: "new_dept_id_123".to_string(),
641            department_id_type: Some("open_id".to_string()),
642        };
643
644        assert_eq!(request.new_department_id, "new_dept_id_123");
645        assert_eq!(request.department_id_type, Some("open_id".to_string()));
646    }
647
648    #[test]
649    fn test_update_department_id_request_with_none_type() {
650        let request = UpdateDepartmentIdRequest {
651            new_department_id: "new_dept_id_456".to_string(),
652            department_id_type: None,
653        };
654
655        assert_eq!(request.new_department_id, "new_dept_id_456");
656        assert_eq!(request.department_id_type, None);
657    }
658
659    #[test]
660    fn test_get_department_request_construction() {
661        let request = GetDepartmentRequest {
662            user_id_type: Some("user_id".to_string()),
663            department_id_type: Some("open_id".to_string()),
664        };
665
666        assert_eq!(request.user_id_type, Some("user_id".to_string()));
667        assert_eq!(request.department_id_type, Some("open_id".to_string()));
668    }
669
670    #[test]
671    fn test_get_department_request_default() {
672        let request = GetDepartmentRequest::default();
673
674        assert_eq!(request.user_id_type, None);
675        assert_eq!(request.department_id_type, None);
676    }
677
678    #[test]
679    fn test_batch_get_departments_request_construction() {
680        let request = BatchGetDepartmentsRequest {
681            department_ids: vec![
682                "dept_1".to_string(),
683                "dept_2".to_string(),
684                "dept_3".to_string(),
685            ],
686            user_id_type: Some("union_id".to_string()),
687            department_id_type: Some("department_id".to_string()),
688        };
689
690        assert_eq!(request.department_ids.len(), 3);
691        assert_eq!(request.department_ids[0], "dept_1");
692        assert_eq!(request.department_ids[2], "dept_3");
693        assert_eq!(request.user_id_type, Some("union_id".to_string()));
694        assert_eq!(
695            request.department_id_type,
696            Some("department_id".to_string())
697        );
698    }
699
700    #[test]
701    fn test_batch_get_departments_request_with_empty_list() {
702        let request = BatchGetDepartmentsRequest {
703            department_ids: vec![],
704            user_id_type: None,
705            department_id_type: None,
706        };
707
708        assert!(request.department_ids.is_empty());
709        assert_eq!(request.user_id_type, None);
710        assert_eq!(request.department_id_type, None);
711    }
712
713    #[test]
714    fn test_get_children_departments_request_construction() {
715        let request = GetChildrenDepartmentsRequest {
716            parent_department_id: Some("parent_dept_123".to_string()),
717            user_id_type: Some("user_id".to_string()),
718            department_id_type: Some("open_id".to_string()),
719            fetch_child: Some(true),
720            page_size: Some(50),
721            page_token: Some("page_token_123".to_string()),
722        };
723
724        assert_eq!(
725            request.parent_department_id,
726            Some("parent_dept_123".to_string())
727        );
728        assert_eq!(request.user_id_type, Some("user_id".to_string()));
729        assert_eq!(request.department_id_type, Some("open_id".to_string()));
730        assert_eq!(request.fetch_child, Some(true));
731        assert_eq!(request.page_size, Some(50));
732        assert_eq!(request.page_token, Some("page_token_123".to_string()));
733    }
734
735    #[test]
736    fn test_get_children_departments_request_default() {
737        let request = GetChildrenDepartmentsRequest::default();
738
739        assert_eq!(request.parent_department_id, None);
740        assert_eq!(request.user_id_type, None);
741        assert_eq!(request.department_id_type, None);
742        assert_eq!(request.fetch_child, None);
743        assert_eq!(request.page_size, None);
744        assert_eq!(request.page_token, None);
745    }
746
747    #[test]
748    fn test_get_parent_department_request_construction() {
749        let request = GetParentDepartmentRequest {
750            department_id: Some("dept_456".to_string()),
751            user_id_type: Some("union_id".to_string()),
752            department_id_type: Some("department_id".to_string()),
753        };
754
755        assert_eq!(request.department_id, Some("dept_456".to_string()));
756        assert_eq!(request.user_id_type, Some("union_id".to_string()));
757        assert_eq!(
758            request.department_id_type,
759            Some("department_id".to_string())
760        );
761    }
762
763    #[test]
764    fn test_get_parent_department_request_default() {
765        let request = GetParentDepartmentRequest::default();
766
767        assert_eq!(request.department_id, None);
768        assert_eq!(request.user_id_type, None);
769        assert_eq!(request.department_id_type, None);
770    }
771
772    #[test]
773    fn test_search_departments_request_construction() {
774        let request = SearchDepartmentsRequest {
775            query: "Engineering".to_string(),
776            page_size: Some(20),
777            page_token: Some("search_token_123".to_string()),
778            user_id_type: Some("open_id".to_string()),
779            department_id_type: Some("open_id".to_string()),
780        };
781
782        assert_eq!(request.query, "Engineering");
783        assert_eq!(request.page_size, Some(20));
784        assert_eq!(request.page_token, Some("search_token_123".to_string()));
785        assert_eq!(request.user_id_type, Some("open_id".to_string()));
786        assert_eq!(request.department_id_type, Some("open_id".to_string()));
787    }
788
789    #[test]
790    fn test_search_departments_request_with_minimal_data() {
791        let request = SearchDepartmentsRequest {
792            query: "HR".to_string(),
793            page_size: None,
794            page_token: None,
795            user_id_type: None,
796            department_id_type: None,
797        };
798
799        assert_eq!(request.query, "HR");
800        assert_eq!(request.page_size, None);
801        assert_eq!(request.page_token, None);
802        assert_eq!(request.user_id_type, None);
803        assert_eq!(request.department_id_type, None);
804    }
805
806    #[test]
807    fn test_delete_department_request_construction() {
808        let request = DeleteDepartmentRequest {
809            department_id_type: Some("department_id".to_string()),
810        };
811
812        assert_eq!(
813            request.department_id_type,
814            Some("department_id".to_string())
815        );
816    }
817
818    #[test]
819    fn test_delete_department_request_default() {
820        let request = DeleteDepartmentRequest::default();
821
822        assert_eq!(request.department_id_type, None);
823    }
824
825    #[test]
826    fn test_create_department_response_default() {
827        let response = CreateDepartmentResponse::default();
828
829        assert_eq!(response.department.name, None);
830        assert_eq!(response.department.department_id, None);
831    }
832
833    #[test]
834    fn test_patch_department_response_default() {
835        let response = PatchDepartmentResponse::default();
836
837        assert_eq!(response.department.name, None);
838        assert_eq!(response.department.department_id, None);
839    }
840
841    #[test]
842    fn test_update_department_response_default() {
843        let response = UpdateDepartmentResponse::default();
844
845        assert_eq!(response.department.name, None);
846        assert_eq!(response.department.department_id, None);
847    }
848
849    #[test]
850    fn test_update_department_id_response_default() {
851        let _response = UpdateDepartmentIdResponse::default();
852        // UpdateDepartmentIdResponse is an empty struct, just test it can be created
853    }
854
855    #[test]
856    fn test_get_department_response_default() {
857        let response = GetDepartmentResponse::default();
858
859        assert_eq!(response.department.name, None);
860        assert_eq!(response.department.department_id, None);
861    }
862
863    #[test]
864    fn test_batch_get_departments_response_default() {
865        let response = BatchGetDepartmentsResponse::default();
866
867        assert!(response.items.is_empty());
868    }
869
870    #[test]
871    fn test_get_children_departments_response_default() {
872        let response = GetChildrenDepartmentsResponse::default();
873
874        assert!(response.items.is_empty());
875        assert_eq!(response.has_more, None);
876        assert_eq!(response.page_token, None);
877    }
878
879    #[test]
880    fn test_get_parent_department_response_default() {
881        let response = GetParentDepartmentResponse::default();
882
883        assert!(response.items.is_empty());
884    }
885
886    #[test]
887    fn test_search_departments_response_default() {
888        let response = SearchDepartmentsResponse::default();
889
890        assert!(response.items.is_empty());
891        assert_eq!(response.has_more, None);
892        assert_eq!(response.page_token, None);
893    }
894
895    #[test]
896    fn test_delete_department_response_default() {
897        let _response = DeleteDepartmentResponse::default();
898        // DeleteDepartmentResponse is an empty struct, just test it can be created
899    }
900
901    #[test]
902    fn test_request_structs_debug_trait() {
903        let department = Department {
904            name: Some("Debug Test Dept".to_string()),
905            ..Default::default()
906        };
907
908        let create_request = CreateDepartmentRequest {
909            department: department.clone(),
910            user_id_type: None,
911            department_id_type: None,
912            client_token: None,
913        };
914
915        let debug_str = format!("{:?}", create_request);
916        assert!(debug_str.contains("CreateDepartmentRequest"));
917        assert!(debug_str.contains("Debug Test Dept"));
918    }
919
920    #[test]
921    fn test_search_departments_request_edge_cases() {
922        // Test with very long query string
923        let long_query = "a".repeat(1000);
924        let request_long = SearchDepartmentsRequest {
925            query: long_query.clone(),
926            page_size: Some(100),
927            page_token: None,
928            user_id_type: None,
929            department_id_type: None,
930        };
931
932        assert_eq!(request_long.query, long_query);
933        assert_eq!(request_long.page_size, Some(100));
934
935        // Test with zero page size
936        let request_zero = SearchDepartmentsRequest {
937            query: "Test".to_string(),
938            page_size: Some(0),
939            page_token: None,
940            user_id_type: None,
941            department_id_type: None,
942        };
943
944        assert_eq!(request_zero.page_size, Some(0));
945
946        // Test with empty query
947        let request_empty = SearchDepartmentsRequest {
948            query: "".to_string(),
949            page_size: Some(10),
950            page_token: None,
951            user_id_type: None,
952            department_id_type: None,
953        };
954
955        assert_eq!(request_empty.query, "");
956    }
957
958    #[test]
959    fn test_batch_get_departments_request_edge_cases() {
960        // Test with very large department ID list
961        let large_list: Vec<String> = (0..1000).map(|i| format!("dept_{}", i)).collect();
962        let request_large = BatchGetDepartmentsRequest {
963            department_ids: large_list.clone(),
964            user_id_type: None,
965            department_id_type: None,
966        };
967
968        assert_eq!(request_large.department_ids.len(), 1000);
969        assert_eq!(request_large.department_ids[999], "dept_999");
970
971        // Test with single department ID
972        let request_single = BatchGetDepartmentsRequest {
973            department_ids: vec!["single_dept".to_string()],
974            user_id_type: None,
975            department_id_type: None,
976        };
977
978        assert_eq!(request_single.department_ids.len(), 1);
979        assert_eq!(request_single.department_ids[0], "single_dept");
980    }
981
982    #[test]
983    fn test_get_children_departments_request_edge_cases() {
984        // Test with very large page size
985        let request_large_page = GetChildrenDepartmentsRequest {
986            parent_department_id: Some("parent_123".to_string()),
987            user_id_type: None,
988            department_id_type: None,
989            fetch_child: Some(true),
990            page_size: Some(10000),
991            page_token: None,
992        };
993
994        assert_eq!(request_large_page.page_size, Some(10000));
995        assert_eq!(request_large_page.fetch_child, Some(true));
996
997        // Test with fetch_child set to false
998        let request_no_fetch = GetChildrenDepartmentsRequest {
999            parent_department_id: None,
1000            user_id_type: None,
1001            department_id_type: None,
1002            fetch_child: Some(false),
1003            page_size: Some(20),
1004            page_token: None,
1005        };
1006
1007        assert_eq!(request_no_fetch.fetch_child, Some(false));
1008        assert_eq!(request_no_fetch.parent_department_id, None);
1009    }
1010
1011    #[test]
1012    fn test_department_service_config_independence() {
1013        let config1 = Config::builder().app_id("dept_app_1").build();
1014
1015        let config2 = Config::builder().app_id("dept_app_2").build();
1016
1017        let service1 = DepartmentService::new(config1);
1018        let service2 = DepartmentService::new(config2);
1019
1020        assert_eq!(service1.config.app_id, "dept_app_1");
1021        assert_eq!(service2.config.app_id, "dept_app_2");
1022        assert_ne!(service1.config.app_id, service2.config.app_id);
1023    }
1024
1025    #[test]
1026    fn test_api_response_trait_implementations() {
1027        // Test that all response types implement ApiResponseTrait correctly
1028        assert_eq!(
1029            CreateDepartmentResponse::data_format(),
1030            crate::core::api_resp::ResponseFormat::Data
1031        );
1032        assert_eq!(
1033            PatchDepartmentResponse::data_format(),
1034            crate::core::api_resp::ResponseFormat::Data
1035        );
1036        assert_eq!(
1037            UpdateDepartmentResponse::data_format(),
1038            crate::core::api_resp::ResponseFormat::Data
1039        );
1040        assert_eq!(
1041            UpdateDepartmentIdResponse::data_format(),
1042            crate::core::api_resp::ResponseFormat::Data
1043        );
1044        assert_eq!(
1045            GetDepartmentResponse::data_format(),
1046            crate::core::api_resp::ResponseFormat::Data
1047        );
1048        assert_eq!(
1049            BatchGetDepartmentsResponse::data_format(),
1050            crate::core::api_resp::ResponseFormat::Data
1051        );
1052        assert_eq!(
1053            GetChildrenDepartmentsResponse::data_format(),
1054            crate::core::api_resp::ResponseFormat::Data
1055        );
1056        assert_eq!(
1057            GetParentDepartmentResponse::data_format(),
1058            crate::core::api_resp::ResponseFormat::Data
1059        );
1060        assert_eq!(
1061            SearchDepartmentsResponse::data_format(),
1062            crate::core::api_resp::ResponseFormat::Data
1063        );
1064        assert_eq!(
1065            DeleteDepartmentResponse::data_format(),
1066            crate::core::api_resp::ResponseFormat::Data
1067        );
1068    }
1069}