fffc01fa5ce0f54df47fd02d19883093ccbaf5bb
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Circ / Transit.pm
1 package OpenILS::Application::Circ::Transit;
2 use base 'OpenSRF::Application';
3 use strict; use warnings;
4 use OpenSRF::EX qw(:try);
5 use Data::Dumper;
6 use OpenSRF::Utils;
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/;
15
16 my $U                                                   = "OpenILS::Application::AppUtils";
17 my $holdcode                            = "OpenILS::Application::Circ::Holds";
18 $Data::Dumper::Indent   = 0;
19
20
21
22 __PACKAGE__->register_method(
23         method  => "copy_transit_receive",
24         api_name        => "open-ils.circ.copy_transit.receive",
25         notes           => q/
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.
35         /);
36
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');
42         return $evt if $evt;
43         ($copy, $evt) = $U->fetch_copy($params{copyid});
44         ($copy, $evt) = $U->fetch_copy_by_barcode($params{barcode}) unless $copy;
45         return $evt if $evt;
46         my $session = $U->start_db_session();
47         $evt = $self->transit_receive( $copy, $requestor, $session );
48         $U->commit_db_session($session) if $U->event_equals($evt,'SUCCESS');
49         return $evt;
50 }
51
52 # ------------------------------------------------------------------------------
53 # If the transit destination is different than the requestor's lib,
54 # a ROUTE_TO event is returned with the org set.
55 # If 
56 # ------------------------------------------------------------------------------
57 sub transit_receive {
58         my ( $class, $copy, $requestor, $session ) = @_;
59         $U->logmark;
60
61         my( $transit, $evt );
62         my $copyid = $copy->id;
63
64         my $status_name = $U->copy_status_to_name($copy->status);
65         $logger->debug("Attempting transit receive on copy $copyid. Copy status is $status_name");
66
67         # fetch the transit
68         ($transit, $evt) = $U->fetch_open_transit_by_copy($copyid);
69         return $evt if $evt;
70
71         if( $transit->dest != $requestor->home_ou ) {
72                 $logger->activity("Fowarding transit on copy which is destined ".
73                         "for a different location. copy=$copyid,current ".
74                         "location=".$requestor->home_ou.",destination location=".$transit->dest);
75
76                 return OpenILS::Event->new('ROUTE_ITEM', org => $transit->dest );
77         }
78
79         # The transit is received, set the receive time
80         $transit->dest_recv_time('now');
81         my $r = $session->request(
82                 'open-ils.storage.direct.action.transit_copy.update', $transit )->gather(1);
83         return $U->DB_UPDATE_FAILED($transit) unless $r;
84
85         my $ishold      = 0;
86         my ($ht)                = $U->fetch_hold_transit( $transit->id );
87         if($ht) {
88                 $logger->info("Hold transit found in transit receive...");
89                 $ishold = 1;
90         }
91
92         $logger->info("Recovering original copy status in transit: ".$transit->copy_status);
93         $copy->status( $transit->copy_status );
94         return $evt if ( $evt = 
95                 $U->update_copy( copy => $copy, editor => $requestor->id, session => $session ));
96
97         return OpenILS::Event->new('SUCCESS', ishold => $ishold, 
98                 payload => { transit => $transit, holdtransit => $ht } );
99 }
100
101
102
103
104
105 __PACKAGE__->register_method(
106         method  => "copy_transit_create",
107         api_name        => "open-ils.circ.copy_transit.create",
108         notes           => q/
109                 Creates a new copy transit.  Requestor must have the 
110                 CREATE_COPY_TRANSIT permission.
111                 @param authtoken The login session key
112                 @param params A param object containing the following keys:
113                         copyid          - the copy id
114                         destination     - the id of the org destination.  If not defined,
115                                 defaults to the copy's circ_lib
116                 @return SUCCESS event on success, other event on error
117         /);
118
119 sub copy_transit_create {
120
121         my( $self, $client, $authtoken, $params ) = @_;
122         my %params = %$params;
123
124         my( $requestor, $evt ) = 
125                 $U->checksesperm( $authtoken, 'CREATE_COPY_TRANSIT' );
126         return $evt if $evt;
127
128         my $copy;
129         ($copy,$evt) = $U->fetch_copy($params{copyid});
130         return $evt if $evt;
131
132         my $session             = $params{session} || $U->start_db_session();
133         my $source              = $requestor->home_ou;
134         my $dest                        = $params{destination} || $copy->circ_lib;
135         my $transit             = Fieldmapper::action::transit_copy->new;
136
137         $logger->activity("User ". $requestor->id ." creating a ".
138                 " new copy transit for copy ".$copy->id." to org $dest");
139
140         $transit->source($source);
141         $transit->dest($dest);
142         $transit->target_copy($copy->id);
143         $transit->source_send_time("now");
144         $transit->copy_status($copy->status);
145         
146         $logger->debug("Creating new copy_transit in DB");
147
148         my $s = $session->request(
149                 "open-ils.storage.direct.action.transit_copy.create", $transit )->gather(1);
150         return $U->DB_UPDATE_FAILED($transit) unless $s;
151         
152         my $stat = $U->copy_status_from_name('in transit');
153
154         $copy->status($stat->id); 
155         return $evt if ($evt = $U->update_copy(
156                 copy => $copy, editor => $requestor->id, session => $session ));
157
158         $U->commit_db_session($session) unless $params{session};
159
160         return OpenILS::Event->new('SUCCESS', 
161                 payload => { copy => $copy, transit => $transit } );
162 }
163
164
165 __PACKAGE__->register_method(
166         method => 'abort_transit',
167         api_name        => 'open-ils.circ.transit.abort',
168         signature       => q/
169                 Deletes a cleans up a transit
170         /
171 );
172
173 sub abort_transit {
174         my( $self, $conn, $authtoken, $params ) = @_;
175
176         my $copyid              = $$params{copyid};
177         my $barcode             = $$params{barcode};
178         my $transitid   = $$params{transitid};
179
180         my $copy;
181         my $transit;
182         my $hold;
183         my $evt;
184
185         my $e = new_editor(xact => 1, authtoken => $authtoken);
186         return $e->event unless $e->checkauth;
187         return $e->event unless $e->allowed('ABORT_TRANSIT');
188
189         # ---------------------------------------------------------------------
190         # Find the related copy and/or transit based on whatever data we have
191         if( $barcode ) {
192                 $copy = $e->search_asset_copy({barcode=>$barcode, deleted => 'f'})->[0];
193                 return $e->event unless $copy;
194
195         } elsif( $copyid ) {
196                 $copy = $e->retrieve_asset_copy($copyid) or return $e->event;
197         }
198
199         if( $transitid ) {
200                 $transit = $e->retrieve_action_transit_copy($transitid)
201                         or return $e->event;
202
203         } elsif( $copy ) {
204
205                 $transit = $e->search_action_transit_copy(
206                         { target_copy => $copy->id, dest_recv_time => undef })->[0];
207                 return $e->event unless $transit;
208         }
209
210         if($transit and !$copy) {
211                 $copy = $e->retrieve_asset_copy($transit->target_copy)
212                         or return $e->event;
213         }
214         # ---------------------------------------------------------------------
215
216         if( $transit->copy_status == OILS_COPY_STATUS_LOST or
217                 $transit->copy_status == OILS_COPY_STATUS_MISSING ) {
218                 $e->rollback;
219                 return OpenILS::Event->new('TRANSIT_ABORT_NOT_ALLOWED');
220         }
221
222
223         if( $transit->dest != $e->requestor->ws_ou 
224                 and $transit->source != $e->requestor->ws_ou ) {
225                 return $e->event unless $e->allowed('ABORT_REMOTE_TRANIST', $e->requestor->ws_ou);
226         }
227
228         # recover the copy status
229         $copy->status( $transit->copy_status );
230         $copy->editor( $e->requestor->id );
231         $copy->edit_date('now');
232
233         my $holdtransit = $e->retrieve_action_hold_transit_copy($transit->id);
234
235         return $e->event unless $e->delete_action_transit_copy($transit);
236         return $e->event unless $e->update_asset_copy($copy);
237
238         $e->commit;
239
240         # if this is a hold transit, un-capture/un-target the hold
241         if($holdtransit) {
242                 $hold = $e->retrieve_action_hold_request($holdtransit->hold)
243                         or return $e->event;
244                 $evt = $holdcode->_reset_hold( $e->requestor, $hold );
245                 return $evt if $evt;
246         }
247
248         return 1;
249 }
250
251
252 __PACKAGE__->register_method(
253         method          => 'get_open_copy_transit',
254         api_name                => 'open-ils.circ.open_copy_transit.retrieve',
255         signature       => q/
256                 Retrieves the open transit object for a given copy
257                 @param auth The login session key
258                 @param copyid The id of the copy
259                 @return Transit object
260  /
261 );
262
263 sub get_open_copy_transit {
264         my( $self, $conn, $auth, $copyid ) = @_;        
265         my $e = new_editor(authtoken=>$auth);
266         return $e->event unless $e->checkauth;
267         return $e->event unless $e->allowed('VIEW_USER'); # XXX rely on editor perms
268         my $t = $e->search_action_transit_copy(
269                 { target_copy => $copyid, dest_recv_time => undef });
270         return $e->event unless @$t;
271         return $$t[0];
272 }
273
274
275
276 __PACKAGE__->register_method(
277         method => 'fetch_transit_by_copy',
278         api_name => 'open-ils.circ.fetch_transit_by_copy',
279 );
280
281 sub fetch_transit_by_copy {
282         my( $self, $conn, $auth, $copyid ) = @_;
283         my $e = new_editor(authtoken=>$auth);
284         return $e->event unless $e->checkauth;
285         my $t = $e->search_action_transit_copy(
286                 {
287                         target_copy => $copyid,
288                         dest_recv_time => undef
289                 }
290         )->[0];
291         return $e->event unless $t;
292         my $ht = $e->retrieve_action_hold_transit_copy($t->id);
293         return { atc => $t, ahtc => $ht };
294 }
295
296
297
298 __PACKAGE__->register_method(
299         method => 'transits_by_lib',
300         api_name => 'open-ils.circ.transit.retrieve_by_lib',
301 );
302
303
304 sub transits_by_lib {
305         my( $self, $conn, $auth, $orgid ) = @_;
306         my $e = new_editor(authtoken=>$auth);
307         return $e->event unless $e->checkauth;
308         return $e->event unless $e->allowed('VIEW_CIRCULATIONS'); # eh.. basically the same permission
309
310         my $tos = $e->search_action_transit_copy(
311                 [{
312                         dest => $orgid,
313                         dest_recv_time => undef,
314                 },
315                 {
316                         order_by => { atc => 'source_send_time' }
317                 }],
318                 { idlist => 1 }
319         );
320
321         my $froms = $e->search_action_transit_copy(
322                 [{
323                         source => $orgid,
324                         dest_recv_time => undef,
325                 },
326                 {
327                         order_by => { atc => 'source_send_time' }
328                 }],
329                 { idlist => 1 }
330         );
331
332         return { from => $froms, to => $tos };
333 }
334
335
336
337 __PACKAGE__->register_method(
338         method => 'fetch_transit',
339         api_name => 'open-ils.circ.transit.retrieve',
340 );
341 sub fetch_transit {
342         my( $self, $conn, $auth, $transid ) = @_;
343         my $e = new_editor(authtoken=>$auth);
344         return $e->event unless $e->checkauth;
345         return $e->event unless $e->allowed('VIEW_CIRCULATIONS'); # eh.. basically the same permission
346
347         my $ht = $e->retrieve_action_hold_transit_copy($transid);
348         return $ht if $ht;
349
350         my $t = $e->retrieve_action_transit_copy($transid)
351                 or return $e->event;
352         return $t;
353 }
354
355         
356
357
358
359
360 1;