evergreen/common/
transit.rs

1use crate as eg;
2use eg::common::holds;
3use eg::constants as C;
4use eg::Editor;
5use eg::EgEvent;
6use eg::EgResult;
7use eg::EgValue;
8
9/// Cancel a transit
10///
11/// Caller is responsible for beginning and committing the `Editor`
12/// transaction.
13pub fn cancel_transit(editor: &mut Editor, transit_id: i64, skip_hold_reset: bool) -> EgResult<()> {
14    let flesh = eg::hash! {
15        "flesh": 1,
16        "flesh_fields": {
17            "atc": ["target_copy", "hold_transit_copy"]
18        }
19    };
20
21    let mut transit = editor
22        .retrieve_with_ops("atc", transit_id, flesh)?
23        .ok_or_else(|| editor.die_event())?;
24
25    let mut copy = transit["target_copy"].take();
26    transit["target_copy"] = copy["id"].clone();
27
28    let tc_status = transit["copy_status"].int()?;
29
30    let to_lost = tc_status == C::COPY_STATUS_LOST || tc_status == C::COPY_STATUS_LOST_AND_PAID;
31
32    let to_missing = tc_status == C::COPY_STATUS_MISSING;
33
34    if (to_lost && !editor.allowed("ABORT_TRANSIT_ON_LOST")?)
35        || (to_missing && !editor.allowed("ABORT_TRANSIT_ON_MISSING")?)
36    {
37        let mut evt = EgEvent::new("TRANSIT_ABORT_NOT_ALLOWED");
38        evt.set_ad_hoc_value("copy_status", EgValue::from(tc_status));
39        return Err(evt.into());
40    }
41
42    let here = editor.requestor_ws_ou().expect("Workstation Required");
43    let source = transit["source"].int()?;
44    let dest = transit["dest"].int()?;
45
46    if source != here && dest != here {
47        // Perl uses "here" as the permission org, but checking
48        // at the source + dest kinda makes more sense.
49        if !editor.allowed_at("ABORT_REMOTE_TRANSIT", here)? {
50            return Err(editor.die_event());
51        }
52    }
53
54    let mut reset_hold_id = None;
55    if transit["hold_transit_copy"].is_object() && !skip_hold_reset {
56        // capture this before the transit is consumed below.
57        reset_hold_id = Some(transit["hold_transit_copy"]["hold"].int()?);
58    }
59
60    transit["cancel_time"] = EgValue::from("now");
61    editor.update(transit)?;
62
63    let copy_status = copy["status"].int()?;
64
65    // The status adopted by the copy in transit depends on
66    // the intended destination status of the copy.
67    if copy_status == C::COPY_STATUS_IN_TRANSIT {
68        if tc_status == C::COPY_STATUS_AVAILABLE
69            || tc_status == C::COPY_STATUS_CHECKED_OUT
70            || tc_status == C::COPY_STATUS_IN_PROCESS
71            || tc_status == C::COPY_STATUS_ON_HOLDS_SHELF
72            || tc_status == C::COPY_STATUS_IN_TRANSIT
73            || tc_status == C::COPY_STATUS_CATALOGING
74            || tc_status == C::COPY_STATUS_ON_RESV_SHELF
75            || tc_status == C::COPY_STATUS_RESHELVING
76        {
77            // These transit copy statuses are discarded.
78            copy["status"] = EgValue::from(C::COPY_STATUS_CANCELED_TRANSIT);
79        } else {
80            // Otherwise, adopt the copy status stored on the transit.
81            copy["status"] = EgValue::from(tc_status);
82        }
83
84        copy["editor"] = EgValue::from(editor.requestor_id()?);
85        copy["edit_date"] = EgValue::from("now");
86
87        editor.update(copy)?;
88    }
89
90    if let Some(hold_id) = reset_hold_id {
91        holds::reset_hold(editor, hold_id)?;
92    }
93
94    Ok(())
95}