adding more permissions and exceptions related to the additions of more accurate...
[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 my $apputils = "OpenILS::Application::AppUtils";
22 use OpenILS::EX;
23 use OpenILS::Perm;
24
25
26
27 __PACKAGE__->register_method(
28         method  => "create_hold",
29         api_name        => "open-ils.circ.holds.create",
30         notes           => <<NOTE);
31 Create a new hold for an item.  From a permissions perspective, 
32 the login session is used as the 'requestor' of the hold.  
33 The hold recipient is determined by the 'usr' setting within
34 the hold object.
35
36 First we verify the requestion has holds request permissions.
37 Then we verify that the recipient is allowed to make the given hold.
38 If not, we see if the requestor has "override" capabilities.  If not,
39 a permission exception is returned.  If permissions allow, we cycle
40 through the set of holds objects and create.
41
42 If the recipient does not have permission to place multiple holds
43 on a single title and said operation is attempted, a permission
44 exception is returned
45 NOTE
46
47 sub create_hold {
48         my( $self, $client, $login_session, @holds) = @_;
49
50         if(!@holds){return 0;}
51         my $user = $apputils->check_user_session($login_session);
52
53
54         my $holds;
55         if(ref($holds[0]) eq 'ARRAY') {
56                 $holds = $holds[0];
57         } else { $holds = [ @holds ]; }
58
59         warn "Iterating over holds requests...\n";
60
61         for my $hold (@$holds) {
62
63                 if(!$hold){next};
64                 my $type = $hold->hold_type;
65
66                 use Data::Dumper;
67                 warn "Hold to create: " . Dumper($hold) . "\n";
68
69                 my $recipient;
70                 if($user->id ne $hold->usr) {
71
72                 } else {
73                         $recipient = $user;
74                 }
75
76                 #enforce the fact that the login is the one requesting the hold
77                 $hold->requestor($user->id); 
78
79                 my $perm = undef;
80
81                 # see if the requestor even has permission to request
82                 if($hold->requestor ne $hold->usr) {
83                         $perm = _check_request_holds_perm($type, $user->id, $user->home_ou);
84                         if($perm) { return $perm; }
85                 }
86
87                 $perm = _check_holds_perm($type, $hold->usr, $recipient->home_ou);
88                 if($perm) { 
89                         #if there is a requestor, see if the requestor has override privelages
90                         if($hold->requestor ne $hold->usr) {
91                                 $perm = _check_request_holds_override($user->id, $user->home_ou);
92                                 if($perm) {return $perm;}
93                         } else {
94                                 return $perm; 
95                         }
96                 }
97
98
99                 #my $session = $apputils->start_db_session();
100                 my $session = OpenSRF::AppSession->create("open-ils.storage");
101                 my $method = "open-ils.storage.direct.action.hold_request.create";
102                 warn "Sending hold request to storage... $method \n";
103
104                 my $req = $session->request( $method, $hold );
105
106                 my $resp = $req->gather(1);
107                 $session->disconnect();
108                 if(!$resp) { return OpenILS::EX->new("UNKNOWN")->ex(); }
109 #               $apputils->commit_db_session($session);
110         }
111
112         return 1;
113 }
114
115 # makes sure that a user has permission to place the type of requested hold
116 # returns the Perm exception if not allowed, returns undef if all is well
117 sub _check_holds_perm {
118         my($type, $user_id, $org_id) = @_;
119
120         if($type eq "M") {
121                 if($apputils->check_user_perms($user_id, $org_id, "MR_HOLDS")) {
122                         return OpenILS::Perm->new("MR_HOLDS");
123                 } 
124
125         } elsif ($type eq "T") {
126                 if($apputils->check_user_perms($user_id, $org_id, "TITLE_HOLDS")) {
127                         return OpenILS::Perm->new("TITLE_HOLDS");
128                 }
129
130         } elsif($type eq "V") {
131                 if($apputils->check_user_perms($user_id, $org_id, "VOLUME_HOLDS")) {
132                         return OpenILS::Perm->new("VOLUME_HOLDS");
133                 }
134
135         } elsif($type eq "C") {
136                 if($apputils->check_user_perms($user_id, $org_id, "COPY_HOLDS")) {
137                         return OpenILS::Perm->new("COPY_HOLDS");
138                 }
139         }
140
141         return undef;
142 }
143
144 # tests if the given user is allowed to place holds on another's behalf
145 sub _check_request_holds_perm {
146         my $user_id = shift;
147         my $org_id = shift;
148         if($apputils->check_user_perms($user_id, $org_id, "REQUEST_HOLDS")) {
149                 return OpenILS::Perm->new("REQUEST_HOLDS");
150         }
151 }
152
153 sub _check_request_holds_override {
154         my $user_id = shift;
155         my $org_id = shift;
156         if($apputils->check_user_perms($user_id, $org_id, "REQUEST_HOLDS_OVERRIDE")) {
157                 return OpenILS::Perm->new("REQUEST_HOLDS_OVERRIDE");
158         }
159 }
160
161
162 __PACKAGE__->register_method(
163         method  => "retrieve_holds",
164         api_name        => "open-ils.circ.holds.retrieve",
165         notes           => <<NOTE);
166 Retrieves all the holds for the specified user id.  The login session
167 is the requestor and if the requestor is different from the user, then
168 the requestor must have VIEW_HOLDS permissions.
169 NOTE
170
171
172 sub retrieve_holds {
173         my($self, $client, $login_session, $user_id) = @_;
174
175         my $user = $apputils->check_user_session($login_session);
176
177         if($user->id ne $user_id) {
178                 if($apputils->check_user_perms($user->id, $user->home_ou, "VIEW_HOLDS")) {
179                         return OpenILS::Perm->new("VIEW_HOLDS");
180                 }
181         }
182
183         my $session = OpenSRF::AppSession->create("open-ils.storage");
184         my $req = $session->request(
185                 "open-ils.storage.direct.action.hold_request.search.atomic",
186                 "usr" =>  $user_id , { order_by => "request_time" });
187
188         my $h = $req->gather(1);
189         $session->disconnect();
190         return $h;
191 }
192
193
194 __PACKAGE__->register_method(
195         method  => "cancel_hold",
196         api_name        => "open-ils.circ.hold.cancel",
197         notes           => <<"  NOTE");
198         Cancels the specified hold.  The login session
199         is the requestor and if the requestor is different from the usr field
200         on the hold, the requestor must have CANCEL_HOLDS permissions.
201         the hold may be either the hold object or the hold id
202         NOTE
203
204 sub cancel_hold {
205         my($self, $client, $login_session, $hold) = @_;
206
207         my $user = $apputils->check_user_session($login_session);
208
209         my $session = OpenSRF::AppSession->create("open-ils.storage");
210         
211         if(!ref($hold)) {
212                 $hold = $session->request(
213                         "open-ils.storage.direct.action.hold_request.retrieve", $hold)->gather(1);
214         }
215
216         if($user->id ne $hold->usr) {
217                 if($apputils->check_user_perms($user->id, $user->home_ou, "CANCEL_HOLDS")) {
218                         return OpenILS::Perm->new("CANCEL_HOLDS");
219                 }
220         }
221
222         use Data::Dumper;
223         warn "Cancelling hold: " . Dumper($hold) . "\n";
224
225         my $req = $session->request(
226                 "open-ils.storage.direct.action.hold_request.delete",
227                 $hold );
228         my $h = $req->gather(1);
229
230         warn "[$h] returned from hold_request delete\n";
231         $session->disconnect();
232         return $h;
233 }
234
235
236 __PACKAGE__->register_method(
237         method  => "update_hold",
238         api_name        => "open-ils.circ.hold.update",
239         notes           => <<"  NOTE");
240         Updates the specified hold.  The login session
241         is the requestor and if the requestor is different from the usr field
242         on the hold, the requestor must have UPDATE_HOLDS permissions.
243         NOTE
244
245 sub update_hold {
246         my($self, $client, $login_session, $hold) = @_;
247
248         my $user = $apputils->check_user_session($login_session);
249
250         if($user->id ne $hold->usr) {
251                 if($apputils->check_user_perms($user->id, $user->home_ou, "UPDATE_HOLDS")) {
252                         return OpenILS::Perm->new("UPDATE_HOLDS");
253                 }
254         }
255
256         use Data::Dumper;
257         warn "Updating hold: " . Dumper($hold) . "\n";
258
259         my $session = OpenSRF::AppSession->create("open-ils.storage");
260         my $req = $session->request(
261                 "open-ils.storage.direct.action.hold_request.update", $hold );
262         my $h = $req->gather(1);
263
264         warn "[$h] returned from hold_request update\n";
265         $session->disconnect();
266         return $h;
267 }
268
269
270 __PACKAGE__->register_method(
271         method  => "retrieve_hold_status",
272         api_name        => "open-ils.circ.hold.status.retrieve",
273         notes           => <<"  NOTE");
274         Calculates the current status of the hold.
275         the requestor must have VIEW_HOLDS permissions if the hold is for a user
276         other than the requestor.
277         Returns -1  on error (for now)
278         Returns 1 for 'waiting for copy to become available'
279         Returns 2 for 'waiting for copy capture'
280         Returns 3 for 'in transit'
281         Returns 4 for 'arrived'
282         NOTE
283
284 sub retrieve_hold_status {
285         my($self, $client, $login_session, $hold_id) = @_;
286
287         my $user = $apputils->check_user_session($login_session);
288
289         my $session = OpenSRF::AppSession->create("open-ils.storage");
290
291         my $hold = $session->request(
292                 "open-ils.storage.direct.action.hold_request.retrieve", $hold_id )->gather(1);
293         return -1 unless $hold; # should be an exception
294
295
296         if($user->id ne $hold->usr) {
297                 if($apputils->check_user_perms($user->id, $user->home_ou, "VIEW_HOLDS")) {
298                         return OpenILS::Perm->new("VIEW_HOLDS");
299                 }
300         }
301         
302         return 1 unless (defined($hold->current_copy));
303
304         #return 2 unless (defined($hold->capture_time));
305
306         my $copy = $session->request(
307                 "open-ils.storage.direct.asset.copy.retrieve", $hold->current_copy )->gather(1);
308         return 1 unless $copy; # should be an exception
309
310         use Data::Dumper;
311         warn "Hold Copy in status check: " . Dumper($copy) . "\n\n";
312
313         return 4 if ($hold->capture_time and $copy->circ_lib eq $hold->pickup_lib);
314
315         my $transit = _fetch_hold_transit($session, $hold->id);
316         return 4 if(ref($transit) and defined($transit->dest_recv_time) ); 
317
318         return 3 if defined($hold->capture_time);
319
320         return 2;
321 }
322
323
324 sub _fetch_hold_transit {
325         my $session = shift;
326         my $holdid = shift;
327         return $session->request(
328                 "open-ils.storage.direct.action.hold_transit_copy.search.hold",
329                 $holdid )->gather(1);
330 }
331
332
333
334
335 1;