]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/EventGroup.pm
LP1958573 PMC messages created by action triggers not patron-visible
[Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Trigger / EventGroup.pm
1 package OpenILS::Application::Trigger::EventGroup;
2 use strict; use warnings;
3 use OpenILS::Application::Trigger::Event;
4 use base 'OpenILS::Application::Trigger::Event';
5 use OpenSRF::EX qw/:try/;
6
7 use OpenSRF::Utils::Logger qw/$logger/;
8
9 use OpenILS::Utils::Fieldmapper;
10 use OpenILS::Utils::CStoreEditor q/:funcs/;
11 use OpenILS::Application::Trigger::ModRunner;
12
13 my $log = 'OpenSRF::Utils::Logger';
14
15 sub new_impl {
16     my $class = shift;
17     my @ids = @{shift()};
18     my $nochanges = shift;
19
20     $class = ref($class) || $class;
21
22     my $editor = new_editor(xact=>1);
23
24     my $self = bless {
25         environment => {},
26         events      => [
27             map {
28                 ref($_) ?
29                     do { $_->standalone(0); $_->editor($editor); $_ } :
30                     OpenILS::Application::Trigger::Event->new($_, $editor, $nochanges)
31             } @ids
32         ],
33         ids         => [ map { ref($_) ? $_->id : $_ } @ids ],
34         editor      => $editor
35     } => $class;
36
37
38     $self->editor->xact_commit; # flush out those updates
39     $self->editor->xact_begin;
40
41     return $self;
42 }
43
44 sub new_nochanges {
45     my $class = shift;
46     my @ids = @_;
47
48     return new_impl($class, \@ids, 1);
49 }
50
51 sub new {
52     my $class = shift;
53     my @ids = @_;
54
55     return new_impl($class, \@ids);
56 }
57
58 sub react {
59     my $self = shift;
60
61     return $self if (defined $self->reacted);
62
63     if ($self->valid) {
64         $self->update_state( 'reacting') || die 'Unable to update event group state';
65         $self->build_environment;
66
67         try {
68             my $env = $self->environment;
69             my $reactor = OpenILS::Application::Trigger::ModRunner::Reactor->new(
70                 $self->event->event_def->reactor,
71                 $env
72             );
73
74             $self->reacted( $reactor->run->final_result);
75
76             if ($env->{usr_message}{usr} && $env->{usr_message}{template}) {
77                 my $message_template_output =
78                     $reactor->pass('ProcessMessage')->run->final_result;
79
80                 if ($message_template_output) {
81                     my $usr_message = Fieldmapper::actor::usr_message->new;
82                     $usr_message->title( $env->{usr_message}{title} || $self->event->event_def->name );
83                     $usr_message->message( $message_template_output );
84                     $usr_message->usr( $env->{usr_message}{usr}->id );
85                     $usr_message->sending_lib( $env->{usr_message}{sending_lib}->id );
86                     $usr_message->pub('t');
87
88                     if ($self->editor->xact_begin) {
89                         if ($self->editor->create_actor_usr_message( $usr_message )) {
90                             $self->editor->xact_commit;
91                         } else {
92                             $self->editor->xact_rollback;
93                         }
94                     }
95                 }
96             }
97
98         } otherwise {
99             $log->error("Event reacting failed with ". shift() );
100             $self->update_state( 'error' ) || die 'Unable to update event group state';
101         };
102
103         if (defined $self->reacted) {
104             $self->update_state( 'reacted' ) || die 'Unable to update event group state';
105         } else {
106             $self->update_state( 'error' ) || die 'Unable to update event group state';
107         }
108     } else {
109         $self->{reacted} = undef;
110     }
111     return $self;
112 }
113
114 sub validate {
115     my $self = shift;
116
117     return $self if (defined $self->valid);
118
119     $self->update_state( 'validating') || die 'Unable to update event group state';
120     $self->editor->xact_begin;
121
122     my @valid_events;
123     try {
124         for my $event ( @{ $self->events } ) {
125             $event->validate;
126             push @valid_events, $event if ($event->valid);
127         }
128         $self->valid(1) if (@valid_events);
129         $self->{events} = \@valid_events;
130         $self->{ids} = [ map { $_->id } @valid_events ];
131         $self->editor->xact_commit;
132     } otherwise {
133         $log->error("Event group validation failed with ". shift() );
134         $self->editor->xact_rollback;
135         $self->update_state( 'error' ) || die 'Unable to update event group state';
136     };
137
138     return $self;
139 }
140  
141 sub revalidate_test {
142     my $self = shift;
143
144     $self->editor->xact_begin;
145
146     my @valid_events;
147     try {
148         for my $event ( @{ $self->events } ) {
149             push @valid_events, $event->id if $event->revalidate_test;
150         }
151         $self->editor->xact_rollback;
152     } otherwise {
153         $log->error("Event group validation failed with ". shift());
154         $self->editor->xact_rollback;
155     };
156
157     return \@valid_events;
158 }
159  
160 sub cleanedup {
161     my $self = shift;
162     return undef unless (ref $self);
163
164     my $c = shift;
165     $self->{cleanedup} = $c if (defined $c);
166     return $self->{cleanedup};
167 }
168
169 sub reacted {
170     my $self = shift;
171     return undef unless (ref $self);
172
173     my $r = shift;
174     $self->{reacted} = $r if (defined $r);
175     return $self->{reacted};
176 }
177
178 sub valid {
179     my $self = shift;
180     return undef unless (ref $self);
181
182     my $v = shift;
183     $self->{valid} = $v if (defined $v);
184     return $self->{valid};
185 }
186
187 sub event {
188     my $self = shift;
189     return undef unless (ref $self);
190
191     return $self->{events}[0]->event;
192 }
193
194 sub events {
195     my $self = shift;
196     return undef unless (ref $self);
197
198     return $self->{events};
199 }
200
201 sub ids {
202     my $self = shift;
203     return undef unless (ref $self);
204
205     return $self->{ids};
206 }
207
208 sub environment {
209     my $self = shift;
210     return undef unless (ref $self);
211
212     my $e = shift;
213     $self->{environment} = $e if (defined $e);
214     return $self->{environment};
215 }
216
217 sub editor {
218     my $self = shift;
219     return undef unless (ref $self);
220
221     my $e = shift;
222     $self->{editor} = $e if (defined $e);
223     return $self->{editor};
224 }
225
226 sub unfind {
227     my $self = shift;
228     return undef unless (ref $self);
229
230     die 'Cannot unfind a reacted event group' if (defined $self->reacted);
231
232     $self->update_state( 'pending' ) || die 'Unable to update event group state';
233     $self->{events} = undef;
234     return $self;
235 }
236
237 sub update_state {
238     my $self = shift;
239     return undef unless ($self && ref $self);
240
241     my $state = shift;
242     return undef unless ($state);
243
244     my $fields = shift;
245
246     $self->editor->xact_begin || return undef;
247
248     my @oks;
249     my $ok;
250     my $last_updated;
251     for my $event ( @{ $self->events } ) {
252         my $e = $self->editor->retrieve_action_trigger_event( $event->id );
253         $e->start_time( 'now' ) unless $e->start_time;
254         $e->update_time( 'now' );
255         $e->update_process( $$ );
256         $e->state( $state );
257
258         $e->clear_start_time() if ($e->state eq 'pending');
259
260         $e->complete_time('now')
261             if ($e->state eq 'complete' && !$e->complete_time);
262
263         if ($fields && ref($fields)) {
264             $e->$_($$fields{$_}) for (keys %$fields);
265         }
266
267         my $ok = $self->editor->update_action_trigger_event( $e );
268         if ($ok) {
269             push @oks, $ok;
270             $last_updated = $e->id;
271         }
272     }
273
274     if (scalar(@oks) < scalar(@{ $self->ids })) {
275         $self->editor->xact_rollback;
276         return undef;
277     } 
278
279     my $updated = $self->editor->retrieve_action_trigger_event($last_updated);
280     $ok = $self->editor->xact_commit;
281
282     if ($ok) {
283         for my $event ( @{ $self->events } ) {
284             my $e = $event->event;
285             $e->start_time( $updated->start_time );
286             $e->update_time( $updated->update_time );
287             $e->update_process( $updated->update_process );
288             $e->state( $updated->state );
289         }
290     }
291
292     return $ok || undef;
293 }
294
295 sub findEvent {
296     my $self = shift;
297     my $member = shift;
298
299     $member = $member->id if (ref($member));
300
301     my @list = grep { $member == $_->id } @{ $self->events };
302
303     return shift(@list);
304 }
305
306 sub build_environment {
307     my $self = shift;
308     my $env = $self->environment;
309
310     $$env{EventProcessor} = $self;
311     $$env{target} = [];
312     $$env{event} = [];
313     $$env{user_data} = [];
314     for my $e ( @{ $self->events } ) {
315         for my $env_part ( keys %{ $e->environment } ) {
316             next if ($env_part eq 'EventProcessor');
317             if ($env_part eq 'target') {
318                 push @{ $$env{target} }, $e->environment->{target};
319             } elsif ($env_part eq 'event') {
320                 push @{ $$env{event} }, $e->environment->{event};
321             } elsif ($env_part eq 'user_data') {
322                 push @{ $$env{user_data} }, $e->environment->{user_data};
323             } else {
324                 $$env{$env_part} = $e->environment->{$env_part};
325             }
326         }
327     }
328
329     return $self;
330 }
331
332 1;