rippling_api/
time_entries.rs

1use anyhow::Result;
2
3use crate::Client;
4#[derive(Clone, Debug)]
5pub struct TimeEntries {
6    pub client: Client,
7}
8
9impl TimeEntries {
10    #[doc(hidden)]
11    pub fn new(client: Client) -> Self {
12        Self { client }
13    }
14
15    #[doc = "List time cards\n\nA List of time cards\n- Requires: `API Tier 2`\n- Filterable fields: `pay_period.start_date`, `worker_id`\n- Expandable fields: `worker`\n- Sortable fields: `id`, `created_at`, `updated_at`\n\n**Parameters:**\n\n- `cursor: Option<String>`\n- `expand: Option<String>`\n- `filter: Option<String>`\n- `order_by: Option<String>`\n\n```rust,no_run\nuse futures_util::TryStreamExt;\nasync fn example_time_entries_list_time_cards_stream() -> anyhow::Result<()> {\n    let client = rippling_api::Client::new_from_env();\n    let mut time_entries = client.time_entries();\n    let mut stream = time_entries.list_time_cards_stream(\n        Some(\"some-string\".to_string()),\n        Some(\"some-string\".to_string()),\n        Some(\"some-string\".to_string()),\n    );\n    loop {\n        match stream.try_next().await {\n            Ok(Some(item)) => {\n                println!(\"{:?}\", item);\n            }\n            Ok(None) => {\n                break;\n            }\n            Err(err) => {\n                return Err(err.into());\n            }\n        }\n    }\n\n    Ok(())\n}\n```"]
16    #[tracing::instrument]
17    pub async fn list_time_cards<'a>(
18        &'a self,
19        cursor: Option<String>,
20        expand: Option<String>,
21        filter: Option<String>,
22        order_by: Option<String>,
23    ) -> Result<crate::types::ListTimeCardsResponse, crate::types::error::Error> {
24        let mut req = self.client.client.request(
25            http::Method::GET,
26            format!("{}/{}", self.client.base_url, "time-cards"),
27        );
28        req = req.bearer_auth(&self.client.token);
29        let mut query_params = vec![];
30        if let Some(p) = cursor {
31            query_params.push(("cursor", p));
32        }
33
34        if let Some(p) = expand {
35            query_params.push(("expand", p));
36        }
37
38        if let Some(p) = filter {
39            query_params.push(("filter", p));
40        }
41
42        if let Some(p) = order_by {
43            query_params.push(("order_by", p));
44        }
45
46        req = req.query(&query_params);
47        let resp = req.send().await?;
48        let status = resp.status();
49        if status.is_success() {
50            let text = resp.text().await.unwrap_or_default();
51            serde_json::from_str(&text).map_err(|err| {
52                crate::types::error::Error::from_serde_error(
53                    format_serde_error::SerdeError::new(text.to_string(), err),
54                    status,
55                )
56            })
57        } else {
58            let text = resp.text().await.unwrap_or_default();
59            Err(crate::types::error::Error::Server {
60                body: text.to_string(),
61                status,
62            })
63        }
64    }
65
66    #[doc = "List time cards\n\nA List of time cards\n- Requires: `API Tier 2`\n- Filterable fields: `pay_period.start_date`, `worker_id`\n- Expandable fields: `worker`\n- Sortable fields: `id`, `created_at`, `updated_at`\n\n**Parameters:**\n\n- `cursor: Option<String>`\n- `expand: Option<String>`\n- `filter: Option<String>`\n- `order_by: Option<String>`\n\n```rust,no_run\nuse futures_util::TryStreamExt;\nasync fn example_time_entries_list_time_cards_stream() -> anyhow::Result<()> {\n    let client = rippling_api::Client::new_from_env();\n    let mut time_entries = client.time_entries();\n    let mut stream = time_entries.list_time_cards_stream(\n        Some(\"some-string\".to_string()),\n        Some(\"some-string\".to_string()),\n        Some(\"some-string\".to_string()),\n    );\n    loop {\n        match stream.try_next().await {\n            Ok(Some(item)) => {\n                println!(\"{:?}\", item);\n            }\n            Ok(None) => {\n                break;\n            }\n            Err(err) => {\n                return Err(err.into());\n            }\n        }\n    }\n\n    Ok(())\n}\n```"]
67    #[tracing::instrument]
68    #[cfg(not(feature = "js"))]
69    pub fn list_time_cards_stream<'a>(
70        &'a self,
71        expand: Option<String>,
72        filter: Option<String>,
73        order_by: Option<String>,
74    ) -> impl futures::Stream<Item = Result<crate::types::TimeCard, crate::types::error::Error>>
75           + Unpin
76           + '_ {
77        use futures::{StreamExt, TryFutureExt, TryStreamExt};
78
79        use crate::types::paginate::Pagination;
80        self.list_time_cards(None, expand, filter, order_by)
81            .map_ok(move |result| {
82                let items = futures::stream::iter(result.items().into_iter().map(Ok));
83                let next_pages = futures::stream::try_unfold(
84                    (None, result),
85                    move |(prev_page_token, new_result)| async move {
86                        if new_result.has_more_pages()
87                            && !new_result.items().is_empty()
88                            && prev_page_token != new_result.next_page_token()
89                        {
90                            async {
91                                let mut req = self.client.client.request(
92                                    http::Method::GET,
93                                    format!("{}/{}", self.client.base_url, "time-cards"),
94                                );
95                                req = req.bearer_auth(&self.client.token);
96                                let mut request = req.build()?;
97                                request = new_result.next_page(request)?;
98                                let resp = self.client.client.execute(request).await?;
99                                let status = resp.status();
100                                if status.is_success() {
101                                    let text = resp.text().await.unwrap_or_default();
102                                    serde_json::from_str(&text).map_err(|err| {
103                                        crate::types::error::Error::from_serde_error(
104                                            format_serde_error::SerdeError::new(
105                                                text.to_string(),
106                                                err,
107                                            ),
108                                            status,
109                                        )
110                                    })
111                                } else {
112                                    let text = resp.text().await.unwrap_or_default();
113                                    Err(crate::types::error::Error::Server {
114                                        body: text.to_string(),
115                                        status,
116                                    })
117                                }
118                            }
119                            .map_ok(|result: crate::types::ListTimeCardsResponse| {
120                                Some((
121                                    futures::stream::iter(result.items().into_iter().map(Ok)),
122                                    (new_result.next_page_token(), result),
123                                ))
124                            })
125                            .await
126                        } else {
127                            Ok(None)
128                        }
129                    },
130                )
131                .try_flatten();
132                items.chain(next_pages)
133            })
134            .try_flatten_stream()
135            .boxed()
136    }
137
138    #[doc = "Retrieve a specific time card\n\nRetrieve a specific time \
139             card\n\n**Parameters:**\n\n- `expand: Option<String>`\n- `id: &'astr`: ID of the \
140             resource to return (required)\n\n```rust,no_run\nasync fn \
141             example_time_entries_get_time_cards() -> anyhow::Result<()> {\n    let client = \
142             rippling_api::Client::new_from_env();\n    let result: \
143             rippling_api::types::GetTimeCardsResponse = client\n        .time_entries()\n        \
144             .get_time_cards(\n            Some(\"some-string\".to_string()),\n            \
145             \"d9797f8d-9ad6-4e08-90d7-2ec17e13471c\",\n        )\n        .await?;\n    \
146             println!(\"{:?}\", result);\n    Ok(())\n}\n```"]
147    #[tracing::instrument]
148    pub async fn get_time_cards<'a>(
149        &'a self,
150        expand: Option<String>,
151        id: &'a str,
152    ) -> Result<crate::types::GetTimeCardsResponse, crate::types::error::Error> {
153        let mut req = self.client.client.request(
154            http::Method::GET,
155            format!(
156                "{}/{}",
157                self.client.base_url,
158                "time-cards/{id}".replace("{id}", id)
159            ),
160        );
161        req = req.bearer_auth(&self.client.token);
162        let mut query_params = vec![];
163        if let Some(p) = expand {
164            query_params.push(("expand", p));
165        }
166
167        req = req.query(&query_params);
168        let resp = req.send().await?;
169        let status = resp.status();
170        if status.is_success() {
171            let text = resp.text().await.unwrap_or_default();
172            serde_json::from_str(&text).map_err(|err| {
173                crate::types::error::Error::from_serde_error(
174                    format_serde_error::SerdeError::new(text.to_string(), err),
175                    status,
176                )
177            })
178        } else {
179            let text = resp.text().await.unwrap_or_default();
180            Err(crate::types::error::Error::Server {
181                body: text.to_string(),
182                status,
183            })
184        }
185    }
186
187    #[doc = "List time entries\n\nA List of time entries\n- Requires: `API Tier 2`\n- Filterable fields: `worker_id`, `start_time`, `pay_period.start_date`\n- Expandable fields: `worker`, `time_card`\n- Sortable fields: `id`, `created_at`, `updated_at`\n\n**Parameters:**\n\n- `cursor: Option<String>`\n- `expand: Option<String>`\n- `filter: Option<String>`\n- `order_by: Option<String>`\n\n```rust,no_run\nuse futures_util::TryStreamExt;\nasync fn example_time_entries_list_stream() -> anyhow::Result<()> {\n    let client = rippling_api::Client::new_from_env();\n    let mut time_entries = client.time_entries();\n    let mut stream = time_entries.list_stream(\n        Some(\"some-string\".to_string()),\n        Some(\"some-string\".to_string()),\n        Some(\"some-string\".to_string()),\n    );\n    loop {\n        match stream.try_next().await {\n            Ok(Some(item)) => {\n                println!(\"{:?}\", item);\n            }\n            Ok(None) => {\n                break;\n            }\n            Err(err) => {\n                return Err(err.into());\n            }\n        }\n    }\n\n    Ok(())\n}\n```"]
188    #[tracing::instrument]
189    pub async fn list<'a>(
190        &'a self,
191        cursor: Option<String>,
192        expand: Option<String>,
193        filter: Option<String>,
194        order_by: Option<String>,
195    ) -> Result<crate::types::ListTimeEntriesResponse, crate::types::error::Error> {
196        let mut req = self.client.client.request(
197            http::Method::GET,
198            format!("{}/{}", self.client.base_url, "time-entries"),
199        );
200        req = req.bearer_auth(&self.client.token);
201        let mut query_params = vec![];
202        if let Some(p) = cursor {
203            query_params.push(("cursor", p));
204        }
205
206        if let Some(p) = expand {
207            query_params.push(("expand", p));
208        }
209
210        if let Some(p) = filter {
211            query_params.push(("filter", p));
212        }
213
214        if let Some(p) = order_by {
215            query_params.push(("order_by", p));
216        }
217
218        req = req.query(&query_params);
219        let resp = req.send().await?;
220        let status = resp.status();
221        if status.is_success() {
222            let text = resp.text().await.unwrap_or_default();
223            serde_json::from_str(&text).map_err(|err| {
224                crate::types::error::Error::from_serde_error(
225                    format_serde_error::SerdeError::new(text.to_string(), err),
226                    status,
227                )
228            })
229        } else {
230            let text = resp.text().await.unwrap_or_default();
231            Err(crate::types::error::Error::Server {
232                body: text.to_string(),
233                status,
234            })
235        }
236    }
237
238    #[doc = "List time entries\n\nA List of time entries\n- Requires: `API Tier 2`\n- Filterable fields: `worker_id`, `start_time`, `pay_period.start_date`\n- Expandable fields: `worker`, `time_card`\n- Sortable fields: `id`, `created_at`, `updated_at`\n\n**Parameters:**\n\n- `cursor: Option<String>`\n- `expand: Option<String>`\n- `filter: Option<String>`\n- `order_by: Option<String>`\n\n```rust,no_run\nuse futures_util::TryStreamExt;\nasync fn example_time_entries_list_stream() -> anyhow::Result<()> {\n    let client = rippling_api::Client::new_from_env();\n    let mut time_entries = client.time_entries();\n    let mut stream = time_entries.list_stream(\n        Some(\"some-string\".to_string()),\n        Some(\"some-string\".to_string()),\n        Some(\"some-string\".to_string()),\n    );\n    loop {\n        match stream.try_next().await {\n            Ok(Some(item)) => {\n                println!(\"{:?}\", item);\n            }\n            Ok(None) => {\n                break;\n            }\n            Err(err) => {\n                return Err(err.into());\n            }\n        }\n    }\n\n    Ok(())\n}\n```"]
239    #[tracing::instrument]
240    #[cfg(not(feature = "js"))]
241    pub fn list_stream<'a>(
242        &'a self,
243        expand: Option<String>,
244        filter: Option<String>,
245        order_by: Option<String>,
246    ) -> impl futures::Stream<Item = Result<crate::types::TimeEntry, crate::types::error::Error>>
247           + Unpin
248           + '_ {
249        use futures::{StreamExt, TryFutureExt, TryStreamExt};
250
251        use crate::types::paginate::Pagination;
252        self.list(None, expand, filter, order_by)
253            .map_ok(move |result| {
254                let items = futures::stream::iter(result.items().into_iter().map(Ok));
255                let next_pages = futures::stream::try_unfold(
256                    (None, result),
257                    move |(prev_page_token, new_result)| async move {
258                        if new_result.has_more_pages()
259                            && !new_result.items().is_empty()
260                            && prev_page_token != new_result.next_page_token()
261                        {
262                            async {
263                                let mut req = self.client.client.request(
264                                    http::Method::GET,
265                                    format!("{}/{}", self.client.base_url, "time-entries"),
266                                );
267                                req = req.bearer_auth(&self.client.token);
268                                let mut request = req.build()?;
269                                request = new_result.next_page(request)?;
270                                let resp = self.client.client.execute(request).await?;
271                                let status = resp.status();
272                                if status.is_success() {
273                                    let text = resp.text().await.unwrap_or_default();
274                                    serde_json::from_str(&text).map_err(|err| {
275                                        crate::types::error::Error::from_serde_error(
276                                            format_serde_error::SerdeError::new(
277                                                text.to_string(),
278                                                err,
279                                            ),
280                                            status,
281                                        )
282                                    })
283                                } else {
284                                    let text = resp.text().await.unwrap_or_default();
285                                    Err(crate::types::error::Error::Server {
286                                        body: text.to_string(),
287                                        status,
288                                    })
289                                }
290                            }
291                            .map_ok(|result: crate::types::ListTimeEntriesResponse| {
292                                Some((
293                                    futures::stream::iter(result.items().into_iter().map(Ok)),
294                                    (new_result.next_page_token(), result),
295                                ))
296                            })
297                            .await
298                        } else {
299                            Ok(None)
300                        }
301                    },
302                )
303                .try_flatten();
304                items.chain(next_pages)
305            })
306            .try_flatten_stream()
307            .boxed()
308    }
309
310    #[doc = "Create a new time entry\n\nCreate a new time entry\n\n```rust,no_run\nasync fn example_time_entries_create() -> anyhow::Result<()> {\n    let client = rippling_api::Client::new_from_env();\n    let result: rippling_api::types::TimeEntry = client\n        .time_entries()\n        .create(&rippling_api::types::TimeEntryRequest {\n            worker_id: \"some-string\".to_string(),\n            duration: Some(3.14 as f64),\n            comments: Some(vec![rippling_api::types::TimeEntryCommentRequest {\n                text: Some(\"some-string\".to_string()),\n            }]),\n            job_shifts: Some(vec![rippling_api::types::JobShiftRequest {\n                start_time: Some(\"some-string\".to_string()),\n                end_time: Some(\"some-string\".to_string()),\n                duration: Some(3.14 as f64),\n                start_date: Some(\"some-string\".to_string()),\n                original_start_time: Some(\"some-string\".to_string()),\n                original_end_time: Some(\"some-string\".to_string()),\n                job_codes_id: Some(vec![\"some-string\".to_string()]),\n                is_hours_only_input: Some(true),\n            }]),\n            breaks: Some(vec![rippling_api::types::BreakRequest {\n                start_time: Some(\"some-string\".to_string()),\n                end_time: Some(\"some-string\".to_string()),\n                break_type_id: Some(\"some-string\".to_string()),\n            }]),\n            tags: Some(vec![\"some-string\".to_string()]),\n            idempotency_key: Some(\"some-string\".to_string()),\n            create_extra_hours_run: Some(true),\n            status: Some(rippling_api::types::TimeEntryRequestStatus::Paid),\n            pay_period: Some(rippling_api::types::PayPeriodRequest {\n                start_date: Some(\"some-string\".to_string()),\n                end_date: Some(\"some-string\".to_string()),\n                pay_schedule_id: Some(\"some-string\".to_string()),\n            }),\n            shift_input_values: Some(vec![rippling_api::types::ShiftInputValueRequest {\n                shift_input_id: \"some-string\".to_string(),\n                author_id: Some(\"some-string\".to_string()),\n            }]),\n        })\n        .await?;\n    println!(\"{:?}\", result);\n    Ok(())\n}\n```"]
311    #[tracing::instrument]
312    pub async fn create<'a>(
313        &'a self,
314        body: &crate::types::TimeEntryRequest,
315    ) -> Result<crate::types::TimeEntry, crate::types::error::Error> {
316        let mut req = self.client.client.request(
317            http::Method::POST,
318            format!("{}/{}", self.client.base_url, "time-entries"),
319        );
320        req = req.bearer_auth(&self.client.token);
321        req = req.json(body);
322        let resp = req.send().await?;
323        let status = resp.status();
324        if status.is_success() {
325            let text = resp.text().await.unwrap_or_default();
326            serde_json::from_str(&text).map_err(|err| {
327                crate::types::error::Error::from_serde_error(
328                    format_serde_error::SerdeError::new(text.to_string(), err),
329                    status,
330                )
331            })
332        } else {
333            let text = resp.text().await.unwrap_or_default();
334            Err(crate::types::error::Error::Server {
335                body: text.to_string(),
336                status,
337            })
338        }
339    }
340
341    #[doc = "Retrieve a specific time entry\n\nRetrieve a specific time entry\n\n**Parameters:**\n\n- `expand: Option<String>`\n- `id: &'astr`: ID of the resource to return (required)\n\n```rust,no_run\nasync fn example_time_entries_get() -> anyhow::Result<()> {\n    let client = rippling_api::Client::new_from_env();\n    let result: rippling_api::types::GetTimeEntriesResponse = client\n        .time_entries()\n        .get(\n            Some(\"some-string\".to_string()),\n            \"d9797f8d-9ad6-4e08-90d7-2ec17e13471c\",\n        )\n        .await?;\n    println!(\"{:?}\", result);\n    Ok(())\n}\n```"]
342    #[tracing::instrument]
343    pub async fn get<'a>(
344        &'a self,
345        expand: Option<String>,
346        id: &'a str,
347    ) -> Result<crate::types::GetTimeEntriesResponse, crate::types::error::Error> {
348        let mut req = self.client.client.request(
349            http::Method::GET,
350            format!(
351                "{}/{}",
352                self.client.base_url,
353                "time-entries/{id}".replace("{id}", id)
354            ),
355        );
356        req = req.bearer_auth(&self.client.token);
357        let mut query_params = vec![];
358        if let Some(p) = expand {
359            query_params.push(("expand", p));
360        }
361
362        req = req.query(&query_params);
363        let resp = req.send().await?;
364        let status = resp.status();
365        if status.is_success() {
366            let text = resp.text().await.unwrap_or_default();
367            serde_json::from_str(&text).map_err(|err| {
368                crate::types::error::Error::from_serde_error(
369                    format_serde_error::SerdeError::new(text.to_string(), err),
370                    status,
371                )
372            })
373        } else {
374            let text = resp.text().await.unwrap_or_default();
375            Err(crate::types::error::Error::Server {
376                body: text.to_string(),
377                status,
378            })
379        }
380    }
381
382    #[doc = "Delete a time entry\n\n**Parameters:**\n\n- `id: &'astr`: ID of the resource to \
383             delete (required)\n\n```rust,no_run\nasync fn example_time_entries_delete() -> \
384             anyhow::Result<()> {\n    let client = rippling_api::Client::new_from_env();\n    \
385             client\n        .time_entries()\n        \
386             .delete(\"d9797f8d-9ad6-4e08-90d7-2ec17e13471c\")\n        .await?;\n    \
387             Ok(())\n}\n```"]
388    #[tracing::instrument]
389    pub async fn delete<'a>(&'a self, id: &'a str) -> Result<(), crate::types::error::Error> {
390        let mut req = self.client.client.request(
391            http::Method::DELETE,
392            format!(
393                "{}/{}",
394                self.client.base_url,
395                "time-entries/{id}".replace("{id}", id)
396            ),
397        );
398        req = req.bearer_auth(&self.client.token);
399        let resp = req.send().await?;
400        let status = resp.status();
401        if status.is_success() {
402            Ok(())
403        } else {
404            let text = resp.text().await.unwrap_or_default();
405            Err(crate::types::error::Error::Server {
406                body: text.to_string(),
407                status,
408            })
409        }
410    }
411
412    #[doc = "Update a time entry\n\nUpdated a specific time entry\n\n**Parameters:**\n\n- `id: &'astr`: ID of the resource to patch (required)\n\n```rust,no_run\nasync fn example_time_entries_update() -> anyhow::Result<()> {\n    let client = rippling_api::Client::new_from_env();\n    let result: rippling_api::types::TimeEntry = client\n        .time_entries()\n        .update(\n            \"d9797f8d-9ad6-4e08-90d7-2ec17e13471c\",\n            &rippling_api::types::TimeEntryRequest {\n                worker_id: \"some-string\".to_string(),\n                duration: Some(3.14 as f64),\n                comments: Some(vec![rippling_api::types::TimeEntryCommentRequest {\n                    text: Some(\"some-string\".to_string()),\n                }]),\n                job_shifts: Some(vec![rippling_api::types::JobShiftRequest {\n                    start_time: Some(\"some-string\".to_string()),\n                    end_time: Some(\"some-string\".to_string()),\n                    duration: Some(3.14 as f64),\n                    start_date: Some(\"some-string\".to_string()),\n                    original_start_time: Some(\"some-string\".to_string()),\n                    original_end_time: Some(\"some-string\".to_string()),\n                    job_codes_id: Some(vec![\"some-string\".to_string()]),\n                    is_hours_only_input: Some(true),\n                }]),\n                breaks: Some(vec![rippling_api::types::BreakRequest {\n                    start_time: Some(\"some-string\".to_string()),\n                    end_time: Some(\"some-string\".to_string()),\n                    break_type_id: Some(\"some-string\".to_string()),\n                }]),\n                tags: Some(vec![\"some-string\".to_string()]),\n                idempotency_key: Some(\"some-string\".to_string()),\n                create_extra_hours_run: Some(true),\n                status: Some(rippling_api::types::TimeEntryRequestStatus::Paid),\n                pay_period: Some(rippling_api::types::PayPeriodRequest {\n                    start_date: Some(\"some-string\".to_string()),\n                    end_date: Some(\"some-string\".to_string()),\n                    pay_schedule_id: Some(\"some-string\".to_string()),\n                }),\n                shift_input_values: Some(vec![rippling_api::types::ShiftInputValueRequest {\n                    shift_input_id: \"some-string\".to_string(),\n                    author_id: Some(\"some-string\".to_string()),\n                }]),\n            },\n        )\n        .await?;\n    println!(\"{:?}\", result);\n    Ok(())\n}\n```"]
413    #[tracing::instrument]
414    pub async fn update<'a>(
415        &'a self,
416        id: &'a str,
417        body: &crate::types::TimeEntryRequest,
418    ) -> Result<crate::types::TimeEntry, crate::types::error::Error> {
419        let mut req = self.client.client.request(
420            http::Method::PATCH,
421            format!(
422                "{}/{}",
423                self.client.base_url,
424                "time-entries/{id}".replace("{id}", id)
425            ),
426        );
427        req = req.bearer_auth(&self.client.token);
428        req = req.json(body);
429        let resp = req.send().await?;
430        let status = resp.status();
431        if status.is_success() {
432            let text = resp.text().await.unwrap_or_default();
433            serde_json::from_str(&text).map_err(|err| {
434                crate::types::error::Error::from_serde_error(
435                    format_serde_error::SerdeError::new(text.to_string(), err),
436                    status,
437                )
438            })
439        } else {
440            let text = resp.text().await.unwrap_or_default();
441            Err(crate::types::error::Error::Server {
442                body: text.to_string(),
443                status,
444            })
445        }
446    }
447}