Skip to main content

concur_api/api/
lists.rs

1//! SAP Concur Lists API v4 and List Items API v4.
2
3use crate::client::ConcurClient;
4use crate::error::Result;
5use crate::models::PagedResponse;
6use reqwest::Method;
7use serde::{Deserialize, Serialize};
8
9/// Lists API.
10pub struct ListsApi<'a> {
11    client: &'a ConcurClient,
12}
13
14impl<'a> ListsApi<'a> {
15    pub fn new(client: &'a ConcurClient) -> Self {
16        Self { client }
17    }
18
19    /// Get all lists with optional filters.
20    pub async fn list(
21        &self,
22        page: Option<u32>,
23        sort_by: Option<&str>,
24        sort_direction: Option<&str>,
25        filters: Option<Vec<(&str, &str)>>,
26    ) -> Result<PagedResponse<List>> {
27        let mut path = "/list/v4/lists".to_string();
28        let mut params: Vec<(String, String)> = Vec::new();
29        if let Some(p) = page {
30            params.push(("page".to_string(), p.to_string()));
31        }
32        if let Some(s) = sort_by {
33            params.push(("sortBy".to_string(), s.to_string()));
34        }
35        if let Some(s) = sort_direction {
36            params.push(("sortDirection".to_string(), s.to_string()));
37        }
38        if let Some(f) = filters {
39            for (k, v) in f {
40                params.push((k.to_string(), v.to_string()));
41            }
42        }
43        if !params.is_empty() {
44            path.push('?');
45            path.push_str(
46                &params
47                    .iter()
48                    .map(|(k, v)| format!("{}={}", k, urlencoding::encode(v)))
49                    .collect::<Vec<_>>()
50                    .join("&"),
51            );
52        }
53        self.client
54            .request(Method::GET, &path)
55            .await?
56            .send()
57            .await?
58            .json()
59            .await
60            .map_err(Into::into)
61    }
62
63    /// Create a new list.
64    pub async fn create(&self, request: &CreateListRequest) -> Result<List> {
65        let req = self.client.request(Method::POST, "/list/v4/lists").await?;
66        let req = ConcurClient::with_json(req, request)?;
67        self.client.execute(req).await
68    }
69
70    /// Update a list.
71    pub async fn update(&self, list_id: &str, request: &CreateListRequest) -> Result<List> {
72        let req = self
73            .client
74            .request(Method::PUT, &format!("/list/v4/lists/{}", list_id))
75            .await?;
76        let req = ConcurClient::with_json(req, request)?;
77        self.client.execute(req).await
78    }
79
80    /// Delete a list.
81    pub async fn delete(&self, list_id: &str) -> Result<()> {
82        self.client
83            .execute_unit(
84                self.client
85                    .request(Method::DELETE, &format!("/list/v4/lists/{}", list_id))
86                    .await?,
87            )
88            .await
89    }
90}
91
92/// List Items API.
93pub struct ListItemsApi<'a> {
94    client: &'a ConcurClient,
95}
96
97impl<'a> ListItemsApi<'a> {
98    pub fn new(client: &'a ConcurClient) -> Self {
99        Self { client }
100    }
101
102    /// Get a list item by ID.
103    pub async fn get(&self, item_id: &str) -> Result<ListItem> {
104        self.client
105            .request(Method::GET, &format!("/list/v4/items/{}", item_id))
106            .await?
107            .send()
108            .await?
109            .json()
110            .await
111            .map_err(Into::into)
112    }
113
114    /// Create a list item.
115    pub async fn create(&self, request: &CreateListItemRequest) -> Result<ListItem> {
116        let req = self.client.request(Method::POST, "/list/v4/items").await?;
117        let req = ConcurClient::with_json(req, request)?;
118        self.client.execute(req).await
119    }
120
121    /// Update a list item.
122    pub async fn update(&self, item_id: &str, request: &CreateListItemRequest) -> Result<ListItem> {
123        let req = self
124            .client
125            .request(Method::PUT, &format!("/list/v4/items/{}", item_id))
126            .await?;
127        let req = ConcurClient::with_json(req, request)?;
128        self.client.execute(req).await
129    }
130
131    /// Delete a list item globally.
132    pub async fn delete(&self, item_id: &str) -> Result<()> {
133        self.client
134            .execute_unit(
135                self.client
136                    .request(Method::DELETE, &format!("/list/v4/items/{}", item_id))
137                    .await?,
138            )
139            .await
140    }
141
142    /// Delete a list item from a specific list.
143    pub async fn delete_from_list(&self, list_id: &str, item_id: &str) -> Result<()> {
144        self.client
145            .execute_unit(
146                self.client
147                    .request(
148                        Method::DELETE,
149                        &format!("/list/v4/lists/{}/items/{}", list_id, item_id),
150                    )
151                    .await?,
152            )
153            .await
154    }
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct List {
159    pub id: String,
160    pub value: String,
161    #[serde(rename = "levelCount")]
162    pub level_count: i32,
163    #[serde(rename = "searchCriteria")]
164    pub search_criteria: String,
165    #[serde(rename = "displayFormat")]
166    pub display_format: String,
167    pub category: ListCategory,
168    #[serde(rename = "isReadOnly")]
169    pub is_read_only: bool,
170    #[serde(rename = "isDeleted")]
171    pub is_deleted: bool,
172    #[serde(rename = "managedBy")]
173    pub managed_by: Option<String>,
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct ListCategory {
178    pub id: String,
179    #[serde(rename = "type")]
180    pub type_: String,
181}
182
183#[derive(Debug, Clone, Default, Serialize, Deserialize)]
184pub struct CreateListRequest {
185    pub value: String,
186    #[serde(rename = "searchCriteria")]
187    pub search_criteria: String,
188    #[serde(rename = "displayFormat")]
189    pub display_format: String,
190    #[serde(rename = "categoryId", skip_serializing_if = "Option::is_none")]
191    pub category_id: Option<String>,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct ListItem {
196    pub id: String,
197    pub code: String,
198    #[serde(rename = "shortCode")]
199    pub short_code: String,
200    pub value: String,
201    #[serde(rename = "parentId")]
202    pub parent_id: Option<String>,
203    pub level: i32,
204    #[serde(rename = "isDeleted")]
205    pub is_deleted: bool,
206    pub lists: Vec<ListItemListRef>,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct ListItemListRef {
211    pub id: String,
212    #[serde(rename = "hasChildren")]
213    pub has_children: bool,
214}
215
216#[derive(Debug, Clone, Default, Serialize, Deserialize)]
217pub struct CreateListItemRequest {
218    #[serde(rename = "listId")]
219    pub list_id: String,
220    #[serde(rename = "shortCode")]
221    pub short_code: String,
222    pub value: String,
223    #[serde(rename = "parentId", skip_serializing_if = "Option::is_none")]
224    pub parent_id: Option<String>,
225    #[serde(rename = "parentCode", skip_serializing_if = "Option::is_none")]
226    pub parent_code: Option<String>,
227}