Stop re-declaring $userpriv, remove unused $userou
[sitka/iNCIPit.git] / iNCIPit.cgi
CommitLineData
4cdc4f67
JS
1#! /usr/bin/perl
2
1ac548f2 3# This file is part of iNCIPit
4cdc4f67
JS
4#
5# iNCIPit is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 2 of the License, or
8# (at your option) any later version.
9#
10# iNCIPit is distributed in the hope that it will be useful, but WITHOUT
11# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
13# License for more details.
14#
15# You should have received a copy of the GNU General Public License
7a94033c 16# along with iNCIPit. If not, see <http://www.gnu.org/licenses/>.
4cdc4f67 17
4cdc4f67 18use warnings;
9061228c 19use strict;
4cdc4f67
JS
20use XML::LibXML;
21use CGI::XMLPost;
22use HTML::Entities;
23use CGI::Carp;
24use XML::XPath;
25use OpenSRF::System;
26use OpenSRF::Utils::SettingsClient;
27use Digest::MD5 qw/md5_hex/;
28use OpenILS::Utils::Fieldmapper;
29use OpenILS::Utils::CStoreEditor qw/:funcs/;
30use OpenILS::Const qw/:const/;
31use Scalar::Util qw(reftype blessed);
32use MARC::Record;
33use MARC::Field;
34use MARC::File::XML;
35use POSIX qw/strftime/;
36use DateTime;
f5e8d07e
JG
37use Config::Tiny;
38
a30f6f9e 39my $U = "OpenILS::Application::AppUtils";
4cdc4f67 40
f5e8d07e
JG
41my $conf = load_config( 'iNCIPit.ini' );
42
60d032c1 43# reject non-https access unless configured otherwise
a8c18053 44unless ($conf->{access}->{permit_plaintext} =~ m/^yes$/i) {
60d032c1
JG
45 unless ($ENV{HTTPS} eq 'on') {
46 print "Content-type: text/plain\n\n";
86fda995
JG
47 print "Access denied.\n";
48 exit 0;
60d032c1
JG
49 }
50}
51
52# TODO: support for multiple load balancer IPs
53my $lb_ip = $conf->{access}->{load_balancer_ip};
54
55# if we are behind a load balancer, check to see that the
56# actual client IP is permitted
57if ($lb_ip) {
58 my @allowed_ips = split(/ *, */, $conf->{access}->{allowed_client_ips});
59
86fda995
JG
60 my $forwarded = $ENV{HTTP_X_FORWARDED_FOR};
61 my $ok = 0;
60d032c1 62
86fda995
JG
63 foreach my $check_ip (@allowed_ips) {
64 $ok = 1 if ($check_ip eq $forwarded);
65 }
60d032c1
JG
66
67 # if we have a load balancer IP and are relying on
68 # X-Forwarded-For, deny requests other than those
69 # from the load balancer
70 # TODO: support for chained X-Forwarded-For -- ignore all but last
86fda995 71 unless ($ok && $ENV{REMOTE_ADDR} eq $lb_ip) {
60d032c1 72 print "Content-type: text/plain\n\n";
86fda995
JG
73 print "Access denied.\n";
74 exit 0;
75 }
60d032c1
JG
76}
77
4cdc4f67 78my $xmlpost = CGI::XMLPost->new();
5f517e0a 79my $xml = $xmlpost->data();
4cdc4f67 80
1ac548f2
JS
81# log posted data
82# XXX: posted ncip message log filename should be in config.
4cdc4f67
JS
83open POST_DATA, ">>post_data.txt";
84print POST_DATA $xml;
85close POST_DATA;
86
87# initialize the parser
88my $parser = new XML::LibXML;
89my $doc = $parser->load_xml( string => $xml );
90
91my %session = login();
92
93# Setup our SIGALRM handler.
94$SIG{'ALRM'} = \&logout;
95
1ac548f2 96if ( defined( $session{authtoken} ) ) {
5f517e0a
DW
97 $doc->exists('/NCIPMessage/LookupUser') ? lookupUser() : (
98 $doc->exists('/NCIPMessage/ItemRequested') ? item_request() : (
99 $doc->exists('/NCIPMessage/ItemShipped') ? item_shipped() : (
100 $doc->exists('/NCIPMessage/ItemCheckedOut') ? item_checked_out() : (
101 $doc->exists('/NCIPMessage/CheckOutItem') ? check_out_item() : (
102 $doc->exists('/NCIPMessage/ItemCheckedIn') ? item_checked_in() : (
103 $doc->exists('/NCIPMessage/CheckInItem') ? check_in_item() : (
104 $doc->exists('/NCIPMessage/ItemReceived') ? item_received() : (
105 $doc->exists('/NCIPMessage/AcceptItem') ? accept_item() : (
106 $doc->exists('/NCIPMessage/ItemRequestCancelled') ? item_cancelled() : (
107 $doc->exists('/NCIPMessage/ItemRenewed') ? item_renew() : (
108 $doc->exists('/NCIPMessage/RenewItem') ? renew_item() :
109 fail("UNKNOWN NCIPMessage")
110 )))))))))));
111
112 # Clear any SIGALRM timers.
113 alarm(0);
114 logout();
4cdc4f67 115} else {
5f517e0a 116 fail("Unable to perform action : Unknown Service Request");
4cdc4f67
JS
117}
118
f5e8d07e
JG
119# load and parse config file
120sub load_config {
121 my $file = shift;
122
123 my $Config = Config::Tiny->new;
124 $Config = Config::Tiny->read( $file ) ||
125 die( "Error reading config file ", $file, ": ", Config::Tiny->errstr, "\n" );
126 return $Config;
127}
128
4cdc4f67 129sub logit {
5f517e0a
DW
130 my ( $msg, $func, $more_info ) = @_;
131 open RESP_DATA, ">>resp_data.txt";
132 print RESP_DATA $msg;
133 print RESP_DATA $more_info unless !$more_info;
134 close RESP_DATA;
135 print $msg || fail($func);
4cdc4f67
JS
136}
137
6e6bdfe9 138sub staff_log {
5f517e0a
DW
139 my ( $taiv, $faiv, $more_info ) = @_;
140 my $now = localtime();
141 open STAFF_LOG, ">>staff_data.csv";
142 print STAFF_LOG "$now, $faiv, $taiv, $more_info\n";
143 close STAFF_LOG;
6e6bdfe9
JS
144}
145
4cdc4f67 146sub item_renew {
5f517e0a
DW
147 my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemRenewed/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
148 my $faidScheme = HTML::Entities::encode($faidSchemeX);
149 my $faidValue = $doc->find('/NCIPMessage/ItemRenewed/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
150 my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemRenewed/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
151 my $taidScheme = HTML::Entities::encode($taidSchemeX);
152 my $taidValue = $doc->find('/NCIPMessage/ItemRenewed/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
153
154 my $pid = $doc->findvalue('/NCIPMessage/ItemRenewed/UniqueUserId/UserIdentifierValue');
155 my $visid = $doc->findvalue('/NCIPMessage/ItemRenewed/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
156 my $due_date = $doc->findvalue('/NCIPMessage/ItemRenewed/DateDue');
157
158 my $r = renewal( $visid, $due_date );
159
160 my $hd = <<ITEMRENEWAL;
4cdc4f67
JS
161Content-type: text/xml
162
163
164<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
165<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
166 <ItemRenewedResponse>
167 <ResponseHeader>
168 <FromAgencyId>
169 <UniqueAgencyId>
170 <Scheme>$faidScheme</Scheme>
171 <Value>$faidValue</Value>
172 </UniqueAgencyId>
173 </FromAgencyId>
174 <ToAgencyId>
175 <UniqueAgencyId>
176 <Scheme>$taidScheme</Scheme>
177 <Value>$taidValue</Value>
178 </UniqueAgencyId>
179 </ToAgencyId>
180 </ResponseHeader>
181 <UniqueItemId>
182 <ItemIdentifierValue datatype="string">$visid</ItemIdentifierValue>
183 </UniqueItemId>
184 </ItemRenewedResponse>
4cdc4f67
JS
185</NCIPMessage>
186
187ITEMRENEWAL
188
5f517e0a 189 my $more_info = <<MOREINFO;
4cdc4f67 190
5f517e0a
DW
191VISID = $visid
192Desired Due Date = $due_date
4cdc4f67
JS
193
194MOREINFO
195
5f517e0a
DW
196 logit( $hd, ( caller(0) )[3], $more_info );
197 staff_log( $taidValue, $faidValue,
198 "ItemRenewal -> Patronid : "
199 . $pid
200 . " | Visid : "
201 . $visid
202 . " | Due Date : "
203 . $due_date );
6e6bdfe9 204}
4cdc4f67 205
6e6bdfe9 206sub renew_item {
5f517e0a
DW
207 my $faidSchemeX = $doc->findvalue('/NCIPMessage/RenewItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
208 my $faidScheme = HTML::Entities::encode($faidSchemeX);
209 my $faidValue = $doc->find('/NCIPMessage/RenewItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
210 my $taidSchemeX = $doc->findvalue('/NCIPMessage/RenewItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
211 my $taidScheme = HTML::Entities::encode($taidSchemeX);
212 my $taidValue = $doc->find('/NCIPMessage/RenewItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
213
214 my $pid = $doc->findvalue('/NCIPMessage/RenewItem/UniqueUserId/UserIdentifierValue');
fd19ff1c 215 my $unique_item_id = $doc->findvalue('/NCIPMessage/RenewItem/UniqueItemId/ItemIdentifierValue');
5f517e0a
DW
216 my $due_date = $doc->findvalue('/NCIPMessage/RenewItem/DateDue');
217
fd19ff1c
JG
218 # we are using the UniqueItemId value as a barcode here
219 my $r = renewal( $unique_item_id, $due_date );
5f517e0a
DW
220
221 my $hd = <<ITEMRENEWAL;
6e6bdfe9
JS
222Content-type: text/xml
223
224
225<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
226<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
227 <RenewItemResponse>
228 <ResponseHeader>
229 <FromAgencyId>
230 <UniqueAgencyId>
231 <Scheme>$faidScheme</Scheme>
232 <Value>$faidValue</Value>
233 </UniqueAgencyId>
234 </FromAgencyId>
235 <ToAgencyId>
236 <UniqueAgencyId>
237 <Scheme>$taidScheme</Scheme>
238 <Value>$taidValue</Value>
239 </UniqueAgencyId>
240 </ToAgencyId>
241 </ResponseHeader>
242 <UniqueItemId>
fd19ff1c 243 <ItemIdentifierValue datatype="string">$unique_item_id</ItemIdentifierValue>
5f517e0a
DW
244 </UniqueItemId>
245 </RenewItemResponse>
6e6bdfe9
JS
246</NCIPMessage>
247
248ITEMRENEWAL
249
5f517e0a 250 my $more_info = <<MOREINFO;
6e6bdfe9 251
fd19ff1c 252UNIQUEID = $unique_item_id
5f517e0a 253Desired Due Date = $due_date
6e6bdfe9
JS
254
255MOREINFO
256
5f517e0a
DW
257 logit( $hd, ( caller(0) )[3], $more_info );
258 staff_log( $taidValue, $faidValue,
259 "RenewItem -> Patronid : "
260 . $pid
fd19ff1c
JG
261 . " | Uniqueid: : "
262 . $unique_item_id
5f517e0a
DW
263 . " | Due Date : "
264 . $due_date );
4cdc4f67
JS
265}
266
267sub accept_item {
5f517e0a
DW
268 my $faidSchemeX = $doc->findvalue('/NCIPMessage/AcceptItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
269 my $faidScheme = HTML::Entities::encode($faidSchemeX);
270 my $faidValue = $doc->find('/NCIPMessage/AcceptItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
271 my $taidSchemeX = $doc->findvalue('/NCIPMessage/AcceptItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
272 my $taidScheme = HTML::Entities::encode($taidSchemeX);
273 my $taidValue = $doc->find('/NCIPMessage/AcceptItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
5f517e0a
DW
274 my $visid = $doc->findvalue('/NCIPMessage/AcceptItem/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
275 my $request_id = $doc->findvalue('/NCIPMessage/AcceptItem/UniqueRequestId/RequestIdentifierValue') || "unknown";
276 my $patron = $doc->findvalue('/NCIPMessage/AcceptItem/UserOptionalFields/VisibleUserId/VisibleUserIdentifier');
277 my $copy = copy_from_barcode($visid);
bf70b77d 278 fail( "accept_item: " . $copy->{textcode} . " $visid" ) unless ( blessed $copy);
ba01d5da 279 my $r2 = update_copy( $copy, $conf->{status}->{hold} ); # put into INN-Reach Hold status
0b0c5299
DW
280
281# TODO: this should probably fulfill the original hold, not just change the status. Eventually we should split the hold type, as holds arriving are not the same as holds needing to be sent
5f517e0a
DW
282
283 my $hd = <<ACCEPTITEM;
4cdc4f67
JS
284Content-type: text/xml
285
286
287<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
288<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
289 <AcceptItemResponse>
290 <ResponseHeader>
291 <FromAgencyId>
292 <UniqueAgencyId>
293 <Scheme>$faidScheme</Scheme>
294 <Value>$faidValue</Value>
295 </UniqueAgencyId>
296 </FromAgencyId>
297 <ToAgencyId>
298 <UniqueAgencyId>
299 <Scheme>$taidScheme</Scheme>
300 <Value>$taidValue</Value>
301 </UniqueAgencyId>
302 </ToAgencyId>
303 </ResponseHeader>
304 <UniqueRequestId>
305 <ItemIdentifierValue datatype="string">$request_id</ItemIdentifierValue>
306 </UniqueRequestId>
307 <UniqueItemId>
308 <ItemIdentifierValue datatype="string">$visid</ItemIdentifierValue>
309 </UniqueItemId>
310 </AcceptItemResponse>
4cdc4f67
JS
311</NCIPMessage>
312
313ACCEPTITEM
314
5f517e0a
DW
315 logit( $hd, ( caller(0) )[3] );
316 staff_log( $taidValue, $faidValue,
0b0c5299 317 "AcceptItem -> Request Id : " . $request_id . " | Patron Id : " . $patron . " | Visible Id :" . $visid );
4cdc4f67
JS
318}
319
320sub item_received {
dfb584fc
JG
321 my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemReceived/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
322 my $faidScheme = HTML::Entities::encode($faidSchemeX);
5f517e0a 323 my $faidValue = $doc->find('/NCIPMessage/ItemReceived/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
dfb584fc
JG
324 my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemReceived/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
325 my $taidScheme = HTML::Entities::encode($taidSchemeX);
326 my $taidValue = $doc->find('/NCIPMessage/ItemReceived/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
0b0c5299
DW
327 my $visid = $doc->findvalue('/NCIPMessage/ItemReceived/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
328 my $copy = copy_from_barcode($visid);
329 fail( $copy->{textcode} . " $visid" ) unless ( blessed $copy);
330 my $r1 = checkin($visid) if ( $copy->status == OILS_COPY_STATUS_CHECKED_OUT ); # checkin the item before delete if ItemCheckedIn step was skipped
5f517e0a
DW
331 my $r2 = delete_copy($copy);
332
333 my $hd = <<ITEMRECEIVED;
4cdc4f67
JS
334Content-type: text/xml
335
336
337<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
338<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
339 <ItemReceivedResponse>
340 <ResponseHeader>
341 <FromAgencyId>
342 <UniqueAgencyId>
343 <Scheme>$faidScheme</Scheme>
344 <Value>$faidValue</Value>
345 </UniqueAgencyId>
346 </FromAgencyId>
347 <ToAgencyId>
348 <UniqueAgencyId>
349 <Scheme>$taidScheme</Scheme>
350 <Value>$taidValue</Value>
351 </UniqueAgencyId>
352 </ToAgencyId>
353 </ResponseHeader>
354 <UniqueItemId>
0b0c5299 355 <ItemIdentifierValue datatype="string">$visid</ItemIdentifierValue>
5f517e0a
DW
356 </UniqueItemId>
357 </ItemReceivedResponse>
4cdc4f67
JS
358</NCIPMessage>
359
360ITEMRECEIVED
361
5f517e0a 362 logit( $hd, ( caller(0) )[3] );
0b0c5299 363 staff_log( $taidValue, $faidValue, "ItemReceived -> Visible ID : " . $visid );
4cdc4f67
JS
364}
365
366sub item_cancelled {
5f517e0a
DW
367 my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
368 my $faidScheme = HTML::Entities::encode($faidSchemeX);
369 my $faidValue = $doc->find('/NCIPMessage/ItemRequestCancelled/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
370
371 my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
372 my $taidScheme = HTML::Entities::encode($taidSchemeX);
373 my $taidValue = $doc->find('/NCIPMessage/ItemRequestCancelled/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
374 my $UniqueItemIdAgencyIdValue = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/UniqueItemId/UniqueAgencyId/Value');
375
376 my $barcode = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/UniqueItemId/ItemIdentifierValue');
377
378 if ( $barcode =~ /^i/ ) { # delete copy only if barcode is an iNUMBER
379 $barcode .= $faidValue;
380 my $copy = copy_from_barcode($barcode);
381 fail( $copy->{textcode} . " $barcode" ) unless ( blessed $copy);
382 my $r = delete_copy($copy);
383 } else {
384
385 # remove hold!
386 my $copy = copy_from_barcode($barcode);
387 fail( $copy->{textcode} . " $barcode" ) unless ( blessed $copy);
0b0c5299 388 my $r = update_copy( $copy, 0 ); # TODO: we need to actually remove the hold, not just reset to available
5f517e0a
DW
389 }
390
391 my $hd = <<ITEMREQUESTCANCELLED;
4cdc4f67
JS
392Content-type: text/xml
393
394
395<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
396<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
397 <ItemRequestCancelledResponse>
398 <ResponseHeader>
399 <FromAgencyId>
400 <UniqueAgencyId>
401 <Scheme>$faidScheme</Scheme>
402 <Value>$faidValue</Value>
403 </UniqueAgencyId>
404 </FromAgencyId>
405 <ToAgencyId>
406 <UniqueAgencyId>
407 <Scheme>$taidScheme</Scheme>
408 <Value>$taidValue</Value>
409 </UniqueAgencyId>
410 </ToAgencyId>
411 </ResponseHeader>
412 <UniqueItemId>
413 <ItemIdentifierValue datatype="string">$barcode</ItemIdentifierValue>
414 </UniqueItemId>
415 </ItemRequestCancelledResponse>
4cdc4f67
JS
416</NCIPMessage>
417
418ITEMREQUESTCANCELLED
419
5f517e0a
DW
420 logit( $hd, ( caller(0) )[3] );
421 staff_log( $taidValue, $faidValue,
422 "ItemRequestCancelled -> Barcode : " . $barcode );
4cdc4f67
JS
423}
424
425sub item_checked_in {
5f517e0a
DW
426 my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedIn/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
427 my $faidScheme = HTML::Entities::encode($faidSchemeX);
428 my $faidValue = $doc->find('/NCIPMessage/ItemCheckedIn/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
429 my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedIn/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
430 my $taidScheme = HTML::Entities::encode($taidSchemeX);
431 my $taidValue = $doc->find('/NCIPMessage/ItemCheckedIn/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
432
0b0c5299
DW
433 my $visid = $doc->findvalue('/NCIPMessage/ItemCheckedIn/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
434 my $r = checkin($visid);
435 my $copy = copy_from_barcode($visid);
436 fail( $copy->{textcode} . " $visid" ) unless ( blessed $copy);
ba01d5da 437 my $r2 = update_copy( $copy, $conf->{status}->{transit_return} ); # "INN-Reach Transit Return" status
5f517e0a
DW
438
439 my $hd = <<ITEMCHECKEDIN;
4cdc4f67
JS
440Content-type: text/xml
441
442
443<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
444<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
445 <ItemCheckedInResponse>
446 <ResponseHeader>
447 <FromAgencyId>
448 <UniqueAgencyId>
449 <Scheme>$faidScheme</Scheme>
450 <Value>$faidValue</Value>
451 </UniqueAgencyId>
452 </FromAgencyId>
453 <ToAgencyId>
454 <UniqueAgencyId>
455 <Scheme>$taidScheme</Scheme>
456 <Value>$taidValue</Value>
457 </UniqueAgencyId>
458 </ToAgencyId>
459 </ResponseHeader>
460 <UniqueItemId>
0b0c5299 461 <ItemIdentifierValue datatype="string">$visid</ItemIdentifierValue>
5f517e0a
DW
462 </UniqueItemId>
463 </ItemCheckedInResponse>
4cdc4f67
JS
464</NCIPMessage>
465
466ITEMCHECKEDIN
467
5f517e0a 468 logit( $hd, ( caller(0) )[3] );
0b0c5299 469 staff_log( $taidValue, $faidValue, "ItemCheckedIn -> Visible ID : " . $visid );
4cdc4f67
JS
470}
471
472sub item_checked_out {
5f517e0a
DW
473 my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedOut/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
474 my $faidScheme = HTML::Entities::encode($faidSchemeX);
475 my $faidValue = $doc->find('/NCIPMessage/ItemCheckedOut/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
476 my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedOut/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
477 my $taidScheme = HTML::Entities::encode($taidSchemeX);
478 my $taidValue = $doc->find('/NCIPMessage/ItemCheckedOut/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
479
0b0c5299 480 my $patron_barcode = $doc->findvalue('/NCIPMessage/ItemCheckedOut/UserOptionalFields/VisibleUserId/VisibleUserIdentifier');
5f517e0a 481 my $due_date = $doc->findvalue('/NCIPMessage/ItemCheckedOut/DateDue');
0b0c5299 482 my $visid = $doc->findvalue('/NCIPMessage/ItemCheckedOut/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
5f517e0a
DW
483
484 my $copy = copy_from_barcode($visid);
485 fail( $copy->{textcode} . " $visid" ) unless ( blessed $copy);
0b0c5299
DW
486 my $r = update_copy( $copy, 0 ); # seemed like copy had to be available before it could be checked out, so ...
487 my $r1 = checkin($visid) if ( $copy->status == OILS_COPY_STATUS_CHECKED_OUT ); # double posted itemcheckedout messages cause error ... trying to simplify
488 my $r2 = checkout( $visid, $patron_barcode, $due_date );
5f517e0a
DW
489
490 my $hd = <<ITEMCHECKEDOUT;
4cdc4f67
JS
491Content-type: text/xml
492
493
494<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
495<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
496 <ItemCheckedOutResponse>
497 <ResponseHeader>
498 <FromAgencyId>
499 <UniqueAgencyId>
500 <Scheme>$faidScheme</Scheme>
501 <Value>$faidValue</Value>
502 </UniqueAgencyId>
503 </FromAgencyId>
504 <ToAgencyId>
505 <UniqueAgencyId>
506 <Scheme>$taidScheme</Scheme>
507 <Value>$taidValue</Value>
508 </UniqueAgencyId>
509 </ToAgencyId>
510 </ResponseHeader>
511 <UniqueItemId>
512 <ItemIdentifierValue datatype="string">$visid</ItemIdentifierValue>
513 </UniqueItemId>
514 </ItemCheckedOutResponse>
4cdc4f67
JS
515</NCIPMessage>
516
517ITEMCHECKEDOUT
518
5f517e0a
DW
519 logit( $hd, ( caller(0) )[3] );
520 staff_log( $taidValue, $faidValue,
0b0c5299 521 "ItemCheckedOut -> Visible Id : " . $visid . " | Patron Barcode : " . $patron_barcode . " | Due Date : " . $due_date );
4cdc4f67
JS
522}
523
524sub check_out_item {
5f517e0a
DW
525 my $faidSchemeX = $doc->findvalue('/NCIPMessage/CheckOutItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
526 my $faidScheme = HTML::Entities::encode($faidSchemeX);
527 my $faidValue = $doc->find('/NCIPMessage/CheckOutItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
528 my $taidSchemeX = $doc->findvalue('/NCIPMessage/CheckOutItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
529 my $taidScheme = HTML::Entities::encode($taidSchemeX);
530 my $taidValue = $doc->find('/NCIPMessage/CheckOutItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
531
532 my $mdate = $doc->findvalue('/NCIPMessage/CheckOutItem/MandatedAction/DateEventOccurred');
0b0c5299 533 my $patron_barcode = "zyyyy"; # XXX: CUSTOMIZATION NEEDED XXX institution/eg_as_item_agency user lookup here
5f517e0a
DW
534
535 my $barcode = $doc->findvalue('/NCIPMessage/CheckOutItem/UniqueItemId/ItemIdentifierValue');
0b0c5299
DW
536
537 # TODO: watch for possible real ids here?
5f517e0a
DW
538 my $due_date = $doc->findvalue('/NCIPMessage/CheckOutItem/DateDue');
539
540 my $copy = copy_from_barcode($barcode);
541 fail( $copy->{textcode} . " $barcode" ) unless ( blessed $copy);
542
0b0c5299
DW
543 my $r2 = checkout( $barcode, $patron_barcode, $due_date );
544
545 # TODO: check for checkout exception (like OPEN_CIRCULATION_EXISTS)
5f517e0a
DW
546
547 my $hd = <<CHECKOUTITEM;
4cdc4f67
JS
548Content-type: text/xml
549
550
551<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
552<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
553 <CheckOutItemResponse>
554 <ResponseHeader>
555 <FromAgencyId>
556 <UniqueAgencyId>
557 <Scheme>$faidScheme</Scheme>
558 <Value>$faidValue</Value>
559 </UniqueAgencyId>
560 </FromAgencyId>
561 <ToAgencyId>
562 <UniqueAgencyId>
563 <Scheme>$taidScheme</Scheme>
564 <Value>$taidValue</Value>
565 </UniqueAgencyId>
566 </ToAgencyId>
567 </ResponseHeader>
568 <UniqueItemId>
569 <ItemIdentifierValue datatype="string">$barcode</ItemIdentifierValue>
570 </UniqueItemId>
571 </CheckOutItemResponse>
4cdc4f67
JS
572</NCIPMessage>
573
574CHECKOUTITEM
575
5f517e0a
DW
576 logit( $hd, ( caller(0) )[3] );
577 staff_log( $taidValue, $faidValue,
0b0c5299 578 "CheckOutItem -> Barcode : " . $barcode . " | Patron Barcode : " . $patron_barcode . " | Due Date : " . $due_date );
4cdc4f67
JS
579}
580
581sub check_in_item {
5f517e0a
DW
582 my $faidSchemeX = $doc->findvalue('/NCIPMessage/CheckInItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
583 my $faidScheme = HTML::Entities::encode($faidSchemeX);
584 my $faidValue = $doc->find('/NCIPMessage/CheckInItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
585 my $taidSchemeX = $doc->findvalue('/NCIPMessage/CheckInItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
586 my $taidScheme = HTML::Entities::encode($taidSchemeX);
587 my $taidValue = $doc->find('/NCIPMessage/CheckInItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
588
589 my $barcode = $doc->findvalue('/NCIPMessage/CheckInItem/UniqueItemId/ItemIdentifierValue');
2606eada
DW
590 my $r = checkin($barcode);
591 fail($r) if $r =~ /^COPY_NOT_CHECKED_OUT/;
592 # TODO: do we need to do these next steps? checkin() should handle everything, and we want this to end up in 'reshelving'. If we are worried about transits, we should handle (abort) them, not just change the status
593 ##my $copy = copy_from_barcode($barcode);
594 ##fail($copy->{textcode}." $barcode") unless (blessed $copy);
595 ## my $r2 = update_copy($copy,0); # Available now
5f517e0a
DW
596
597 my $hd = <<CHECKINITEM;
4cdc4f67
JS
598Content-type: text/xml
599
600
601<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
602<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
603 <CheckInItemResponse>
604 <ResponseHeader>
605 <FromAgencyId>
606 <UniqueAgencyId>
607 <Scheme>$faidScheme</Scheme>
608 <Value>$faidValue</Value>
609 </UniqueAgencyId>
610 </FromAgencyId>
611 <ToAgencyId>
612 <UniqueAgencyId>
613 <Scheme>$taidScheme</Scheme>
614 <Value>$taidValue</Value>
615 </UniqueAgencyId>
616 </ToAgencyId>
617 </ResponseHeader>
618 <UniqueItemId>
619 <ItemIdentifierValue datatype="string">$barcode</ItemIdentifierValue>
620 </UniqueItemId>
621 </CheckInItemResponse>
4cdc4f67
JS
622</NCIPMessage>
623
624CHECKINITEM
625
5f517e0a
DW
626 logit( $hd, ( caller(0) )[3] );
627 staff_log( $taidValue, $faidValue, "CheckInItem -> Barcode : " . $barcode );
4cdc4f67
JS
628}
629
630sub item_shipped {
5f517e0a
DW
631 my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemShipped/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
632 my $faidScheme = HTML::Entities::encode($faidSchemeX);
633 my $faidValue = $doc->find('/NCIPMessage/ItemShipped/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
634 my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemShipped/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
635 my $taidScheme = HTML::Entities::encode($taidSchemeX);
636 my $taidValue = $doc->find('/NCIPMessage/ItemShipped/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
637
638 my $visid = $doc->findvalue('/NCIPMessage/ItemShipped/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
639 my $barcode = $doc->findvalue('/NCIPMessage/ItemShipped/UniqueItemId/ItemIdentifierValue') . $faidValue;
640 my $title = $doc->findvalue('/NCIPMessage/ItemShipped/ItemOptionalFields/BibliographicDescription/Title');
641 my $callnumber = $doc->findvalue('/NCIPMessage/ItemShipped/ItemOptionalFields/ItemDescription/CallNumber');
642
643 my $copy = copy_from_barcode($barcode);
644 fail( $copy->{textcode} . " $barcode" ) unless ( blessed $copy);
ba01d5da 645 my $r = update_copy_shipped( $copy, $conf->{status}->{transit}, $visid ); # put copy into INN-Reach Transit status & modify barcode = Visid != tempIIIiNumber
5f517e0a
DW
646
647 my $hd = <<ITEMSHIPPED;
4cdc4f67
JS
648Content-type: text/xml
649
650
651<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
652<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
653 <ItemShippedResponse>
654 <ResponseHeader>
655 <FromAgencyId>
656 <UniqueAgencyId>
657 <Scheme>$faidScheme</Scheme>
658 <Value>$faidValue</Value>
659 </UniqueAgencyId>
660 </FromAgencyId>
661 <ToAgencyId>
662 <UniqueAgencyId>
663 <Scheme>$taidScheme</Scheme>
664 <Value>$taidValue</Value>
665 </UniqueAgencyId>
666 </ToAgencyId>
667 </ResponseHeader>
668 <UniqueItemId>
669 <ItemIdentifierValue datatype="string">$visid</ItemIdentifierValue>
670 </UniqueItemId>
671 </ItemShippedResponse>
4cdc4f67
JS
672</NCIPMessage>
673
674ITEMSHIPPED
675
5f517e0a
DW
676 logit( $hd, ( caller(0) )[3] );
677 staff_log( $taidValue, $faidValue,
0b0c5299 678 "ItemShipped -> Visible Id : " . $visid . " | Barcode : " . $barcode . " | Title : " . $title . " | Call Number : " . $callnumber );
4cdc4f67
JS
679}
680
681sub item_request {
5f517e0a
DW
682 my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequested/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
683 my $faidScheme = HTML::Entities::encode($faidSchemeX);
684 my $faidValue = $doc->find('/NCIPMessage/ItemRequested/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
685
686 my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequested/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
687 my $taidScheme = HTML::Entities::encode($taidSchemeX);
688 my $taidValue = $doc->find('/NCIPMessage/ItemRequested/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
689 my $UniqueItemIdAgencyIdValue = $doc->findvalue('/NCIPMessage/ItemRequested/UniqueItemId/UniqueAgencyId/Value');
690
0b0c5299
DW
691 # TODO: should we use the VisibleID for item agency variation of this method call
692
693 my $pid = $doc->findvalue('/NCIPMessage/ItemRequested/UniqueUserId/UserIdentifierValue');
5f517e0a
DW
694 my $barcode = $doc->findvalue('/NCIPMessage/ItemRequested/UniqueItemId/ItemIdentifierValue');
695 my $author = $doc->findvalue('/NCIPMessage/ItemRequested/ItemOptionalFields/BibliographicDescription/Author');
696 my $title = $doc->findvalue('/NCIPMessage/ItemRequested/ItemOptionalFields/BibliographicDescription/Title');
697 my $callnumber = $doc->findvalue('/NCIPMessage/ItemRequested/ItemOptionalFields/ItemDescription/CallNumber');
698 my $medium_type = $doc->find('/NCIPMessage/ItemRequested/ItemOptionalFields/BibliographicDescription/MediumType/Value');
699
700 my $r = "default error checking response";
701
a30f6f9e 702 if ( $barcode =~ /^i/ ) { # XXX EG is User Agency # create copy only if barcode is an iNUMBER
ba01d5da 703 my $copy_status_id = $conf->{status}->{loan_requested}; # INN-Reach Loan Requested - local configured status
5f517e0a 704 $barcode .= $faidValue;
a30f6f9e
DW
705 # we want our custom status to be then end result, so create the copy with status of "Available, then hold it, then update the status
706 $r = create_copy( $title, $callnumber, $barcode, 0, $medium_type );
707 my $copy = copy_from_barcode($barcode);
708 my $r2 = place_simple_hold( $copy->id, $pid );
709 my $r3 = update_copy( $copy, $copy_status_id );
710 } else { # XXX EG is Item Agency
15d084ee
JG
711 unless ( $conf->{behavior}->{no_item_agency_holds} =~ m/^y/i ) {
712 # place hold for user UniqueUserId/UniqueAgencyId/Value = institution account
713 my $copy = copy_from_barcode($barcode);
714 my $pid2 = 1013459; # XXX CUSTOMIZATION NEEDED XXX # this is the id of a user representing your DCB system, TODO: use agency information to create and link to individual accounts per agency, if needed
715 $r = place_simple_hold( $copy->id, $pid2 );
716 my $r2 = update_copy( $copy, $conf->{status}->{hold} ); # put into INN-Reach Hold status
717 }
5f517e0a
DW
718 }
719
720 my $hd = <<ITEMREQ;
4cdc4f67
JS
721Content-type: text/xml
722
723
724<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
725<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
726 <ItemRequestedResponse>
727 <ResponseHeader>
728 <FromAgencyId>
729 <UniqueAgencyId>
730 <Scheme>$faidScheme</Scheme>
731 <Value>$faidValue</Value>
732 </UniqueAgencyId>
733 </FromAgencyId>
734 <ToAgencyId>
735 <UniqueAgencyId>
736 <Scheme>$taidScheme</Scheme>
737 <Value>$taidValue</Value>
738 </UniqueAgencyId>
739 </ToAgencyId>
740 </ResponseHeader>
741 <UniqueUserId>
742 <UniqueAgencyId>
743 <Scheme datatype="string">$taidScheme</Scheme>
744 <Value datatype="string">$taidValue</Value>
745 </UniqueAgencyId>
0b0c5299 746 <UserIdentifierValue datatype="string">$pid</UserIdentifierValue>
5f517e0a
DW
747 </UniqueUserId>
748 <UniqueItemId>
749 <ItemIdentifierValue datatype="string">$barcode</ItemIdentifierValue>
750 </UniqueItemId>
751 <ItemOptionalFields>
752 <BibliographicDescription>
753 <Author datatype="string">$author</Author>
754 <Title datatype="string">$title</Title>
755 </BibliographicDescription>
756 <ItemDescription>
757 <CallNumber datatype="string">$callnumber</CallNumber>
758 </ItemDescription>
759 </ItemOptionalFields>
760 </ItemRequestedResponse>
4cdc4f67
JS
761</NCIPMessage>
762
763ITEMREQ
764
5f517e0a
DW
765 logit( $hd, ( caller(0) )[3] );
766 staff_log( $taidValue, $faidValue,
0b0c5299 767 "ItemRequested -> Barcode : " . $barcode . " | Title : " . $title . " | Call Number : " . $callnumber . " | Patronid :" . $pid );
4cdc4f67
JS
768}
769
1ac548f2
JS
770sub lookupUser {
771
5f517e0a
DW
772 my $faidScheme = $doc->findvalue('/NCIPMessage/LookupUser/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
773 $faidScheme = HTML::Entities::encode($faidScheme);
774 my $faidValue = $doc->find('/NCIPMessage/LookupUser/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
775 my $taidScheme = $doc->findvalue('/NCIPMessage/LookupUser/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
776 $taidScheme = HTML::Entities::encode($taidScheme);
777
778 my $taidValue = $doc->find('/NCIPMessage/LookupUser/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
779 my $id = $doc->findvalue('/NCIPMessage/LookupUser/VisibleUserId/VisibleUserIdentifier');
780 my $uidValue = user_id_from_barcode($id);
781
782 if ( !defined($uidValue)
783 || ( ref($uidValue) && reftype($uidValue) eq 'HASH' ) )
784 {
785 do_lookup_user_error_stanza("PATRON_NOT_FOUND : $id");
786 die;
787 }
788
3bcdd8ae
JG
789 my ( $propername, $email, $good_until, $userpriv, $block_stanza ) =
790 ( "name here", "", "good until", "", "" ); # defaults
5f517e0a
DW
791
792 my $patron = flesh_user($uidValue);
793
794 #if (blessed($patron)) {
795 my $patron_ok = 1;
796 my @penalties = @{ $patron->standing_penalties };
797
798 if ( $patron->deleted eq 't' ) {
799 do_lookup_user_error_stanza("PATRON_DELETED : $uidValue");
800 die;
801 } elsif ( $patron->barred eq 't' ) {
802 do_lookup_user_error_stanza("PATRON_BARRED : $uidValue");
803 die;
804 } elsif ( $patron->active eq 'f' ) {
805 do_lookup_user_error_stanza("PATRON_INACTIVE : $uidValue");
806 die;
807 }
808
809 elsif ( $#penalties > -1 ) {
810
811# my $penalty;
812# foreach $penalty (@penalties) {
813# if (defined($penalty->standing_penalty->block_list)) {
814# my @block_list = split(/\|/, $penalty->standing_penalty->block_list);
815# foreach my $block (@block_list) {
816# foreach my $block_on (@$block_types) {
817# if ($block eq $block_on) {
818# $block_stanza .= "\n".$penalty->standing_penalty->name;
819# $patron_ok = 0;
820# }
821# last unless ($patron_ok);
822# }
823# last unless ($patron_ok);
824# }
825# }
826# }
827 $block_stanza = qq(
828 <BlockOrTrap>
829 <UniqueAgencyId>
830 <Scheme datatype="string">http://just.testing.now</Scheme>
831 <Value datatype="string">$faidValue</Value>
832 </UniqueAgencyId>
833 <BlockOrTrapType>
834 <Scheme datatype="string">http://just.testing.now</Scheme>
835 <Value datatype="string">Block Hold</Value>
836 </BlockOrTrapType>
837 </BlockOrTrap>);
838 }
839
5809d230 840 if ( defined( $patron->email ) && $conf->{behavior}->{omit_patron_email} !~ m/^y/i ) {
5f517e0a
DW
841 $email = qq(
842 <UserAddressInformation>
843 <ElectronicAddress>
844 <ElectronicAddressType>
845 <Scheme datatype="string">http://testing.now</Scheme>
846 <Value datatype="string">mailto</Value>
847 </ElectronicAddressType>
848 <ElectronicAddressData datatype="string">)
849 . HTML::Entities::encode( $patron->email )
850 . qq(</ElectronicAddressData>
851 </ElectronicAddress>
852 </UserAddressInformation>);
853 }
854
855 $propername = $patron->first_given_name . " " . $patron->family_name;
856 $good_until = $patron->expire_date || "unknown";
33a39c82 857 $userpriv = $patron->profile->name;
5f517e0a
DW
858
859 #} else {
860 # do_lookup_user_error_stanza("PATRON_NOT_FOUND : $id");
861 # die;
862 #}
0b0c5299
DW
863 my $uniqid = $patron->id;
864 my $visid = $patron->card->barcode;
5f517e0a 865 my $hd = <<LOOKUPUSERRESPONSE;
4cdc4f67
JS
866Content-type: text/xml
867
868
869<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
870<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
871 <LookupUserResponse>
872 <ResponseHeader>
873 <FromAgencyId>
874 <UniqueAgencyId>
875 <Scheme>$taidScheme</Scheme>
876 <Value>$taidValue</Value>
877 </UniqueAgencyId>
878 </FromAgencyId>
879 <ToAgencyId>
880 <UniqueAgencyId>
881 <Scheme>$faidScheme</Scheme>
882 <Value>$faidValue</Value>
883 </UniqueAgencyId>
884 </ToAgencyId>
885 </ResponseHeader>
886 <UniqueUserId>
887 <UniqueAgencyId>
888 <Scheme>$taidScheme</Scheme>
889 <Value>$taidValue</Value>
890 </UniqueAgencyId>
0b0c5299 891 <UserIdentifierValue>$uniqid</UserIdentifierValue>
5f517e0a
DW
892 </UniqueUserId>
893 <UserOptionalFields>
894 <VisibleUserId>
895 <VisibleUserIdentifierType>
896 <Scheme datatype="string">http://blah.com</Scheme>
897 <Value datatype="string">Barcode</Value>
898 </VisibleUserIdentifierType>
0b0c5299 899 <VisibleUserIdentifier datatype="string">$visid</VisibleUserIdentifier>
5f517e0a
DW
900 </VisibleUserId>
901 <NameInformation>
902 <PersonalNameInformation>
903 <UnstructuredPersonalUserName datatype="string">$propername</UnstructuredPersonalUserName>
904 </PersonalNameInformation>
905 </NameInformation>
906 <UserPrivilege>
907 <UniqueAgencyId>
908 <Scheme datatype="string">$faidScheme</Scheme>
909 <Value datatype="string">$faidValue</Value>
910 </UniqueAgencyId>
911 <AgencyUserPrivilegeType>
912 <Scheme datatype="string">http://testing.purposes.only</Scheme>
3bcdd8ae 913 <Value datatype="string">$userpriv</Value>
5f517e0a
DW
914 </AgencyUserPrivilegeType>
915 <ValidToDate datatype="string">$good_until</ValidToDate>
916 </UserPrivilege> $email $block_stanza
917 </UserOptionalFields>
4cdc4f67
JS
918 </LookupUserResponse>
919</NCIPMessage>
920
921LOOKUPUSERRESPONSE
922
5f517e0a
DW
923 logit( $hd, ( caller(0) )[3] );
924 staff_log( $taidValue, $faidValue,
925 "LookupUser -> Patron Barcode : "
926 . $id
927 . " | Patron Id : "
928 . $uidValue
929 . " | User Name : "
930 . $propername
931 . " | User Priv : "
932 . $userpriv );
4cdc4f67
JS
933}
934
4cdc4f67 935sub fail {
5f517e0a
DW
936 my $error_msg =
937 shift || "THIS IS THE DEFAULT / DO NOT HANG III NCIP RESP MSG";
938 print "Content-type: text/xml\n\n";
4cdc4f67 939
5f517e0a 940 print <<ITEMREQ;
4cdc4f67
JS
941<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
942<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
943 <ItemRequestedResponse>
944 <ResponseHeader>
945 <FromAgencyId>
946 <UniqueAgencyId>
947 <Scheme>http://136.181.125.166:6601/IRCIRCD?target=get_scheme_values&amp;scheme=UniqueAgencyId</Scheme>
948 <Value></Value>
949 </UniqueAgencyId>
950 </FromAgencyId>
951 <ToAgencyId>
952 <UniqueAgencyId>
953 <Scheme>http://136.181.125.166:6601/IRCIRCD?target=get_scheme_values&amp;scheme=UniqueAgencyId</Scheme>
954 <Value>$error_msg</Value>
955 </UniqueAgencyId>
956 </ToAgencyId>
957 </ResponseHeader>
958 </ItemRequestedResponse>
4cdc4f67
JS
959</NCIPMessage>
960
961ITEMREQ
6e6bdfe9 962
601be0bb
JG
963 # XXX: we should log FromAgencyId and ToAgencyId values here, but they are not available to the code at this point
964 staff_log( '', '',
5f517e0a
DW
965 ( ( caller(0) )[3] . " -> " . $error_msg ) );
966 die;
4cdc4f67
JS
967}
968
969sub do_lookup_user_error_stanza {
970
601be0bb 971 # XXX: we should include FromAgencyId and ToAgencyId values, but they are not available to the code at this point
5f517e0a
DW
972 my $error = shift;
973 my $hd = <<LOOKUPPROB;
4cdc4f67
JS
974Content-type: text/xml
975
976
977<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
978<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
5f517e0a
DW
979 <LookupUserResponse>
980 <ResponseHeader>
981 <FromAgencyId>
982 <UniqueAgencyId>
601be0bb
JG
983 <Scheme></Scheme>
984 <Value></Value>
5f517e0a
DW
985 </UniqueAgencyId>
986 </FromAgencyId>
987 <ToAgencyId>
988 <UniqueAgencyId>
601be0bb
JG
989 <Scheme></Scheme>
990 <Value></Value>
5f517e0a
DW
991 </UniqueAgencyId>
992 </ToAgencyId>
993 </ResponseHeader>
994 <Problem>
995 <ProcessingError>
996 <ProcessingErrorType>
997 <Scheme>http://www.niso.org/ncip/v1_0/schemes/processingerrortype/lookupuserprocessingerror.scm</Scheme>
998 <Value>$error</Value>
999 </ProcessingErrorType>
1000 <ProcessingErrorElement>
1001 <ElementName>AuthenticationInput</ElementName>
1002 </ProcessingErrorElement>
1003 </ProcessingError>
1004 </Problem>
1005 </LookupUserResponse>
4cdc4f67
JS
1006</NCIPMessage>
1007
1008LOOKUPPROB
1009
5f517e0a 1010 logit( $hd, ( caller(0) )[3] );
601be0bb
JG
1011 # XXX: we should log FromAgencyId and ToAgencyId values here, but they are not available to the code at this point
1012 staff_log( '', '', ( ( caller(0) )[3] . " -> " . $error ) );
5f517e0a 1013 die;
4cdc4f67
JS
1014}
1015
1016# Login to the OpenSRF system/Evergreen.
1017#
1018# Returns a hash with the authtoken, authtime, and expiration (time in
1019# seconds since 1/1/1970).
1020sub login {
1ac548f2
JS
1021
1022 # XXX: local opensrf core conf filename should be in config.
1023 # XXX: STAFF account with ncip service related permissions should be in config.
5f517e0a 1024 my $bootstrap = '/openils/conf/opensrf_core.xml';
f5e8d07e
JG
1025 my $uname = $conf->{auth}->{username};
1026 my $password = $conf->{auth}->{password};
5f517e0a
DW
1027
1028 # Bootstrap the client
1029 OpenSRF::System->bootstrap_client( config_file => $bootstrap );
1030 my $idl = OpenSRF::Utils::SettingsClient->new->config_value("IDL");
1031 Fieldmapper->import( IDL => $idl );
1032
1033 # Initialize CStoreEditor:
1034 OpenILS::Utils::CStoreEditor->init;
1035
1036 my $seed = OpenSRF::AppSession->create('open-ils.auth')
1037 ->request( 'open-ils.auth.authenticate.init', $uname )->gather(1);
1038
1039 return undef unless $seed;
1040
1041 my $response = OpenSRF::AppSession->create('open-ils.auth')->request(
1042 'open-ils.auth.authenticate.complete',
1043 {
1044 username => $uname,
1045 password => md5_hex( $seed . md5_hex($password) ),
1046 type => 'staff'
1047 }
1048 )->gather(1);
1049
1050 return undef unless $response;
1051
1052 my %result;
1053 $result{'authtoken'} = $response->{payload}->{authtoken};
1054 $result{'authtime'} = $response->{payload}->{authtime};
1055 $result{'expiration'} = time() + $result{'authtime'}
1056 if ( defined( $result{'authtime'} ) );
1057 return %result;
4cdc4f67
JS
1058}
1059
1060# Check the time versus the session expiration time and login again if
1061# the session has expired, consequently resetting the session
1062# paramters. We want to run this before doing anything that requires
1063# us to have a current session in OpenSRF.
1064#
1065# Arguments
1066# none
1067#
1068# Returns
1069# Nothing
1070sub check_session_time {
5f517e0a
DW
1071 if ( time() > $session{'expiration'} ) {
1072 %session = login();
1073 if ( !%session ) {
1074 die("Failed to reinitialize the session after expiration.");
1075 }
1076 }
4cdc4f67
JS
1077}
1078
1079# Retrieve the logged in user.
1080#
1081sub get_session {
5f517e0a
DW
1082 my $response =
1083 OpenSRF::AppSession->create('open-ils.auth')
1084 ->request( 'open-ils.auth.session.retrieve', $session{authtoken} )
1085 ->gather(1);
1086 return $response;
4cdc4f67
JS
1087}
1088
1089# Logout/destroy the OpenSRF session
1090#
1091# Argument is
1092# none
1093#
1094# Returns
1095# Does not return anything
1096sub logout {
5f517e0a
DW
1097 if ( time() < $session{'expiration'} ) {
1098 my $response =
1099 OpenSRF::AppSession->create('open-ils.auth')
1100 ->request( 'open-ils.auth.session.delete', $session{authtoken} )
1101 ->gather(1);
1102 if ($response) {
1103
1104 # strong.silent.success
1105 exit(0);
1106 } else {
1107 fail("Logout unsuccessful. Good-bye, anyway.");
1108 }
1109 }
4cdc4f67
JS
1110}
1111
1112sub update_copy {
5f517e0a
DW
1113 check_session_time();
1114 my ( $copy, $status_id ) = @_;
1115 my $e = new_editor( authtoken => $session{authtoken} );
1116 return $e->event->{textcode} unless ( $e->checkauth );
1117 $e->xact_begin;
1118 $copy->status($status_id);
1119 return $e->event unless $e->update_asset_copy($copy);
1120 $e->commit;
1121 return 'SUCCESS';
4cdc4f67
JS
1122}
1123
1124# my paranoia re barcode on shipped items using visid for unique value
1125sub update_copy_shipped {
5f517e0a
DW
1126 check_session_time();
1127 my ( $copy, $status_id, $barcode ) = @_;
1128 my $e = new_editor( authtoken => $session{authtoken} );
1129 return $e->event->{textcode} unless ( $e->checkauth );
1130 $e->xact_begin;
1131 $copy->status($status_id);
1132 $copy->barcode($barcode);
1133 return $e->event unless $e->update_asset_copy($copy);
1134 $e->commit;
1135 return 'SUCCESS';
4cdc4f67
JS
1136}
1137
1138# Delete a copy
1139#
1140# Argument
1141# Fieldmapper asset.copy object
1142#
1143# Returns
1144# "SUCCESS" on success
1145# Event textcode if an error occurs
1146sub delete_copy {
5f517e0a
DW
1147 check_session_time();
1148 my ($copy) = @_;
1149
1150 my $e = new_editor( authtoken => $session{authtoken} );
1151 return $e->event->{textcode} unless ( $e->checkauth );
1152
1153 # Get the calnumber
1154 my $vol = $e->retrieve_asset_call_number( $copy->call_number );
1155 return $e->event->{textcode} unless ($vol);
1156
1157 # Get the biblio.record_entry
1158 my $bre = $e->retrieve_biblio_record_entry( $vol->record );
1159 return $e->event->{textcode} unless ($bre);
1160
1161 # Delete everything in a transaction and rollback if anything fails.
0b0c5299 1162 # TODO: I think there is a utility function which handles all this
5f517e0a
DW
1163 $e->xact_begin;
1164 my $r; # To hold results of editor calls
1165 $r = $e->delete_asset_copy($copy);
1166 unless ($r) {
1167 my $lval = $e->event->{textcode};
1168 $e->rollback;
1169 return $lval;
1170 }
1171 my $list =
1172 $e->search_asset_copy( { call_number => $vol->id, deleted => 'f' } );
1173 unless (@$list) {
1174 $r = $e->delete_asset_call_number($vol);
1175 unless ($r) {
1176 my $lval = $e->event->{textcode};
1177 $e->rollback;
1178 return $lval;
1179 }
0b0c5299 1180 $list = $e->search_asset_call_number( { record => $bre->id, deleted => 'f' } );
5f517e0a 1181 unless (@$list) {
0b0c5299 1182 $r = $e->delete_biblio_record_entry($bre);
5f517e0a
DW
1183 unless ($r) {
1184 my $lval = $e->event->{textcode};
1185 $e->rollback;
1186 return $lval;
1187 }
1188 }
1189 }
1190 $e->commit;
1191 return 'SUCCESS';
4cdc4f67
JS
1192}
1193
1194# Get asset.copy from asset.copy.barcode.
1195# Arguments
1196# copy barcode
1197#
1198# Returns
1199# asset.copy fieldmaper object
1200# or hash on error
1201sub copy_from_barcode {
5f517e0a
DW
1202 check_session_time();
1203 my ($barcode) = @_;
1204 my $response =
1205 OpenSRF::AppSession->create('open-ils.search')
1206 ->request( 'open-ils.search.asset.copy.find_by_barcode', $barcode )
1207 ->gather(1);
1208 return $response;
4cdc4f67
JS
1209}
1210
1211sub locid_from_barcode {
5f517e0a
DW
1212 my ($barcode) = @_;
1213 my $response =
1214 OpenSRF::AppSession->create('open-ils.search')
1215 ->request( 'open-ils.search.biblio.find_by_barcode', $barcode )
1216 ->gather(1);
1217 return $response->{ids}[0];
4cdc4f67
JS
1218}
1219
1220# Convert a MARC::Record to XML for Evergreen
1221#
6e6bdfe9 1222# Copied from Dyrcona's issa framework which copied
1ac548f2 1223# it from MVLC's Safari Load program which copied it
4cdc4f67
JS
1224# from some code in the Open-ILS example import scripts.
1225#
1226# Argument
1227# A MARC::Record object
1228#
1229# Returns
1230# String with XML for the MARC::Record as Evergreen likes it
1231sub convert2marcxml {
5f517e0a
DW
1232 my $input = shift;
1233 ( my $xml = $input->as_xml_record() ) =~ s/\n//sog;
1234 $xml =~ s/^<\?xml.+\?\s*>//go;
1235 $xml =~ s/>\s+</></go;
1236 $xml =~ s/\p{Cc}//go;
0b0c5299 1237 $xml = $U->entityize($xml);
5f517e0a
DW
1238 $xml =~ s/[\x00-\x1f]//go;
1239 return $xml;
4cdc4f67
JS
1240}
1241
1242# Create a copy and marc record
1243#
1244# Arguments
1245# title
1246# call number
1247# copy barcode
1248#
1249# Returns
1250# bib id on succes
1251# event textcode on failure
1252sub create_copy {
5f517e0a
DW
1253 check_session_time();
1254 my ( $title, $callnumber, $barcode, $copy_status_id, $medium_type ) = @_;
4cdc4f67 1255
5f517e0a
DW
1256 my $e = new_editor( authtoken => $session{authtoken} );
1257 return $e->event->{textcode} unless ( $e->checkauth );
1ac548f2 1258
5f517e0a
DW
1259 my $r = $e->allowed( [ 'CREATE_COPY', 'CREATE_MARC', 'CREATE_VOLUME' ] );
1260 if ( ref($r) eq 'HASH' ) {
1261 return $r->{textcode} . ' ' . $r->{ilsperm};
1262 }
4cdc4f67 1263
5f517e0a
DW
1264 # Check if the barcode exists in asset.copy and bail if it does.
1265 my $list = $e->search_asset_copy( { deleted => 'f', barcode => $barcode } );
1266 if (@$list) {
6e6bdfe9 1267# in the future, can we update it, if it exists and only if it is an INN-Reach status item ?
5f517e0a
DW
1268 $e->finish;
1269 fail( 'BARCODE_EXISTS ! Barcode : ' . $barcode );
1270 die;
1271 }
1272
1273 # Create MARC record
1274 my $record = MARC::Record->new();
1275 $record->encoding('UTF-8');
1276 $record->leader('00881nam a2200193 4500');
1277 my $datespec = strftime( "%Y%m%d%H%M%S.0", localtime );
1278 my @fields = ();
1279 push( @fields, MARC::Field->new( '005', $datespec ) );
1280 push( @fields, MARC::Field->new( '082', '0', '4', 'a' => $callnumber ) );
1281 push( @fields, MARC::Field->new( '245', '0', '0', 'a' => $title ) );
1282 $record->append_fields(@fields);
1283
1284 # Convert the record to XML
1285 my $xml = convert2marcxml($record);
1286
1287 my $bre =
1288 OpenSRF::AppSession->create('open-ils.cat')
1289 ->request( 'open-ils.cat.biblio.record.xml.import',
1290 $session{authtoken}, $xml, 'System Local', 1 )->gather(1);
1291 return $bre->{textcode} if ( ref($bre) eq 'HASH' );
1292
1293 # Create volume record
1294 my $vol =
1295 OpenSRF::AppSession->create('open-ils.cat')
ba01d5da 1296 ->request( 'open-ils.cat.call_number.find_or_create', $session{authtoken}, $callnumber, $bre->id, $conf->{volume}->{owning_lib} )
0b0c5299 1297 ->gather(1);
5f517e0a
DW
1298 return $vol->{textcode} if ( $vol->{textcode} );
1299
1300 # Retrieve the user
1301 my $user = get_session;
1302
1303 # Create copy record
1304 my $copy = Fieldmapper::asset::copy->new();
0b0c5299
DW
1305 # XXX CUSTOMIZATION NEEDED XXX
1306 # You will need to either create a circ mod for every expected medium type,
1307 # OR you should create a single circ mod for all requests from the external
1308 # system.
1309 # Adjust these lines as needed.
1310 # $copy->circ_modifier(qq($medium_type)); # XXX CUSTOMIZATION NEEDED XXX
1311 # OR
ba01d5da 1312 $copy->circ_modifier($conf->{copy}->{circ_modifier});
5f517e0a
DW
1313 $copy->barcode($barcode);
1314 $copy->call_number( $vol->{acn_id} );
ba01d5da 1315 $copy->circ_lib($conf->{copy}->{circ_lib});
5f517e0a
DW
1316 $copy->circulate('t');
1317 $copy->holdable('t');
1318 $copy->opac_visible('t');
1319 $copy->deleted('f');
1320 $copy->fine_level(2);
1321 $copy->loan_duration(2);
ba01d5da 1322 $copy->location($conf->{copy}->{location});
5f517e0a
DW
1323 $copy->status($copy_status_id);
1324 $copy->editor('1');
1325 $copy->creator('1');
1326
1327 # Add the configured stat cat entries.
1328 #my @stat_cats;
1329 #my $nodes = $xpath->find("/copy/stat_cat_entry");
1330 #foreach my $node ($nodes->get_nodelist) {
1331 # next unless ($node->isa('XML::XPath::Node::Element'));
1332 # my $stat_cat_id = $node->getAttribute('stat_cat');
1333 # my $value = $node->string_value();
1334 # # Need to search for an existing asset.stat_cat_entry
0b0c5299 1335 # my $asce = $e->search_asset_stat_cat_entry({'stat_cat' => $stat_cat_id, 'value' => $value})->[0];
5f517e0a
DW
1336 # unless ($asce) {
1337 # # if not, create a new one and use its id.
1338 # $asce = Fieldmapper::asset::stat_cat_entry->new();
1339 # $asce->stat_cat($stat_cat_id);
1340 # $asce->value($value);
1341 # $asce->owner($ou->id);
1342 # $e->xact_begin;
1343 # $asce = $e->create_asset_stat_cat_entry($asce);
1344 # $e->xact_commit;
1345 # }
1346 # push(@stat_cats, $asce);
1347 #}
1348
1349 $e->xact_begin;
1350 $copy = $e->create_asset_copy($copy);
1351
1352 #if (scalar @stat_cats) {
1353 # foreach my $asce (@stat_cats) {
1354 # my $ascecm = Fieldmapper::asset::stat_cat_entry_copy_map->new();
1355 # $ascecm->stat_cat($asce->stat_cat);
1356 # $ascecm->stat_cat_entry($asce->id);
1357 # $ascecm->owning_copy($copy->id);
1358 # $ascecm = $e->create_asset_stat_cat_entry_copy_map($ascecm);
1359 # }
1360 #}
1361 $e->commit;
1362 return $e->event->{textcode} unless ($r);
1363 return 'SUCCESS';
4cdc4f67
JS
1364}
1365
1366# Checkout a copy to a patron
1367#
1368# Arguments
1369# copy barcode
1370# patron barcode
1371#
1372# Returns
1373# textcode of the OSRF response.
1ac548f2 1374sub checkout {
5f517e0a
DW
1375 check_session_time();
1376 my ( $copy_barcode, $patron_barcode, $due_date ) = @_;
1377
1378 # Check for copy:
1379 my $copy = copy_from_barcode($copy_barcode);
1380 unless ( defined($copy) && blessed($copy) ) {
1381 return 'COPY_BARCODE_NOT_FOUND : ' . $copy_barcode;
1382 }
1383
1384 # Check for user
1385 my $uid = user_id_from_barcode($patron_barcode);
1386 return 'PATRON_BARCODE_NOT_FOUND : ' . $patron_barcode if ( ref($uid) );
1387
1388 my $response = OpenSRF::AppSession->create('open-ils.circ')->request(
1389 'open-ils.circ.checkout.full.override',
1390 $session{authtoken},
1391 {
1392 copy_barcode => $copy_barcode,
1393 patron_id => $uid,
1394 due_date => $due_date
1395 }
1396 )->gather(1);
1397 return $response->{textcode};
4cdc4f67
JS
1398}
1399
1ac548f2 1400sub renewal {
5f517e0a
DW
1401 check_session_time();
1402 my ( $copy_barcode, $due_date ) = @_;
1403
1404 # Check for copy:
1405 my $copy = copy_from_barcode($copy_barcode);
1406 unless ( defined($copy) && blessed($copy) ) {
1407 return 'COPY_BARCODE_NOT_FOUND : ' . $copy_barcode;
1408 }
1409
1410 my $response = OpenSRF::AppSession->create('open-ils.circ')->request(
1411 'open-ils.circ.renew.override',
1412 $session{authtoken},
1413 {
1414 copy_barcode => $copy_barcode,
1415 due_date => $due_date
1416 }
1417 )->gather(1);
1418 return $response->{textcode};
4cdc4f67
JS
1419}
1420
1ac548f2 1421# Check a copy in
4cdc4f67
JS
1422#
1423# Arguments
1424# copy barcode
4cdc4f67
JS
1425#
1426# Returns
1427# "SUCCESS" on success
1428# textcode of a failed OSRF request
0b0c5299 1429# 'COPY_NOT_CHECKED_OUT' when the copy is not checked out
6e6bdfe9 1430
1ac548f2 1431sub checkin {
5f517e0a
DW
1432 check_session_time();
1433 my ($barcode) = @_;
1434
1435 my $copy = copy_from_barcode($barcode);
1436 return $copy->{textcode} unless ( blessed $copy);
1437
1438 return ("COPY_NOT_CHECKED_OUT $barcode")
1439 unless ( $copy->status == OILS_COPY_STATUS_CHECKED_OUT );
1440
1441 my $e = new_editor( authtoken => $session{authtoken} );
1442 return $e->event->{textcode} unless ( $e->checkauth );
1443
1444 my $circ = $e->search_action_circulation(
1445 [ { target_copy => $copy->id, xact_finish => undef } ] )->[0];
1446 my $r =
1447 OpenSRF::AppSession->create('open-ils.circ')
1448 ->request( 'open-ils.circ.checkin.override',
1449 $session{authtoken}, { force => 1, copy_id => $copy->id } )->gather(1);
1450 return 'SUCCESS' if ( $r->{textcode} eq 'ROUTE_ITEM' );
1451 return $r->{textcode};
4cdc4f67
JS
1452}
1453
1454# Get actor.usr.id from barcode.
1455# Arguments
1456# patron barcode
1457#
1458# Returns
1459# actor.usr.id
1460# or hash on error
1461sub user_id_from_barcode {
5f517e0a
DW
1462 check_session_time();
1463 my ($barcode) = @_;
4cdc4f67 1464
5f517e0a 1465 my $response;
4cdc4f67 1466
5f517e0a
DW
1467 my $e = new_editor( authtoken => $session{authtoken} );
1468 return $response unless ( $e->checkauth );
4cdc4f67 1469
5f517e0a
DW
1470 my $card = $e->search_actor_card( { barcode => $barcode, active => 't' } );
1471 return $e->event unless ($card);
4cdc4f67 1472
5f517e0a 1473 $response = $card->[0]->usr if (@$card);
4cdc4f67 1474
5f517e0a 1475 $e->finish;
4cdc4f67 1476
5f517e0a 1477 return $response;
4cdc4f67
JS
1478}
1479
6e6bdfe9 1480# Place a simple hold for a patron.
4cdc4f67
JS
1481#
1482# Arguments
1483# Target object appropriate for type of hold
1484# Patron for whom the hold is place
1485#
1486# Returns
1487# "SUCCESS" on success
1488# textcode of a failed OSRF request
1489# "HOLD_TYPE_NOT_SUPPORTED" if the hold type is not supported
1490# (Currently only support 'T' and 'C')
1491
1ac548f2 1492# simple hold should be removed and full holds sub should be used instead - pragmatic solution only
5082b884 1493
4cdc4f67 1494sub place_simple_hold {
5f517e0a 1495 check_session_time();
1ac548f2 1496
5f517e0a 1497 #my ($type, $target, $patron, $pickup_ou) = @_;
7e2d6432 1498 my ( $target, $patron_id ) = @_;
1ac548f2 1499
ba01d5da 1500 require $conf->{path}->{oils_header};
5f517e0a 1501 use vars qw/ $apputils $memcache $user $authtoken $authtime /;
1ac548f2 1502
ba01d5da 1503 osrf_connect( $conf->{path}->{opensrf_core} );
f5e8d07e 1504 oils_login( $conf->{auth}->{username}, $conf->{auth}->{password} );
7e2d6432
DW
1505 my $ahr = Fieldmapper::action::hold_request->new();
1506 $ahr->hold_type('C');
1507 # The targeter doesn't like our special statuses, and changing the status after the targeter finishes is difficult because it runs asynchronously. Our workaround is to create the hold frozen, unfreeze it, then run the targeter manually.
1508 $ahr->target($target);
1509 $ahr->usr($patron_id);
ba01d5da
JG
1510 $ahr->requestor($conf->{hold}->{requestor});
1511 # NOTE: When User Agency, we don't know the pickup location until ItemShipped time
1512 # TODO: When Item Agency and using holds, set this to requested copy's circ lib?
1513 $ahr->pickup_lib($conf->{hold}->{init_pickup_lib});
1514 $ahr->phone_notify(''); # TODO: set this based on usr prefs
1515 $ahr->email_notify(1); # TODO: set this based on usr prefs
7e2d6432
DW
1516 $ahr->frozen('t');
1517 my $resp = simplereq( CIRC(), 'open-ils.circ.holds.create', $authtoken, $ahr );
1518 my $e = new_editor( xact => 1, authtoken => $session{authtoken} );
1519 $ahr = $e->retrieve_action_hold_request($resp); # refresh from db
1520 $ahr->frozen('f');
1521 $e->update_action_hold_request($ahr);
1522 $e->commit;
1523 $U->storagereq( 'open-ils.storage.action.hold_request.copy_targeter', undef, $ahr->id );
5f517e0a
DW
1524
1525 #oils_event_die($resp);
1526 my $errors = "";
1527 if ( ref($resp) eq 'ARRAY' ) {
1528 ( $errors .= "error : " . $_->{textcode} ) for @$resp;
1529 return $errors;
1530 } elsif ( ref($resp) ne 'HASH' ) {
1531 return "Hold placed! hold_id = " . $resp . "\n";
1532 }
4cdc4f67
JS
1533}
1534
1535# Place a hold for a patron.
1536#
1537# Arguments
1538# Type of hold
1539# Target object appropriate for type of hold
1540# Patron for whom the hold is place
1541# OU where hold is to be picked up
1542#
1543# Returns
1544# "SUCCESS" on success
1545# textcode of a failed OSRF request
1546# "HOLD_TYPE_NOT_SUPPORTED" if the hold type is not supported
1547# (Currently only support 'T' and 'C')
877ae895
DW
1548# XXX NOT USED OR WORKING, COMMENTING OUT FOR NOW
1549#sub place_hold {
1550# check_session_time();
1551# my ( $type, $target, $patron, $pickup_ou ) = @_;
1552#
1553# my $ou = org_unit_from_shortname($work_ou); # $work_ou is global
1554# my $ahr = Fieldmapper::action::hold_request->new;
1555# $ahr->hold_type($type);
1556# if ( $type eq 'C' ) {
1557#
1558# # Check if we own the copy.
1559# if ( $ou->id == $target->circ_lib ) {
1560#
1561# # We own it, so let's place a copy hold.
1562# $ahr->target( $target->id );
1563# $ahr->current_copy( $target->id );
1564# } else {
1565#
1566# # We don't own it, so let's place a title hold instead.
1567# my $bib = bre_from_barcode( $target->barcode );
1568# $ahr->target( $bib->id );
1569# $ahr->hold_type('T');
1570# }
1571# } elsif ( $type eq 'T' ) {
1572# $ahr->target($target);
1573# } else {
1574# return "HOLD_TYPE_NOT_SUPPORTED";
1575# }
1576# $ahr->usr( user_id_from_barcode($id) );
1577#
1578# #$ahr->pickup_lib($pickup_ou->id);
1579# $ahr->pickup_lib('3');
1580# if ( !$patron->email ) {
1581# $ahr->email_notify('f');
1582# $ahr->phone_notify( $patron->day_phone ) if ( $patron->day_phone );
1583# } else {
1584# $ahr->email_notify('t');
1585# }
1586#
1587# # We must have a title hold and we want to change the hold
1588# # expiration date if we're sending the copy to the VC.
1589# set_title_hold_expiration($ahr) if ( $ahr->pickup_lib == $ou->id );
1590#
1591# my $params = {
1592# pickup_lib => $ahr->pickup_lib,
1593# patronid => $ahr->usr,
1594# hold_type => $ahr->hold_type
1595# };
1596#
1597# if ( $ahr->hold_type eq 'C' ) {
1598# $params->{copy_id} = $ahr->target;
1599# } else {
1600# $params->{titleid} = $ahr->target;
1601# }
1602#
1603# my $r =
1604# OpenSRF::AppSession->create('open-ils.circ')
1605# ->request( 'open-ils.circ.title_hold.is_possible',
1606# $session{authtoken}, $params )->gather(1);
1607#
1608# if ( $r->{textcode} ) {
1609# return $r->{textcode};
1610# } elsif ( $r->{success} ) {
1611# $r =
1612# OpenSRF::AppSession->create('open-ils.circ')
1613# ->request( 'open-ils.circ.holds.create.override',
1614# $session{authtoken}, $ahr )->gather(1);
1615#
1616# my $returnValue = "SUCCESS";
1617# if ( ref($r) eq 'HASH' ) {
1618# $returnValue =
1619# ( $r->{textcode} eq 'PERM_FAILURE' )
1620# ? $r->{ilsperm}
1621# : $r->{textcode};
1622# $returnValue =~ s/\.override$//
1623# if ( $r->{textcode} eq 'PERM_FAILURE' );
1624# }
1625# return $returnValue;
1626# } else {
1627# return 'HOLD_NOT_POSSIBLE';
1628# }
1629#}
4cdc4f67
JS
1630
1631# Set the expiration date on title holds
1632#
1633# Argument
1634# Fieldmapper action.hold_request object
1635#
1636# Returns
1637# Nothing
877ae895
DW
1638# XXX NOT USED OR WORKING, COMMENTING OUT FOR NOW
1639#sub set_title_hold_expiration {
1640# my $hold = shift;
1641# if ( $title_holds->{unit} && $title_holds->{duration} ) {
1642# my $expiration = DateTime->now( time_zone => $tz );
1643# $expiration->add( $title_holds->{unit} => $title_holds->{duration} );
1644# $hold->expire_time( $expiration->iso8601() );
1645# }
1646#}
4cdc4f67
JS
1647
1648# Get actor.org_unit from the shortname
1649#
1650# Arguments
1651# org_unit shortname
1652#
1653# Returns
1654# Fieldmapper aou object
1655# or HASH on error
1656sub org_unit_from_shortname {
5f517e0a
DW
1657 check_session_time();
1658 my ($shortname) = @_;
1659 my $ou =
1660 OpenSRF::AppSession->create('open-ils.actor')
1661 ->request( 'open-ils.actor.org_unit.retrieve_by_shortname', $shortname )
1662 ->gather(1);
1663 return $ou;
4cdc4f67
JS
1664}
1665
1666# Flesh user information
1667# Arguments
1668# actor.usr.id
1669#
1670# Returns
1671# fieldmapped, fleshed user or
1672# event hash on error
1673sub flesh_user {
5f517e0a
DW
1674 check_session_time();
1675 my ($id) = @_;
1676 my $response =
1677 OpenSRF::AppSession->create('open-ils.actor')
1678 ->request( 'open-ils.actor.user.fleshed.retrieve',
1679 $session{'authtoken'}, $id,
1680 [ 'card', 'cards', 'standing_penalties', 'home_ou', 'profile' ] )
1681 ->gather(1);
1682 return $response;
4cdc4f67 1683}