db909a51b1918d90b0162fad2082d978f53deb89
[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 sub fourty_two { return 42 }
11 sub NOOP_True { return 1 }
12 sub NOOP_False { return 0 }
13
14 my $U = 'OpenILS::Application::AppUtils';
15
16 sub CircIsOpen {
17     my $self = shift;
18     my $env = shift;
19
20     return 0 if (defined($env->{target}->checkin_time));
21
22     if ($env->{params}->{min_target_age}) {
23         $env->{params}->{target_age_field} = 'xact_start';
24         return 0 if (!$self->MinPassiveTargetAge($env));
25     }
26
27     return 1;
28 }
29
30 sub MinPassiveTargetAge {
31     my $self = shift;
32     my $env = shift;
33     my $target = $env->{target};
34     my $delay_field = $env->{params}->{target_age_field} || $env->{event}->event_def->delay_field;
35
36     unless($env->{params}->{min_target_age}) {
37         $logger->warn("'min_target_age' parameter required for MinPassiveTargetAge validator");
38         return 0; # no-op false
39     }
40
41     unless($delay_field) {
42         $logger->warn("'target_age_field' parameter or delay_field required for MinPassiveTargetAge validator");
43         return 0; # no-op false
44     }
45
46     my $delay_field_ts = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($target->$delay_field()));
47
48     # to get the minimum time that the target must have aged to, add the min age to the delay field
49     $delay_field_ts->add( seconds => interval_to_seconds( $env->{params}->{min_target_age} ) );
50
51     return 1 if $delay_field_ts <= DateTime->now;
52     return 0;
53 }
54
55 sub CircIsOverdue {
56     my $self = shift;
57     my $env = shift;
58     my $circ = $env->{target};
59
60     return 0 if $circ->checkin_time;
61     return 0 if $circ->stop_fines and not $circ->stop_fines =~ /MAXFINES|LONGOVERDUE/;
62
63     if ($env->{params}->{min_target_age}) {
64         $env->{params}->{target_age_field} = 'xact_start';
65         return 0 if (!$self->MinPassiveTargetAge($env));
66     }
67
68     my $due_date = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($circ->due_date));
69     return 0 if $due_date > DateTime->now;
70
71     return 1;
72 }
73
74 sub HoldIsAvailable {
75     my $self = shift;
76     my $env = shift;
77
78     my $hold = $env->{target};
79
80     if ($env->{params}->{check_email_notify}) {
81         return 0 unless $U->is_true($hold->email_notify);
82     }
83     if ($env->{params}->{check_sms_notify}) {
84         return 0 unless $hold->sms_notify;
85     }
86     if ($env->{params}->{check_phone_notify}) {
87         return 0 unless $hold->phone_notify;
88     }
89
90     return 1 if 
91         !$hold->cancel_time and
92         !$hold->fulfillment_time and
93         $hold->current_shelf_lib and
94         (ref $hold->current_shelf_lib ? $hold->current_shelf_lib->id : $hold->current_shelf_lib)
95             eq (ref $hold->pickup_lib ? $hold->pickup_lib->id : $hold->pickup_lib) and
96         $hold->capture_time and # redundant
97         $hold->current_copy and # redundant
98         $hold->shelf_time and   # redundant
99         $hold->current_copy->status == OILS_COPY_STATUS_ON_HOLDS_SHELF; # redundant
100
101     return 0;
102 }
103
104 sub ReservationIsAvailable {
105     my $self = shift;
106     my $env = shift;
107     my $reservation = $env->{target};
108
109     return 1 if
110         !$reservation->cancel_time and
111         $reservation->capture_time and
112         $reservation->current_resource;
113
114     return 0;
115 }
116
117 sub HoldIsCancelled {
118     my $self = shift;
119     my $env = shift;
120
121     my $hold = $env->{target};
122
123     if ($env->{params}->{check_email_notify}) {
124         return 0 unless $U->is_true($hold->email_notify);
125     }
126     if ($env->{params}->{check_sms_notify}) {
127         return 0 unless $hold->sms_notify;
128     }
129     if ($env->{params}->{check_phone_notify}) {
130         return 0 unless $hold->phone_notify;
131     }
132
133     return ($hold->cancel_time) ? 1 : 0;
134 }
135
136 sub HoldNotifyCheck {
137     my $self = shift;
138     my $env = shift;
139
140     my $hold = $env->{target};
141
142     if ($env->{params}->{check_email_notify}) {
143         return 0 unless $U->is_true($hold->email_notify);
144     }
145     if ($env->{params}->{check_sms_notify}) {
146         return 0 unless $hold->sms_notify;
147     }
148     if ($env->{params}->{check_phone_notify}) {
149         return 0 unless $hold->phone_notify;
150     }
151
152     return 1;
153 }
154
155 # core_type au
156 sub PatronBarred {
157     my ($self, $env) = @_;
158     return $U->is_true($env->{target}->barred);
159 }
160
161 sub PatronNotBarred {
162     return !PatronBarred(@_);
163 }
164
165 # core type "circ".
166 # Being "In Collections" means having the PATRON_IN_COLLECTIONS penalty 
167 # applied to the user at or above the circ_lib of the target circ.
168 sub PatronNotInCollections {
169     my ($self, $env) = @_;
170     my $user = $env->{target}->usr;
171     my $org = $env->{target}->circ_lib;
172
173     # beware environment fleshing
174     $user = $user->id if ref $user;
175     $org = $org->id if ref $org;
176
177     my $existing = new_editor()->search_actor_user_standing_penalty({
178         usr => $user,
179         org_unit => $U->get_org_ancestors($org, 1),
180         standing_penalty => 30, # PATRON_IN_COLLECTIONS
181         '-or' => [
182             {stop_date => undef},
183             {stop_date => {'>' => 'now'}}
184         ]
185     });
186
187     return @$existing ? 0 : 1;
188 }
189
190
191 1;