]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Utils/PermitHold.pm
added hold permit flag for new holds to prevent max-holds checks on existing holds
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Utils / PermitHold.pm
1 package OpenILS::Utils::PermitHold;
2 use strict; use warnings;
3 use Data::Dumper;
4 use OpenSRF::Utils;
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);
11 use OpenILS::Event;
12 my $U   = "OpenILS::Application::AppUtils";
13
14 my $script;                     # - the permit script
15 my $script_libs;        # - extra script libs
16
17 # mental note:  open-ils.storage.biblio.record_entry.ranged_tree
18
19
20 # params within a hash are: copy, patron, 
21 # requestor, request_lib, title, title_descriptor
22 sub permit_copy_hold {
23         my $params      = shift;
24         my @allevents;
25
26         my $ctx = {
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,
34                 _direct => {
35                         requestLib      => $$params{request_lib},
36                         pickupLib       => $$params{pickup_lib},
37             newHold    => $$params{new_hold},
38                 }
39         };
40
41         my $runner = OpenILS::Application::Circ::ScriptBuilder->build($ctx);
42
43         my $ets = $ctx->{_events};
44
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 ];
51         } else { $ets = []; }
52
53         if( @$ets ) {
54                 push( @allevents, @$ets);
55
56                 # --------------------------------------------------------------
57                 # If scriptbuilder returned any events, then the script context
58                 # is undefined and should not be used
59                 # --------------------------------------------------------------
60
61         } else {
62
63                 # check the various holdable flags
64                 push( @allevents, OpenILS::Event->new('ITEM_NOT_HOLDABLE') )
65                         unless $U->is_true($ctx->{copy}->holdable);
66         
67                 push( @allevents, OpenILS::Event->new('ITEM_NOT_HOLDABLE') )
68                         unless $U->is_true($ctx->{copy}->location->holdable);
69         
70                 push( @allevents, OpenILS::Event->new('ITEM_NOT_HOLDABLE') )
71                         unless $U->is_true($ctx->{copy}->status->holdable);
72         
73       my $evt;
74
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};
80
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");
83       } else {
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;
87       }
88         
89                 $logger->debug("Running permit_copy_hold on copy " . $$params{copy}->id);
90         
91                 load_scripts($runner);
92                 my $result = $runner->run or 
93                         throw OpenSRF::EX::ERROR ("Hold Copy Permit Script Died: $@");
94
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]");
100         
101                 push( @allevents, OpenILS::Event->new($_)) for @$events;
102         }
103
104         my %hash = map { ($_->{ilsevent} => $_) } @allevents;
105         @allevents = values %hash;
106
107         $runner->cleanup;
108
109         return \@allevents if $$params{show_event_list};
110         return 1 unless @allevents;
111         return 0;
112 }
113
114
115 sub load_scripts {
116         my $runner = shift;
117
118         if(!$script) {
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];
124         }
125
126         $runner->add_path($_) for(@$script_libs);
127         $runner->load($script);
128 }
129
130
131 sub check_age_protect {
132         my( $patron, $copy ) = @_;
133
134         return undef unless $copy and $copy->age_protect and $patron;
135
136         my $hou = (ref $patron->home_ou) ? $patron->home_ou->id : $patron->home_ou;
137
138         my $prox = $U->storagereq(
139                 'open-ils.storage.asset.copy.proximity', $copy->id, $hou );
140
141         # If this copy is within the appropriate proximity, 
142         # age protect does not apply
143         return undef if $prox <= $copy->age_protect->prox;
144
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 },
149                 },
150                 { order_by => 'age' }
151         );
152
153         # Now, now many seconds old is this copy
154         my $create_date = DateTime::Format::ISO8601
155                 ->new
156                 ->parse_datetime( OpenSRF::Utils::clense_ISO8601($copy->create_date) )
157                 ->epoch;
158
159         my $age = time - $create_date;
160
161         for my $protection ( @$protection_list ) {
162
163                 $logger->info("analyzing age protect ".$protection->name);
164
165                 # age protect does not apply if within the proximity
166                 last if $prox <= $protection->prox;
167
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);
170
171                 $logger->info("age_protect interval=$interval, create_date=$create_date, age=$age");
172
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 );
178                 }
179         }
180                 
181         return undef;
182 }
183
184 23;