1 package OpenILS::Application::Circ::Transit;
2 use base 'OpenILS::Application';
3 use strict; use warnings;
4 use OpenSRF::EX qw(:try);
7 use OpenSRF::Utils::Cache;
8 use Digest::MD5 qw(md5_hex);
9 use OpenILS::Utils::CStoreEditor qw/:funcs/;
10 use OpenILS::Application::AppUtils;
11 use OpenILS::Application::Circ::Holds;
12 use OpenSRF::Utils::Logger qw(:logger);
13 use OpenSRF::AppSession;
14 use OpenILS::Const qw/:const/;
16 my $U = "OpenILS::Application::AppUtils";
17 my $holdcode = "OpenILS::Application::Circ::Holds";
18 $Data::Dumper::Indent = 0;
22 __PACKAGE__->register_method(
23 method => "copy_transit_receive",
24 api_name => "open-ils.circ.copy_transit.receive",
26 Closes out a copy transit
27 Requestor needs the COPY_TRANSIT_RECEIVE permission
28 @param authtoken The login session key
29 @param params An object of named params including
30 copyid - the id of the copy in quest
31 barcode - the barcode of the copy in question
32 If copyid is not sent, this is used.
33 @return A ROUTE_ITEM if the copy is destined for a different location.
34 A SUCCESS event on success. Other events on error.
37 sub copy_transit_receive {
38 my( $self, $client, $authtoken, $params ) = @_;
39 my %params = %$params;
40 my( $evt, $copy, $requestor );
41 ($requestor, $evt) = $U->checksesperm($authtoken, 'COPY_TRANSIT_RECEIVE');
43 ($copy, $evt) = $U->fetch_copy($params{copyid});
44 ($copy, $evt) = $U->fetch_copy_by_barcode($params{barcode}) unless $copy;
46 my $session = $U->start_db_session();
47 $U->set_audit_info($session, $authtoken, $requestor->id, $requestor->wsid);
48 $evt = transit_receive( $self, $copy, $requestor, $session );
49 $U->commit_db_session($session) if $U->event_equals($evt,'SUCCESS');
53 # ------------------------------------------------------------------------------
54 # If the transit destination is different than the requestor's lib,
55 # a ROUTE_TO event is returned with the org set.
57 # ------------------------------------------------------------------------------
59 my ( $class, $copy, $requestor, $session ) = @_;
63 my $copyid = $copy->id;
65 my $status_name = $U->copy_status_to_name($copy->status);
66 $logger->debug("Attempting transit receive on copy $copyid. Copy status is $status_name");
69 ($transit, $evt) = $U->fetch_open_transit_by_copy($copyid);
72 if( $transit->dest != $requestor->home_ou ) {
73 $logger->activity("Fowarding transit on copy which is destined ".
74 "for a different location. copy=$copyid,current ".
75 "location=".$requestor->home_ou.",destination location=".$transit->dest);
77 return OpenILS::Event->new('ROUTE_ITEM', org => $transit->dest );
80 # The transit is received, set the receive time
81 $transit->dest_recv_time('now');
82 my $r = $session->request(
83 'open-ils.storage.direct.action.transit_copy.update', $transit )->gather(1);
84 return $U->DB_UPDATE_FAILED($transit) unless $r;
87 my ($ht) = $U->fetch_hold_transit( $transit->id );
89 $logger->info("Hold transit found in transit receive...");
93 $logger->info("Recovering original copy status in transit: ".$transit->copy_status);
94 $copy->status( $transit->copy_status );
95 return $evt if ( $evt =
96 $U->update_copy( copy => $copy, editor => $requestor->id, session => $session ));
98 return OpenILS::Event->new('SUCCESS', ishold => $ishold,
99 payload => { transit => $transit, holdtransit => $ht } );
106 __PACKAGE__->register_method(
107 method => "copy_transit_create",
108 api_name => "open-ils.circ.copy_transit.create",
110 Creates a new copy transit. Requestor must have the
111 CREATE_COPY_TRANSIT permission.
112 @param authtoken The login session key
113 @param params A param object containing the following keys:
115 destination - the id of the org destination. If not defined,
116 defaults to the copy's circ_lib
117 @return SUCCESS event on success, other event on error
120 sub copy_transit_create {
122 my( $self, $client, $authtoken, $params ) = @_;
123 my %params = %$params;
125 my( $requestor, $evt ) =
126 $U->checksesperm( $authtoken, 'CREATE_COPY_TRANSIT' );
130 ($copy,$evt) = $U->fetch_copy($params{copyid});
133 my $session = $params{session} || $U->start_db_session();
134 my $source = $requestor->home_ou;
135 my $dest = $params{destination} || $copy->circ_lib;
136 my $transit = Fieldmapper::action::transit_copy->new;
137 $U->set_audit_info($session, $authtoken, $requestor->id, $requestor->wsid);
139 $logger->activity("User ". $requestor->id ." creating a ".
140 " new copy transit for copy ".$copy->id." to org $dest");
142 $transit->source($source);
143 $transit->dest($dest);
144 $transit->target_copy($copy->id);
145 $transit->source_send_time("now");
146 $transit->copy_status($copy->status);
148 $logger->debug("Creating new copy_transit in DB");
150 my $s = $session->request(
151 "open-ils.storage.direct.action.transit_copy.create", $transit )->gather(1);
152 return $U->DB_UPDATE_FAILED($transit) unless $s;
154 my $stat = $U->copy_status_from_name('in transit');
156 $copy->status($stat->id);
157 return $evt if ($evt = $U->update_copy(
158 copy => $copy, editor => $requestor->id, session => $session ));
160 $U->commit_db_session($session) unless $params{session};
162 return OpenILS::Event->new('SUCCESS',
163 payload => { copy => $copy, transit => $transit } );
167 __PACKAGE__->register_method(
168 method => 'abort_transit',
169 api_name => 'open-ils.circ.transit.abort',
171 Deletes a cleans up a transit
176 my( $self, $conn, $authtoken, $params ) = @_;
178 my $copyid = $$params{copyid};
179 my $barcode = $$params{barcode};
180 my $transitid = $$params{transitid};
186 my $e = new_editor(xact => 1, authtoken => $authtoken);
187 return $e->event unless $e->checkauth;
188 return $e->event unless $e->allowed('ABORT_TRANSIT');
190 # ---------------------------------------------------------------------
191 # Find the related copy and/or transit based on whatever data we have
193 $copy = $e->search_asset_copy({barcode=>$barcode, deleted => 'f'})->[0];
194 return $e->event unless $copy;
197 $copy = $e->retrieve_asset_copy($copyid) or return $e->event;
201 $transit = $e->retrieve_action_transit_copy($transitid)
206 $transit = $e->search_action_transit_copy(
207 { target_copy => $copy->id, dest_recv_time => undef })->[0];
208 return $e->event unless $transit;
211 if($transit and !$copy) {
212 $copy = $e->retrieve_asset_copy($transit->target_copy)
215 # ---------------------------------------------------------------------
217 return __abort_transit( $e, $transit, $copy );
222 sub __abort_transit {
224 my( $e, $transit, $copy, $no_reset_hold, $no_commit ) = @_;
229 if( (($transit->copy_status == OILS_COPY_STATUS_LOST || $transit->copy_status == OILS_COPY_STATUS_LOST_AND_PAID)
230 and !$e->allowed('ABORT_TRANSIT_ON_LOST')) or
231 ($transit->copy_status == OILS_COPY_STATUS_MISSING and !$e->allowed('ABORT_TRANSIT_ON_MISSING')) ) {
233 return OpenILS::Event->new('TRANSIT_ABORT_NOT_ALLOWED', copy_status => $transit->copy_status);
237 if( $transit->dest != $e->requestor->ws_ou
238 and $transit->source != $e->requestor->ws_ou ) {
239 return $e->die_event unless $e->allowed('ABORT_REMOTE_TRANSIT', $e->requestor->ws_ou);
242 # recover the copy status
243 $copy->status( $transit->copy_status );
244 $copy->editor( $e->requestor->id );
245 $copy->edit_date('now');
247 my $holdtransit = $e->retrieve_action_hold_transit_copy($transit->id);
250 $logger->info("setting copy to reshelving on hold transit abort");
251 $copy->status( OILS_COPY_STATUS_RESHELVING );
254 return $e->die_event unless $e->delete_action_transit_copy($transit);
255 return $e->die_event unless $e->update_asset_copy($copy);
257 $e->commit unless $no_commit;
259 # if this is a hold transit, un-capture/un-target the hold
260 if($holdtransit and !$no_reset_hold) {
261 $hold = $e->retrieve_action_hold_request($holdtransit->hold)
262 or return $e->die_event;
263 $evt = $holdcode->_reset_hold( $e->requestor, $hold );
271 __PACKAGE__->register_method(
272 method => 'get_open_copy_transit',
273 api_name => 'open-ils.circ.open_copy_transit.retrieve',
275 Retrieves the open transit object for a given copy
276 @param auth The login session key
277 @param copyid The id of the copy
278 @return Transit object
282 sub get_open_copy_transit {
283 my( $self, $conn, $auth, $copyid ) = @_;
284 my $e = new_editor(authtoken=>$auth);
285 return $e->event unless $e->checkauth;
286 return $e->event unless $e->allowed('VIEW_USER'); # XXX rely on editor perms
287 my $t = $e->search_action_transit_copy(
288 { target_copy => $copyid, dest_recv_time => undef });
289 return $e->event unless @$t;
295 __PACKAGE__->register_method(
296 method => 'fetch_transit_by_copy',
297 api_name => 'open-ils.circ.fetch_transit_by_copy',
300 sub fetch_transit_by_copy {
301 my( $self, $conn, $auth, $copyid ) = @_;
302 my $e = new_editor(authtoken=>$auth);
303 return $e->event unless $e->checkauth;
304 my $t = $e->search_action_transit_copy(
306 target_copy => $copyid,
307 dest_recv_time => undef
310 return $e->event unless $t;
311 my $ht = $e->retrieve_action_hold_transit_copy($t->id);
312 return { atc => $t, ahtc => $ht };
317 __PACKAGE__->register_method(
318 method => 'transits_by_lib',
319 api_name => 'open-ils.circ.transit.retrieve_by_lib',
323 # start_date and end_date are optional endpoints for the transit creation date
324 sub transits_by_lib {
325 my( $self, $conn, $auth, $orgid, $start_date, $end_date ) = @_;
326 my $e = new_editor(authtoken=>$auth);
327 return $e->event unless $e->checkauth;
328 return $e->event unless $e->allowed('VIEW_CIRCULATIONS'); # eh.. basically the same permission
330 my $order_by = {order_by => { atc => 'source_send_time' }};
331 my $search = { dest_recv_time => undef };
335 $search->{source_send_time} = {between => [$start_date, $end_date]};
337 $search->{source_send_time} = {'<=' => $end_date};
339 } elsif($start_date) {
340 $search->{source_send_time} = {'>=' => $start_date};
343 $search->{dest} = $orgid;
345 my $tos = $e->search_action_transit_copy([ $search, $order_by ], {idlist=>1});
347 delete $$search{dest};
348 $search->{source} = $orgid;
350 my $froms = $e->search_action_transit_copy([ $search, $order_by ], {idlist=>1});
352 return { from => $froms, to => $tos };
357 __PACKAGE__->register_method(
358 method => 'fetch_transit',
359 api_name => 'open-ils.circ.transit.retrieve',
362 my( $self, $conn, $auth, $transid ) = @_;
363 my $e = new_editor(authtoken=>$auth);
364 return $e->event unless $e->checkauth;
365 return $e->event unless $e->allowed('VIEW_CIRCULATIONS'); # eh.. basically the same permission
367 my $ht = $e->retrieve_action_hold_transit_copy($transid);
370 my $t = $e->retrieve_action_transit_copy($transid)