Bug 32519: In Elasticsearch mappings table use of search field name and label
[koha.git] / misc / cronjobs / runreport.pl
1 #!/usr/bin/perl
2 #
3 # Copyright 2008 Liblime
4 # Copyright 2014 Foundations Bible College, Inc.
5 #
6 # This file is part of Koha.
7 #
8 # Koha is free software; you can redistribute it and/or modify it
9 # under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # Koha is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20
21 use Modern::Perl;
22
23 use Koha::Script -cron;
24 use C4::Reports::Guided qw( store_results execute_query );
25 use Koha::Reports;
26 use C4::Context;
27 use C4::Log qw( cronlogaction );
28 use Koha::Email;
29 use Koha::DateUtils qw( dt_from_string );
30 use Koha::SMTP::Servers;
31
32 use Getopt::Long qw( GetOptions );
33 use Pod::Usage qw( pod2usage );
34 use Text::CSV::Encoded;
35 use CGI qw ( -utf8 );
36 use Carp qw( carp );
37 use Encode qw( decode );
38 use JSON qw( to_json );
39 use Try::Tiny qw( catch try );
40
41 =head1 NAME
42
43 runreport.pl - Run pre-existing saved reports
44
45 =head1 SYNOPSIS
46
47 runreport.pl [ -h | -m ] [ -v ] reportID [ reportID ... ]
48
49  Options:
50    -h --help       brief help message
51    -m --man        full documentation, same as --help --verbose
52    -v --verbose    verbose output
53
54    --format=s      selects format. Choice of text, html, csv or tsv
55
56    -e --email      whether to use e-mail (implied by --to or --from)
57    -a --attachment additionally attach the report as a file. cannot be used with html format
58    --username      username to pass to the SMTP server for authentication
59    --password      password to pass to the SMTP server for authentication
60    --method        method is the type of authentication. Ie. LOGIN, DIGEST-MD5, etc.
61    --to=s          e-mail address to send report to
62    --from=s        e-mail address to send report from
63    --subject=s     subject for the e-mail
64    --param=s      parameters for the report
65    --store-results store the result of the report
66    --csv-header    add column names as first line of csv output
67
68
69  Arguments:
70    reportID        report ID Number from saved_sql.id, multiple ID's may be specified
71
72 =head1 OPTIONS
73
74 =over
75
76 =item B<--help>
77
78 Print a brief help message and exits.
79
80 =item B<--man>
81
82 Prints the manual page and exits.
83
84 =item B<-v>
85
86 Verbose. Without this flag set, only fatal errors are reported.
87
88 =item B<--format>
89
90 Current options are text, html, csv, and tsv. At the moment, text and tsv both produce tab-separated tab-separated output.
91
92 =item B<--email>
93
94 Whether to use e-mail (implied by --to or --from).
95
96 =item B<--username>
97
98 Username to pass to the SMTP server for authentication
99
100 =item B<--password>
101
102 Password to pass to the SMTP server for authentication
103
104 =item B<--method>
105
106 Method is the type of authentication. Ie. LOGIN, DIGEST-MD5, etc.
107
108 =item B<--to>
109
110 E-mail address to send report to. Defaults to KohaAdminEmailAddress.
111
112 =item B<--from>
113
114 E-mail address to send report from. Defaults to KohaAdminEmailAddress.
115
116 =item B<--subject>
117
118 Subject for the e-mail message. Defaults to "Koha Saved Report"
119
120 =item B<--param>
121
122 Repeatable, should provide one param per param requested for the report.
123 Report params are not combined as on the staff side, so you may need to repeat
124 params.
125
126 =item B<--store-results>
127
128 Store the result of the report into the saved_reports DB table.
129
130 To access the results, go on Reports > Guided reports > Saved report.
131
132 =back
133
134 =head1 DESCRIPTION
135
136 This script is designed to run existing Saved Reports.
137
138 =head1 USAGE EXAMPLES
139
140 B<runreport.pl 16>
141
142 In the most basic form, runs the report specified by ID number from 
143 saved_sql.id, in this case #16, outputting the results to STDOUT.  
144
145 B<runreport.pl 16 17>
146
147 Same as above, but also runs report #17. 
148
149 =head1 TO DO
150
151 =over
152
153
154 =item *
155
156 Allow Saved Results option.
157
158
159 =back
160
161 =head1 SEE ALSO
162
163 Reports - Guided Reports
164
165 =cut
166
167 binmode STDOUT, ":encoding(UTF-8)";
168
169 # These variables can be set by command line options,
170 # initially set to default values.
171
172 my $help    = 0;
173 my $man     = 0;
174 my $verbose = 0;
175 my $send_email = 0;
176 my $attachment = 0;
177 my $format  = "text";
178 my $to      = "";
179 my $from    = "";
180 my $subject = "";
181 my @params = ();
182 my $separator = ',';
183 my $quote = '"';
184 my $store_results = 0;
185 my $csv_header = 0;
186
187 my $username = undef;
188 my $password = undef;
189 my $method = 'LOGIN';
190
191 my $command_line_options = join(" ",@ARGV);
192
193 GetOptions(
194     'help|?'            => \$help,
195     'man'               => \$man,
196     'verbose'           => \$verbose,
197     'format=s'          => \$format,
198     'to=s'              => \$to,
199     'from=s'            => \$from,
200     'subject=s'         => \$subject,
201     'param=s'           => \@params,
202     'email'             => \$send_email,
203     'a|attachment'      => \$attachment,
204     'username:s'        => \$username,
205     'password:s'        => \$password,
206     'method:s'          => \$method,
207     'store-results'     => \$store_results,
208     'csv-header'        => \$csv_header,
209
210 ) or pod2usage(2);
211 pod2usage( -verbose => 2 ) if ($man);
212 pod2usage( -verbose => 2 ) if ($help and $verbose);
213 pod2usage(1) if $help;
214
215 cronlogaction({ info => $command_line_options });
216
217 unless ($format) {
218     $verbose and print STDERR "No format specified, assuming 'text'\n";
219     $format = 'text';
220 }
221
222 if ($format eq 'tsv' || $format eq 'text') {
223     $format = 'csv';
224     $separator = "\t";
225 }
226
227 if ($to or $from or $send_email) {
228     $send_email = 1;
229     $from or $from = C4::Context->preference('KohaAdminEmailAddress');
230     $to   or $to   = C4::Context->preference('KohaAdminEmailAddress');
231 }
232
233 unless (scalar(@ARGV)) {
234     print STDERR "ERROR: No reportID(s) specified\n";
235     pod2usage(1);
236 }
237 ($verbose) and print scalar(@ARGV), " argument(s) after options: " . join(" ", @ARGV) . "\n";
238
239 my $today = dt_from_string();
240 my $date = $today->ymd();
241
242 foreach my $report_id (@ARGV) {
243     my $report = Koha::Reports->find( $report_id );
244     unless ($report) {
245         warn "ERROR: No saved report $report_id found";
246         next;
247     }
248     my $sql         = $report->savedsql;
249     my $report_name = $report->report_name;
250     my $type        = $report->type;
251
252     $verbose and print "SQL: $sql\n\n";
253     if ( $subject eq "" )
254     {
255         if ( defined($report_name) and $report_name ne "")
256         {
257             $subject = $report_name ;
258         }
259         else
260         {
261             $subject = 'Koha Saved Report';
262         }
263     }
264
265     # convert SQL parameters to placeholders
266     my $params_needed = ( $sql =~ s/(<<[^>]+>>)/\?/g );
267     die("You supplied ". scalar @params . " parameter(s) and $params_needed are required by the report") if scalar @params != $params_needed;
268
269     my ($sth) = execute_query(
270         {
271             sql        => $sql,
272             sql_params => \@params,
273             report_id  => $report_id,
274         }
275     );
276     my $count = scalar($sth->rows);
277     unless ($count) {
278         print "NO OUTPUT: 0 results from execute_query\n";
279         next;
280     }
281     $verbose and print "$count results from execute_query\n";
282
283     my $message;
284     my @rows_to_store;
285     if ($format eq 'html') {
286         my $cgi = CGI->new();
287         my @rows;
288         while (my $line = $sth->fetchrow_arrayref) {
289             foreach (@$line) { defined($_) or $_ = ''; }    # catch undef values, replace w/ ''
290             push @rows, $cgi->TR( join('', $cgi->td($line)) ) . "\n";
291             push @rows_to_store, [@$line] if $store_results;
292         }
293         $message = $cgi->table(join "", @rows);
294     } elsif ($format eq 'csv') {
295         my $csv = Text::CSV::Encoded->new({
296             encoding_out => 'utf8',
297             binary      => 1,
298             quote_char  => $quote,
299             sep_char    => $separator,
300             });
301
302         if ( $csv_header ) {
303             my @fields = map { decode( 'utf8', $_ ) } @{ $sth->{NAME} };
304             $csv->combine( @fields );
305             $message .= $csv->string() . "\n";
306             push @rows_to_store, [@fields] if $store_results;
307         }
308
309         while (my $line = $sth->fetchrow_arrayref) {
310             $csv->combine(@$line);
311             $message .= $csv->string() . "\n";
312             push @rows_to_store, [@$line] if $store_results;
313         }
314         $message = Encode::decode_utf8($message);
315     }
316     if ( $store_results ) {
317         my $json = to_json( \@rows_to_store );
318         C4::Reports::Guided::store_results( $report_id, $json );
319     }
320     if ($send_email) {
321
322         my $email = Koha::Email->new(
323             {
324                 to      => $to,
325                 from    => $from,
326                 subject => $subject,
327             }
328         );
329
330         if ( $format eq 'html' ) {
331             $message = "<html><head><style>tr:nth-child(2n+1) { background-color: #ccc;}</style></head><body>$message</body></html>";
332             $email->html_body($message);
333         }
334         else {
335             $email->text_body($message);
336         }
337
338         $email->attach(
339             Encode::encode_utf8($message),
340             content_type => "text/$format",
341             name         => "report$report_id-$date.$format",
342             disposition  => 'attachment',
343         ) if $attachment;
344
345         my $smtp_server = Koha::SMTP::Servers->get_default;
346         $smtp_server->set(
347             {
348                 user_name => $username,
349                 password  => $password,
350             }
351         )
352             if $username;
353
354         $email->transport( $smtp_server->transport );
355         try {
356             $email->send_or_die;
357         }
358         catch {
359             carp "Mail not sent: $_";
360         };
361     }
362     else {
363         print $message;
364     }
365 }
366
367 cronlogaction({ action => 'End', info => "COMPLETED" });