]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/lib/OpenILS/SIP.pm
53937659942f78b8df6693656cc7d4e0b993f90f
[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 sub get_ou_setting {
245     my $self = shift;
246     my $setting = shift;
247     my $sess = $self->fetch_session;
248     return $U->ou_ancestor_setting_value($sess->home_ou, $setting);
249 }
250
251 sub get_barcode_regex {
252     my $self = shift;
253     if (!defined($self->{bc_regex})) {
254         $self->{bc_regex} = $self->get_ou_setting('opac.barcode_regex');
255         $self->{bc_regex} = '^\d' unless ($self->{bc_regex});
256     }
257     return $self->{bc_regex};
258 }
259
260 #
261 # find_patron($barcode);
262 # find_patron(barcode => $barcode);   # same as above
263 # find_patron(usr => $id);
264 # find_patron(usrname => $usrname);
265
266 sub find_patron {
267     my $self = shift;
268     my $key  =  (@_ > 1) ? shift : 'barcode';  # if we have multiple args, the first is the key index (default barcode)
269     my $patron_id = shift;
270
271     # Check for usrname or barcode in the same, simple way that the OPAC does.
272     my $bc_regex = $self->get_barcode_regex();
273     if ($key eq 'barcode' && $patron_id !~ /$bc_regex/) {
274         $key = 'usrname';
275     }
276
277     $self->verify_session;
278     return OpenILS::SIP::Patron->new($key => $patron_id, authtoken => $self->{authtoken}, @_);
279 }
280
281
282 sub find_item {
283     my $self = shift;
284     $self->verify_session;
285     return OpenILS::SIP::Item->new(@_);
286 }
287
288
289 sub institution {
290     my $self = shift;
291     return $self->{institution}->{id};  # consider making this return the whole institution
292 }
293
294 sub institution_id {
295     my $self = shift;
296     return $self->{institution}->{id};  # then use this for just the ID
297 }
298
299 sub supports {
300     my ($self, $op) = @_;
301     my ($i) = grep { $_->{name} eq $op }  
302         @{$config->{implementation_config}->{supports}->{item}};
303     return to_bool($i->{value});
304 }
305
306 sub check_inst_id {
307     my ($self, $id, $whence) = @_;
308     if ($id ne $self->{institution}->{id}) {
309         syslog("LOG_WARNING", "OILS: %s: received institution '%s', expected '%s'", $whence, $id, $self->{institution}->{id});
310         # Just an FYI check, we don't expect the user to change location from that in SIPconfig.xml
311     }
312 }
313
314
315 sub to_bool {
316     my $bool = shift;
317     # If it's defined, and matches a true sort of string, or is
318     # a non-zero number, then it's true.
319     defined($bool) or return;                   # false
320     ($bool =~ /true|y|yes/i) and return 1;      # true
321     return ($bool =~ /^\d+$/ and $bool != 0);   # true for non-zero numbers, false otherwise
322 }
323
324 sub checkout_ok {
325     return to_bool($config->{policy}->{checkout});
326 }
327
328 sub checkin_ok {
329     return to_bool($config->{policy}->{checkin});
330 }
331
332 sub renew_ok {
333     return to_bool($config->{policy}->{renewal});
334 }
335
336 sub status_update_ok {
337     return to_bool($config->{policy}->{status_update});
338 }
339
340 sub offline_ok {
341     return to_bool($config->{policy}->{offline});
342 }
343
344
345
346 ##
347 ## Checkout(patron_id, item_id, sc_renew, fee_ack):
348 ##    patron_id & item_id are the identifiers send by the terminal
349 ##    sc_renew is the renewal policy configured on the terminal
350 ## returns a status opject that can be queried for the various bits
351 ## of information that the protocol (SIP or NCIP) needs to generate
352 ## the response.
353 ##    fee_ack is the fee_acknowledged field (BO) sent from the sc
354 ## when doing chargeable loans.
355 ##
356
357 sub checkout {
358     my ($self, $patron_id, $item_id, $sc_renew, $fee_ack) = @_;
359     # In order to allow renewals the selfcheck AND the config have to say they are allowed
360     $sc_renew = (chr($sc_renew) eq 'Y' && $self->renew_ok());
361
362     $self->verify_session;
363
364     syslog('LOG_DEBUG', "OILS: OpenILS::Checkout attempt: patron=$patron_id, item=$item_id");
365
366     my $xact   = OpenILS::SIP::Transaction::Checkout->new( authtoken => $self->{authtoken} );
367     my $patron = $self->find_patron($patron_id);
368     my $item   = $self->find_item($item_id);
369
370     $xact->patron($patron);
371     $xact->item($item);
372
373     if (!$patron) {
374         $xact->screen_msg("Invalid Patron Barcode '$patron_id'");
375         return $xact;
376     }
377
378     if (!$patron->charge_ok) {
379         $xact->screen_msg("Patron Blocked");
380         return $xact;
381     }
382
383     if( !$item ) {
384         $xact->screen_msg("Invalid Item Barcode: '$item_id'");
385         return $xact;
386     }
387
388     syslog('LOG_DEBUG', "OILS: OpenILS::Checkout data loaded OK, checking out...");
389
390     if ($item->{patron} && ($item->{patron} eq $patron_id)) {
391         $xact->renew_ok(1); # So that accept/reject responses have the correct value later
392         if($sc_renew) {
393             syslog('LOG_INFO', "OILS: OpenILS::Checkout data loaded OK, doing renew...");
394         } else {
395             syslog('LOG_INFO', "OILS: OpenILS::Checkout appears to be renew, but renewal disallowed...");
396             $xact->screen_msg("Renewals not permitted");
397             $xact->ok(0);
398             return $xact; # Don't attempt later
399         }
400     } elsif ($item->{patron} && ($item->{patron} ne $patron_id)) {
401         # I can't deal with this right now
402         # XXX check in then check out?
403         $xact->screen_msg("Item checked out to another patron");
404         $xact->ok(0);
405         return $xact; # Don't wipe out the screen message later
406     } else {
407         $sc_renew = 0;
408     } 
409
410     # Check for fee and $fee_ack. If there is a fee, and $fee_ack
411     # is 'Y', we proceed, otherwise we reject the checkout.
412     if ($item->fee > 0.0) {
413         $xact->fee_amount($item->fee);
414         $xact->sip_fee_type($item->sip_fee_type);
415         $xact->sip_currency($item->fee_currency);
416         if ($fee_ack && $fee_ack eq 'Y') {
417             $xact->fee_ack(1);
418         } else {
419             $xact->screen_msg('Fee required');
420             $xact->ok(0);
421             return $xact;
422         }
423     }
424
425     $xact->do_checkout($sc_renew);
426     $xact->desensitize(!$item->magnetic);
427
428     if( $xact->ok ) {
429         #editor()->commit;
430         syslog("LOG_DEBUG", "OILS: OpenILS::Checkout: " .
431             "patron %s checkout %s succeeded", $patron_id, $item_id);
432     } else {
433         #editor()->xact_rollback;
434         syslog("LOG_DEBUG", "OILS: OpenILS::Checkout: " .
435             "patron %s checkout %s FAILED, rolling back xact...", $patron_id, $item_id);
436     }
437
438     return $xact;
439 }
440
441
442 sub checkin {
443     my ($self, $item_id, $inst_id, $trans_date, $return_date,
444         $current_loc, $item_props, $cancel) = @_;
445
446     my $start_time = time();
447
448     $self->verify_session;
449
450     syslog('LOG_DEBUG', "OILS: OpenILS::Checkin of item=$item_id (to $inst_id)");
451     
452     my $xact = OpenILS::SIP::Transaction::Checkin->new(authtoken => $self->{authtoken});
453     my $item = OpenILS::SIP::Item->new($item_id);
454
455     unless ( $xact->item($item) ) {
456         $xact->ok(0);
457         # $circ->alert(1); $circ->alert_type(99);
458         $xact->screen_msg("Invalid Item Barcode: '$item_id'");
459         syslog('LOG_INFO', "OILS: Checkin failed.  " . $xact->screen_msg() );
460         return $xact;
461     }
462
463     $xact->do_checkin( $self, $inst_id, $trans_date, $return_date, $current_loc, $item_props );
464     
465     if ($xact->ok) {
466         $xact->patron($self->find_patron(usr => $xact->{circ_user_id}, slim_user => 1)) if $xact->{circ_user_id};
467         delete $item->{patron};
468         delete $item->{due_date};
469         syslog('LOG_INFO', "OILS: Checkin succeeded");
470     } else {
471         syslog('LOG_WARNING', "OILS: Checkin failed");
472     }
473
474     syslog('LOG_INFO', "OILS: SIP Checkin request took %0.3f seconds", (time() - $start_time));
475     return $xact;
476 }
477
478 ## If the ILS caches patron information, this lets it free it up.
479 ## Also, this could be used for centrally logging session duration.
480 ## We don't do anything with it.
481 sub end_patron_session {
482     my ($self, $patron_id) = @_;
483     return (1, 'Thank you!', '');
484 }
485
486
487 sub pay_fee {
488     my ($self, $patron_id, $patron_pwd, $fee_amt, $fee_type,
489     $pay_type, $fee_id, $trans_id, $currency) = @_;
490
491     $self->verify_session;
492
493     my $xact = OpenILS::SIP::Transaction::FeePayment->new(authtoken => $self->{authtoken});
494     my $patron = $self->find_patron($patron_id);
495
496     if (!$patron) {
497         $xact->screen_msg("Invalid Patron Barcode '$patron_id'");
498         $xact->ok(0);
499         return $xact;
500     }
501
502     $xact->patron($patron);
503     $xact->sip_currency($currency);
504     $xact->fee_amount($fee_amt);
505     $xact->sip_fee_type($fee_type);
506     $xact->transaction_id($trans_id);
507     $xact->fee_id($fee_id);
508     $xact->sip_payment_type($pay_type);
509     # We don't presently use this, but we might in the future.
510     $xact->patron_password($patron_pwd);
511
512     $xact->do_fee_payment();
513
514     return $xact;
515 }
516
517 #sub add_hold {
518 #    my ($self, $patron_id, $patron_pwd, $item_id, $title_id,
519 #    $expiry_date, $pickup_location, $hold_type, $fee_ack) = @_;
520 #    my ($patron, $item);
521 #    my $hold;
522 #    my $trans;
523 #
524 #
525 #    $trans = new ILS::Transaction::Hold;
526 #
527 #    # BEGIN TRANSACTION
528 #    $patron = new ILS::Patron $patron_id;
529 #    if (!$patron
530 #    || (defined($patron_pwd) && !$patron->check_password($patron_pwd))) {
531 #    $trans->screen_msg("Invalid Patron.");
532 #
533 #    return $trans;
534 #    }
535 #
536 #    $item = new ILS::Item ($item_id || $title_id);
537 #    if (!$item) {
538 #    $trans->screen_msg("No such item.");
539 #
540 #    # END TRANSACTION (conditionally)
541 #    return $trans;
542 #    } elsif ($item->fee && ($fee_ack ne 'Y')) {
543 #    $trans->screen_msg = "Fee required to place hold.";
544 #
545 #    # END TRANSACTION (conditionally)
546 #    return $trans;
547 #    }
548 #
549 #    $hold = {
550 #    item_id         => $item->id,
551 #    patron_id       => $patron->id,
552 #    expiration_date => $expiry_date,
553 #    pickup_location => $pickup_location,
554 #    hold_type       => $hold_type,
555 #    };
556 #
557 #    $trans->ok(1);
558 #    $trans->patron($patron);
559 #    $trans->item($item);
560 #    $trans->pickup_location($pickup_location);
561 #
562 #    push(@{$item->hold_queue}, $hold);
563 #    push(@{$patron->{hold_items}}, $hold);
564 #
565 #
566 #    # END TRANSACTION
567 #    return $trans;
568 #}
569 #
570
571 # Note: item_id in this context is the hold id
572 sub cancel_hold {
573     my ($self, $patron_id, $patron_pwd, $item_id, $title_id) = @_;
574
575     my $trans = OpenILS::SIP::Transaction::Hold->new(authtoken => $self->{authtoken});
576     my $patron = $self->find_patron($patron_id);
577
578     if (!$patron) {
579         $trans->screen_msg("Invalid patron barcode.");
580         $trans->ok(0);
581         return $trans;
582     }
583
584     if (defined($patron_pwd) && !$patron->check_password($patron_pwd)) {
585         $trans->screen_msg('Invalid patron password.');
586         $trans->ok(0);
587         return $trans;
588     }
589
590     $trans->patron($patron);
591     my $hold = $patron->find_hold_from_copy($item_id);
592
593     if (!$hold) {
594         syslog('LOG_WARNING', "OILS: No hold found from copy $item_id");
595         $trans->screen_msg("No such hold.");
596         $trans->ok(0);
597         return $trans;
598     }
599
600     if ($hold->usr ne $patron->{user}->id) {
601         $trans->screen_msg("No such hold on patron record.");
602         $trans->ok(0);
603         return $trans;
604     }
605
606     $trans->hold($hold);
607     $trans->do_hold_cancel($self);
608
609     if ($trans->cancel_ok) {
610         $trans->screen_msg("Hold Cancelled.");
611     } else {
612         $trans->screen_msg("Hold was not cancelled.");
613     }
614
615     # if the hold had no current_copy, use the representative
616     # item as the item for the hold.  Without this, the SIP 
617     # server gets angry.
618     $trans->item($self->find_item($item_id)) unless $trans->item;
619
620     return $trans;
621 }
622
623 #
624 ## The patron and item id's can't be altered, but the
625 ## date, location, and type can.
626 #sub alter_hold {
627 #    my ($self, $patron_id, $patron_pwd, $item_id, $title_id,
628 #    $expiry_date, $pickup_location, $hold_type, $fee_ack) = @_;
629 #    my ($patron, $item);
630 #    my $hold;
631 #    my $trans;
632 #
633 #    $trans = new ILS::Transaction::Hold;
634 #
635 #    # BEGIN TRANSACTION
636 #    $patron = new ILS::Patron $patron_id;
637 #    if (!$patron) {
638 #    $trans->screen_msg("Invalid patron barcode.");
639 #
640 #    return $trans;
641 #    }
642 #
643 #    foreach my $i (0 .. scalar @{$patron->{hold_items}}) {
644 #    $hold = $patron->{hold_items}[$i];
645 #
646 #    if ($hold->{item_id} eq $item_id) {
647 #        # Found it.  So fix it.
648 #        $hold->{expiration_date} = $expiry_date if $expiry_date;
649 #        $hold->{pickup_location} = $pickup_location if $pickup_location;
650 #        $hold->{hold_type} = $hold_type if $hold_type;
651 #
652 #        $trans->ok(1);
653 #        $trans->screen_msg("Hold updated.");
654 #        $trans->patron($patron);
655 #        $trans->item(new ILS::Item $hold->{item_id});
656 #        last;
657 #    }
658 #    }
659 #
660 #    # The same hold structure is linked into both the patron's
661 #    # list of hold items and into the queue of outstanding holds
662 #    # for the item, so we don't need to search the hold queue for
663 #    # the item, since it's already been updated by the patron code.
664 #
665 #    if (!$trans->ok) {
666 #    $trans->screen_msg("No such outstanding hold.");
667 #    }
668 #
669 #    return $trans;
670 #}
671
672
673 sub renew {
674     my ($self, $patron_id, $patron_pwd, $item_id, $title_id,
675         $no_block, $nb_due_date, $third_party, $item_props, $fee_ack) = @_;
676
677     $self->verify_session;
678
679     my $trans = OpenILS::SIP::Transaction::Renew->new( authtoken => $self->{authtoken} );
680     $trans->patron($self->find_patron($patron_id));
681     $trans->item($self->find_item($item_id));
682
683     if(!$trans->patron) {
684         $trans->screen_msg("Invalid patron barcode.");
685         $trans->ok(0);
686         return $trans;
687     }
688
689     if(!$trans->patron->renew_ok) {
690         $trans->screen_msg("Renewals not allowed.");
691         $trans->ok(0);
692         return $trans;
693     }
694
695     if(!$trans->item) {
696         if( $title_id ) {
697             $trans->screen_msg("Title ID renewal not supported.  Use item barcode.");
698         } else {
699             $trans->screen_msg("Invalid item barcode.");
700         }
701         $trans->ok(0);
702         return $trans;
703     }
704
705     if(!$trans->item->{patron} or 
706             $trans->item->{patron} ne $patron_id) {
707         $trans->screen_msg("Item not checked out to " . $trans->patron->name);
708         $trans->ok(0);
709         return $trans;
710     }
711
712     # Perform the renewal
713     $trans->do_renew();
714
715     $trans->desensitize(0);    # It's already checked out
716     $trans->item->{due_date} = $nb_due_date if $no_block eq 'Y';
717     $trans->item->{sip_item_properties} = $item_props if $item_props;
718
719     return $trans;
720 }
721
722
723 sub renew_all {
724     my ($self, $patron_id, $patron_pwd, $fee_ack) = @_;
725
726     $self->verify_session;
727
728     my $trans = OpenILS::SIP::Transaction::RenewAll->new(authtoken => $self->{authtoken});
729     $trans->patron($self->find_patron($patron_id));
730
731     if(!$trans->patron) {
732         $trans->screen_msg("Invalid patron barcode.");
733         $trans->ok(0);
734         return $trans;
735     }
736
737     if(!$trans->patron->renew_ok) {
738         $trans->screen_msg("Renewals not allowed.");
739         $trans->ok(0);
740         return $trans;
741     }
742
743     $trans->do_renew_all($self);
744     return $trans;
745 }
746
747
748 #
749 #sub renew_all {
750 #    my ($self, $patron_id, $patron_pwd, $fee_ack) = @_;
751 #    my ($patron, $item_id);
752 #    my $trans;
753 #
754 #    $trans = new ILS::Transaction::RenewAll;
755 #
756 #    $trans->patron($patron = new ILS::Patron $patron_id);
757 #    if (defined $patron) {
758 #    syslog("LOG_DEBUG", "ILS::renew_all: patron '%s': renew_ok: %s",
759 #           $patron->name, $patron->renew_ok);
760 #    } else {
761 #    syslog("LOG_DEBUG", "ILS::renew_all: Invalid patron id: '%s'",
762 #           $patron_id);
763 #    }
764 #
765 #    if (!defined($patron)) {
766 #    $trans->screen_msg("Invalid patron barcode.");
767 #    return $trans;
768 #    } elsif (!$patron->renew_ok) {
769 #    $trans->screen_msg("Renewals not allowed.");
770 #    return $trans;
771 #    } elsif (defined($patron_pwd) && !$patron->check_password($patron_pwd)) {
772 #    $trans->screen_msg("Invalid patron password.");
773 #    return $trans;
774 #    }
775 #
776 #    foreach $item_id (@{$patron->{items}}) {
777 #    my $item = new ILS::Item $item_id;
778 #
779 #    if (!defined($item)) {
780 #        syslog("LOG_WARNING",
781 #           "renew_all: Invalid item id associated with patron '%s'",
782 #           $patron->id);
783 #        next;
784 #    }
785 #
786 #    if (@{$item->hold_queue}) {
787 #        # Can't renew if there are outstanding holds
788 #        push @{$trans->unrenewed}, $item_id;
789 #    } else {
790 #        $item->{due_date} = time + (14*24*60*60); # two weeks hence
791 #        push @{$trans->renewed}, $item_id;
792 #    }
793 #    }
794 #
795 #    $trans->ok(1);
796 #
797 #    return $trans;
798 #}
799
800 1;