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