c45d1eae5f784369fd4ea054cf88c796ab10e722
[working/Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Trigger / Validator.pm
1 package OpenILS::Application::Trigger::Validator;
2 use strict; use warnings;
3 use DateTime;
4 use DateTime::Format::ISO8601;
5 use OpenSRF::Utils qw/:datetime/;
6 use OpenSRF::Utils::Logger qw/:logger/;
7 use OpenILS::Const qw/:const/;
8 use OpenILS::Application::AppUtils;
9 use OpenILS::Utils::CStoreEditor qw/:funcs/;
10 use Data::Dumper;
11
12 sub fourty_two { return 42 }
13 sub NOOP_True { return 1 }
14 sub NOOP_False { return 0 }
15
16 my $U = 'OpenILS::Application::AppUtils';
17
18 sub CircIsOpen {
19     my $self = shift;
20     my $env = shift;
21
22     return 0 if (defined($env->{target}->checkin_time));
23     return 0 if (defined($env->{target}->xact_finish));
24
25     if ($env->{params}->{min_target_age}) {
26         $env->{params}->{target_age_field} = 'xact_start';
27         return 0 if (!$self->MinPassiveTargetAge($env));
28     }
29
30     $logger->info("AUTORENEW: CircIsOpen is TRUE!");
31     return 1;
32 }
33
34 sub MinPassiveTargetAge {
35     my $self = shift;
36     my $env = shift;
37     my $target = $env->{target};
38     my $delay_field = $env->{params}->{target_age_field} || $env->{event}->event_def->delay_field;
39
40     unless($env->{params}->{min_target_age}) {
41         $logger->warn("'min_target_age' parameter required for MinPassiveTargetAge validator");
42         return 0; # no-op false
43     }
44
45     unless($delay_field) {
46         $logger->warn("'target_age_field' parameter or delay_field required for MinPassiveTargetAge validator");
47         return 0; # no-op false
48     }
49
50     my $delay_field_ts = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($target->$delay_field()));
51
52     # to get the minimum time that the target must have aged to, add the min age to the delay field
53     $delay_field_ts->add( seconds => interval_to_seconds( $env->{params}->{min_target_age} ) );
54
55     return 1 if $delay_field_ts <= DateTime->now;
56     return 0;
57 }
58
59 sub CircIsOverdue {
60     my $self = shift;
61     my $env = shift;
62     my $circ = $env->{target};
63
64     return 0 if $circ->checkin_time;
65     return 0 if $circ->stop_fines and not $circ->stop_fines =~ /MAXFINES|LONGOVERDUE/;
66
67     if ($env->{params}->{min_target_age}) {
68         $env->{params}->{target_age_field} = 'xact_start';
69         return 0 if (!$self->MinPassiveTargetAge($env));
70     }
71
72     my $due_date = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($circ->due_date));
73     return 0 if $due_date > DateTime->now;
74
75     return 1;
76 }
77
78 sub HoldIsAvailable {
79     my $self = shift;
80     my $env = shift;
81
82     my $hold = $env->{target};
83
84     if ($env->{params}->{check_email_notify}) {
85         return 0 unless $U->is_true($hold->email_notify);
86     }
87     if ($env->{params}->{check_sms_notify}) {
88         return 0 unless $hold->sms_notify;
89     }
90     if ($env->{params}->{check_phone_notify}) {
91         return 0 unless $hold->phone_notify;
92     }
93
94     return 1 if 
95         !$hold->cancel_time and
96         !$hold->fulfillment_time and
97         $hold->current_shelf_lib and
98         (ref $hold->current_shelf_lib ? $hold->current_shelf_lib->id : $hold->current_shelf_lib)
99             eq (ref $hold->pickup_lib ? $hold->pickup_lib->id : $hold->pickup_lib) and
100         $hold->capture_time and # redundant
101         $hold->current_copy and # redundant
102         $hold->shelf_time and   # redundant
103         $hold->current_copy->status == OILS_COPY_STATUS_ON_HOLDS_SHELF; # redundant
104
105     return 0;
106 }
107
108 sub ReservationIsAvailable {
109     my $self = shift;
110     my $env = shift;
111     my $reservation = $env->{target};
112
113     return 1 if
114         !$reservation->cancel_time and
115         $reservation->capture_time and
116         $reservation->current_resource;
117
118     return 0;
119 }
120
121 sub HoldIsCancelled {
122     my $self = shift;
123     my $env = shift;
124
125     my $hold = $env->{target};
126
127     if ($env->{params}->{check_email_notify}) {
128         return 0 unless $U->is_true($hold->email_notify);
129     }
130     if ($env->{params}->{check_sms_notify}) {
131         return 0 unless $hold->sms_notify;
132     }
133     if ($env->{params}->{check_phone_notify}) {
134         return 0 unless $hold->phone_notify;
135     }
136
137     return ($hold->cancel_time) ? 1 : 0;
138 }
139
140 sub HoldNotifyCheck {
141     my $self = shift;
142     my $env = shift;
143
144     my $hold = $env->{target};
145
146     if ($env->{params}->{check_email_notify}) {
147         return 0 unless $U->is_true($hold->email_notify);
148     }
149     if ($env->{params}->{check_sms_notify}) {
150         return 0 unless $hold->sms_notify;
151     }
152     if ($env->{params}->{check_phone_notify}) {
153         return 0 unless $hold->phone_notify;
154     }
155
156     return 1;
157 }
158
159 # core_type au
160 sub PatronBarred {
161     my ($self, $env) = @_;
162     return $U->is_true($env->{target}->barred);
163 }
164
165 sub PatronNotBarred {
166     return !PatronBarred(@_);
167 }
168
169 # core type "circ".
170 # Being "In Collections" means having the PATRON_IN_COLLECTIONS penalty 
171 # applied to the user at or above the circ_lib of the target circ.
172 sub PatronNotInCollections {
173     my ($self, $env) = @_;
174     my $user = $env->{target}->usr;
175     my $org = $env->{target}->circ_lib;
176
177     # beware environment fleshing
178     $user = $user->id if ref $user;
179     $org = $org->id if ref $org;
180
181     my $existing = new_editor()->search_actor_user_standing_penalty({
182         usr => $user,
183         org_unit => $U->get_org_ancestors($org, 1),
184         standing_penalty => 30, # PATRON_IN_COLLECTIONS
185         '-or' => [
186             {stop_date => undef},
187             {stop_date => {'>' => 'now'}}
188         ]
189     });
190
191     return @$existing ? 0 : 1;
192 }
193
194 # core type circ in $env->{target}
195 sub CircIsAutoRenewable {
196     my $self = shift;
197     my $env = shift;
198
199     my $circ = $env->{target};
200     my $userId = $env->{target}->usr;
201     # 1. check if circ is open
202     if (!$self->CircIsOpen($env)){
203         return 0;
204     }
205
206     # 2. Check if patron is barred
207
208     my ($user, $res) = $U->fetch_user($userId);
209     if ( $U->is_true($user->barred()) ){
210
211         my %user_data = (
212             is_renewed => 0,
213             reason => 'Please contact your library about your account.',
214         );
215
216         $U->create_events_for_hook('autorenewal', $circ, $user->home_ou(), 'system_autorenewal', \%user_data);
217
218         return 0;
219     }
220
221     return 1;
222 }
223
224 1;