zeebe_rs/job/
complete.rs

1use crate::{Client, ClientError, proto};
2use serde::Serialize;
3
4/// Corrections that can be applied when completing a job
5#[derive(Debug, Clone)]
6pub struct JobResultCorrections {
7    assignee: Option<String>,
8    due_date: Option<String>,
9    follow_up_date: Option<String>,
10    candidate_users: Option<Vec<String>>,
11    candidate_groups: Option<Vec<String>>,
12    priority: Option<i32>,
13}
14
15/// Result of a completed job including possible corrections
16#[derive(Debug, Clone)]
17pub struct JobResult {
18    /// Whether the job completion was denied
19    denied: Option<bool>,
20    /// Corrections to apply to the job
21    corrections: Option<JobResultCorrections>,
22}
23
24/// Builder for constructing job results
25#[derive(Debug, Clone)]
26pub struct JobResultBuilder {
27    source_request: CompleteJobRequest<WithKey>,
28    job_result: Option<JobResult>,
29}
30
31impl JobResultBuilder {
32    fn new(source_request: CompleteJobRequest<WithKey>) -> JobResultBuilder {
33        JobResultBuilder {
34            source_request,
35            job_result: None,
36        }
37    }
38
39    /// Sets whether the job completion was denied
40    ///
41    /// # Arguments
42    ///
43    /// * `denied` - A boolean indicating if the job completion was denied
44    ///
45    /// # Returns
46    ///
47    /// The updated `JobResultBuilder` instance
48    pub fn with_denied(mut self, denied: bool) -> Self {
49        if let Some(job_result) = self.job_result.as_mut() {
50            job_result.denied = Some(denied);
51        } else {
52            self.job_result = Some(JobResult {
53                denied: Some(denied),
54                corrections: None,
55            });
56        }
57
58        self
59    }
60
61    /// Internal helper to ensure job result corrections are initialized
62    ///
63    /// Creates default corrections if they don't exist and returns a mutable reference
64    /// to allow modifying individual correction fields.
65    ///
66    /// # Returns
67    ///
68    /// A mutable reference to `JobResultCorrections`
69    fn ensure_corrections(&mut self) -> &mut JobResultCorrections {
70        if self.job_result.is_none() {
71            self.job_result = Some(JobResult {
72                denied: None,
73                corrections: Some(JobResultCorrections {
74                    assignee: None,
75                    due_date: None,
76                    follow_up_date: None,
77                    candidate_users: None,
78                    candidate_groups: None,
79                    priority: None,
80                }),
81            });
82        }
83
84        let job_result = self.job_result.as_mut().unwrap();
85        if job_result.corrections.is_none() {
86            job_result.corrections = Some(JobResultCorrections {
87                assignee: None,
88                due_date: None,
89                follow_up_date: None,
90                candidate_users: None,
91                candidate_groups: None,
92                priority: None,
93            });
94        }
95
96        job_result.corrections.as_mut().unwrap()
97    }
98
99    /// Sets a new assignee for the job
100    ///
101    /// # Arguments
102    ///
103    /// * `assignee` - The new assignee to be set for the job
104    ///
105    /// # Returns
106    ///
107    /// The updated `JobResultBuilder` instance
108    pub fn with_assignee(mut self, assignee: String) -> Self {
109        self.ensure_corrections().assignee = Some(assignee);
110        self
111    }
112
113    /// Sets a new due date for the job
114    ///
115    /// # Arguments
116    ///
117    /// * `due_date` - The new due date to be set for the job
118    ///
119    /// # Returns
120    ///
121    /// The updated `JobResultBuilder` instance
122    pub fn with_due_date(mut self, due_date: String) -> Self {
123        self.ensure_corrections().due_date = Some(due_date);
124        self
125    }
126
127    /// Sets a new follow-up date for the job
128    ///
129    /// # Arguments
130    ///
131    /// * `follow_up_date` - The new follow-up date to be set for the job
132    ///
133    /// # Returns
134    ///
135    /// The updated `JobResultBuilder` instance
136    pub fn with_follow_up_date(mut self, follow_up_date: String) -> Self {
137        self.ensure_corrections().follow_up_date = Some(follow_up_date);
138        self
139    }
140
141    /// Sets new candidate users for the job
142    ///
143    /// # Arguments
144    ///
145    /// * `candidate_users` - List of user IDs that are candidates for this job
146    ///
147    /// # Returns
148    ///
149    /// The updated `JobResultBuilder` instance
150    pub fn with_candidate_users(mut self, candidate_users: Vec<String>) -> Self {
151        self.ensure_corrections().candidate_users = Some(candidate_users);
152        self
153    }
154
155    /// Sets new candidate groups for the job
156    ///
157    /// # Arguments
158    ///
159    /// * `candidate_groups` - List of group IDs that are candidates for this job
160    ///
161    /// # Returns
162    ///
163    /// The updated `JobResultBuilder` instance
164    pub fn with_candidate_groups(mut self, candidate_groups: Vec<String>) -> Self {
165        self.ensure_corrections().candidate_groups = Some(candidate_groups);
166        self
167    }
168
169    /// Sets a new priority for the job
170    ///
171    /// # Arguments
172    ///
173    /// * `priority` - The new priority value to be set for the job
174    ///
175    /// # Returns
176    ///
177    /// The updated `JobResultBuilder` instance
178    pub fn with_priority(mut self, priority: i32) -> Self {
179        self.ensure_corrections().priority = Some(priority);
180        self
181    }
182
183    /// Builds the final CompleteJobRequest with the configured job result
184    ///
185    /// Consumes the builder and returns the configured request ready for sending
186    ///
187    /// # Returns
188    ///
189    /// The configured `CompleteJobRequest<WithKey>` instance
190    pub fn build(mut self) -> CompleteJobRequest<WithKey> {
191        self.source_request.result = self.job_result;
192        self.source_request
193    }
194}
195
196#[derive(Debug, Clone)]
197pub struct Initial;
198
199#[derive(Debug, Clone)]
200pub struct WithKey;
201
202pub trait CompleteJobRequestState {}
203impl CompleteJobRequestState for Initial {}
204impl CompleteJobRequestState for WithKey {}
205
206/// Request to complete a job in Zeebe for a process instance
207///
208/// # Examples
209///
210/// ```ignore
211/// client
212///     .complete_job()
213///     .with_job_key(123456)
214///     .send()
215///     .await?;
216/// ```
217#[derive(Debug, Clone)]
218pub struct CompleteJobRequest<T: CompleteJobRequestState> {
219    client: Client,
220    job_key: i64,
221    variables: serde_json::Value,
222    result: Option<JobResult>,
223    _state: std::marker::PhantomData<T>,
224}
225
226impl<T: CompleteJobRequestState> CompleteJobRequest<T> {
227    pub(crate) fn new(client: Client) -> CompleteJobRequest<Initial> {
228        CompleteJobRequest {
229            client,
230            job_key: 0,
231            variables: serde_json::Value::default(),
232            result: None,
233            _state: std::marker::PhantomData,
234        }
235    }
236
237    fn transition<NewState: CompleteJobRequestState>(self) -> CompleteJobRequest<NewState> {
238        CompleteJobRequest {
239            client: self.client,
240            job_key: self.job_key,
241            variables: self.variables,
242            result: self.result,
243            _state: std::marker::PhantomData,
244        }
245    }
246}
247
248impl CompleteJobRequest<Initial> {
249    /// Sets the job key to identify which job to complete
250    ///
251    /// # Arguments
252    ///
253    /// * `job_key` - The unique key identifying the job
254    ///
255    /// # Returns
256    ///
257    /// A new instance of `CompleteJobRequest<WithKey>`
258    pub fn with_job_key(mut self, job_key: i64) -> CompleteJobRequest<WithKey> {
259        self.job_key = job_key;
260        self.transition()
261    }
262}
263
264impl CompleteJobRequest<WithKey> {
265    /// Sets variables to be included with the job completion
266    ///
267    /// # Arguments
268    ///
269    /// * `data` - The variables to be set when completing the job
270    ///
271    /// # Returns
272    ///
273    /// A result containing the updated `CompleteJobRequest<WithKey>` instance or a `ClientError`
274    pub fn with_variables<T: Serialize>(mut self, data: T) -> Result<Self, ClientError> {
275        self.variables = serde_json::to_value(data)
276            .map_err(|e| ClientError::SerializationFailed { source: e })?;
277        Ok(self)
278    }
279
280    /// Starts building a job result with corrections
281    ///
282    /// # Returns
283    ///
284    /// A new instance of `JobResultBuilder`
285    pub fn with_job_result(self) -> JobResultBuilder {
286        JobResultBuilder::new(self)
287    }
288
289    /// Sends the job completion request to the Zeebe workflow engine
290    ///
291    /// # Returns
292    ///
293    /// A result containing the `CompleteJobResponse` or a `ClientError`
294    pub async fn send(mut self) -> Result<CompleteJobResponse, ClientError> {
295        let res = self
296            .client
297            .gateway_client
298            .complete_job(proto::CompleteJobRequest {
299                job_key: self.job_key,
300                variables: self.variables.to_string(),
301                result: self.result.map(|x| proto::JobResult {
302                    denied: x.denied,
303                    corrections: x.corrections.map(|c| proto::JobResultCorrections {
304                        assignee: c.assignee,
305                        due_date: c.due_date,
306                        follow_up_date: c.follow_up_date,
307                        candidate_users: c.candidate_users.map(|u| proto::StringList { values: u }),
308                        candidate_groups: c
309                            .candidate_groups
310                            .map(|g| proto::StringList { values: g }),
311                        priority: c.priority,
312                    }),
313                }),
314            })
315            .await?;
316
317        Ok(res.into_inner().into())
318    }
319}
320
321/// Response from completing a job
322#[derive(Debug, Clone)]
323pub struct CompleteJobResponse {}
324
325impl From<proto::CompleteJobResponse> for CompleteJobResponse {
326    fn from(_value: proto::CompleteJobResponse) -> CompleteJobResponse {
327        CompleteJobResponse {}
328    }
329}