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