Can now add definitions to reports
[koha.git] / reports / guided_reports.pl
1 #!/usr/bin/perl
2
3 # Copyright 2007 Liblime ltd
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19 use CGI::Carp qw(fatalsToBrowser);
20 use strict;
21 use C4::Auth;
22 use CGI;
23 use C4::Output;
24 use C4::Reports;
25
26 =head1 NAME
27
28 Script to control the guided report creation
29
30 =head1 DESCRIPTION
31
32
33 =over2
34
35 =cut
36
37 my $input = new CGI;
38 my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
39     {
40         template_name   => "reports/guided_reports_start.tmpl",
41         query           => $input,
42         type            => "intranet",
43         authnotrequired => 0,
44         flagsrequired   => { editcatalogue => 1 },
45         debug           => 1,
46     }
47 );
48
49 my $phase = $input->param('phase');
50 my $no_html = 0; # this will be set if we dont want to print out an html::template
51
52 if ( !$phase ) {
53     $template->param( 'start' => 1 );
54
55     # show welcome page
56 }
57
58 elsif ( $phase eq 'Build new' ) {
59
60     # build a new report
61     $template->param( 'build1' => 1 );
62
63     # get report areas
64     my $areas = C4::Reports::get_report_areas();
65     $template->param( 'areas' => $areas );
66
67 }
68
69 elsif ( $phase eq 'Used saved' ) {
70
71     # use a saved report
72     # get list of reports and display them
73     $template->param( 'saved1' => 1 );
74     my $reports = get_saved_reports();
75     $template->param( 'savedreports' => $reports );
76 }
77
78 elsif ( $phase eq 'Report on this Area' ) {
79
80     # they have choosen a new report and the area to report on
81     # get area
82     my $area = $input->param('areas');
83     $template->param(
84         'build2' => 1,
85         'area'   => $area
86     );
87
88     # get report types
89     my $types = C4::Reports::get_report_types();
90     $template->param( 'types' => $types );
91 }
92
93 elsif ( $phase eq 'Choose this type' ) {
94
95     # they have chosen type and area
96     # get area and type and pass them to the template
97     my $area = $input->param('area');
98     my $type = $input->param('types');
99     $template->param(
100         'build3' => 1,
101         'area'   => $area,
102         'type'   => $type,
103     );
104
105     # get columns
106     my $columns = get_columns($area);
107     $template->param( 'columns' => $columns );
108 }
109
110 elsif ( $phase eq 'Choose these columns' ) {
111
112     # we now know type, area, and columns
113     # next step is the constraints
114     my $area    = $input->param('area');
115     my $type    = $input->param('type');
116     my @columns = $input->param('columns');
117     my $column  = join( ',', @columns );
118         my $definitions = get_from_dictionary($area);
119     $template->param(
120         'build4' => 1,
121         'area'   => $area,
122         'type'   => $type,
123         'column' => $column,
124     );
125     my $criteria = get_criteria($area);
126     $template->param( 'criteria' => $criteria,
127         'definitions' => $definitions);
128 }
129
130 elsif ( $phase eq 'Choose these criteria' ) {
131     my $area     = $input->param('area');
132     my $type     = $input->param('type');
133     my $column   = $input->param('column');
134         my @definitions = $input->param('definition');
135         my $definition = join (',',@definitions);
136     my @criteria = $input->param('criteria_column');
137         my $query_criteria;
138     foreach my $crit (@criteria) {
139         my $value = $input->param( $crit . "_value" );
140         if ($value) {
141             $query_criteria .= " AND $crit='$value'";
142         }
143     }
144
145     $template->param(
146         'build5'         => 1,
147         'area'           => $area,
148         'type'           => $type,
149         'column'         => $column,
150                 'definition'     => $definition,
151         'criteriastring' => $query_criteria,
152     );
153
154     # get columns
155     my @columns = split( ',', $column );
156     my @total_by;
157
158     # build structue for use by tmpl_loop to choose columns to order by
159     # need to do something about the order of the order :)
160         # we also want to use the %columns hash to get the plain english names
161     foreach my $col (@columns) {
162         my %total;
163         $total{'name'} = $col;
164         my @selects;
165         my %select1;
166         $select1{'value'} = 'sum';
167         push @selects, \%select1;
168         my %select2;
169         $select2{'value'} = 'min';
170         push @selects, \%select2;
171         my %select3;
172         $select3{'value'} = 'max';
173         push @selects, \%select3;
174         my %select4;
175         $select4{'value'} = 'avg';
176         push @selects, \%select4;
177         my %select5;
178         $select5{'value'} = 'count';
179         push @selects, \%select5;
180
181         $total{'select'} = \@selects;
182         push @total_by, \%total;
183     }
184
185     $template->param( 'total_by' => \@total_by );
186 }
187
188 elsif ( $phase eq 'Choose Totals' ) {
189     my $area     = $input->param('area');
190     my $type     = $input->param('type');
191     my $column   = $input->param('column');
192     my $criteria = $input->param('criteria');
193         my $definition = $input->param('definition');
194     my @total_by = $input->param('total_by');
195     my $totals;
196     foreach my $total (@total_by) {
197         my $value = $input->param( $total . "_tvalue" );
198         $totals .= "$value($total),";
199     }
200
201     $template->param(
202         'build6'         => 1,
203         'area'           => $area,
204         'type'           => $type,
205         'column'         => $column,
206         'criteriastring' => $criteria,
207         'totals'         => $totals,
208                 'definition'    => $definition,
209     );
210
211     # get columns
212     my @columns = split( ',', $column );
213     my @order_by;
214
215     # build structue for use by tmpl_loop to choose columns to order by
216     # need to do something about the order of the order :)
217     foreach my $col (@columns) {
218         my %order;
219         $order{'name'} = $col;
220         my @selects;
221         my %select1;
222         $select1{'value'} = 'asc';
223         push @selects, \%select1;
224         my %select2;
225         $select2{'value'} = 'desc';
226         push @selects, \%select2;
227         $order{'select'} = \@selects;
228         push @order_by, \%order;
229     }
230
231     $template->param( 'order_by' => \@order_by );
232 }
233
234 elsif ( $phase eq 'Build Report' ) {
235
236     # now we have all the info we need and can build the sql
237     my $area     = $input->param('area');
238     my $type     = $input->param('type');
239     my $column   = $input->param('column');
240     my $crit     = $input->param('criteria');
241     my $totals   = $input->param('totals');
242         my $definition = $input->param('definition');
243 #    my @criteria = split( ',', $crit );
244     my $query_criteria=$crit;
245     # split the columns up by ,
246     my @columns = split( ',', $column );
247     my @order_by = $input->param('order_by');
248
249     my $query_orderby;
250     foreach my $order (@order_by) {
251         my $value = $input->param( $order . "_ovalue" );
252         if ($query_orderby) {
253             $query_orderby .= ",$order $value";
254         }
255         else {
256             $query_orderby = " ORDER BY $order $value";
257         }
258     }
259
260     # get the sql
261     my $sql =
262       build_query( \@columns, $query_criteria, $query_orderby, $area, $totals, $definition );
263     $template->param(
264         'showreport' => 1,
265         'sql'        => $sql,
266         'type'       => $type
267     );
268 }
269
270 elsif ( $phase eq 'Save' ) {
271         # Save the report that has just been built
272     my $sql  = $input->param('sql');
273     my $type = $input->param('type');
274     $template->param(
275         'save' => 1,
276         'sql'  => $sql,
277         'type' => $type
278     );
279 }
280
281 elsif ( $phase eq 'Save Report' ) {
282     # save the sql pasted in by a user 
283     my $sql  = $input->param('sql');
284     my $name = $input->param('reportname');
285     my $type = $input->param('type');
286         my $notes = $input->param('notes');
287     save_report( $sql, $name, $type, $notes );
288 }
289
290 elsif ( $phase eq 'Execute' ) {
291         # run the sql, and output results in a template 
292     my $sql     = $input->param('sql');
293     my $type    = $input->param('type');
294     my $results = execute_query($sql,$type);
295     $template->param(
296         'results' => $results,
297                 'sql' => $sql,
298         'execute' => 1
299     );
300 }
301
302 elsif ($phase eq 'Run this report'){
303     # execute a saved report
304         my $report = $input->param('reports');
305         my ($sql,$type) = get_saved_report($report);
306         my $results = execute_query($sql,$type);
307     $template->param(
308         'results' => $results,
309                 'sql' => $sql,
310         'execute' => 1
311     );
312 }       
313
314 elsif ($phase eq 'Export'){
315         # export results to tab separated text
316         my $sql     = $input->param('sql');
317         $no_html=1;
318         print $input->header(   -type => 'application/octet-stream',
319                   -attachment=>'reportresults.csv');
320         my $format=$input->param('format');
321         my $results = execute_query($sql,1,$format);
322         print $results;
323         
324 }
325
326 elsif ($phase eq 'Create report from SQL'){
327         # alllow the user to paste in sql 
328         $template->param('create' => 1);
329          my $types = C4::Reports::get_report_types();
330         $template->param( 'types' => $types ); 
331 }
332
333 elsif ($phase eq 'Create Compound Report'){
334         my $reports = get_saved_reports();  
335         $template->param( 'savedreports' => $reports,
336                 'compound' => 1,
337         );
338 }
339
340 elsif ($phase eq 'Save Compound'){
341     my $master = $input->param('master');
342         my $subreport = $input->param('subreport');
343 #       my $compound_report = create_compound($master,$subreport);
344 #       my $results = run_compound($compound_report);
345         my ($mastertables,$subtables) = create_compound($master,$subreport);
346         $template->param( 'save_compound' => 1,
347                 master=>$mastertables,
348                 subsql=>$subtables
349         );
350 }
351
352 elsif ($phase eq 'View Dictionary'){
353         # view the dictionary we use to set up abstract variables such as all borrowers over fifty who live in a certain town
354         ( $template, $borrowernumber, $cookie ) = get_template_and_user(
355     {
356         template_name   => "reports/dictionary.tmpl",
357         query           => $input,
358         type            => "intranet",
359         authnotrequired => 0,
360         flagsrequired   => { editcatalogue => 1 },
361         debug           => 1,
362     }
363         );
364         my $areas = C4::Reports::get_report_areas();
365         my $definitions = get_from_dictionary();
366         $template->param( 'areas' => $areas ,
367                 'start_dictionary' => 1,
368                 'definitions' => $definitions,
369         );
370 }
371 elsif ($phase eq 'Add New Definition'){
372         # display form allowing them to add a new definition
373         ( $template, $borrowernumber, $cookie ) = get_template_and_user(
374     {
375         template_name   => "reports/dictionary.tmpl",
376         query           => $input,
377         type            => "intranet",
378         authnotrequired => 0,
379         flagsrequired   => { editcatalogue => 1 },
380         debug           => 1,
381     }
382         );
383
384         $template->param( 'new_dictionary' => 1,
385                 );
386 }
387
388 elsif ($phase eq 'New Term step 2'){
389         # Choosing the area
390         ( $template, $borrowernumber, $cookie ) = get_template_and_user(
391     {
392         template_name   => "reports/dictionary.tmpl",
393         query           => $input,
394         type            => "intranet",
395         authnotrequired => 0,
396         flagsrequired   => { editcatalogue => 1 },
397         debug           => 1,
398     }
399         );
400         my $areas = C4::Reports::get_report_areas();
401         my $definition_name=$input->param('definition_name');
402         my $definition_description=$input->param('definition_description');             
403         $template->param( 'step_2' => 1,
404                 'areas' => $areas,
405                 'definition_name' => $definition_name,
406                 'definition_description' => $definition_description,
407         );
408 }
409
410 elsif ($phase eq 'New Term step 3'){
411         # Choosing the columns
412         ( $template, $borrowernumber, $cookie ) = get_template_and_user(
413     {
414         template_name   => "reports/dictionary.tmpl",
415         query           => $input,
416         type            => "intranet",
417         authnotrequired => 0,
418         flagsrequired   => { editcatalogue => 1 },
419         debug           => 1,
420     }
421         );
422         my $area = $input->param('areas');
423         my $columns = get_columns($area);
424         my $definition_name=$input->param('definition_name');
425         my $definition_description=$input->param('definition_description');             
426         $template->param( 'step_3' => 1,
427                 'area' => $area,
428                 'columns' => $columns,
429                 'definition_name' => $definition_name,
430                 'definition_description' => $definition_description,
431         );
432 }
433
434 elsif ($phase eq 'New Term step 4'){
435         # Choosing the values
436         ( $template, $borrowernumber, $cookie ) = get_template_and_user(
437     {
438         template_name   => "reports/dictionary.tmpl",
439         query           => $input,
440         type            => "intranet",
441         authnotrequired => 0,
442         flagsrequired   => { editcatalogue => 1 },
443         debug           => 1,
444     }
445         );
446         my $area=$input->param('area');
447         my $definition_name=$input->param('definition_name');
448         my $definition_description=$input->param('definition_description');             
449     my @columns = $input->param('columns');
450         my $columnstring = join (',',@columns);
451         my @column_loop;
452         foreach my $column (@columns){
453                 my %tmp_hash;
454                 $tmp_hash{'name'}=$column;
455                 my $type =get_column_type($column);
456                 if ($type eq 'distinct'){
457                         my $values = get_distinct_values($column);
458                         $tmp_hash{'values'} = $values;
459                         $tmp_hash{'distinct'} = 1;
460                           
461                 }
462                 if ($type eq 'DATE'){
463                         $tmp_hash{'date'}=1;
464                 }
465 #               else {
466 #                       die $type;#
467 #                       }
468                 push @column_loop,\%tmp_hash;
469                 }
470
471         $template->param( 'step_4' => 1,
472                 'area' => $area,
473                 'definition_name' => $definition_name,
474                 'definition_description' => $definition_description,
475                 'columns' => \@column_loop,
476                 'columnstring' => $columnstring,
477
478         );
479 }
480
481 elsif ($phase eq 'New Term step 5'){
482         # Confirmation screen
483         ( $template, $borrowernumber, $cookie ) = get_template_and_user(
484     {
485         template_name   => "reports/dictionary.tmpl",
486         query           => $input,
487         type            => "intranet",
488         authnotrequired => 0,
489         flagsrequired   => { editcatalogue => 1 },
490         debug           => 1,
491     }
492         );
493         my $area = $input->param('area');
494         my $columnstring = $input->param('columnstring');
495         my $definition_name=$input->param('definition_name');
496         my $definition_description=$input->param('definition_description');     
497         my @criteria = $input->param('criteria_column'); 
498         my $query_criteria;
499         my @criteria_loop;
500         foreach my $crit (@criteria) {
501                 my $value = $input->param( $crit . "_value" );
502                 if ($value) {
503                         $query_criteria .= " AND $crit='$value'";
504                         my %tmp_hash;
505                         $tmp_hash{'name'}=$crit;
506                         $tmp_hash{'value'} = $value;
507                         push @criteria_loop,\%tmp_hash;
508                 }
509                 
510                 $value = $input->param( $crit . "_start_value" );
511                 if ($value) {
512                         $query_criteria .= " AND $crit > '$value'";
513                         my %tmp_hash;
514                         $tmp_hash{'name'}="$crit Start";
515                         $tmp_hash{'value'} = $value;
516                         push @criteria_loop,\%tmp_hash;
517                 }
518                 $value = $input->param( $crit . "_end_value" );
519                 if ($value) {
520                         $query_criteria .= " AND $crit <= '$value'";
521                         my %tmp_hash;
522                         $tmp_hash{'name'}="$crit End";
523                         $tmp_hash{'value'} = $value;
524                         push @criteria_loop,\%tmp_hash;
525                 }                 
526         }
527         $template->param( 'step_5' => 1,
528                 'area' => $area,
529                 'definition_name' => $definition_name,
530                 'definition_description' => $definition_description,
531                 'query' => $query_criteria,
532                 'columnstring' => $columnstring,
533                 'criteria_loop' => \@criteria_loop,
534         );
535 }
536
537 elsif ($phase eq 'New Term step 6'){
538         # Choosing the columns
539         ( $template, $borrowernumber, $cookie ) = get_template_and_user(
540     {
541         template_name   => "reports/dictionary.tmpl",
542         query           => $input,
543         type            => "intranet",
544         authnotrequired => 0,
545         flagsrequired   => { editcatalogue => 1 },
546         debug           => 1,
547     }
548         );
549         my $area = $input->param('area');
550         my $definition_name=$input->param('definition_name');
551         my $definition_description=$input->param('definition_description');             
552         my $sql=$input->param('sql');
553         save_dictionary($definition_name,$definition_description,$sql,$area);
554         $template->param( 'step_6' => 1,
555                 'area' => $area,
556                 'definition_name' => $definition_name,
557                 'definition_description' => $definition_description,
558         );
559 }
560 elsif ($phase eq 'Delete Definition'){
561         $no_html=1;
562         my $id = $input->param('id');
563         delete_definition($id);
564         print $input->redirect("/cgi-bin/koha/reports/guided_reports.pl?phase=View%20Dictionary");
565         }
566
567 if (!$no_html){
568         output_html_with_http_headers $input, $cookie, $template->output;
569 }