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