evergreen/common/
penalty.rs1use crate as eg;
3use eg::common::settings::Settings;
4use eg::common::trigger;
5use eg::editor::Editor;
6use eg::result::EgResult;
7use eg::EgValue;
8
9fn number(v: &EgValue) -> i64 {
13 v.int().expect("Has Number")
14}
15
16pub fn calculate_penalties(
17 editor: &mut Editor,
18 user_id: i64,
19 context_org: i64,
20 only_penalties: Option<&Vec<EgValue>>,
21) -> EgResult<()> {
22 let query = eg::hash! {
23 from: [
24 "actor.calculate_system_penalties",
25 user_id, context_org
26 ]
27 };
28
29 let penalties = editor.json_query(query)?;
32
33 let penalties = trim_to_wanted_penalties(editor, context_org, only_penalties, penalties)?;
34
35 if penalties.is_empty() {
36 return Ok(());
38 }
39
40 let mut existing_penalties: Vec<&EgValue> =
42 penalties.iter().filter(|p| !p["id"].is_null()).collect();
43
44 let wanted_penalties: Vec<&EgValue> = penalties.iter().filter(|p| p["id"].is_null()).collect();
46
47 let mut trigger_events: Vec<(String, EgValue, i64)> = Vec::new();
48
49 for pen_hash in wanted_penalties {
50 let org_unit = number(&pen_hash["org_unit"]);
51 let penalty = number(&pen_hash["standing_penalty"]);
52
53 let existing = existing_penalties.iter().find(|p| {
55 let e_org_unit = number(&p["org_unit"]);
56 let e_penalty = number(&p["standing_penalty"]);
57 org_unit == e_org_unit && penalty == e_penalty
58 });
59
60 if let Some(epen) = existing {
61 let id = number(&epen["id"]);
64
65 existing_penalties.retain(|p| number(&p["id"]) != id);
66 } else {
67 let new_pen = EgValue::create("ausp", pen_hash.clone())?;
69 let new_pen = editor.create(new_pen)?;
70
71 let csp_id = pen_hash["standing_penalty"].clone();
73
74 let csp = editor
75 .retrieve("csp", csp_id)?
76 .ok_or_else(|| editor.die_event())?;
77
78 let evt_name = format!("penalty.{}", csp["name"]);
79 trigger_events.push((evt_name, new_pen, context_org));
80 }
81 }
82
83 for pen_hash in existing_penalties {
85 let del_pen = EgValue::create("ausp", pen_hash.clone())?;
86 editor.delete(del_pen)?;
87 }
88
89 for events in trigger_events {
90 trigger::create_events_for_object(
91 editor, &events.0, &events.1, events.2, None, None, false, )?;
98 }
99
100 Ok(())
101}
102
103fn trim_to_wanted_penalties(
107 editor: &mut Editor,
108 context_org: i64,
109 only_penalties: Option<&Vec<EgValue>>,
110 all_penalties: Vec<EgValue>,
111) -> EgResult<Vec<EgValue>> {
112 let only_penalties = match only_penalties {
113 Some(op) => op,
114 None => return Ok(all_penalties),
115 };
116
117 if only_penalties.is_empty() {
118 return Ok(all_penalties);
119 }
120
121 let mut penalty_id_list: Vec<EgValue> = Vec::new();
123 let mut penalty_name_list: Vec<EgValue> = Vec::new();
124
125 for pen in only_penalties {
126 if pen.is_number() {
127 penalty_id_list.push(pen.clone());
128 } else if pen.is_string() {
129 penalty_name_list.push(pen.clone());
130 }
131 }
132
133 if penalty_name_list.is_empty() {
134 let query = eg::hash! {"name": {"in": penalty_name_list.clone()}};
136 let penalty_types = editor.search("csp", query)?;
137 for ptype in penalty_types {
138 penalty_id_list.push(ptype["id"].clone());
139 }
140
141 let mut settings = Settings::new(editor);
144 settings.set_org_id(context_org);
145
146 let names: Vec<String> = penalty_name_list
147 .iter()
148 .map(|n| format!("circ.custom_penalty_override.{n}"))
149 .collect();
150
151 let names: Vec<&str> = names.iter().map(|n| n.as_str()).collect();
152
153 settings.fetch_values(names.as_slice())?; for name in names.iter() {
156 let pen_id = settings.get_value(name)?;
157 if let Some(n) = pen_id.as_int() {
159 penalty_id_list.push(EgValue::from(n));
160 }
161 }
162 }
163
164 let mut final_penalties: Vec<EgValue> = Vec::new();
167 for pen in all_penalties {
168 if penalty_id_list
169 .iter()
170 .any(|id| id == &pen["standing_penalty"])
171 {
172 final_penalties.push(pen);
173 }
174 }
175
176 Ok(final_penalties)
177}