evergreen/common/
renew.rs1use crate as eg;
2use eg::common::circulator::{CircOp, Circulator};
3use eg::common::holds;
4use eg::date;
5use eg::EgEvent;
6use eg::EgResult;
7use eg::EgValue;
8
9impl Circulator<'_> {
11 pub fn renew(&mut self) -> EgResult<()> {
16 self.circ_op = CircOp::Renew;
17 self.init()?;
18
19 log::info!("{self} starting renew");
20
21 self.load_renewal_circ()?;
22 self.basic_renewal_checks()?;
23
24 if !self.editor.allowed_at("COPY_CHECKOUT", self.circ_lib)? {
27 return Err(self.editor().die_event());
28 }
29
30 self.checkin()?;
31 self.checkout()
32 }
33
34 pub fn load_renewal_circ(&mut self) -> EgResult<()> {
36 let mut query = eg::hash! {
37 "target_copy": self.copy_id,
38 "xact_finish": EgValue::Null,
39 "checkin_time": EgValue::Null,
40 };
41
42 if self.patron_id > 0 {
43 query["usr"] = EgValue::from(self.patron_id);
45 }
46
47 let flesh = eg::hash! {
48 "flesh": 2,
49 "flesh_fields": {
50 "circ": ["usr"],
51 "au": ["card"],
52 }
53 };
54
55 let mut circ = self
56 .editor()
57 .search_with_ops("circ", query, flesh)?
58 .pop()
59 .ok_or_else(|| self.editor().die_event())?;
60
61 let circ_id = circ.id()?;
62 let patron = circ["usr"].take(); self.patron_id = patron.id()?;
64 self.patron = Some(patron);
65
66 circ["usr"] = EgValue::from(self.patron_id);
68
69 self.parent_circ = Some(circ_id);
70 self.circ = Some(circ);
71
72 Ok(())
73 }
74
75 fn basic_renewal_checks(&mut self) -> EgResult<()> {
78 let circ = self.circ.as_ref().unwrap();
79 let patron = self.patron.as_ref().unwrap();
80
81 let orig_circ_lib = circ["circ_lib"].int()?;
82
83 let renewal_remaining = circ["renewal_remaining"].int()?;
84 let auto_renewal_remaining = circ["auto_renewal_remaining"].int();
86
87 let expire_date = patron["expire_date"].as_str().unwrap(); let expire_dt = date::parse_datetime(expire_date)?;
89
90 let circ_lib = self.set_renewal_circ_lib(orig_circ_lib)?;
91
92 if self.patron_id != self.requestor_id()?
93 && !self.editor().allowed_at("RENEW_CIRC", circ_lib)?
94 {
95 return Err(self.editor().die_event());
96 }
97
98 if renewal_remaining < 1 {
99 self.exit_err_on_event_code("MAX_RENEWALS_REACHED")?;
100 }
101
102 self.renewal_remaining = renewal_remaining - 1;
103
104 if let Ok(n) = auto_renewal_remaining {
106 if n < 1 {
107 self.exit_err_on_event_code("MAX_RENEWALS_REACHED")?;
108 }
109 self.auto_renewal_remaining = Some(n - 1);
110 }
111
112 if expire_dt < date::now() {
114 let allow = self.settings.get_value("circ.renew.expired_patron_allow")?;
115 if !allow.boolish() {
116 self.exit_err_on_event_code("PATRON_ACCOUNT_EXPIRED")?;
117 }
118 }
119
120 let copy_id = self.copy_id;
121 let block_for_holds = self
122 .settings
123 .get_value("circ.block_renews_for_holds")?
124 .boolish();
125
126 if block_for_holds {
127 let holds = holds::find_nearest_permitted_hold(self.editor(), copy_id, true)?;
128 if holds.is_some() {
129 self.add_event(EgEvent::new("COPY_NEEDED_FOR_HOLD"));
130 }
131 }
132
133 Ok(())
134 }
135
136 fn set_renewal_circ_lib(&mut self, orig_circ_lib: i64) -> EgResult<i64> {
137 let is_opac = self
138 .options
139 .get("opac_renewal")
140 .unwrap_or(&eg::NULL)
141 .boolish();
142 let is_auto = self
143 .options
144 .get("auto_renewal")
145 .unwrap_or(&eg::NULL)
146 .boolish();
147 let is_desk = self
148 .options
149 .get("desk_renewal")
150 .unwrap_or(&eg::NULL)
151 .boolish();
152
153 if is_opac || is_auto {
154 if let Some(setting) = self
155 .editor()
156 .retrieve("cgf", "circ.opac_renewal.use_original_circ_lib")?
157 .take()
158 {
159 if setting["enabled"].boolish() {
160 self.circ_lib = orig_circ_lib;
161 self.settings.set_org_id(orig_circ_lib);
162 return Ok(orig_circ_lib);
163 }
164 }
165 }
166
167 if is_desk {
168 if let Some(setting) = self
169 .editor()
170 .retrieve("cgf", "circ.desk_renewal.use_original_circ_lib")?
171 .take()
172 {
173 if setting["enabled"].boolish() {
174 self.circ_lib = orig_circ_lib;
175 self.settings.set_org_id(orig_circ_lib);
176 return Ok(orig_circ_lib);
177 }
178 }
179 }
180
181 Ok(self.circ_lib)
183 }
184}