evergreen/
samples.rs

1//! Evergreen sample data and tools
2use crate as eg;
3use eg::constants as C;
4use eg::Editor;
5use eg::EgResult;
6use eg::EgValue;
7
8// Sample data based on the Evergreen Concerto sample data set.
9
10pub const ACN_CREATOR: i64 = 1;
11pub const ACN_RECORD: i64 = 1;
12pub const ACN_LABEL: &str = "_EG_TEST_";
13pub const ACN_LABEL_CLASS: i64 = 1; // Generic
14pub const ACP_STATUS: i64 = C::COPY_STATUS_AVAILABLE;
15pub const ACP_BARCODE: &str = "_EG_TEST_";
16pub const ACP_LOAN_DURATION: i64 = C::CIRC_DURATION_NORMAL;
17pub const ACP_FINE_LEVEL: i64 = C::CIRC_FINE_LEVEL_MEDIUM;
18pub const AOU_BR1_ID: i64 = 4;
19pub const AOU_BR1_SHORTNAME: &str = "BR1";
20pub const AOU_BR2_ID: i64 = 5;
21pub const AOU_BR2_SHORTNAME: &str = "BR2";
22
23pub const AU_BARCODE: &str = "_EG_TEST_";
24pub const AU_PROFILE: i64 = 2; // Patrons
25pub const AU_IDENT_TYPE: i64 = 3; // Other
26
27pub const AU_STAFF_ID: i64 = 195; // br1mclark
28
29pub const PAYMENT_TYPES: [&str; 8] = [
30    "credit_card_payment",
31    "credit_payment",
32    "check_payment",
33    "work_payment",
34    "forgive_payment",
35    "goods_payment",
36    "account_adjustment",
37    "debit_card_payment",
38];
39
40pub struct SampleData {
41    pub acn_creator: i64,
42    pub acn_record: i64,
43    pub aou_id: i64,
44    pub aou_shortname: String,
45    pub acn_label: String,
46    pub acn_label_class: i64,
47    pub acp_barcode: String,
48    pub au_barcode: String,
49    pub au_profile: i64,
50    pub au_ident_type: i64,
51
52    /// If we create any transactions, this tracks the ID of the most
53    /// recently created transaction.
54    pub last_xact_id: Option<i64>,
55}
56
57impl Default for SampleData {
58    fn default() -> Self {
59        SampleData {
60            acn_creator: ACN_CREATOR,
61            acn_record: ACN_RECORD,
62            aou_id: AOU_BR1_ID,
63            acn_label: ACN_LABEL.to_string(),
64            acn_label_class: ACN_LABEL_CLASS,
65            acp_barcode: ACP_BARCODE.to_string(),
66            aou_shortname: AOU_BR1_SHORTNAME.to_string(),
67            au_barcode: AU_BARCODE.to_string(),
68            au_profile: AU_PROFILE,
69            au_ident_type: AU_IDENT_TYPE,
70            last_xact_id: None,
71        }
72    }
73}
74
75impl SampleData {
76    pub fn new() -> SampleData {
77        Default::default()
78    }
79
80    pub fn create_default_acn(&self, e: &mut Editor) -> EgResult<EgValue> {
81        let mut acn = eg::hash! {
82            creator: self.acn_creator,
83            editor: self.acn_creator,
84            record: self.acn_record,
85            owning_lib: self.aou_id,
86            label: self.acn_label.to_string(),
87            label_class: self.acn_label_class,
88        };
89
90        acn.bless("acn")?;
91
92        e.create(acn)
93    }
94
95    pub fn create_default_acp(&self, e: &mut Editor, acn_id: i64) -> EgResult<EgValue> {
96        let mut acp = eg::hash! {
97            call_number: acn_id,
98            creator: self.acn_creator,
99            editor: self.acn_creator,
100            status: ACP_STATUS,
101            circ_lib: self.aou_id,
102            loan_duration: ACP_LOAN_DURATION,
103            fine_level: ACP_FINE_LEVEL,
104            barcode: self.acp_barcode.to_string(),
105        };
106
107        acp.bless("acp")?;
108
109        e.create(acp)
110    }
111
112    pub fn delete_default_acn(&self, e: &mut Editor) -> EgResult<()> {
113        let mut acns = e.search(
114            "acn",
115            eg::hash! {label: self.acn_label.to_string(), deleted: "f"},
116        )?;
117
118        if let Some(acn) = acns.pop() {
119            e.delete(acn)?;
120        }
121
122        Ok(())
123    }
124
125    pub fn get_default_acp(&self, e: &mut Editor) -> EgResult<EgValue> {
126        e.search(
127            "acp",
128            eg::hash! {barcode: self.acp_barcode.to_string(), deleted: "f"},
129        )?
130        .pop()
131        .ok_or_else(|| "Cannot find default copy".into())
132    }
133
134    pub fn delete_default_acp(&self, e: &mut Editor) -> EgResult<()> {
135        if let Ok(acp) = self.get_default_acp(e) {
136            e.delete(acp)?;
137        }
138        Ok(())
139    }
140
141    pub fn modify_default_acp(&self, e: &mut Editor, mut values: EgValue) -> EgResult<()> {
142        let mut acp = self.get_default_acp(e)?;
143        for (k, v) in values.entries_mut() {
144            acp[k] = v.take();
145        }
146        e.update(acp)
147    }
148
149    /// Create default user with a default card.
150    pub fn create_default_au(&self, e: &mut Editor) -> EgResult<EgValue> {
151        let mut au = eg::hash! {
152            profile: self.au_profile,
153            usrname: self.au_barcode.to_string(),
154            passwd: self.au_barcode.to_string(),
155            ident_type: self.au_ident_type,
156            first_given_name: "_EG_TEST_",
157            family_name: "_EG_TEST_",
158            home_ou: self.aou_id,
159        };
160
161        au.bless("au")?;
162
163        let mut au = e.create(au)?;
164
165        let mut ac = eg::hash! {
166            barcode: self.au_barcode.to_string(),
167            usr: au["id"].clone(),
168        };
169
170        ac.bless("ac")?;
171
172        let ac = e.create(ac)?;
173
174        // Link the user back to the card
175        au["card"] = ac["id"].clone();
176        e.update(au.clone())?;
177
178        Ok(au)
179    }
180
181    /// Create a new "grocery" billable transaction with a single billing
182    ///
183    /// Returns the billing value with its "xact" field fleshed.
184    pub fn add_billing(&mut self, e: &mut Editor, btype: i64, amount: f64) -> EgResult<EgValue> {
185        let user_id = self.get_default_user_id(e)?;
186
187        let xact = eg::blessed! {
188            "_classname": "mg",
189            "usr": user_id,
190            "billing_location": self.aou_id,
191        }?;
192
193        let xact = e.create(xact)?;
194
195        self.last_xact_id = Some(xact.id()?);
196
197        let billing = eg::blessed! {
198            "_classname": "mb",
199            "xact": xact.id()?,
200            "btype": btype,
201            "billing_type": "Testing",
202            "amount": amount,
203        }?;
204
205        let mut billing = e.create(billing)?;
206
207        billing["xact"] = xact;
208
209        Ok(billing)
210    }
211
212    fn get_default_user_id(&self, e: &mut Editor) -> EgResult<Option<i64>> {
213        let query = eg::hash! {
214            "barcode": self.au_barcode.as_str(),
215        };
216
217        if let Some(user) = e.search("ac", query)?.pop() {
218            Ok(Some(user.id()?))
219        } else {
220            Ok(None)
221        }
222    }
223
224    /// Deletes the transaction and all linked billings and payments.
225    pub fn delete_user_xacts(&self, e: &mut Editor) -> EgResult<()> {
226        let user_id = self.get_default_user_id(e)?;
227
228        let query = eg::hash! {"usr": user_id};
229        let flesh = eg::hash! {
230            "flesh": 2,
231            "flesh_fields": {
232                "mbt": ["billings", "payments"],
233                "mp": PAYMENT_TYPES.as_slice(),
234            }
235        };
236
237        let mut xacts = e.search_with_ops("mbt", query, flesh)?;
238
239        for mut xact in xacts.drain(..) {
240            // These are both arrays
241            let mut payments = xact["payments"].take();
242            let mut billings = xact["billings"].take();
243
244            for mut payment_view in payments.take_vec().unwrap().drain(..) {
245                for paytype in PAYMENT_TYPES {
246                    let payment = payment_view[paytype].take();
247                    // maybe null
248                    if payment.is_blessed() {
249                        e.delete(payment)?;
250                    }
251                }
252            }
253
254            for billing in billings.take_vec().unwrap().drain(..) {
255                e.delete(billing)?;
256            }
257
258            e.delete(xact)?;
259        }
260
261        Ok(())
262    }
263
264    /// Purge the default user, including its linked card, transactions, etc.
265    pub fn delete_default_au(&self, e: &mut Editor) -> EgResult<()> {
266        let cards = e.search("ac", eg::hash! {barcode: self.au_barcode.to_string()})?;
267
268        if let Some(ac) = cards.first() {
269            // Purge the user, attached card, and any other data
270            // linked to the user.
271            let query = eg::hash! {
272                from: ["actor.usr_delete", ac["usr"].clone(), EgValue::Null]
273            };
274
275            e.json_query(query)?;
276        }
277
278        Ok(())
279    }
280}