]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Circ/Holds.pm
added method
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Circ / Holds.pm
1 # ---------------------------------------------------------------
2 # Copyright (C) 2005  Georgia Public Library Service 
3 # Bill Erickson <highfalutin@gmail.com>
4
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 # ---------------------------------------------------------------
15
16
17 package OpenILS::Application::Circ::Holds;
18 use base qw/OpenSRF::Application/;
19 use strict; use warnings;
20 use OpenILS::Application::AppUtils;
21 use Data::Dumper;
22 use OpenILS::EX;
23 use OpenSRF::EX qw(:try);
24 use OpenILS::Perm;
25 use OpenILS::Event;
26 use OpenSRF::Utils::Logger qw(:logger);
27 use OpenILS::Utils::Editor;
28
29 my $apputils = "OpenILS::Application::AppUtils";
30 my $U = $apputils;
31
32
33
34 __PACKAGE__->register_method(
35         method  => "create_hold",
36         api_name        => "open-ils.circ.holds.create",
37         notes           => <<NOTE);
38 Create a new hold for an item.  From a permissions perspective, 
39 the login session is used as the 'requestor' of the hold.  
40 The hold recipient is determined by the 'usr' setting within
41 the hold object.
42
43 First we verify the requestion has holds request permissions.
44 Then we verify that the recipient is allowed to make the given hold.
45 If not, we see if the requestor has "override" capabilities.  If not,
46 a permission exception is returned.  If permissions allow, we cycle
47 through the set of holds objects and create.
48
49 If the recipient does not have permission to place multiple holds
50 on a single title and said operation is attempted, a permission
51 exception is returned
52 NOTE
53
54 sub create_hold {
55         my( $self, $client, $login_session, @holds) = @_;
56
57         if(!@holds){return 0;}
58         my( $user, $evt ) = $apputils->checkses($login_session);
59         return $evt if $evt;
60
61         my $holds;
62         if(ref($holds[0]) eq 'ARRAY') {
63                 $holds = $holds[0];
64         } else { $holds = [ @holds ]; }
65
66         $logger->debug("Iterating over holds requests...");
67
68         for my $hold (@$holds) {
69
70                 if(!$hold){next};
71                 my $type = $hold->hold_type;
72
73                 $logger->activity("User " . $user->id . 
74                         " creating new hold of type $type for user " . $hold->usr);
75
76                 my $recipient;
77                 if($user->id ne $hold->usr) {
78                         ( $recipient, $evt ) = $apputils->fetch_user($hold->usr);
79                         return $evt if $evt;
80
81                 } else {
82                         $recipient = $user;
83                 }
84
85
86                 my $perm = undef;
87
88                 # am I allowed to place holds for this user?
89                 if($hold->requestor ne $hold->usr) {
90                         $perm = _check_request_holds_perm($user->id, $user->home_ou);
91                         if($perm) { return $perm; }
92                 }
93
94                 # is this user allowed to have holds of this type?
95                 $perm = _check_holds_perm($type, $hold->usr, $recipient->home_ou);
96                 if($perm) { 
97                         #if there is a requestor, see if the requestor has override privelages
98                         if($hold->requestor ne $hold->usr) {
99                                 $perm = _check_request_holds_override($user->id, $user->home_ou);
100                                 if($perm) {return $perm;}
101
102                         } else {
103                                 return $perm; 
104                         }
105                 }
106
107                 #enforce the fact that the login is the one requesting the hold
108                 $hold->requestor($user->id); 
109                 $hold->selection_ou($recipient->home_ou) unless $hold->selection_ou;
110
111                 my $resp = $apputils->simplereq(
112                         'open-ils.storage',
113                         'open-ils.storage.direct.action.hold_request.create', $hold );
114
115                 if(!$resp) { 
116                         return OpenSRF::EX::ERROR ("Error creating hold"); 
117                 }
118         }
119
120         return 1;
121 }
122
123 # makes sure that a user has permission to place the type of requested hold
124 # returns the Perm exception if not allowed, returns undef if all is well
125 sub _check_holds_perm {
126         my($type, $user_id, $org_id) = @_;
127
128         my $evt;
129         if($type eq "M") {
130                 if($evt = $apputils->check_perms(
131                         $user_id, $org_id, "MR_HOLDS")) {
132                         return $evt;
133                 } 
134
135         } elsif ($type eq "T") {
136                 if($evt = $apputils->check_perms(
137                         $user_id, $org_id, "TITLE_HOLDS")) {
138                         return $evt;
139                 }
140
141         } elsif($type eq "V") {
142                 if($evt = $apputils->check_perms(
143                         $user_id, $org_id, "VOLUME_HOLDS")) {
144                         return $evt;
145                 }
146
147         } elsif($type eq "C") {
148                 if($evt = $apputils->check_perms(
149                         $user_id, $org_id, "COPY_HOLDS")) {
150                         return $evt;
151                 }
152         }
153
154         return undef;
155 }
156
157 # tests if the given user is allowed to place holds on another's behalf
158 sub _check_request_holds_perm {
159         my $user_id = shift;
160         my $org_id = shift;
161         if(my $evt = $apputils->check_perms(
162                 $user_id, $org_id, "REQUEST_HOLDS")) {
163                 return $evt;
164         }
165 }
166
167 sub _check_request_holds_override {
168         my $user_id = shift;
169         my $org_id = shift;
170         if(my $evt = $apputils->check_perms(
171                 $user_id, $org_id, "REQUEST_HOLDS_OVERRIDE")) {
172                 return $evt;
173         }
174 }
175
176 __PACKAGE__->register_method(
177         method  => "retrieve_holds_by_id",
178         api_name        => "open-ils.circ.holds.retrieve_by_id",
179         notes           => <<NOTE);
180 Retrieve the hold, with hold transits attached, for the specified id
181 The login session is the requestor and if the requestor is
182 different from the user, then the requestor must have VIEW_HOLD permissions.
183 NOTE
184
185
186 sub retrieve_holds_by_id {
187         my($self, $client, $login_session, $hold_id) = @_;
188
189         #FIXME
190         #my( $user, $target, $evt ) = $apputils->checkses_requestor(
191         #       $login_session, $user_id, 'VIEW_HOLD' );
192         #return $evt if $evt;
193
194         my $holds = $apputils->simplereq(
195                 'open-ils.storage',
196                 "open-ils.storage.direct.action.hold_request.search.atomic",
197                 "id" =>  $hold_id , fulfillment_time => undef, { order_by => "request_time" });
198         
199         for my $hold ( @$holds ) {
200                 $hold->transit(
201                         $apputils->simplereq(
202                                 'open-ils.storage',
203                                 "open-ils.storage.direct.action.hold_transit_copy.search.hold.atomic" => $hold->id,
204                                 { order_by => 'id desc', limit => 1 }
205                         )->[0]
206                 );
207         }
208
209         return $holds;
210 }
211
212
213 __PACKAGE__->register_method(
214         method  => "retrieve_holds",
215         api_name        => "open-ils.circ.holds.retrieve",
216         notes           => <<NOTE);
217 Retrieves all the holds, with hold transits attached, for the specified
218 user id.  The login session is the requestor and if the requestor is
219 different from the user, then the requestor must have VIEW_HOLD permissions.
220 NOTE
221
222
223 sub retrieve_holds {
224         my($self, $client, $login_session, $user_id) = @_;
225
226         my( $user, $target, $evt ) = $apputils->checkses_requestor(
227                 $login_session, $user_id, 'VIEW_HOLD' );
228         return $evt if $evt;
229
230         my $holds = $apputils->simplereq(
231                 'open-ils.storage',
232                 "open-ils.storage.direct.action.hold_request.search.atomic",
233                 "usr" =>  $user_id , fulfillment_time => undef, { order_by => "request_time" });
234         
235         for my $hold ( @$holds ) {
236                 $hold->transit(
237                         $apputils->simplereq(
238                                 'open-ils.storage',
239                                 "open-ils.storage.direct.action.hold_transit_copy.search.hold.atomic" => $hold->id,
240                                 { order_by => 'id desc', limit => 1 }
241                         )->[0]
242                 );
243         }
244
245         return $holds;
246 }
247
248 __PACKAGE__->register_method(
249         method  => "retrieve_holds_by_pickup_lib",
250         api_name        => "open-ils.circ.holds.retrieve_by_pickup_lib",
251         notes           => <<NOTE);
252 Retrieves all the holds, with hold transits attached, for the specified
253 pickup_ou id. 
254 NOTE
255
256
257 sub retrieve_holds_by_pickup_lib {
258         my($self, $client, $login_session, $ou_id) = @_;
259
260         #FIXME -- put an appropriate permission check here
261         #my( $user, $target, $evt ) = $apputils->checkses_requestor(
262         #       $login_session, $user_id, 'VIEW_HOLD' );
263         #return $evt if $evt;
264
265         my $holds = $apputils->simplereq(
266                 'open-ils.storage',
267                 "open-ils.storage.direct.action.hold_request.search.atomic",
268                 "pickup_lib" =>  $ou_id , fulfillment_time => undef, { order_by => "request_time" });
269         
270         for my $hold ( @$holds ) {
271                 $hold->transit(
272                         $apputils->simplereq(
273                                 'open-ils.storage',
274                                 "open-ils.storage.direct.action.hold_transit_copy.search.hold.atomic" => $hold->id,
275                                 { order_by => 'id desc', limit => 1 }
276                         )->[0]
277                 );
278         }
279
280         return $holds;
281 }
282
283
284 __PACKAGE__->register_method(
285         method  => "cancel_hold",
286         api_name        => "open-ils.circ.hold.cancel",
287         notes           => <<"  NOTE");
288         Cancels the specified hold.  The login session
289         is the requestor and if the requestor is different from the usr field
290         on the hold, the requestor must have CANCEL_HOLDS permissions.
291         the hold may be either the hold object or the hold id
292         NOTE
293
294 sub cancel_hold {
295         my($self, $client, $login_session, $holdid) = @_;
296         my $hold;       
297
298         my($user, $evt) = $U->checkses($login_session);
299         return $evt if $evt;
300
301         ( $hold, $evt ) = $U->fetch_hold($holdid);
302         return $evt if $evt;
303
304         if($user->id ne $hold->usr) { #am I allowed to cancel this user's hold?
305                 if($evt = $apputils->check_perms(
306                         $user->id, $user->home_ou, 'CANCEL_HOLDS')) {
307                         return $evt;
308                 }
309         }
310
311         $logger->activity( "User " . $user->id . 
312                 " canceling hold $holdid for user " . $hold->usr );
313
314         return $apputils->simplereq(
315                 'open-ils.storage',
316                 "open-ils.storage.direct.action.hold_request.delete", $hold );
317 }
318
319
320 __PACKAGE__->register_method(
321         method  => "update_hold",
322         api_name        => "open-ils.circ.hold.update",
323         notes           => <<"  NOTE");
324         Updates the specified hold.  The login session
325         is the requestor and if the requestor is different from the usr field
326         on the hold, the requestor must have UPDATE_HOLDS permissions.
327         NOTE
328
329 sub update_hold {
330         my($self, $client, $login_session, $hold) = @_;
331
332         my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
333                 $login_session, $hold->usr, 'UPDATE_HOLD' );
334         return $evt if $evt;
335
336         $logger->activity('User ' . $requestor->id . 
337                 ' updating hold ' . $hold->id . ' for user ' . $target->id );
338
339         return $U->storagereq(
340                 "open-ils.storage.direct.action.hold_request.update", $hold );
341 }
342
343
344 __PACKAGE__->register_method(
345         method  => "retrieve_hold_status",
346         api_name        => "open-ils.circ.hold.status.retrieve",
347         notes           => <<"  NOTE");
348         Calculates the current status of the hold.
349         the requestor must have VIEW_HOLD permissions if the hold is for a user
350         other than the requestor.
351         Returns -1  on error (for now)
352         Returns 1 for 'waiting for copy to become available'
353         Returns 2 for 'waiting for copy capture'
354         Returns 3 for 'in transit'
355         Returns 4 for 'arrived'
356         NOTE
357
358 sub retrieve_hold_status {
359         my($self, $client, $login_session, $hold_id) = @_;
360
361
362         my( $requestor, $target, $hold, $copy, $transit, $evt );
363
364         ( $hold, $evt ) = $apputils->fetch_hold($hold_id);
365         return $evt if $evt;
366
367         ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
368                 $login_session, $hold->usr, 'VIEW_HOLD' );
369         return $evt if $evt;
370
371         return 1 unless (defined($hold->current_copy));
372         
373         ( $copy, $evt ) = $apputils->fetch_copy($hold->current_copy);
374         return $evt if $evt;
375
376         return 4 if ($hold->capture_time and $copy->circ_lib eq $hold->pickup_lib);
377
378         ( $transit, $evt ) = $apputils->fetch_hold_transit_by_hold( $hold->id );
379         return 4 if(ref($transit) and defined($transit->dest_recv_time) ); 
380
381         return 3 if defined($hold->capture_time);
382
383         return 2;
384 }
385
386
387
388
389
390 __PACKAGE__->register_method(
391         method  => "capture_copy",
392         api_name        => "open-ils.circ.hold.capture_copy.barcode",
393         notes           => <<"  NOTE");
394         Captures a copy to fulfil a hold
395         Params is login session and copy barcode
396         Optional param is 'flesh'.  If set, we also return the
397         relevant copy and title
398         login mus have COPY_CHECKIN permissions (since this is essentially
399         copy checkin)
400         NOTE
401
402 # XXX deprecate me XXX
403
404 sub capture_copy {
405         my( $self, $client, $login_session, $params ) = @_;
406         my %params = %$params;
407         my $barcode = $params{barcode};
408
409
410         my( $user, $target, $copy, $hold, $evt );
411
412         ( $user, $evt ) = $apputils->checkses($login_session);
413         return $evt if $evt;
414
415         # am I allowed to checkin a copy?
416         $evt = $apputils->check_perms($user->id, $user->home_ou, "COPY_CHECKIN");
417         return $evt if $evt;
418
419         $logger->info("Capturing copy with barcode $barcode");
420
421         my $session = $apputils->start_db_session();
422
423         ($copy, $evt) = $apputils->fetch_copy_by_barcode($barcode);
424         return $evt if $evt;
425
426         $logger->debug("Capturing copy " . $copy->id);
427
428         ( $hold, $evt ) = _find_local_hold_for_copy($session, $copy, $user);
429         return $evt if $evt;
430
431         warn "Found hold " . $hold->id . "\n";
432         $logger->info("We found a hold " .$hold->id. "for capturing copy with barcode $barcode");
433
434         $hold->current_copy($copy->id);
435         $hold->capture_time("now"); 
436
437         #update the hold
438         my $stat = $session->request(
439                         "open-ils.storage.direct.action.hold_request.update", $hold)->gather(1);
440         if(!$stat) { throw OpenSRF::EX::ERROR 
441                 ("Error updating hold request " . $copy->id); }
442
443         $copy->status(8); #status on holds shelf
444
445         # if the staff member capturing this item is not at the pickup lib
446         if( $user->home_ou ne $hold->pickup_lib ) {
447                 $self->_build_hold_transit( $login_session, $session, $hold, $user, $copy );
448         }
449
450         $copy->editor($user->id);
451         $copy->edit_date("now");
452         $stat = $session->request(
453                 "open-ils.storage.direct.asset.copy.update", $copy )->gather(1);
454         if(!$stat) { throw OpenSRF::EX ("Error updating copy " . $copy->id); }
455
456         my $payload = { hold => $hold };
457         $payload->{copy} = $copy if $params{flesh_copy};
458
459         if($params{flesh_record}) {
460                 my $record;
461                 ($record, $evt) = $apputils->fetch_record_by_copy( $copy->id );
462                 return $evt if $evt;
463                 $record = $apputils->record_to_mvr($record);
464                 $payload->{record} = $record;
465         }
466
467         $apputils->commit_db_session($session);
468
469         return OpenILS::Event->new('ROUTE_ITEM', 
470                 route_to => $hold->pickup_lib, payload => $payload );
471 }
472
473 sub _build_hold_transit {
474         my( $self, $login_session, $session, $hold, $user, $copy ) = @_;
475         my $trans = Fieldmapper::action::hold_transit_copy->new;
476
477         $trans->hold($hold->id);
478         $trans->source($user->home_ou);
479         $trans->dest($hold->pickup_lib);
480         $trans->source_send_time("now");
481         $trans->target_copy($copy->id);
482         $trans->copy_status($copy->status);
483
484         my $meth = $self->method_lookup("open-ils.circ.hold_transit.create");
485         my ($stat) = $meth->run( $login_session, $trans, $session );
486         if(!$stat) { throw OpenSRF::EX ("Error creating new hold transit"); }
487         else { $copy->status(6); } #status in transit 
488 }
489
490
491 sub find_local_hold {
492         my( $class, $session, $copy, $user ) = @_;
493         return _find_local_hold_for_copy($session, $copy, $user);
494 }
495
496 sub _find_local_hold_for_copy {
497
498         my $session = shift;
499         my $copy = shift;
500         my $user = shift;
501         my $evt = OpenILS::Event->new('HOLD_NOT_FOUND');
502
503         # first see if this copy has already been selected to fulfill a hold
504         my $hold  = $session->request(
505                 "open-ils.storage.direct.action.hold_request.search_where",
506                 { current_copy => $copy->id, capture_time => undef } )->gather(1);
507
508         if($hold) {return $hold;}
509
510         $logger->debug("searching for local hold at org " . 
511                 $user->home_ou . " and copy " . $copy->id);
512
513         my $holdid = $session->request(
514                 "open-ils.storage.action.hold_request.nearest_hold",
515                 $user->home_ou, $copy->id )->gather(1);
516
517         return (undef, $evt) unless defined $holdid;
518
519         $logger->debug("Found hold id $holdid while ".
520                 "searching nearest hold to " .$user->home_ou);
521
522         return $apputils->fetch_hold($holdid);
523 }
524
525
526 __PACKAGE__->register_method(
527         method  => "create_hold_transit",
528         api_name        => "open-ils.circ.hold_transit.create",
529         notes           => <<"  NOTE");
530         Creates a new transit object
531         NOTE
532
533 sub create_hold_transit {
534         my( $self, $client, $login_session, $transit, $session ) = @_;
535
536         my( $user, $evt ) = $apputils->checkses($login_session);
537         return $evt if $evt;
538         $evt = $apputils->check_perms($user->id, $user->home_ou, "CREATE_TRANSIT");
539         return $evt if $evt;
540
541         my $ses;
542         if($session) { $ses = $session; } 
543         else { $ses = OpenSRF::AppSession->create("open-ils.storage"); }
544
545         return $ses->request(
546                 "open-ils.storage.direct.action.hold_transit_copy.create", $transit )->gather(1);
547 }
548
549
550 sub fetch_open_hold_by_current_copy {
551         my $class = shift;
552         my $copyid = shift;
553         my $hold = $apputils->simplereq(
554                 'open-ils.storage', 
555                 'open-ils.storage.direct.action.hold_request.search.atomic',
556                          current_copy =>  $copyid , fulfillment_time => undef );
557         return $hold->[0] if ref($hold);
558         return undef;
559 }
560
561 sub fetch_related_holds {
562         my $class = shift;
563         my $copyid = shift;
564         return $apputils->simplereq(
565                 'open-ils.storage', 
566                 'open-ils.storage.direct.action.hold_request.search.atomic',
567                          current_copy =>  $copyid , fulfillment_time => undef );
568 }
569
570
571 __PACKAGE__->register_method (
572         method          => "hold_pull_list",
573         api_name                => "open-ils.circ.hold_pull_list.retrieve",
574         signature       => q/
575                 Returns a list of hold ID's that need to be "pulled"
576                 by a given location
577         /
578 );
579
580 sub hold_pull_list {
581         my( $self, $conn, $authtoken, $limit, $offset ) = @_;
582         my( $reqr, $evt ) = $U->checkses($authtoken);
583         return $evt if $evt;
584
585         my $org = $reqr->ws_ou || $reqr->home_ou;
586         # the perm locaiton shouldn't really matter here since holds
587         # will exist all over and VIEW_HOLDS should be universal
588         $evt = $U->check_perms($reqr->id, $org, 'VIEW_HOLD');
589         return $evt if $evt;
590
591         return $U->storagereq(
592                 'open-ils.storage.direct.action.hold_request.pull_list.search.current_copy_circ_lib.atomic',
593                 $org, $limit, $offset ); # XXX change to workstation
594 }
595
596 __PACKAGE__->register_method (
597         method          => 'fetch_hold_notify',
598         api_name                => 'open-ils.circ.hold_notification.retrieve_by_hold',
599         signature       => q/ 
600                 Returns a list of hold notification objects based on hold id.
601                 @param authtoken The loggin session key
602                 @param holdid The id of the hold whose notifications we want to retrieve
603                 @return An array of hold notification objects, event on error.
604         /
605 );
606
607 sub fetch_hold_notify {
608         my( $self, $conn, $authtoken, $holdid ) = @_;
609         my( $requestor, $evt ) = $U->checkses($authtoken);
610         return $evt if $evt;
611         my ($hold, $patron);
612         ($hold, $evt) = $U->fetch_hold($holdid);
613         return $evt if $evt;
614         ($patron, $evt) = $U->fetch_user($hold->usr);
615         return $evt if $evt;
616
617         $evt = $U->check_perms($requestor->id, $patron->home_ou, 'VIEW_HOLD_NOTIFICATION');
618         return $evt if $evt;
619
620         $logger->info("User ".$requestor->id." fetching hold notifications for hold $holdid");
621         return $U->storagereq(
622                 'open-ils.storage.direct.action.hold_notification.search.hold.atomic', $holdid );
623 }
624
625
626 __PACKAGE__->register_method (
627         method          => 'create_hold_notify',
628         api_name                => 'open-ils.circ.hold_notification.create',
629         signature       => q/
630                 Creates a new hold notification object
631                 @param authtoken The login session key
632                 @param notification The hold notification object to create
633                 @return ID of the new object on success, Event on error
634                 /
635 );
636 sub create_hold_notify {
637         my( $self, $conn, $authtoken, $notification ) = @_;
638         my( $requestor, $evt ) = $U->checkses($authtoken);
639         return $evt if $evt;
640         my ($hold, $patron);
641         ($hold, $evt) = $U->fetch_hold($notification->hold);
642         return $evt if $evt;
643         ($patron, $evt) = $U->fetch_user($hold->usr);
644         return $evt if $evt;
645
646         # XXX perm depth probably doesn't matter here -- should always be consortium level
647         $evt = $U->check_perms($requestor->id, $patron->home_ou, 'CREATE_HOLD_NOTIFICATION');
648         return $evt if $evt;
649
650         # Set the proper notifier 
651         $notification->notify_staff($requestor->id);
652         my $id = $U->storagereq(
653                 'open-ils.storage.direct.action.hold_notification.create', $notification );
654         return $U->DB_UPDATE_FAILED($notification) unless $id;
655         $logger->info("User ".$requestor->id." successfully created new hold notification $id");
656         return $id;
657 }
658
659
660 __PACKAGE__->register_method(
661         method  => 'reset_hold',
662         api_name        => 'open-ils.circ.hold.reset',
663         signature       => q/
664                 Un-captures and un-targets a hold, essentially returning
665                 it to the state it was in directly after it was placed,
666                 then attempts to re-target the hold
667                 @param authtoken The login session key
668                 @param holdid The id of the hold
669         /
670 );
671
672
673 sub reset_hold {
674         my( $self, $conn, $auth, $holdid ) = @_;
675         my $reqr;
676         my ($hold, $evt) = $U->fetch_hold($holdid);
677         return $evt if $evt;
678         ($reqr, $evt) = $U->checksesperm($auth, 'UPDATE_HOLD');
679         return $evt if $evt;
680         $evt = $self->_reset_hold($reqr, $hold);
681         return $evt if $evt;
682         return 1;
683 }
684
685 sub _reset_hold {
686         my ($self, $reqr, $hold, $session) = @_;
687
688         my $x;
689         if(!$session) {
690                 $x = 1;
691                 $session = $U->start_db_session();
692         }
693
694         $hold->clear_capture_time;
695         $hold->clear_current_copy;
696
697         return $U->DB_UPDATE_FAILED($hold) unless 
698                 $session->request(
699                         'open-ils.storage.direct.action.hold_request.update', $hold )->gather(1);
700
701         $session->request(
702                 'open-ils.storage.action.hold_request.copy_targeter', undef, $hold->id )->gather(1);
703
704         $U->commit_db_session($session) unless $x;
705         return undef;
706 }
707
708
709 __PACKAGE__->register_method(
710         method => 'fetch_open_title_holds',
711         api_name        => 'open-ils.circ.open_holds.retrieve',
712         signature       => q/
713                 Returns a list ids of un-fulfilled holds for a given title id
714                 @param authtoken The login session key
715                 @param id the id of the item whose holds we want to retrieve
716                 @param type The hold type - M, T, V, C
717         /
718 );
719
720 sub fetch_open_title_holds {
721         my( $self, $conn, $auth, $id, $type, $org ) = @_;
722         my $e = OpenILS::Utils::Editor->new( authtoken => $auth );
723         return $e->event unless $e->checkauth;
724
725         $type ||= "T";
726         $org ||= $e->requestor->ws_ou;
727
728 #       return $e->search_action_hold_request(
729 #               { target => $id, hold_type => $type, fulfillment_time => undef }, {idlist=>1});
730
731         # XXX make me return IDs in the future ^--
732         return $e->search_action_hold_request(
733                 { target => $id, hold_type => $type, fulfillment_time => undef });
734 }
735
736
737
738
739 __PACKAGE__->register_method(
740         method => 'fetch_captured_holds',
741         api_name        => 'open-ils.circ.captured_holds.on_shelf.retrieve',
742         signature       => q/
743                 Returns a list ids of un-fulfilled holds for a given title id
744                 @param authtoken The login session key
745                 @param org The org id of the location in question
746         /
747 );
748 sub fetch_captured_holds {
749         my( $self, $conn, $auth, $org ) = @_;
750
751         my $e = OpenILS::Utils::Editor->new(authtoken => $auth);
752         return $e->event unless $e->checkauth;
753         return $e->event unless $e->allowed('VIEW_HOLD'); # XXX rely on editor perm
754
755         $org ||= $e->requestor->ws_ou;
756
757         my $holds = $e->search_action_hold_request(
758                 { 
759                         capture_time            => { "!=" => undef },
760                         current_copy            => { "!=" => undef },
761                         fulfillment_time        => undef,
762                         pickup_lib                      => $org
763                 }
764         );
765
766         my @res;
767         my $stat = $U->copy_status_from_name('on holds shelf');
768         for my $h (@$holds) {
769                 my $copy = $e->retrieve_asset_copy($h->current_copy)
770                         or return $e->event;
771                 push( @res, $h ) if $copy->status == $stat->id; # eventually, push IDs here
772         }
773
774         return \@res;
775 }
776
777
778
779 1;