1 package OpenILS::Utils::PermitHold;
2 use strict; use warnings;
5 use OpenSRF::Utils::SettingsClient;
6 use OpenILS::Utils::ScriptRunner;
7 use OpenILS::Application::AppUtils;
8 use DateTime::Format::ISO8601;
9 use OpenILS::Application::Circ::ScriptBuilder;
10 use OpenSRF::Utils::Logger qw(:logger);
12 my $U = "OpenILS::Application::AppUtils";
14 my $script; # - the permit script
15 my $script_libs; # - extra script libs
17 # mental note: open-ils.storage.biblio.record_entry.ranged_tree
20 # params within a hash are: copy, patron,
21 # requestor, request_lib, title, title_descriptor
22 sub permit_copy_hold {
27 patron_id => $$params{patron_id},
28 patron => $$params{patron},
29 copy => $$params{copy},
30 requestor => $$params{requestor},
31 title => $$params{title},
32 volume => $$params{volume},
33 flesh_age_protect => 1,
35 requestLib => $$params{request_lib},
36 pickupLib => $$params{pickup_lib},
37 newHold => $$params{new_hold},
41 my $runner = OpenILS::Application::Circ::ScriptBuilder->build($ctx);
43 my $ets = $ctx->{_events};
45 # --------------------------------------------------------------
46 # Strip the expired event since holds are still allowed to be
47 # captured on expired patrons.
48 # --------------------------------------------------------------
49 if( $ets and @$ets ) {
50 $ets = [ grep { $_->{textcode} ne 'PATRON_ACCOUNT_EXPIRED' } @$ets ];
54 push( @allevents, @$ets);
56 # --------------------------------------------------------------
57 # If scriptbuilder returned any events, then the script context
58 # is undefined and should not be used
59 # --------------------------------------------------------------
63 # check the various holdable flags
64 push( @allevents, OpenILS::Event->new('ITEM_NOT_HOLDABLE') )
65 unless $U->is_true($ctx->{copy}->holdable);
67 push( @allevents, OpenILS::Event->new('ITEM_NOT_HOLDABLE') )
68 unless $U->is_true($ctx->{copy}->location->holdable);
70 push( @allevents, OpenILS::Event->new('ITEM_NOT_HOLDABLE') )
71 unless $U->is_true($ctx->{copy}->status->holdable);
75 # grab the data safely
76 my $rlib = ref($$params{request_lib}) ? $$params{request_lib}->id : $$params{request_lib};
77 my $olib = ref($ctx->{volume}) ? $ctx->{volume}->owning_lib : -1;
78 my $rid = ref($ctx->{requestor}) ? $ctx->{requestor}->id : -2;
79 my $pid = ($params->{patron}) ? $params->{patron}->id : $params->{patron_id};
81 if( ($rid ne $pid) and ($olib eq $rlib) ) {
82 $logger->info("Item owning lib $olib is the same as the request lib. No age_protection will be checked");
84 $logger->info("item owning lib = $olib, request lib = $rlib, requestor=$rid, patron=$pid. checking age_protection");
85 $evt = check_age_protect($ctx->{patron}, $ctx->{copy});
86 push( @allevents, $evt ) if $evt;
89 $logger->debug("Running permit_copy_hold on copy " . $$params{copy}->id);
91 load_scripts($runner);
92 my $result = $runner->run or
93 throw OpenSRF::EX::ERROR ("Hold Copy Permit Script Died: $@");
95 # --------------------------------------------------------------
96 # Extract and uniquify the event list
97 # --------------------------------------------------------------
98 my $events = $result->{events};
99 $logger->debug("circ_permit_hold for user $pid returned events: [@$events]");
101 push( @allevents, OpenILS::Event->new($_)) for @$events;
104 my %hash = map { ($_->{ilsevent} => $_) } @allevents;
105 @allevents = values %hash;
109 return \@allevents if $$params{show_event_list};
110 return 1 unless @allevents;
119 my $conf = OpenSRF::Utils::SettingsClient->new;
120 my @pfx = ( "apps", "open-ils.circ","app_settings" );
121 my $libs = $conf->config_value(@pfx, 'script_path');
122 $script = $conf->config_value(@pfx, 'scripts', 'circ_permit_hold');
123 $script_libs = (ref($libs)) ? $libs : [$libs];
126 $runner->add_path($_) for(@$script_libs);
127 $runner->load($script);
131 sub check_age_protect {
132 my( $patron, $copy ) = @_;
134 return undef unless $copy and $copy->age_protect and $patron;
136 my $hou = (ref $patron->home_ou) ? $patron->home_ou->id : $patron->home_ou;
138 my $prox = $U->storagereq(
139 'open-ils.storage.asset.copy.proximity', $copy->id, $hou );
141 # If this copy is within the appropriate proximity,
142 # age protect does not apply
143 return undef if $prox <= $copy->age_protect->prox;
145 my $protection_list = $U->storagereq(
146 'open-ils.storage.direct.config.rules.age_hold_protect.search_where.atomic',
147 { age => { '>=' => $copy->age_protect->age },
148 prox => { '>=' => $copy->age_protect->prox },
150 { order_by => 'age' }
153 # Now, now many seconds old is this copy
154 my $create_date = DateTime::Format::ISO8601
156 ->parse_datetime( OpenSRF::Utils::clense_ISO8601($copy->create_date) )
159 my $age = time - $create_date;
161 for my $protection ( @$protection_list ) {
163 $logger->info("analyzing age protect ".$protection->name);
165 # age protect does not apply if within the proximity
166 last if $prox <= $protection->prox;
168 # How many seconds old does the copy have to be to escape age protection
169 my $interval = OpenSRF::Utils::interval_to_seconds($protection->age);
171 $logger->info("age_protect interval=$interval, create_date=$create_date, age=$age");
173 if( $interval > $age ) {
174 # if age of the item is less than the protection interval,
175 # the item falls within the age protect range
176 $logger->info("age_protect prevents copy from having a hold placed on it: ".$copy->id);
177 return OpenILS::Event->new('ITEM_AGE_PROTECTED', copy => $copy->id );