Make Evergreen Perl modules installable via Module::Build to match OpenSRF
[working/Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Trigger / Reactor.pm
1 package OpenILS::Application::Trigger::Reactor;
2 use strict; use warnings;
3 use Template;
4 use DateTime;
5 use DateTime::Format::ISO8601;
6 use Unicode::Normalize;
7 use OpenSRF::Utils qw/:datetime/;
8 use OpenSRF::Utils::Logger qw(:logger);
9 use OpenILS::Application::AppUtils;
10 use OpenILS::Utils::CStoreEditor qw/:funcs/;
11 my $U = 'OpenILS::Application::AppUtils';
12
13 sub fourty_two { return 42 }
14 sub NOOP_True  { return  1 }
15 sub NOOP_False { return  0 }
16
17
18
19 # helper functions inserted into the TT environment
20 my $_TT_helpers = {
21
22     # turns a date into something TT can understand
23     format_date => sub {
24         my $date = shift;
25         $date = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($date));
26         return sprintf(
27             "%0.2d:%0.2d:%0.2d %0.2d-%0.2d-%0.4d",
28             $date->hour,
29             $date->minute,
30             $date->second,
31             $date->day,
32             $date->month,
33             $date->year
34         );
35     },
36
37     # escapes a string for inclusion in an XML document.  escapes &, <, and > characters
38     escape_xml => sub {
39         my $str = shift;
40         $str =~ s/&/&amp;/sog;
41         $str =~ s/</&lt;/sog;
42         $str =~ s/>/&gt;/sog;
43         return $str;
44     },
45
46     escape_json => sub {
47         my $str = shift;
48         $str =~ s/([\x{0080}-\x{fffd}])/sprintf('\u%0.4x',ord($1))/sgoe;
49         return $str;
50     },
51
52     # strip non-ASCII characters after splitting base characters and diacritics
53     # least common denominator for EDIFACT messages using the UNOB character set
54     force_jedi_unob => sub {
55         my $str = shift;
56         $str = NFD($str);
57         $str =~ s/[\x{0080}-\x{fffd}]//g;
58         return $str;
59     },
60
61     # returns the calculated user locale
62     get_user_locale => sub { 
63         my $user_id = shift;
64         return $U->get_user_locale($user_id);
65     },
66
67     # returns the calculated copy price
68     get_copy_price => sub {
69         my $copy_id = shift;
70         return $U->get_copy_price(new_editor(xact=>1), $copy_id);
71     },
72
73     # given a copy, returns the title and author in a hash
74     get_copy_bib_basics => sub {
75         my $copy_id = shift;
76         my $copy = new_editor(xact=>1)->retrieve_asset_copy([
77             $copy_id,
78             {
79                 flesh => 2,
80                 flesh_fields => {
81                     acp => ['call_number'],
82                     acn => ['record']
83                 }
84             }
85         ]);
86         if($copy->call_number->id == -1) {
87             return {
88                 title  => $copy->dummy_title,
89                 author => $copy->dummy_author,
90             };
91         } else {
92             my $mvr = $U->record_to_mvr($copy->call_number->record);
93             return {
94                 title  => $mvr->title,
95                 author => $mvr->author
96             };
97         }
98     },
99
100     # returns the org unit setting value
101     get_org_setting => sub {
102         my($org_id, $setting) = @_;
103         return $U->ou_ancestor_setting_value($org_id, $setting);
104     },
105
106     # This basically greps/maps out ths isbn string values, but also promotes the first isbn-13 to the
107     # front of the line (so that the EDI translator takes it as primary) if there is one.
108     get_li_isbns => sub {
109         my $attrs = shift;
110         my @isbns;
111         my $primary;
112         foreach (@$attrs) {
113             $_->attr_name eq 'isbn' or next;
114             my $val = $_->attr_value;
115             if (! $primary and length($val) == 13) {
116                 $primary = $val;
117             } else {
118                 push @isbns, $val;
119             }
120         }
121         $primary and unshift @isbns, $primary;
122         $logger->debug("get_li_isbns returning isbns: " . join(', ', @isbns));
123         return @isbns;
124     },
125
126     # helpers.get_li_attr('isbn_13', li.attributes)
127     # returns matching line item attribute, or undef
128     get_li_attr => sub {
129         my $name = shift or return;     # the first arg is always the name
130         my ($type, $attr) = (scalar(@_) == 1) ? (undef, $_[0]) : @_;
131         # if the next is the last, it's the attributes, otherwise type
132         # use Data::Dumper; $logger->warn("get_li_attr: " . Dumper($attr));
133         ($name and @$attr) or return;
134         my $length;
135         $name =~ s/^(\D+)_(\d+)$/$1/ and $length = $2;
136         foreach (@$attr) {
137             $_->attr_name eq $name or next;
138             next if $length and $length != length($_->attr_value);
139             return $_->attr_value if (! $type) or $type eq $_->attr_type;
140         }
141         return;
142     },
143 };
144
145
146 # processes templates.  Returns template output on success, undef on error
147 sub run_TT {
148     my $self = shift;
149     my $env = shift;
150     my $nostore = shift;
151     return undef unless $env->{template};
152
153     my $error;
154     my $output = '';
155     my $tt = Template->new;
156     # my $tt = Template->new(ENCODING => 'utf8');   # ??
157     $env->{helpers} = $_TT_helpers;
158
159     unless( $tt->process(\$env->{template}, $env, \$output) ) {
160         $output = undef;
161         ($error = $tt->error) =~ s/\n/ /og;
162         $logger->error("Error processing Trigger template: $error");
163     }
164
165     if ( $error or (!$nostore && $output) ) {
166         my $t_o = Fieldmapper::action_trigger::event_output->new;
167         $t_o->data( ($error) ? $error : $output );
168         $t_o->is_error( ($error) ? 't' : 'f' );
169         $logger->info("trigger: writing " . length($t_o->data) . " bytes to template output");
170
171         $env->{EventProcessor}->editor->xact_begin;
172         $t_o = $env->{EventProcessor}->editor->create_action_trigger_event_output( $t_o );
173
174         my $state = (ref $$env{event} eq 'ARRAY') ? $$env{event}->[0]->state : $env->{event}->state;
175         my $key = ($error) ? 'error_output' : 'template_output';
176         $env->{EventProcessor}->update_state( $state, { $key => $t_o->id } );
177     }
178         
179     return $output;
180 }
181
182
183 1;