]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Trigger.pm
fix active autocreate; add passive autocreate function (accepts optional object filter)
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Trigger.pm
1 package OpenILS::Application::Trigger;
2 use strict; use warnings;
3 use OpenILS::Application;
4 use base qw/OpenILS::Application/;
5
6 use OpenSRF::EX qw/:try/;
7
8 use OpenSRF::AppSession;
9 use OpenSRF::Utils::SettingsClient;
10 use OpenSRF::Utils::Logger qw/:level/;
11 use OpenSRF::Utils qw/:datetime/;
12
13 use DateTime;
14 use DateTime::Format::ISO8601;
15
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Utils::CStoreEditor q/:funcs/;
18 use OpenILS::Application::Trigger::Event;
19 use OpenILS::Application::Trigger::EventGroup;
20
21
22 my $log = 'OpenSRF::Utils::Logger';
23
24 sub initialize {}
25 sub child_init {}
26
27 sub create_active_events_for_object {
28     my $self = shift;
29     my $client = shift;
30     my $key = shift;
31     my $target = shift;
32     my $location = shift;
33
34     my $ident = $target->Identity;
35     my $ident_value = $target->$ident();
36
37     my $editor = new_editor(xact=>1);
38
39     my $hooks = $editor->search_action_trigger_hook(
40         { key       => $key,
41           core_type => $target->json_hint
42         }
43     );
44
45     my %hook_hash = map { ($_->key, $_) } @$hooks;
46
47     my $orgs = $editor->json_query({ from => [ 'actor.org_unit_ancestors' => $location ] });
48     my $defs = $editor->search_action_trigger_event_definition(
49         { hook   => [ keys %hook_hash ],
50           owner  => [ map { $_->{id} } @$orgs  ],
51           active => 't'
52         }
53     );
54
55     for my $def ( @$defs ) {
56
57         my $date = DateTime->now;
58
59         if ($hook_hash{$def->hook}->passive eq 'f') {
60
61             if (my $dfield = $def->delay_field) {
62                 if ($target->$dfield()) {
63                     $date = DateTime::Format::ISO8601->new->parse_datetime( clense_ISO8601($target->$dfield) );
64                 } else {
65                     next;
66                 }
67             }
68
69             $date->add( seconds => interval_to_seconds($def->delay) );
70         }
71
72         my $event = Fieldmapper::action_trigger::event->new();
73         $event->target( $ident_value );
74         $event->event_def( $def->id );
75         $event->run_time( $date->strftime( '%F %T%z' ) );
76
77         $editor->create_action_trigger_event( $event );
78
79         $client->respond( $event->id );
80     }
81
82     $editor->commit;
83
84     return undef;
85 }
86 __PACKAGE__->register_method(
87     api_name => 'open-ils.trigger.event.autocreate',
88     method   => 'create_active_events_for_object',
89     api_level=> 1,
90     stream   => 1,
91     argc     => 3
92 );
93
94 sub _fm_class_by_hint {
95     my $hint = shift;
96
97     my ($class) = grep {
98         Fieldmapper->publish_fieldmapper->{$_}->{hint} eq $hint
99     } keys %{ Fieldmapper->publish_fieldmapper };
100
101     return $class;
102 }
103
104 sub create_passive_events {
105     my $self = shift;
106     my $client = shift;
107     my $key = shift;
108     my $location_field = shift; # where to look for event_def.owner filtering ... circ_lib, for instance, where hook.core_type = circ
109     my $filter = shift || {};
110
111     return undef unless ($key && $location_field);
112
113     my $editor = new_editor(xact=>1);
114     my $hooks = $editor->search_action_trigger_hook(
115         { passive => 't', key => $key }
116     );
117
118     my %hook_hash = map { ($_->key, $_) } @$hooks;
119
120     my $defs = $editor->search_action_trigger_event_definition(
121         { hook   => [ keys %hook_hash ], active => 't' },
122     );
123
124     for my $def ( @$defs ) {
125
126         my $date = DateTime->now->subtract( seconds => interval_to_seconds($def->delay) );
127
128         my $orgs = $editor->json_query({ from => [ 'actor.org_unit_ancestors' => $location_field ] });
129
130         # we may need to do some work to backport this to 1.2
131         $filter->{ $location_field } = { 'in' =>
132             {
133                 select  => { aou => [{ column => 'id', transform => 'actor.org_unit_descendents', result_field => 'id' }] },
134                 from    => 'aou',
135                 where   => { id => $def->owner }
136             }
137         };
138
139         $filter->{ $def->delay_field } = {
140             '<=' => DateTime
141                 ->now
142                 ->subtract( seconds => interval_to_seconds($def->delay) )
143                 ->strftime( '%F %T%z' )
144         };
145
146         my $class = _fm_class_by_hint($hook_hash{$def->hook}->core_type);
147         $class =~ s/^Fieldmapper:://o;
148         $class =~ s/::/_/go;
149
150         my $method = 'search_'. $class;
151         my $objects = $editor->$method( $filter );
152
153         for my $o (@$objects) {
154
155             my $ident = $o->Identity;
156             my $ident_value = $o->$ident();
157
158             my $previous = $editor->search_action_trigger_event({
159                 event_def => $def->id,
160                 target    => $ident_value
161             });
162
163
164             # only allow one event of type $def for each target
165             next if (@$previous);
166
167             my $event = Fieldmapper::action_trigger::event->new();
168             $event->target( $ident_value );
169             $event->event_def( $def->id );
170             $event->run_time( 'now' );
171
172             $editor->create_action_trigger_event( $event );
173
174             $client->respond( $event->id );
175         }
176     }
177
178     $editor->commit;
179
180     return undef;
181 }
182 __PACKAGE__->register_method(
183     api_name => 'open-ils.trigger.passive.event.autocreate',
184     method   => 'create_passive_events',
185     api_level=> 1,
186     stream   => 1,
187     argc     => 3
188 );
189
190
191 sub fire_single_event {
192     my $self = shift;
193     my $client = shift;
194     my $event_id = shift;
195
196     my $e = OpenILS::Application::Trigger::Event->new($event_id);
197
198     if ($e->validate->valid) {
199         $e->react->cleanup;
200     }
201
202     return {
203         valid     => $e->valid,
204         reacted   => $e->reacted,
205         cleanedup => $e->cleanedup,
206         event     => $e->event
207     };
208 }
209 __PACKAGE__->register_method(
210     api_name => 'open-ils.trigger.event.fire',
211     method   => 'fire_single_event',
212     api_level=> 1,
213     argc     => 1
214 );
215
216 sub fire_event_group {
217     my $self = shift;
218     my $client = shift;
219     my $events = shift;
220
221     my $e = OpenILS::Application::Trigger::EventGroup->new(@$events);
222
223     if ($e->validate->valid) {
224         $e->react->cleanup;
225     }
226
227     return {
228         valid     => $e->valid,
229         reacted   => $e->reacted,
230         cleanedup => $e->cleanedup,
231         events    => [map { $_->event } @{$e->events}]
232     };
233 }
234 __PACKAGE__->register_method(
235     api_name => 'open-ils.trigger.event_group.fire',
236     method   => 'fire_event_group',
237     api_level=> 1,
238     argc     => 1
239 );
240
241 sub pending_events {
242     my $self = shift;
243     my $client = shift;
244
245     my $editor = new_editor();
246
247     return $editor->search_action_trigger_event([
248         { state => 'pending', run_time => {'<' => 'now'} },
249         { idlist=> 1 }
250     ]);
251 }
252 __PACKAGE__->register_method(
253     api_name => 'open-ils.trigger.event.find_pending',
254     method   => 'pending_events',
255     api_level=> 1
256 );
257
258
259 sub grouped_events {
260     my $self = shift;
261     my $client = shift;
262
263     my ($events) = $self->method_lookup('open-ils.trigger.event.find_pending')->run();
264
265     my %groups = ( '*' => [] );
266
267     for my $e_id ( @$events ) {
268         my $e = OpenILS::Application::Trigger::Event->new($e_id);
269         if ($e->validate->valid) {
270             if (my $group = $e->event->event_def->group_field) {
271
272                 # split the grouping link steps
273                 my @steps = split '.', $group;
274
275                 # find the grouping object
276                 my $node = $e->target;
277                 $node = $node->$_() for ( @steps );
278
279                 # get the pkey value for the grouping object on this event
280                 my $node_ident = $node->Identity;
281                 my $ident_value = $node->$node_ident();
282
283                 # push this event onto the event+grouping_pkey_value stack
284                 $groups{$e->event->event_def->id}{$ident_value} ||= [];
285                 push @{ $groups{$e->event->event_def->id}{$ident_value} }, $e;
286             } else {
287                 # it's a non-grouped event
288                 push @{ $groups{'*'} }, $e;
289             }
290         }
291     }
292
293     return \%groups;
294 }
295 __PACKAGE__->register_method(
296     api_name => 'open-ils.trigger.event.find_pending_by_group',
297     method   => 'grouped_events',
298     api_level=> 1
299 );
300
301 sub run_all_events {
302     my $self = shift;
303     my $client = shift;
304
305     my ($groups) = $self->method_lookup('open-ils.trigger.event.find_pending_by_group')->run();
306
307     for my $def ( %$groups ) {
308         if ($def eq '*') {
309             for my $event ( @{ $$groups{'*'} } ) {
310                 $client->respond(
311                     $self
312                         ->method_lookup('open-ils.trigger.event.fire')
313                         ->run($event)
314                 );
315             }
316         } else {
317             my $defgroup = $$groups{$def};
318             for my $ident ( keys %$defgroup ) {
319                 $client->respond(
320                     $self
321                         ->method_lookup('open-ils.trigger.event_group.fire')
322                         ->run($$defgroup{$ident})
323                 );
324             }
325         }
326     }
327                 
328             
329 }
330 __PACKAGE__->register_method(
331     api_name => 'open-ils.trigger.event.run_all_pending',
332     method   => 'run_all_events',
333     api_level=> 1
334 );
335
336
337 1;