Bug 31203: Alter other cronjobs that currenlty use cronlogaction
[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 # These variables can be set by command line options,
168 # initially set to default values.
169
170 my $help    = 0;
171 my $man     = 0;
172 my $verbose = 0;
173 my $send_email = 0;
174 my $attachment = 0;
175 my $format  = "text";
176 my $to      = "";
177 my $from    = "";
178 my $subject = "";
179 my @params = ();
180 my $separator = ',';
181 my $quote = '"';
182 my $store_results = 0;
183 my $csv_header = 0;
184
185 my $username = undef;
186 my $password = undef;
187 my $method = 'LOGIN';
188
189 my $command_line_options = join(" ",@ARGV);
190
191 GetOptions(
192     'help|?'            => \$help,
193     'man'               => \$man,
194     'verbose'           => \$verbose,
195     'format=s'          => \$format,
196     'to=s'              => \$to,
197     'from=s'            => \$from,
198     'subject=s'         => \$subject,
199     'param=s'           => \@params,
200     'email'             => \$send_email,
201     'a|attachment'      => \$attachment,
202     'username:s'        => \$username,
203     'password:s'        => \$password,
204     'method:s'          => \$method,
205     'store-results'     => \$store_results,
206     'csv-header'        => \$csv_header,
207
208 ) or pod2usage(2);
209 pod2usage( -verbose => 2 ) if ($man);
210 pod2usage( -verbose => 2 ) if ($help and $verbose);
211 pod2usage(1) if $help;
212
213 cronlogaction({ info => $command_line_options });
214
215 unless ($format) {
216     $verbose and print STDERR "No format specified, assuming 'text'\n";
217     $format = 'text';
218 }
219
220 if ($format eq 'tsv' || $format eq 'text') {
221     $format = 'csv';
222     $separator = "\t";
223 }
224
225 if ($to or $from or $send_email) {
226     $send_email = 1;
227     $from or $from = C4::Context->preference('KohaAdminEmailAddress');
228     $to   or $to   = C4::Context->preference('KohaAdminEmailAddress');
229 }
230
231 unless (scalar(@ARGV)) {
232     print STDERR "ERROR: No reportID(s) specified\n";
233     pod2usage(1);
234 }
235 ($verbose) and print scalar(@ARGV), " argument(s) after options: " . join(" ", @ARGV) . "\n";
236
237 my $today = dt_from_string();
238 my $date = $today->ymd();
239
240 foreach my $report_id (@ARGV) {
241     my $report = Koha::Reports->find( $report_id );
242     unless ($report) {
243         warn "ERROR: No saved report $report_id found";
244         next;
245     }
246     my $sql         = $report->savedsql;
247     my $report_name = $report->report_name;
248     my $type        = $report->type;
249
250     $verbose and print "SQL: $sql\n\n";
251     if ( $subject eq "" )
252     {
253         if ( defined($report_name) and $report_name ne "")
254         {
255             $subject = $report_name ;
256         }
257         else
258         {
259             $subject = 'Koha Saved Report';
260         }
261     }
262
263     # convert SQL parameters to placeholders
264     my $params_needed = ( $sql =~ s/(<<[^>]+>>)/\?/g );
265     die("You supplied ". scalar @params . " parameter(s) and $params_needed are required by the report") if scalar @params != $params_needed;
266
267     my ($sth) = execute_query(
268         {
269             sql        => $sql,
270             sql_params => \@params,
271             report_id  => $report_id,
272         }
273     );
274     my $count = scalar($sth->rows);
275     unless ($count) {
276         print "NO OUTPUT: 0 results from execute_query\n";
277         next;
278     }
279     $verbose and print "$count results from execute_query\n";
280
281     my $message;
282     my @rows_to_store;
283     if ($format eq 'html') {
284         my $cgi = CGI->new();
285         my @rows;
286         while (my $line = $sth->fetchrow_arrayref) {
287             foreach (@$line) { defined($_) or $_ = ''; }    # catch undef values, replace w/ ''
288             push @rows, $cgi->TR( join('', $cgi->td($line)) ) . "\n";
289             push @rows_to_store, [@$line] if $store_results;
290         }
291         $message = $cgi->table(join "", @rows);
292     } elsif ($format eq 'csv') {
293         my $csv = Text::CSV::Encoded->new({
294             encoding_out => 'utf8',
295             binary      => 1,
296             quote_char  => $quote,
297             sep_char    => $separator,
298             });
299
300         if ( $csv_header ) {
301             my @fields = map { decode( 'utf8', $_ ) } @{ $sth->{NAME} };
302             $csv->combine( @fields );
303             $message .= $csv->string() . "\n";
304             push @rows_to_store, [@fields] if $store_results;
305         }
306
307         while (my $line = $sth->fetchrow_arrayref) {
308             $csv->combine(@$line);
309             $message .= $csv->string() . "\n";
310             push @rows_to_store, [@$line] if $store_results;
311         }
312         $message = Encode::decode_utf8($message);
313     }
314     if ( $store_results ) {
315         my $json = to_json( \@rows_to_store );
316         C4::Reports::Guided::store_results( $report_id, $json );
317     }
318     if ($send_email) {
319
320         my $email = Koha::Email->new(
321             {
322                 to      => $to,
323                 from    => $from,
324                 subject => $subject,
325             }
326         );
327
328         if ( $format eq 'html' ) {
329             $message = "<html><head><style>tr:nth-child(2n+1) { background-color: #ccc;}</style></head><body>$message</body></html>";
330             $email->html_body($message);
331         }
332         else {
333             $email->text_body($message);
334         }
335
336         $email->attach(
337             Encode::encode_utf8($message),
338             content_type => "text/$format",
339             name         => "report$report_id-$date.$format",
340             disposition  => 'attachment',
341         ) if $attachment;
342
343         my $smtp_server = Koha::SMTP::Servers->get_default;
344         $smtp_server->set(
345             {
346                 user_name => $username,
347                 password  => $password,
348             }
349         )
350             if $username;
351
352         $email->transport( $smtp_server->transport );
353         try {
354             $email->send_or_die;
355         }
356         catch {
357             carp "Mail not sent: $_";
358         };
359     }
360     else {
361         print $message;
362     }
363 }
364
365 cronlogaction({ action => 'End', info => "COMPLETED" });