1 # ---------------------------------------------------------------
2 # Copyright (C) 2005 Georgia Public Library Service
3 # Bill Erickson <highfalutin@gmail.com>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 # ---------------------------------------------------------------
16 package OpenILS::Application::Circ::Rules;
17 use base qw/OpenSRF::Application/;
18 use strict; use warnings;
20 use OpenSRF::Utils::SettingsClient;
21 use OpenILS::Utils::Fieldmapper;
23 use OpenSRF::Utils::Logger qw(:level);
25 use Template qw(:template);
28 use Time::HiRes qw(time);
29 use OpenILS::Utils::ModsParser;
32 use OpenSRF::EX qw(:try);
34 use OpenILS::Application::AppUtils;
35 my $apputils = "OpenILS::Application::AppUtils";
36 use Digest::MD5 qw(md5_hex);
38 my $log = "OpenSRF::Utils::Logger";
40 # ----------------------------------------------------------------
43 my $permission_script;
45 my $recurring_fines_script;
47 my $permit_hold_script;
48 my $permit_renew_script;
49 # ----------------------------------------------------------------
52 # data used for this circulation transaction
53 my $circ_objects = {};
55 # some static data from the database
59 my $shelving_locations;
64 # memcache for caching the circ objects
68 use constant NO_COPY => 100;
73 my $conf = OpenSRF::Utils::SettingsClient->new;
75 # ----------------------------------------------------------------
76 # set up the rules scripts
77 # ----------------------------------------------------------------
78 $circ_script = $conf->config_value(
79 "apps", "open-ils.circ","app_settings", "rules", "main");
81 $permission_script = $conf->config_value(
82 "apps", "open-ils.circ","app_settings", "rules", "permission");
84 $duration_script = $conf->config_value(
85 "apps", "open-ils.circ","app_settings", "rules", "duration");
87 $recurring_fines_script = $conf->config_value(
88 "apps", "open-ils.circ","app_settings", "rules", "recurring_fines");
90 $max_fines_script = $conf->config_value(
91 "apps", "open-ils.circ","app_settings", "rules", "max_fines");
93 $permit_hold_script = $conf->config_value(
94 "apps", "open-ils.circ","app_settings", "rules", "permit_hold");
96 $permit_renew_script = $conf->config_value(
97 "apps", "open-ils.circ","app_settings", "rules", "permit_renew");
99 $log->debug("Loaded rules scripts for circ:\n".
100 "main - $circ_script : permit circ - $permission_script\n".
101 "duration - $duration_script : recurring - $recurring_fines_script\n".
102 "max fines - $max_fines_script : permit hold - $permit_hold_script", DEBUG);
105 $cache_handle = OpenSRF::Utils::Cache->new();
109 sub _grab_patron_standings {
111 if(!$patron_standings) {
112 my $standing_req = $session->request(
113 "open-ils.storage.direct.config.standing.retrieve.all.atomic");
114 $patron_standings = $standing_req->gather(1);
116 { map { (''.$_->id => $_->value) } @$patron_standings };
120 sub _grab_patron_profiles {
122 if(!$patron_profiles) {
123 my $profile_req = $session->request(
124 "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
125 $patron_profiles = $profile_req->gather(1);
127 { map { (''.$_->id => $_->name) } @$patron_profiles };
134 my $patron_id = shift;
135 my $patron_req = $session->request(
136 "open-ils.storage.direct.actor.user.retrieve",
138 return $patron_req->gather(1);
142 sub _grab_title_by_copy {
145 my $title_req = $session->request(
146 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
148 return $title_req->gather(1);
151 sub _grab_patron_summary {
153 my $patron_id = shift;
154 my $summary_req = $session->request(
155 "open-ils.storage.action.circulation.patron_summary",
157 return $summary_req->gather(1);
160 sub _grab_copy_by_barcode {
161 my($session, $barcode) = @_;
162 warn "Searching for copy with barcode $barcode\n";
163 my $copy_req = $session->request(
164 "open-ils.storage.fleshed.asset.copy.search.barcode",
166 return $copy_req->gather(1);
169 sub _grab_copy_by_id {
170 my($session, $id) = @_;
171 warn "Searching for copy with id $id\n";
172 my $copy_req = $session->request(
173 "open-ils.storage.direct.asset.copy.retrieve",
175 my $c = $copy_req->gather(1);
176 if($c) { return _grab_copy_by_barcode($session, $c->barcode); }
181 sub gather_hold_objects {
182 my($session, $hold, $copy, $args) = @_;
184 _grab_patron_standings($session);
185 _grab_patron_profiles($session);
189 $copy = _grab_copy_by_barcode($session, $copy->barcode);
191 my $hold_objects = {};
192 $hold_objects->{standings} = $patron_standings;
193 $hold_objects->{copy} = $copy;
194 $hold_objects->{hold} = $hold;
195 $hold_objects->{title} = $$args{title} || _grab_title_by_copy($session, $copy->id);
196 $hold_objects->{requestor} = _grab_user($session, $hold->requestor);
197 my $patron = _grab_user($session, $hold->usr);
199 $copy->status( $copy->status->name );
200 $patron->standing($patron_standings->{$patron->standing()});
201 $patron->profile( $patron_profiles->{$patron->profile});
203 $hold_objects->{patron} = $patron;
205 return $hold_objects;
210 __PACKAGE__->register_method(
211 method => "permit_hold",
212 api_name => "open-ils.circ.permit_hold",
213 notes => <<" NOTES");
214 Determines whether a given copy is eligible to be held
218 my( $self, $client, $hold, $copy, $args ) = @_;
220 my $session = OpenSRF::AppSession->create("open-ils.storage");
222 # collect items necessary for circ calculation
223 my $hold_objects = gather_hold_objects( $session, $hold, $copy, $args );
225 $stash = Template::Stash->new(
226 circ_objects => $hold_objects,
229 $stash->set("run_block", $permit_hold_script);
231 # grab the number of copies checked out by the patron as
232 # well as the total fines
233 my $summary = _grab_patron_summary($session, $hold_objects->{patron}->id);
235 $summary->[1] ||= 0.0;
237 $stash->set("patron_copies", $summary->[0] );
238 $stash->set("patron_fines", $summary->[1] );
240 # run the permissibility script
242 my $result = $stash->get("result");
244 # 0 means OK in the script
245 return 1 if($result->[0] == 0);
254 # ----------------------------------------------------------------
255 # Collect all of the objects necessary for calculating the
257 # ----------------------------------------------------------------
258 sub gather_circ_objects {
259 my( $session, $barcode_string, $patron_id ) = @_;
261 throw OpenSRF::EX::ERROR
262 ("gather_circ_objects needs data")
263 unless ($barcode_string and $patron_id);
265 warn "Gathering circ objects with barcode $barcode_string and patron id $patron_id\n";
267 # see if all of the circ objects are in cache
268 my $cache_key = "circ_object_" . md5_hex( $barcode_string, $patron_id );
269 $circ_objects = $cache_handle->get_cache($cache_key);
272 $stash = Template::Stash->new(
273 circ_objects => $circ_objects,
275 target_copy_status => 1,
280 # only necessary if the circ objects have not been built yet
282 _grab_patron_standings($session);
283 _grab_patron_profiles($session);
286 my $copy = _grab_copy_by_barcode($session, $barcode_string);
287 if(!$copy) { return NO_COPY; }
289 my $patron = _grab_user($session, $patron_id);
291 $copy->status( $copy->status->name );
292 $circ_objects->{copy} = $copy;
294 $patron->standing($patron_standings->{$patron->standing()});
295 $patron->profile( $patron_profiles->{$patron->profile});
296 $circ_objects->{patron} = $patron;
297 $circ_objects->{standings} = $patron_standings;
299 #$circ_objects->{title} = $title_req->gather(1);
300 $circ_objects->{title} = _grab_title_by_copy($session, $circ_objects->{copy}->id);
301 $cache_handle->put_cache( $cache_key, $circ_objects, 30 );
303 $stash = Template::Stash->new(
304 circ_objects => $circ_objects,
306 target_copy_status => 1,
316 my $template = Template->new(
324 my $status = $template->process($circ_script);
327 throw OpenSRF::EX::ERROR
328 ("Error processing circ script " . $template->error());
331 warn "Script result: $result\n";
337 __PACKAGE__->register_method(
338 method => "permit_circ",
339 api_name => "open-ils.circ.permit_checkout",
343 my( $self, $client, $user_session, $barcode, $user_id, $outstanding_count ) = @_;
345 my $copy_status_mangled;
348 if(defined($outstanding_count) && $outstanding_count eq "renew") {
350 $outstanding_count = 0;
351 } else { $outstanding_count ||= 0; }
353 my $session = OpenSRF::AppSession->create("open-ils.storage");
355 # collect items necessary for circ calculation
356 my $status = gather_circ_objects( $session, $barcode, $user_id );
358 if( $status == NO_COPY ) {
359 return { record => undef,
361 text => "No copy available with barcode $barcode"
364 my $copy = $stash->get("circ_objects")->{copy};
366 if( $copy->status eq "8" ) {
367 $copy_status_mangled = 8;
372 $stash->set("run_block", $permission_script);
374 # grab the number of copies checked out by the patron as
375 # well as the total fines
376 my $summary_req = $session->request(
377 "open-ils.storage.action.circulation.patron_summary",
378 $stash->get("circ_objects")->{patron}->id );
379 my $summary = $summary_req->gather(1);
382 $summary->[1] ||= 0.0;
384 $stash->set("patron_copies", $summary->[0] + $outstanding_count );
385 $stash->set("patron_fines", $summary->[1] );
386 $stash->set("renew", 1) if $renew;
388 # run the permissibility script
391 my $arr = $stash->get("result");
393 if( $arr->[0] eq "0" and $copy_status_mangled == 8) {
394 my $hold = $session->request(
395 "open-ils.storage.direct.action.hold_request.search.current_copy",
396 $copy->id )->gather(1);
398 if( $hold->usr eq $user_id ) {
399 return { status => 0, text => "OK" };
401 return { status => 6,
402 text => "Copy is needed by a different user to fulfill a hold" };
409 return { status => $arr->[0], text => $arr->[1] };
415 __PACKAGE__->register_method(
416 method => "circulate",
417 api_name => "open-ils.circ.checkout.barcode",
421 my( $self, $client, $user_session, $barcode, $patron, $isrenew, $numrenews ) = @_;
424 my $session = $apputils->start_db_session();
426 gather_circ_objects( $session, $barcode, $patron );
428 # grab the copy statuses if we don't already have them
429 if(!$copy_statuses) {
430 my $csreq = $session->request(
431 "open-ils.storage.direct.config.copy_status.retrieve.all.atomic" );
432 $copy_statuses = $csreq->gather(1);
435 # put copy statuses into the stash
436 $stash->set("copy_statuses", $copy_statuses );
438 my $copy = $circ_objects->{copy};
439 my ($circ, $duration, $recurring, $max) = run_circ_scripts($session);
442 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
443 gmtime(OpenSRF::Utils->interval_to_seconds($circ->duration) + int(time()));
444 $year += 1900; $mon += 1;
445 my $due_date = sprintf(
446 '%s-%0.2d-%0.2dT%s:%0.2d:%0.s2-00',
447 $year, $mon, $mday, $hour, $min, $sec);
449 warn "Setting due date to $due_date\n";
450 $circ->due_date($due_date);
453 warn "Renewing circ.... ".$circ->id ." and setting num renews to " . $numrenews - 1 . "\n";
456 $circ->renewal_remaining($numrenews - 1);
460 # commit new circ object to db
461 my $commit = $session->request(
462 "open-ils.storage.direct.action.circulation.create",
464 my $id = $commit->gather(1);
467 throw OpenSRF::EX::ERROR
468 ("Error creating new circulation object");
471 # update the copy with the new circ
472 $copy->status( $stash->get("target_copy_status") );
473 $copy->location( $copy->location->id );
474 $copy->circ_lib( $copy->circ_lib->id ); #XXX XXX needs to point to the lib that actually checked out the item (user->home_ou)?
477 my $copy_update = $session->request(
478 "open-ils.storage.direct.asset.copy.update",
480 $copy_update->gather(1);
482 $apputils->commit_db_session($session);
484 # remove our circ object from the cache
485 $cache_handle->delete_cache("circ_object_" . md5_hex($barcode, $patron));
487 # re-retrieve the the committed circ object
488 $circ = $apputils->simple_scalar_request(
490 "open-ils.storage.direct.action.circulation.retrieve",
494 # push the rules and due date into the circ object
495 $circ->duration_rule($duration);
496 $circ->max_fine_rule($max);
497 $circ->recuring_fine_rule($recurring);
499 # turn the biblio record into a friendly object
500 my $obj = $stash->get("circ_objects");
501 my $u = OpenILS::Utils::ModsParser->new();
502 $u->start_mods_batch( $circ_objects->{title}->marc() );
503 my $mods = $u->finish_mods_batch();
506 return { circ => $circ, copy => $copy, record => $mods };
512 # runs the duration, recurring_fines, and max_fines scripts.
513 # builds the new circ object based on the rules returned from
515 # returns (circ, duration_rule, recurring_fines_rule, max_fines_rule)
516 sub run_circ_scripts {
519 # go through all of the scripts and process
520 # each script returns
521 # [ rule_name, level (appropriate to the script) ]
522 $stash->set("result", [] );
523 $stash->set("run_block", $duration_script);
525 my $duration_rule = $stash->get("result");
527 $stash->set("run_block", $recurring_fines_script);
528 $stash->set("result", [] );
530 my $rec_fines_rule = $stash->get("result");
532 $stash->set("run_block", $max_fines_script);
533 $stash->set("result", [] );
535 my $max_fines_rule = $stash->get("result");
537 my $obj = $stash->get("circ_objects");
539 # ----------------------------------------------------------
540 # find the rules objects based on the rule names returned from
541 # the various scripts.
542 my $dur_req = $session->request(
543 "open-ils.storage.direct.config.rules.circ_duration.search.name.atomic",
544 $duration_rule->[0] );
546 my $rec_req = $session->request(
547 "open-ils.storage.direct.config.rules.recuring_fine.search.name.atomic",
548 $rec_fines_rule->[0] );
550 my $max_req = $session->request(
551 "open-ils.storage.direct.config.rules.max_fine.search.name.atomic",
552 $max_fines_rule->[0] );
554 my $duration = $dur_req->gather(1)->[0];
555 my $recurring = $rec_req->gather(1)->[0];
556 my $max = $max_req->gather(1)->[0];
558 my $copy = $circ_objects->{copy};
561 warn "Building a new circulation object with\n".
562 "=> copy " . Dumper($copy) .
563 "=> duration_rule " . Dumper($duration_rule) .
564 "=> rec_files_rule " . Dumper($rec_fines_rule) .
565 "=> duration " . Dumper($duration) .
566 "=> recurring " . Dumper($recurring) .
567 "=> max " . Dumper($max);
570 # build the new circ object
571 my $circ = build_circ_object($session, $copy, $duration_rule->[1],
572 $rec_fines_rule->[1], $duration, $recurring, $max );
574 return ($circ, $duration, $recurring, $max);
578 # ------------------------------------------------------------------
579 # Builds a new circ object
580 # ------------------------------------------------------------------
581 sub build_circ_object {
582 my( $session, $copy, $dur_level, $rec_level,
583 $duration, $recurring, $max ) = @_;
585 my $circ = new Fieldmapper::action::circulation;
587 $circ->circ_lib( $copy->circ_lib->id() );
588 if($dur_level == 1) {
589 $circ->duration( $duration->shrt );
590 } elsif($dur_level == 2) {
591 $circ->duration( $duration->normal );
592 } elsif($dur_level == 3) {
593 $circ->duration( $duration->extended );
596 if($rec_level == 1) {
597 $circ->recuring_fine( $recurring->low );
598 } elsif($rec_level == 2) {
599 $circ->recuring_fine( $recurring->normal );
600 } elsif($rec_level == 3) {
601 $circ->recuring_fine( $recurring->high );
604 $circ->duration_rule( $duration->name );
605 $circ->recuring_fine_rule( $recurring->name );
606 $circ->max_fine_rule( $max->name );
607 $circ->max_fine( $max->amount );
609 $circ->fine_interval($recurring->recurance_interval);
610 $circ->renewal_remaining( $duration->max_renewals );
611 $circ->target_copy( $copy->id );
612 $circ->usr( $circ_objects->{patron}->id );
618 __PACKAGE__->register_method(
619 method => "transit_receive",
620 api_name => "open-ils.circ.transit.receive",
621 notes => <<" NOTES");
622 Receives a copy that is in transit.
623 Params are login_session and copyid.
624 Logged in user must have COPY_CHECKIN priveleges.
626 status 3 means that this transit is destined for somewhere else
627 status 10 means the copy is not in transit
628 status 11 means the transit is complete, does not need processing
629 status 12 means copy is in transit but no tansit was found
633 sub transit_receive {
634 my( $self, $client, $login_session, $copyid ) = @_;
636 my $user = $apputils->check_user_session($login_session);
638 if($apputils->check_user_perms($user->id, $user->home_ou, "COPY_CHECKIN")) {
639 return OpenILS::Perm->new("COPY_CHECKIN");
642 my $session = $apputils->start_db_session();
643 my $copy = _grab_copy_by_id($session, $copyid);
646 if(!$copy->status eq "6") {
647 return { status => 10, route_to => $copy->circ_lib };
651 $transit = $session->request(
652 "open-ils.storage.direct.action.transit_copy.search_where",
653 { target_copy => $copy->id, dest_recv_time => undef } )->gather(1);
657 if( defined($transit->dest_recv_time) ) {
658 return { status => 11, route_to => $copy->circ_lib };
661 if($transit->dest ne $user->home_ou) {
662 return { status => 3, route_to => $transit->dest };
665 $transit->dest_recv_time("now");
666 my $s = $session->request(
667 "open-ils.storage.direct.action.transit_copy.update",
670 my $holdtransit = $session->request(
671 "open-ils.storage.direct.action.hold_transit_copy.retrieve",
676 my $hold = $session->request(
677 "open-ils.storage.direct.action.hold_request.retrieve",
678 $holdtransit->hold )->gather(1);
680 throw OpenSRF::EX::ERROR ("No hold found to match transit " . $holdtransit->id);
683 # put copy on the holds shelf
684 $copy->status(8); #hold shelf status
685 $copy->editor($user->id); #hold shelf status
686 $copy->edit_date("now"); #hold shelf status
688 my $s = $session->request(
689 "open-ils.storage.direct.asset.copy.update", $copy )->gather(1);
690 if(!$s) {throw OpenSRF::EX::ERROR ("Error putting copy on holds shelf ".$copy->id);} # blah..
692 return { status => 0, route_to => $hold->pickup_lib };
696 return { status => 12, route_to => $copy->circ_lib };
703 __PACKAGE__->register_method(
705 api_name => "open-ils.circ.checkin.barcode",
706 notes => <<" NOTES");
707 Checks in based on barcode
708 Returns record, status, text, circ, copy, route_to
711 1 = 'copy required to fulfil a hold'
715 my( $self, $client, $user_session, $barcode, $isrenewal, $backdate ) = @_;
722 my $user = $apputils->check_user_session($user_session);
724 if($apputils->check_user_perms($user->id, $user->home_ou, "COPY_CHECKIN")) {
725 return OpenILS::Perm->new("COPY_CHECKIN");
728 my $session = $apputils->start_db_session();
734 warn "retrieving copy for checkin\n";
737 my $copy_req = $session->request(
738 "open-ils.storage.direct.asset.copy.search.barcode.atomic",
740 $copy = $copy_req->gather(1)->[0];
742 $client->respond_complete(OpenILS::EX->new("UNKNOWN_BARCODE")->ex);
745 if($copy->status eq "6") { #copy is in transit, deal with it
746 my $method = $self->method_lookup("open-ils.circ.transit.receive");
747 return $method->run( $user_session, $copy->id );
751 if(!$shelving_locations) {
752 my $sh_req = $session->request(
753 "open-ils.storage.direct.asset.copy_location.retrieve.all.atomic");
754 $shelving_locations = $sh_req->gather(1);
755 $shelving_locations =
756 { map { (''.$_->id => $_->name) } @$shelving_locations };
762 # find circ's where the transaction is still open for the
763 # given copy. should only be one.
764 warn "Retrieving circ for checkin\n";
765 my $circ_req = $session->request(
766 "open-ils.storage.direct.action.circulation.search.atomic",
767 { target_copy => $copy->id, xact_finish => undef } );
769 $circ = $circ_req->gather(1)->[0];
773 $err = "No circulation exists for the given barcode";
777 $transaction = $session->request(
778 "open-ils.storage.direct.money.billable_transaction_summary.retrieve", $circ->id)->gather(1);
780 warn "Checking in circ ". $circ->id . "\n";
782 $circ->stop_fines("CHECKIN");
783 $circ->stop_fines("RENEW") if($isrenewal);
784 $circ->xact_finish("now") if($transaction->balance_owed <= 0 );
786 my $cp_up = $session->request(
787 "open-ils.storage.direct.asset.copy.update", $copy );
790 my $ci_up = $session->request(
791 "open-ils.storage.direct.action.circulation.update",
796 warn "Checkin succeeded\n";
801 $err = "Error checking in: $e";
806 return { record => undef, status => -1, text => $err };
811 my $status_text = "OK";
813 # see if this copy can fulfill a hold
814 my $hold = OpenILS::Application::Circ::Holds::_find_local_hold_for_copy( $session, $copy, $user );
816 my $route_to = $shelving_locations->{$copy->location};
820 $status_text = "Copy needed to fulfill hold";
821 $route_to = $hold->pickup_lib;
824 $apputils->commit_db_session($session);
826 my $record = $apputils->simple_scalar_request(
828 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
831 my $u = OpenILS::Utils::ModsParser->new();
832 $u->start_mods_batch( $record->marc() );
833 my $mods = $u->finish_mods_batch();
838 text => $status_text,
841 route_to => $route_to,
853 # ------------------------------------------------------------------------------
855 # ------------------------------------------------------------------------------
858 __PACKAGE__->register_method(
860 api_name => "open-ils.circ.renew",
861 notes => <<" NOTES");
862 open-ils.circ.renew(login_session, circ_object);
863 Renews the provided circulation. login_session is the requestor of the
864 renewal and if the logged in user is not the same as circ->usr, then
865 the logged in user must have RENEW_CIRC permissions.
869 my($self, $client, $login_session, $circ) = @_;
871 throw OpenSRF::EX::InvalidArg
872 ("open-ils.circ.renew no circ") unless defined($circ);
874 my $user = $apputils->check_user_session($login_session);
876 my $session = OpenSRF::AppSession->create("open-ils.storage");
877 my $copy = _grab_copy_by_id($session, $circ->target_copy);
879 my $r = $session->request(
880 "open-ils.storage.direct.action.hold_copy_map.search.target_copy.atomic",
881 $copy->id )->gather(1);
883 my @holdids = map { $_->hold } @$r;
887 my $holds = $session->request(
888 "open-ils.storage.direct.action.hold_request.search_where",
889 { id => \@holdids, current_copy => undef } )->gather(1);
891 if( $holds and $user->id ne $circ->usr ) {
892 if($apputils->check_user_perms($user->id, $user->home_ou, "RENEW_HOLD_OVERRIDE")) {
893 return OpenILS::Perm->new("RENEW_HOLD_OVERRIDE");
897 return OpenILS::EX->new("COPY_NEEDED_FOR_HOLD")->ex;
902 $circ = $session->request(
903 "open-ils.storage.direct.action.circulation.retrieve", $circ )->gather(1);
907 warn "Attempting to renew circ " . $iid . "\n";
909 if($user->id ne $circ->usr) {
910 if($apputils->check_user_perms($user->id, $user->home_ou, "RENEW_CIRC")) {
911 return OpenILS::Perm->new("RENEW_CIRC");
915 if($circ->renewal_remaining <= 0) {
916 return OpenILS::EX->new("MAX_RENEWALS_REACHED")->ex; }
920 # XXX XXX See if the copy this circ points to is needed to fulfill a hold!
921 # XXX check overdue..?
923 my $checkin = $self->method_lookup("open-ils.circ.checkin.barcode");
924 my ($status) = $checkin->run($login_session, $copy->barcode, 1);
925 return $status if ($status->{status} ne "0");
926 warn "Renewal checkin completed for $iid\n";
928 my $permit_checkout = $self->method_lookup("open-ils.circ.permit_checkout");
929 ($status) = $permit_checkout->run($login_session, $copy->barcode, $circ->usr, "renew");
930 return $status if($status->{status} ne "0");
931 warn "Renewal permit checkout completed for $iid\n";
933 my $checkout = $self->method_lookup("open-ils.circ.checkout.barcode");
934 ($status) = $checkout->run($login_session, $copy->barcode, $circ->usr, 1, $circ->renewal_remaining);
935 warn "Renewal checkout completed for $iid\n";