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