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