sz_configtool_lib/calls/
distinct.rs1use crate::error::{Result, SzConfigError};
7use crate::helpers::{
8 find_in_config_array, get_next_id, lookup_dfunc_id, lookup_element_id, lookup_feature_id,
9};
10use serde_json::{Value, json};
11
12#[derive(Debug, Clone)]
18pub struct AddDistinctCallParams {
19 pub ftype_code: String,
20 pub dfunc_code: String,
21 pub element_list: Vec<String>,
22}
23
24impl TryFrom<&Value> for AddDistinctCallParams {
25 type Error = SzConfigError;
26
27 fn try_from(json: &Value) -> Result<Self> {
28 Ok(Self {
29 ftype_code: json
30 .get("ftypeCode")
31 .and_then(|v| v.as_str())
32 .ok_or_else(|| SzConfigError::MissingField("ftypeCode".to_string()))?
33 .to_string(),
34 dfunc_code: json
35 .get("dfuncCode")
36 .and_then(|v| v.as_str())
37 .ok_or_else(|| SzConfigError::MissingField("dfuncCode".to_string()))?
38 .to_string(),
39 element_list: json
40 .get("elementList")
41 .and_then(|v| v.as_array())
42 .map(|arr| {
43 arr.iter()
44 .filter_map(|v| v.as_str().map(|s| s.to_string()))
45 .collect()
46 })
47 .unwrap_or_default(),
48 })
49 }
50}
51
52#[derive(Debug, Clone)]
54pub struct AddDistinctCallElementParams {
55 pub dfcall_id: i64,
56 pub ftype_id: i64,
57 pub felem_id: i64,
58 pub exec_order: i64,
59}
60
61#[derive(Debug, Clone)]
63pub struct DeleteDistinctCallElementParams {
64 pub dfcall_id: i64,
65 pub ftype_id: i64,
66 pub felem_id: i64,
67 pub exec_order: i64,
68}
69
70#[derive(Debug, Clone, Default)]
72pub struct SetDistinctCallParams {
73 pub dfcall_id: i64,
74 pub exec_order: Option<i64>,
75}
76
77impl TryFrom<&Value> for SetDistinctCallParams {
78 type Error = SzConfigError;
79
80 fn try_from(json: &Value) -> Result<Self> {
81 let dfcall_id = json
82 .get("dfcallId")
83 .and_then(|v| v.as_i64())
84 .ok_or_else(|| SzConfigError::MissingField("dfcallId".to_string()))?;
85
86 Ok(Self {
87 dfcall_id,
88 exec_order: json.get("execOrder").and_then(|v| v.as_i64()),
89 })
90 }
91}
92
93#[derive(Debug, Clone)]
95pub struct SetDistinctCallElementParams {
96 pub dfcall_id: i64,
97 pub ftype_id: i64,
98 pub felem_id: i64,
99 pub exec_order: i64,
100 pub updates: Value,
101}
102
103pub fn add_distinct_call(config: &str, params: AddDistinctCallParams) -> Result<(String, Value)> {
120 let mut config_data: Value =
121 serde_json::from_str(config).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
122
123 if params.element_list.is_empty() {
125 return Err(SzConfigError::InvalidInput(
126 "No elements were found in the elementList".to_string(),
127 ));
128 }
129
130 for (idx, element_code) in params.element_list.iter().enumerate() {
132 if element_code.trim().is_empty() {
133 return Err(SzConfigError::InvalidInput(format!(
134 "Element cannot be blank in item {} on the element list",
135 idx + 1
136 )));
137 }
138 }
139
140 let dfcall_id = get_next_id(&config_data, "G2_CONFIG.CFG_DFCALL", "DFCALL_ID", 1000)?;
142
143 let ftype_id = lookup_feature_id(config, ¶ms.ftype_code)?;
145
146 let call_exists = config_data["G2_CONFIG"]["CFG_DFCALL"]
148 .as_array()
149 .map(|arr| {
150 arr.iter()
151 .any(|call| call["FTYPE_ID"].as_i64() == Some(ftype_id))
152 })
153 .unwrap_or(false);
154
155 if call_exists {
156 return Err(SzConfigError::AlreadyExists(format!(
157 "Distinct call for feature {} already set",
158 params.ftype_code
159 )));
160 }
161
162 let dfunc_id = lookup_dfunc_id(config, ¶ms.dfunc_code)?;
164
165 let mut dfbom_records = Vec::new();
167 let mut exec_order = 0;
168
169 for (idx, element_code) in params.element_list.iter().enumerate() {
170 exec_order += 1;
171
172 if element_code.trim().is_empty() {
174 return Err(SzConfigError::InvalidInput(format!(
175 "Element cannot be blank in item {} on the element list",
176 idx + 1
177 )));
178 }
179
180 let bom_felem_id = lookup_element_id(config, element_code)?;
182
183 dfbom_records.push(json!({
185 "DFCALL_ID": dfcall_id,
186 "FTYPE_ID": ftype_id,
187 "FELEM_ID": bom_felem_id,
188 "EXEC_ORDER": exec_order
189 }));
190 }
191
192 let new_record = json!({
194 "DFCALL_ID": dfcall_id,
195 "FTYPE_ID": ftype_id,
196 "DFUNC_ID": dfunc_id,
197 "EXEC_ORDER": 1
198 });
199
200 if let Some(dfcall_array) = config_data["G2_CONFIG"]["CFG_DFCALL"].as_array_mut() {
202 dfcall_array.push(new_record.clone());
203 } else {
204 return Err(SzConfigError::MissingSection("CFG_DFCALL".to_string()));
205 }
206
207 if let Some(dfbom_array) = config_data["G2_CONFIG"]["CFG_DFBOM"].as_array_mut() {
208 dfbom_array.extend(dfbom_records);
209 } else {
210 return Err(SzConfigError::MissingSection("CFG_DFBOM".to_string()));
211 }
212
213 let modified_config =
214 serde_json::to_string(&config_data).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
215
216 Ok((modified_config, new_record))
217}
218
219pub fn delete_distinct_call(config: &str, dfcall_id: i64) -> Result<String> {
233 let mut config_data: Value =
234 serde_json::from_str(config).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
235
236 let call_exists = config_data["G2_CONFIG"]["CFG_DFCALL"]
238 .as_array()
239 .map(|arr| {
240 arr.iter()
241 .any(|call| call["DFCALL_ID"].as_i64() == Some(dfcall_id))
242 })
243 .unwrap_or(false);
244
245 if !call_exists {
246 return Err(SzConfigError::NotFound(format!(
247 "Distinct call ID {dfcall_id} does not exist"
248 )));
249 }
250
251 if let Some(dfcall_array) = config_data["G2_CONFIG"]["CFG_DFCALL"].as_array_mut() {
253 dfcall_array.retain(|record| record["DFCALL_ID"].as_i64() != Some(dfcall_id));
254 }
255
256 if let Some(dfbom_array) = config_data["G2_CONFIG"]["CFG_DFBOM"].as_array_mut() {
258 dfbom_array.retain(|record| record["DFCALL_ID"].as_i64() != Some(dfcall_id));
259 }
260
261 serde_json::to_string(&config_data).map_err(|e| SzConfigError::JsonParse(e.to_string()))
262}
263
264pub fn get_distinct_call(config: &str, dfcall_id: i64) -> Result<Value> {
276 find_in_config_array(config, "CFG_DFCALL", "DFCALL_ID", &dfcall_id.to_string())?.ok_or_else(
277 || SzConfigError::NotFound(format!("Distinct call ID {dfcall_id} does not exist")),
278 )
279}
280
281pub fn list_distinct_calls(config: &str) -> Result<Vec<Value>> {
291 let config_data: Value =
292 serde_json::from_str(config).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
293
294 let empty_array = vec![];
295 let dfcall_array = config_data
296 .get("G2_CONFIG")
297 .and_then(|g| g.get("CFG_DFCALL"))
298 .and_then(|v| v.as_array())
299 .unwrap_or(&empty_array);
300
301 let ftype_array = config_data
302 .get("G2_CONFIG")
303 .and_then(|g| g.get("CFG_FTYPE"))
304 .and_then(|v| v.as_array())
305 .unwrap_or(&empty_array);
306
307 let dfunc_array = config_data
308 .get("G2_CONFIG")
309 .and_then(|g| g.get("CFG_DFUNC"))
310 .and_then(|v| v.as_array())
311 .unwrap_or(&empty_array);
312
313 let resolve_ftype = |ftype_id: i64| -> String {
315 ftype_array
316 .iter()
317 .find(|ft| ft.get("FTYPE_ID").and_then(|v| v.as_i64()) == Some(ftype_id))
318 .and_then(|ft| ft.get("FTYPE_CODE"))
319 .and_then(|v| v.as_str())
320 .unwrap_or("unknown")
321 .to_string()
322 };
323
324 let resolve_dfunc = |dfunc_id: i64| -> String {
325 dfunc_array
326 .iter()
327 .find(|df| df.get("DFUNC_ID").and_then(|v| v.as_i64()) == Some(dfunc_id))
328 .and_then(|df| df.get("DFUNC_CODE"))
329 .and_then(|v| v.as_str())
330 .unwrap_or("unknown")
331 .to_string()
332 };
333
334 let items: Vec<Value> = dfcall_array
336 .iter()
337 .map(|item| {
338 let ftype_id = item.get("FTYPE_ID").and_then(|v| v.as_i64()).unwrap_or(0);
339 let dfunc_id = item.get("DFUNC_ID").and_then(|v| v.as_i64()).unwrap_or(0);
340
341 json!({
342 "id": item.get("DFCALL_ID").and_then(|v| v.as_i64()).unwrap_or(0),
343 "feature": resolve_ftype(ftype_id),
344 "function": resolve_dfunc(dfunc_id),
345 "execOrder": item.get("EXEC_ORDER").and_then(|v| v.as_i64()).unwrap_or(1)
346 })
347 })
348 .collect();
349
350 Ok(items)
351}
352
353pub fn set_distinct_call(config: &str, _params: SetDistinctCallParams) -> Result<String> {
362 Ok(config.to_string())
364}
365
366pub fn add_distinct_call_element(
377 config: &str,
378 params: AddDistinctCallElementParams,
379) -> Result<(String, Value)> {
380 let mut config_data: Value =
381 serde_json::from_str(config).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
382
383 if let Some(dbom_array) = config_data
385 .get("G2_CONFIG")
386 .and_then(|g| g.get("CFG_DFBOM"))
387 .and_then(|v| v.as_array())
388 {
389 for item in dbom_array {
390 if item.get("DFCALL_ID").and_then(|v| v.as_i64()) == Some(params.dfcall_id)
391 && item.get("FTYPE_ID").and_then(|v| v.as_i64()) == Some(params.ftype_id)
392 && item.get("FELEM_ID").and_then(|v| v.as_i64()) == Some(params.felem_id)
393 && item.get("EXEC_ORDER").and_then(|v| v.as_i64()) == Some(params.exec_order)
394 {
395 return Err(SzConfigError::AlreadyExists(
396 "Distinct call element already exists".to_string(),
397 ));
398 }
399 }
400 }
401
402 let new_record = json!({
404 "DFCALL_ID": params.dfcall_id,
405 "FTYPE_ID": params.ftype_id,
406 "FELEM_ID": params.felem_id,
407 "EXEC_ORDER": params.exec_order
408 });
409
410 if let Some(dbom_array) = config_data["G2_CONFIG"]["CFG_DFBOM"].as_array_mut() {
412 dbom_array.push(new_record.clone());
413 } else {
414 return Err(SzConfigError::MissingSection("CFG_DFBOM".to_string()));
415 }
416
417 let modified_config =
418 serde_json::to_string(&config_data).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
419
420 Ok((modified_config, new_record))
421}
422
423pub fn delete_distinct_call_element(
432 config: &str,
433 params: DeleteDistinctCallElementParams,
434) -> Result<String> {
435 let mut config_data: Value =
436 serde_json::from_str(config).map_err(|e| SzConfigError::JsonParse(e.to_string()))?;
437
438 let element_exists = config_data["G2_CONFIG"]["CFG_DFBOM"]
440 .as_array()
441 .map(|arr| {
442 arr.iter().any(|item| {
443 item.get("DFCALL_ID").and_then(|v| v.as_i64()) == Some(params.dfcall_id)
444 && item.get("FTYPE_ID").and_then(|v| v.as_i64()) == Some(params.ftype_id)
445 && item.get("FELEM_ID").and_then(|v| v.as_i64()) == Some(params.felem_id)
446 && item.get("EXEC_ORDER").and_then(|v| v.as_i64()) == Some(params.exec_order)
447 })
448 })
449 .unwrap_or(false);
450
451 if !element_exists {
452 return Err(SzConfigError::NotFound(
453 "Distinct call element not found".to_string(),
454 ));
455 }
456
457 if let Some(dbom_array) = config_data["G2_CONFIG"]["CFG_DFBOM"].as_array_mut() {
459 dbom_array.retain(|item| {
460 !(item.get("DFCALL_ID").and_then(|v| v.as_i64()) == Some(params.dfcall_id)
461 && item.get("FTYPE_ID").and_then(|v| v.as_i64()) == Some(params.ftype_id)
462 && item.get("FELEM_ID").and_then(|v| v.as_i64()) == Some(params.felem_id)
463 && item.get("EXEC_ORDER").and_then(|v| v.as_i64()) == Some(params.exec_order))
464 });
465 }
466
467 serde_json::to_string(&config_data).map_err(|e| SzConfigError::JsonParse(e.to_string()))
468}
469
470pub fn set_distinct_call_element(
479 config: &str,
480 _params: SetDistinctCallElementParams,
481) -> Result<String> {
482 Ok(config.to_string())
484}