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