]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/lib/OpenILS/SIP.pm
Exports are broken
[working/Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / SIP.pm
1 #
2 # ILS.pm: Test ILS interface module
3 #
4
5 package OpenILS::SIP;
6 use warnings; use strict;
7
8 use Sys::Syslog qw(syslog);
9 use Time::HiRes q/time/;
10
11 use OpenILS::SIP::Item;
12 use OpenILS::SIP::Patron;
13 use OpenILS::SIP::Transaction;
14 use OpenILS::SIP::Transaction::Checkout;
15 use OpenILS::SIP::Transaction::Checkin;
16 use OpenILS::SIP::Transaction::Renew;
17 use OpenILS::SIP::Transaction::FeePayment;
18
19 use OpenSRF::System;
20 use OpenSRF::AppSession;
21 use OpenILS::Utils::Fieldmapper;
22 use OpenSRF::Utils::SettingsClient;
23 use OpenILS::Application::AppUtils;
24 use OpenSRF::Utils qw/:datetime/;
25 use DateTime::Format::ISO8601;
26 use Encode;
27 use Unicode::Normalize;
28
29 my $U = 'OpenILS::Application::AppUtils';
30
31 my $editor;
32 my $config;
33 my $login_account;
34 my $target_encoding;    # FIXME: this is configured at the institution level. 
35
36 use Digest::MD5 qw(md5_hex);
37
38 # Copied from Sip::Constants
39 use constant {
40     SIP_DATETIME => "%Y%m%d    %H%M%S",
41 };
42
43 sub new {
44     my ($class, $institution, $login) = @_;
45     my $type = ref($class) || $class;
46     my $self = {};
47
48     $self->{login} = $login_account = $login;
49
50     $config = $institution;
51     syslog("LOG_DEBUG", "OILS: new ILS '%s'", $institution->{id});
52     $self->{institution} = $institution;
53
54     my $bsconfig     = $institution->{implementation_config}->{bootstrap};
55     $target_encoding = $institution->{implementation_config}->{encoding} || 'ascii';
56
57     syslog('LOG_DEBUG', "OILS: loading bootstrap config: $bsconfig");
58
59     # ingress will persist throughout
60     OpenSRF::AppSession->ingress('sip2');
61     
62     local $/ = "\n";    # why?
63     OpenSRF::System->bootstrap_client(config_file => $bsconfig);
64     syslog('LOG_DEBUG', "OILS: bootstrap loaded..");
65
66     $self->{osrf_config} = OpenSRF::Utils::SettingsClient->new;
67
68     Fieldmapper->import($self->{osrf_config}->config_value('IDL'));
69
70     bless( $self, $type );
71
72     return undef unless 
73         $self->login( $login->{id}, $login->{password} );
74
75     return $self;
76 }
77
78 sub fetch_session {
79     my $self = shift;
80
81     my $ses = $U->simplereq( 
82         'open-ils.auth',
83         'open-ils.auth.session.retrieve',  $self->{authtoken});
84
85     return undef if $U->event_code($ses); # auth timed out
86     return $self->{login_session} = $ses;
87 }
88
89 sub verify_session {
90     my $self = shift;
91
92     return 1 if $self->fetch_session;
93
94     syslog('LOG_INFO', "OILS: Logging back after session timeout as user ".$self->{login}->{id});
95     return $self->login( $self->{login}->{id}, $self->{login}->{password} );
96 }
97
98 sub editor {
99     return $editor = make_editor();
100 }
101
102 sub config {
103     return $config;
104 }
105 sub login_account {
106     return $login_account;
107 }
108
109 sub get_option_value {
110     my($self, $option) = @_;
111     my $ops = $config->{implementation_config}->{options}->{option};
112     $ops = [$ops] unless ref $ops eq 'ARRAY';
113     my @vals = grep { $_->{name} eq $option } @$ops;
114     return @vals ? $vals[0]->{value} : undef;
115 }
116
117
118 # Creates the global editor object
119 my $cstore_init = 1; # call init on first use
120 sub make_editor {
121     OpenILS::Utils::CStoreEditor::init() if $cstore_init;
122     $cstore_init = 0;
123     return OpenILS::Utils::CStoreEditor->new;
124 }
125
126 =head2 clean_text(scalar)
127
128 Evergreen uses the UTF8 encoding for everything from the database up. Perl
129 doesn't know this, however, so we have to convince it to treat our UTF8 strings
130 as UTF8 strings. This may enable OpenNCIP to correctly calculate the checksums
131 for UTF8 text for SIP clients that support such modern options.
132
133 The target encoding is set in the <encoding> element of the SIPServer.pm
134 configuration file.
135
136 =cut
137
138 sub clean_text {
139     my $text = shift || '';
140
141     # Convert our incoming UTF8 data into Perl's internal string format
142
143     # Also convert to Normalization Form D, as the ASCII, iso-8859-1,
144     # and latin-1 encodings (at least) require this to substitute
145     # characters rather than simply returning a string truncated
146     # after the first non-ASCII character
147     $text = NFD(decode_utf8($text));
148
149     if ($target_encoding eq 'ascii') {
150
151         # Try to maintain a reasonable version of the content by
152         # stripping diacritics from the text, given that the SIP client
153         # wants just plain ASCII. This is the base requirement according
154         # to the SIP2 specification.
155
156         # Stripping the combining characters converts ""béè♁ts"
157         # into "bee?ts" instead of "b???ts" - better, eh?
158         $text =~ s/\pM+//og;
159     }
160
161     # Characters that cannot be represented in the target encoding will
162     # generally be replaced with a question mark (?) character.
163     $text = encode($target_encoding, $text);
164
165     return $text;
166 }
167
168 my %org_sn_cache;
169 sub shortname_from_id {
170     my $id = shift or return;
171     return $id->shortname if ref $id;
172     return $org_sn_cache{$id} if $org_sn_cache{$id};
173     return $org_sn_cache{$id} = editor()->retrieve_actor_org_unit($id)->shortname;
174 }
175 sub patron_barcode_from_id {
176     my $id = shift or return;
177     return editor()->search_actor_card({ usr => $id, active => 't' })->[0]->barcode;
178 }
179
180 sub format_date {
181     my $class = shift;
182     my $date = shift;
183     my $type = shift || 'dob';
184
185     return "" unless $date;
186
187     my $dt = DateTime::Format::ISO8601->new->
188         parse_datetime(OpenSRF::Utils::cleanse_ISO8601($date));
189     my @time = localtime($dt->epoch);
190
191     my $year   = $time[5]+1900;
192     my $mon    = $time[4]+1;
193     my $day    = $time[3];
194     my $hour   = $time[2];
195     my $minute = $time[1];
196     my $second = $time[0];
197   
198     $date = sprintf("%04d%02d%02d", $year, $mon, $day);
199
200     # Due dates need hyphen separators and time of day as well
201     if ($type eq 'due') {
202
203         my $use_sdf = $class->get_option_value('use_sip_date_format') | '';
204
205         if ($use_sdf =~ /true/i) {
206             $date = $dt->strftime(SIP_DATETIME);
207
208         } else {
209             $date = sprintf("%04d-%02d-%02d %02d:%02d:%02d", 
210                 $year, $mon, $day, $hour, $minute, $second);
211         }
212     }
213
214     syslog('LOG_DEBUG', "OILS: formatted date [type=$type]: $date");
215     return $date;
216 }
217
218
219
220 sub login {
221     my( $self, $username, $password ) = @_;
222     syslog('LOG_DEBUG', "OILS: Logging in with username $username");
223
224     my $seed = $U->simplereq( 
225         'open-ils.auth',
226         'open-ils.auth.authenticate.init', $username );
227
228     my $response = $U->simplereq(
229         'open-ils.auth', 
230         'open-ils.auth.authenticate.complete', 
231         {    
232             username => $username, 
233             password => md5_hex($seed . md5_hex($password)), 
234             type     => 'opac',
235         }
236     );
237
238     if( my $code = $U->event_code($response) ) {
239         my $txt = $response->{textcode};
240         syslog('LOG_WARNING', "OILS: Login failed for $username.  $txt:$code");
241         return undef;
242     }
243
244     my $key = $response->{payload}->{authtoken};
245     syslog('LOG_INFO', "OILS: Login succeeded for $username : authkey = $key");
246
247     $self->{authtoken} = $key;
248
249     $self->fetch_session; # to cache the login
250
251     return $key;
252 }
253
254 #
255 # find_patron($barcode);
256 # find_patron(barcode => $barcode);   # same as above
257 # find_patron(usr => $id);
258
259 sub find_patron {
260     my $self = shift;
261     my $key  =  (@_ > 1) ? shift : 'barcode';  # if we have multiple args, the first is the key index (default barcode)
262     my $patron_id = shift;
263
264     return OpenILS::SIP::Patron->new($key => $patron_id, authtoken => $self->{authtoken}, @_);
265 }
266
267
268 sub find_item {
269     my $self = shift;
270     return OpenILS::SIP::Item->new(@_);
271 }
272
273
274 sub institution {
275     my $self = shift;
276     return $self->{institution}->{id};  # consider making this return the whole institution
277 }
278
279 sub institution_id {
280     my $self = shift;
281     return $self->{institution}->{id};  # then use this for just the ID
282 }
283
284 sub supports {
285     my ($self, $op) = @_;
286     my ($i) = grep { $_->{name} eq $op }  
287         @{$config->{implementation_config}->{supports}->{item}};
288     return to_bool($i->{value});
289 }
290
291 sub check_inst_id {
292     my ($self, $id, $whence) = @_;
293     if ($id ne $self->{institution}->{id}) {
294         syslog("LOG_WARNING", "OILS: %s: received institution '%s', expected '%s'", $whence, $id, $self->{institution}->{id});
295         # Just an FYI check, we don't expect the user to change location from that in SIPconfig.xml
296     }
297 }
298
299
300 sub to_bool {
301     my $bool = shift;
302     # If it's defined, and matches a true sort of string, or is
303     # a non-zero number, then it's true.
304     defined($bool) or return;                   # false
305     ($bool =~ /true|y|yes/i) and return 1;      # true
306     return ($bool =~ /^\d+$/ and $bool != 0);   # true for non-zero numbers, false otherwise
307 }
308
309 sub checkout_ok {
310     return to_bool($config->{policy}->{checkout});
311 }
312
313 sub checkin_ok {
314     return to_bool($config->{policy}->{checkin});
315 }
316
317 sub renew_ok {
318     return to_bool($config->{policy}->{renewal});
319 }
320
321 sub status_update_ok {
322     return to_bool($config->{policy}->{status_update});
323 }
324
325 sub offline_ok {
326     return to_bool($config->{policy}->{offline});
327 }
328
329
330
331 ##
332 ## Checkout(patron_id, item_id, sc_renew, fee_ack):
333 ##    patron_id & item_id are the identifiers send by the terminal
334 ##    sc_renew is the renewal policy configured on the terminal
335 ## returns a status opject that can be queried for the various bits
336 ## of information that the protocol (SIP or NCIP) needs to generate
337 ## the response.
338 ##    fee_ack is the fee_acknowledged field (BO) sent from the sc
339 ## when doing chargeable loans.
340 ##
341
342 sub checkout {
343     my ($self, $patron_id, $item_id, $sc_renew, $fee_ack) = @_;
344     # In order to allow renewals the selfcheck AND the config have to say they are allowed
345     $sc_renew = (chr($sc_renew) eq 'Y' && $self->renew_ok());
346
347     $self->verify_session;
348
349     syslog('LOG_DEBUG', "OILS: OpenILS::Checkout attempt: patron=$patron_id, item=$item_id");
350
351     my $xact   = OpenILS::SIP::Transaction::Checkout->new( authtoken => $self->{authtoken} );
352     my $patron = $self->find_patron($patron_id);
353     my $item   = $self->find_item($item_id);
354
355     $xact->patron($patron);
356     $xact->item($item);
357
358     if (!$patron) {
359         $xact->screen_msg("Invalid Patron Barcode '$patron_id'");
360         return $xact;
361     }
362
363     if (!$patron->charge_ok) {
364         $xact->screen_msg("Patron Blocked");
365         return $xact;
366     }
367
368     if( !$item ) {
369         $xact->screen_msg("Invalid Item Barcode: '$item_id'");
370         return $xact;
371     }
372
373     syslog('LOG_DEBUG', "OILS: OpenILS::Checkout data loaded OK, checking out...");
374
375     if ($item->{patron} && ($item->{patron} eq $patron_id)) {
376         $xact->renew_ok(1); # So that accept/reject responses have the correct value later
377         if($sc_renew) {
378             syslog('LOG_INFO', "OILS: OpenILS::Checkout data loaded OK, doing renew...");
379         } else {
380             syslog('LOG_INFO', "OILS: OpenILS::Checkout appears to be renew, but renewal disallowed...");
381             $xact->screen_msg("Renewals not permitted");
382             $xact->ok(0);
383             return $xact; # Don't attempt later
384         }
385     } elsif ($item->{patron} && ($item->{patron} ne $patron_id)) {
386         # I can't deal with this right now
387         # XXX check in then check out?
388         $xact->screen_msg("Item checked out to another patron");
389         $xact->ok(0);
390         return $xact; # Don't wipe out the screen message later
391     } else {
392         $sc_renew = 0;
393     } 
394
395     # Check for fee and $fee_ack. If there is a fee, and $fee_ack
396     # is 'Y', we proceed, otherwise we reject the checkout.
397     if ($item->fee > 0.0) {
398         $xact->fee_amount($item->fee);
399         $xact->sip_fee_type($item->sip_fee_type);
400         $xact->sip_currency($item->fee_currency);
401         if ($fee_ack && $fee_ack eq 'Y') {
402             $xact->fee_ack(1);
403         } else {
404             $xact->screen_msg('Fee required');
405             $xact->ok(0);
406             return $xact;
407         }
408     }
409
410     $xact->do_checkout($sc_renew);
411     $xact->desensitize(!$item->magnetic);
412
413     if( $xact->ok ) {
414         #editor()->commit;
415         syslog("LOG_DEBUG", "OILS: OpenILS::Checkout: " .
416             "patron %s checkout %s succeeded", $patron_id, $item_id);
417     } else {
418         #editor()->xact_rollback;
419         syslog("LOG_DEBUG", "OILS: OpenILS::Checkout: " .
420             "patron %s checkout %s FAILED, rolling back xact...", $patron_id, $item_id);
421     }
422
423     return $xact;
424 }
425
426
427 sub checkin {
428     my ($self, $item_id, $inst_id, $trans_date, $return_date,
429         $current_loc, $item_props, $cancel) = @_;
430
431     my $start_time = time();
432
433     $self->verify_session;
434
435     syslog('LOG_DEBUG', "OILS: OpenILS::Checkin of item=$item_id (to $inst_id)");
436     
437     my $xact = OpenILS::SIP::Transaction::Checkin->new(authtoken => $self->{authtoken});
438     my $item = OpenILS::SIP::Item->new($item_id);
439
440     unless ( $xact->item($item) ) {
441         $xact->ok(0);
442         # $circ->alert(1); $circ->alert_type(99);
443         $xact->screen_msg("Invalid Item Barcode: '$item_id'");
444         syslog('LOG_INFO', "OILS: Checkin failed.  " . $xact->screen_msg() );
445         return $xact;
446     }
447
448     $xact->do_checkin( $self, $inst_id, $trans_date, $return_date, $current_loc, $item_props );
449     
450     if ($xact->ok) {
451         $xact->patron($self->find_patron(usr => $xact->{circ_user_id}, slim_user => 1)) if $xact->{circ_user_id};
452         delete $item->{patron};
453         delete $item->{due_date};
454         syslog('LOG_INFO', "OILS: Checkin succeeded");
455     } else {
456         syslog('LOG_WARNING', "OILS: Checkin failed");
457     }
458
459     syslog('LOG_INFO', "OILS: SIP Checkin request took %0.3f seconds", (time() - $start_time));
460     return $xact;
461 }
462
463 ## If the ILS caches patron information, this lets it free it up.
464 ## Also, this could be used for centrally logging session duration.
465 ## We don't do anything with it.
466 sub end_patron_session {
467     my ($self, $patron_id) = @_;
468     return (1, 'Thank you!', '');
469 }
470
471
472 sub pay_fee {
473     my ($self, $patron_id, $patron_pwd, $fee_amt, $fee_type,
474     $pay_type, $fee_id, $trans_id, $currency) = @_;
475
476     $self->verify_session;
477
478     my $xact = OpenILS::SIP::Transaction::FeePayment->new(authtoken => $self->{authtoken});
479     my $patron = $self->find_patron($patron_id);
480
481     if (!$patron) {
482         $xact->screen_msg("Invalid Patron Barcode '$patron_id'");
483         $xact->ok(0);
484         return $xact;
485     }
486
487     $xact->patron($patron);
488     $xact->sip_currency($currency);
489     $xact->fee_amount($fee_amt);
490     $xact->sip_fee_type($fee_type);
491     $xact->transaction_id($trans_id);
492     $xact->fee_id($fee_id);
493     $xact->sip_payment_type($pay_type);
494     # We don't presently use this, but we might in the future.
495     $xact->patron_password($patron_pwd);
496
497     $xact->do_fee_payment();
498
499     return $xact;
500 }
501
502 #sub add_hold {
503 #    my ($self, $patron_id, $patron_pwd, $item_id, $title_id,
504 #    $expiry_date, $pickup_location, $hold_type, $fee_ack) = @_;
505 #    my ($patron, $item);
506 #    my $hold;
507 #    my $trans;
508 #
509 #
510 #    $trans = new ILS::Transaction::Hold;
511 #
512 #    # BEGIN TRANSACTION
513 #    $patron = new ILS::Patron $patron_id;
514 #    if (!$patron
515 #    || (defined($patron_pwd) && !$patron->check_password($patron_pwd))) {
516 #    $trans->screen_msg("Invalid Patron.");
517 #
518 #    return $trans;
519 #    }
520 #
521 #    $item = new ILS::Item ($item_id || $title_id);
522 #    if (!$item) {
523 #    $trans->screen_msg("No such item.");
524 #
525 #    # END TRANSACTION (conditionally)
526 #    return $trans;
527 #    } elsif ($item->fee && ($fee_ack ne 'Y')) {
528 #    $trans->screen_msg = "Fee required to place hold.";
529 #
530 #    # END TRANSACTION (conditionally)
531 #    return $trans;
532 #    }
533 #
534 #    $hold = {
535 #    item_id         => $item->id,
536 #    patron_id       => $patron->id,
537 #    expiration_date => $expiry_date,
538 #    pickup_location => $pickup_location,
539 #    hold_type       => $hold_type,
540 #    };
541 #
542 #    $trans->ok(1);
543 #    $trans->patron($patron);
544 #    $trans->item($item);
545 #    $trans->pickup_location($pickup_location);
546 #
547 #    push(@{$item->hold_queue}, $hold);
548 #    push(@{$patron->{hold_items}}, $hold);
549 #
550 #
551 #    # END TRANSACTION
552 #    return $trans;
553 #}
554 #
555 #sub cancel_hold {
556 #    my ($self, $patron_id, $patron_pwd, $item_id, $title_id) = @_;
557 #    my ($patron, $item, $hold);
558 #    my $trans;
559 #
560 #    $trans = new ILS::Transaction::Hold;
561 #
562 #    # BEGIN TRANSACTION
563 #    $patron = new ILS::Patron $patron_id;
564 #    if (!$patron) {
565 #    $trans->screen_msg("Invalid patron barcode.");
566 #
567 #    return $trans;
568 #    } elsif (defined($patron_pwd) && !$patron->check_password($patron_pwd)) {
569 #    $trans->screen_msg('Invalid patron password.');
570 #
571 #    return $trans;
572 #    }
573 #
574 #    $item = new ILS::Item ($item_id || $title_id);
575 #    if (!$item) {
576 #    $trans->screen_msg("No such item.");
577 #
578 #    # END TRANSACTION (conditionally)
579 #    return $trans;
580 #    }
581 #
582 #    # Remove the hold from the patron's record first
583 #    $trans->ok($patron->drop_hold($item_id));
584 #
585 #    if (!$trans->ok) {
586 #    # We didn't find it on the patron record
587 #    $trans->screen_msg("No such hold on patron record.");
588 #
589 #    # END TRANSACTION (conditionally)
590 #    return $trans;
591 #    }
592 #
593 #    # Now, remove it from the item record.  If it was on the patron
594 #    # record but not on the item record, we'll treat that as success.
595 #    foreach my $i (0 .. scalar @{$item->hold_queue}) {
596 #    $hold = $item->hold_queue->[$i];
597 #
598 #    if ($hold->{patron_id} eq $patron->id) {
599 #        # found it: delete it.
600 #        splice @{$item->hold_queue}, $i, 1;
601 #        last;
602 #    }
603 #    }
604 #
605 #    $trans->screen_msg("Hold Cancelled.");
606 #    $trans->patron($patron);
607 #    $trans->item($item);
608 #
609 #    return $trans;
610 #}
611 #
612 #
613 ## The patron and item id's can't be altered, but the
614 ## date, location, and type can.
615 #sub alter_hold {
616 #    my ($self, $patron_id, $patron_pwd, $item_id, $title_id,
617 #    $expiry_date, $pickup_location, $hold_type, $fee_ack) = @_;
618 #    my ($patron, $item);
619 #    my $hold;
620 #    my $trans;
621 #
622 #    $trans = new ILS::Transaction::Hold;
623 #
624 #    # BEGIN TRANSACTION
625 #    $patron = new ILS::Patron $patron_id;
626 #    if (!$patron) {
627 #    $trans->screen_msg("Invalid patron barcode.");
628 #
629 #    return $trans;
630 #    }
631 #
632 #    foreach my $i (0 .. scalar @{$patron->{hold_items}}) {
633 #    $hold = $patron->{hold_items}[$i];
634 #
635 #    if ($hold->{item_id} eq $item_id) {
636 #        # Found it.  So fix it.
637 #        $hold->{expiration_date} = $expiry_date if $expiry_date;
638 #        $hold->{pickup_location} = $pickup_location if $pickup_location;
639 #        $hold->{hold_type} = $hold_type if $hold_type;
640 #
641 #        $trans->ok(1);
642 #        $trans->screen_msg("Hold updated.");
643 #        $trans->patron($patron);
644 #        $trans->item(new ILS::Item $hold->{item_id});
645 #        last;
646 #    }
647 #    }
648 #
649 #    # The same hold structure is linked into both the patron's
650 #    # list of hold items and into the queue of outstanding holds
651 #    # for the item, so we don't need to search the hold queue for
652 #    # the item, since it's already been updated by the patron code.
653 #
654 #    if (!$trans->ok) {
655 #    $trans->screen_msg("No such outstanding hold.");
656 #    }
657 #
658 #    return $trans;
659 #}
660
661
662 sub renew {
663     my ($self, $patron_id, $patron_pwd, $item_id, $title_id,
664         $no_block, $nb_due_date, $third_party, $item_props, $fee_ack) = @_;
665
666     $self->verify_session;
667
668     my $trans = OpenILS::SIP::Transaction::Renew->new( authtoken => $self->{authtoken} );
669     $trans->patron($self->find_patron($patron_id));
670     $trans->item($self->find_item($item_id));
671
672     if(!$trans->patron) {
673         $trans->screen_msg("Invalid patron barcode.");
674         $trans->ok(0);
675         return $trans;
676     }
677
678     if(!$trans->patron->renew_ok) {
679         $trans->screen_msg("Renewals not allowed.");
680         $trans->ok(0);
681         return $trans;
682     }
683
684     if(!$trans->item) {
685         if( $title_id ) {
686             $trans->screen_msg("Title ID renewal not supported.  Use item barcode.");
687         } else {
688             $trans->screen_msg("Invalid item barcode.");
689         }
690         $trans->ok(0);
691         return $trans;
692     }
693
694     if(!$trans->item->{patron} or 
695             $trans->item->{patron} ne $patron_id) {
696         $trans->screen_msg("Item not checked out to " . $trans->patron->name);
697         $trans->ok(0);
698         return $trans;
699     }
700
701     # Perform the renewal
702     $trans->do_renew();
703
704     $trans->desensitize(0);    # It's already checked out
705     $trans->item->{due_date} = $nb_due_date if $no_block eq 'Y';
706     $trans->item->{sip_item_properties} = $item_props if $item_props;
707
708     return $trans;
709 }
710
711
712
713
714
715 #
716 #sub renew_all {
717 #    my ($self, $patron_id, $patron_pwd, $fee_ack) = @_;
718 #    my ($patron, $item_id);
719 #    my $trans;
720 #
721 #    $trans = new ILS::Transaction::RenewAll;
722 #
723 #    $trans->patron($patron = new ILS::Patron $patron_id);
724 #    if (defined $patron) {
725 #    syslog("LOG_DEBUG", "ILS::renew_all: patron '%s': renew_ok: %s",
726 #           $patron->name, $patron->renew_ok);
727 #    } else {
728 #    syslog("LOG_DEBUG", "ILS::renew_all: Invalid patron id: '%s'",
729 #           $patron_id);
730 #    }
731 #
732 #    if (!defined($patron)) {
733 #    $trans->screen_msg("Invalid patron barcode.");
734 #    return $trans;
735 #    } elsif (!$patron->renew_ok) {
736 #    $trans->screen_msg("Renewals not allowed.");
737 #    return $trans;
738 #    } elsif (defined($patron_pwd) && !$patron->check_password($patron_pwd)) {
739 #    $trans->screen_msg("Invalid patron password.");
740 #    return $trans;
741 #    }
742 #
743 #    foreach $item_id (@{$patron->{items}}) {
744 #    my $item = new ILS::Item $item_id;
745 #
746 #    if (!defined($item)) {
747 #        syslog("LOG_WARNING",
748 #           "renew_all: Invalid item id associated with patron '%s'",
749 #           $patron->id);
750 #        next;
751 #    }
752 #
753 #    if (@{$item->hold_queue}) {
754 #        # Can't renew if there are outstanding holds
755 #        push @{$trans->unrenewed}, $item_id;
756 #    } else {
757 #        $item->{due_date} = time + (14*24*60*60); # two weeks hence
758 #        push @{$trans->renewed}, $item_id;
759 #    }
760 #    }
761 #
762 #    $trans->ok(1);
763 #
764 #    return $trans;
765 #}
766
767 1;