1 package OpenILS::Application::Trigger;
2 use strict; use warnings;
3 use OpenILS::Application;
4 use base qw/OpenILS::Application/;
6 use OpenSRF::EX qw/:try/;
8 use OpenSRF::AppSession;
9 use OpenSRF::Utils::SettingsClient;
10 use OpenSRF::Utils::Logger qw/:level/;
11 use OpenSRF::Utils qw/:datetime/;
14 use DateTime::Format::ISO8601;
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Utils::CStoreEditor q/:funcs/;
18 use OpenILS::Application::Trigger::Event;
19 use OpenILS::Application::Trigger::EventGroup;
22 my $log = 'OpenSRF::Utils::Logger';
27 sub create_active_events_for_object {
34 my $ident = $target->Identity;
35 my $ident_value = $target->$ident();
37 my $editor = new_editor(xact=>1);
39 my $hooks = $editor->search_action_trigger_hook(
41 core_type => $target->json_hint
45 my %hook_hash = map { ($_->key, $_) } @$hooks;
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 ],
55 for my $def ( @$defs ) {
57 my $date = DateTime->now;
59 if ($hook_hash{$def->hook}->passive eq 'f') {
61 if (my $dfield = $def->delay_field) {
62 if ($target->$dfield()) {
63 $date = DateTime::Format::ISO8601->new->parse_datetime( clense_ISO8601($target->$dfield) );
69 $date->add( seconds => interval_to_seconds($def->delay) );
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' ) );
77 $editor->create_action_trigger_event( $event );
79 $client->respond( $event->id );
86 __PACKAGE__->register_method(
87 api_name => 'open-ils.trigger.event.autocreate',
88 method => 'create_active_events_for_object',
94 sub _fm_class_by_hint {
98 Fieldmapper->publish_fieldmapper->{$_}->{hint} eq $hint
99 } keys %{ Fieldmapper->publish_fieldmapper };
104 sub create_passive_events {
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 || {};
111 return undef unless ($key && $location_field);
113 my $editor = new_editor(xact=>1);
114 my $hooks = $editor->search_action_trigger_hook(
115 { passive => 't', key => $key }
118 my %hook_hash = map { ($_->key, $_) } @$hooks;
120 my $defs = $editor->search_action_trigger_event_definition(
121 { hook => [ keys %hook_hash ], active => 't' },
124 for my $def ( @$defs ) {
126 my $date = DateTime->now->subtract( seconds => interval_to_seconds($def->delay) );
128 my $orgs = $editor->json_query({ from => [ 'actor.org_unit_ancestors' => $location_field ] });
130 # we may need to do some work to backport this to 1.2
131 $filter->{ $location_field } = { 'in' =>
133 select => { aou => [{ column => 'id', transform => 'actor.org_unit_descendents', result_field => 'id' }] },
135 where => { id => $def->owner }
139 $filter->{ $def->delay_field } = {
142 ->subtract( seconds => interval_to_seconds($def->delay) )
143 ->strftime( '%F %T%z' )
146 my $class = _fm_class_by_hint($hook_hash{$def->hook}->core_type);
147 $class =~ s/^Fieldmapper:://o;
150 my $method = 'search_'. $class;
151 my $objects = $editor->$method( $filter );
153 for my $o (@$objects) {
155 my $ident = $o->Identity;
156 my $ident_value = $o->$ident();
158 my $previous = $editor->search_action_trigger_event({
159 event_def => $def->id,
160 target => $ident_value
164 # only allow one event of type $def for each target
165 next if (@$previous);
167 my $event = Fieldmapper::action_trigger::event->new();
168 $event->target( $ident_value );
169 $event->event_def( $def->id );
170 $event->run_time( 'now' );
172 $editor->create_action_trigger_event( $event );
174 $client->respond( $event->id );
182 __PACKAGE__->register_method(
183 api_name => 'open-ils.trigger.passive.event.autocreate',
184 method => 'create_passive_events',
191 sub fire_single_event {
194 my $event_id = shift;
196 my $e = OpenILS::Application::Trigger::Event->new($event_id);
198 if ($e->validate->valid) {
204 reacted => $e->reacted,
205 cleanedup => $e->cleanedup,
209 __PACKAGE__->register_method(
210 api_name => 'open-ils.trigger.event.fire',
211 method => 'fire_single_event',
216 sub fire_event_group {
221 my $e = OpenILS::Application::Trigger::EventGroup->new(@$events);
223 if ($e->validate->valid) {
229 reacted => $e->reacted,
230 cleanedup => $e->cleanedup,
231 events => [map { $_->event } @{$e->events}]
234 __PACKAGE__->register_method(
235 api_name => 'open-ils.trigger.event_group.fire',
236 method => 'fire_event_group',
245 my $editor = new_editor();
247 return $editor->search_action_trigger_event([
248 { state => 'pending', run_time => {'<' => 'now'} },
252 __PACKAGE__->register_method(
253 api_name => 'open-ils.trigger.event.find_pending',
254 method => 'pending_events',
263 my ($events) = $self->method_lookup('open-ils.trigger.event.find_pending')->run();
265 my %groups = ( '*' => [] );
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) {
272 # split the grouping link steps
273 my @steps = split '.', $group;
275 # find the grouping object
276 my $node = $e->target;
277 $node = $node->$_() for ( @steps );
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();
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;
287 # it's a non-grouped event
288 push @{ $groups{'*'} }, $e;
295 __PACKAGE__->register_method(
296 api_name => 'open-ils.trigger.event.find_pending_by_group',
297 method => 'grouped_events',
305 my ($groups) = $self->method_lookup('open-ils.trigger.event.find_pending_by_group')->run();
307 for my $def ( %$groups ) {
309 for my $event ( @{ $$groups{'*'} } ) {
312 ->method_lookup('open-ils.trigger.event.fire')
317 my $defgroup = $$groups{$def};
318 for my $ident ( keys %$defgroup ) {
321 ->method_lookup('open-ils.trigger.event_group.fire')
322 ->run($$defgroup{$ident})
330 __PACKAGE__->register_method(
331 api_name => 'open-ils.trigger.event.run_all_pending',
332 method => 'run_all_events',