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