Koha/reports/guided_reports.pl
Chris Nighswonger 953a46a088 kohabug 2417 Removing hardcoded query limit from reports
This patch removes a hardcoded 'LIMIT 20' which was added to all report queries
thus limiting all reports to only the first twenty rows of applicable data. In
its place this patch introduces code to paginate through all applicable data,
regardless of how many rows are available. The code will also honor any user
defined 'LIMIT' in reports based on SQL entered directly by the user.

This patch also adds column labels to 'tab' and 'csv' files generated by reports.
NOTE: Only user defined 'LIMIT's apply to 'tab,' 'csv,' and 'text' files.

Signed-off-by: Galen Charlton <galen.charlton@liblime.com>
Signed-off-by: Joshua Ferraro <jmf@liblime.com>
2008-08-04 15:26:50 -05:00

419 lines
11 KiB
Perl
Executable file

#!/usr/bin/perl
# Copyright 2007 Liblime ltd
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA
use strict;
use CGI;
use C4::Reports;
use C4::Auth;
use C4::Output;
use C4::Dates qw( DHTMLcalendar );
use C4::Debug;
=head1 NAME
Script to control the guided report creation
=head1 DESCRIPTION
=over2
=cut
my $input = new CGI;
my $referer = $input->referer();
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
{
template_name => "reports/guided_reports_start.tmpl",
query => $input,
type => "intranet",
authnotrequired => 0,
flagsrequired => { editcatalogue => 1 },
debug => 1,
}
);
my $phase = $input->param('phase');
my $no_html = 0; # this will be set if we dont want to print out an html::template
if ( !$phase ) {
$template->param( 'start' => 1 );
# show welcome page
}
elsif ( $phase eq 'Build new' ) {
# build a new report
$template->param( 'build1' => 1 );
# get report areas
my $areas = C4::Reports::get_report_areas();
$template->param( 'areas' => $areas );
}
elsif ( $phase eq 'Used saved' ) {
# use a saved report
# get list of reports and display them
$template->param( 'saved1' => 1 );
my $reports = get_saved_reports();
$template->param( 'savedreports' => $reports );
}
elsif ( $phase eq 'Delete Saved') {
# delete a report from the saved reports list
$no_html = 1;
my $id = $input->param('reports');
delete_report($id);
print $input->redirect("/cgi-bin/koha/reports/guided_reports.pl?phase=Used%20saved");
}
elsif ( $phase eq 'Show SQL'){
my $id = $input->param('reports');
my $sql = get_sql($id);
$template->param(
'sql' => $sql,
'showsql' => 1,
);
}
elsif ($phase eq 'retrieve results') {
my $id = $input->param('id');
my ($results,$name,$notes) = format_results($id);
# do something
$template->param(
'retresults' => 1,
'results' => $results,
'name' => $name,
'notes' => $notes,
);
}
elsif ( $phase eq 'Report on this Area' ) {
# they have choosen a new report and the area to report on
# get area
my $area = $input->param('areas');
$template->param(
'build2' => 1,
'area' => $area
);
# get report types
my $types = C4::Reports::get_report_types();
$template->param( 'types' => $types );
}
elsif ( $phase eq 'Choose this type' ) {
# they have chosen type and area
# get area and type and pass them to the template
my $area = $input->param('area');
my $type = $input->param('types');
$template->param(
'build3' => 1,
'area' => $area,
'type' => $type,
);
# get columns
my $columns = get_columns($area,$input);
$template->param( 'columns' => $columns );
}
elsif ( $phase eq 'Choose these columns' ) {
# we now know type, area, and columns
# next step is the constraints
my $area = $input->param('area');
my $type = $input->param('type');
my @columns = $input->param('columns');
my $column = join( ',', @columns );
my $definitions = get_from_dictionary($area);
$template->param(
'build4' => 1,
'area' => $area,
'type' => $type,
'column' => $column,
);
my $criteria = get_criteria($area,$input);
$template->param( 'criteria' => $criteria,
'definitions' => $definitions);
}
elsif ( $phase eq 'Choose these criteria' ) {
my $area = $input->param('area');
my $type = $input->param('type');
my $column = $input->param('column');
my @definitions = $input->param('definition');
my $definition = join (',',@definitions);
my @criteria = $input->param('criteria_column');
my $query_criteria;
foreach my $crit (@criteria) {
my $value = $input->param( $crit . "_value" );
if ($value) {
if ($value =~ C4::Dates->regexp(C4::Context->preference('dateformat'))) {
my $date = C4::Dates->new($value);
$value = $date->output("iso");
}
$query_criteria .= " AND $crit='$value'";
}
}
$template->param(
'build5' => 1,
'area' => $area,
'type' => $type,
'column' => $column,
'definition' => $definition,
'criteriastring' => $query_criteria,
);
# get columns
my @columns = split( ',', $column );
my @total_by;
# build structue for use by tmpl_loop to choose columns to order by
# need to do something about the order of the order :)
# we also want to use the %columns hash to get the plain english names
foreach my $col (@columns) {
my %total;
$total{'name'} = $col;
my @selects;
my %select1;
$select1{'value'} = 'sum';
push @selects, \%select1;
my %select2;
$select2{'value'} = 'min';
push @selects, \%select2;
my %select3;
$select3{'value'} = 'max';
push @selects, \%select3;
my %select4;
$select4{'value'} = 'avg';
push @selects, \%select4;
my %select5;
$select5{'value'} = 'count';
push @selects, \%select5;
$total{'select'} = \@selects;
push @total_by, \%total;
}
$template->param( 'total_by' => \@total_by );
}
elsif ( $phase eq 'Choose These Operations' ) {
my $area = $input->param('area');
my $type = $input->param('type');
my $column = $input->param('column');
my $criteria = $input->param('criteria');
my $definition = $input->param('definition');
my @total_by = $input->param('total_by');
my $totals;
foreach my $total (@total_by) {
my $value = $input->param( $total . "_tvalue" );
$totals .= "$value($total),";
}
$template->param(
'build6' => 1,
'area' => $area,
'type' => $type,
'column' => $column,
'criteriastring' => $criteria,
'totals' => $totals,
'definition' => $definition,
);
# get columns
my @columns = split( ',', $column );
my @order_by;
# build structue for use by tmpl_loop to choose columns to order by
# need to do something about the order of the order :)
foreach my $col (@columns) {
my %order;
$order{'name'} = $col;
my @selects;
my %select1;
$select1{'value'} = 'asc';
push @selects, \%select1;
my %select2;
$select2{'value'} = 'desc';
push @selects, \%select2;
$order{'select'} = \@selects;
push @order_by, \%order;
}
$template->param( 'order_by' => \@order_by );
}
elsif ( $phase eq 'Build Report' ) {
# now we have all the info we need and can build the sql
my $area = $input->param('area');
my $type = $input->param('type');
my $column = $input->param('column');
my $crit = $input->param('criteria');
my $totals = $input->param('totals');
my $definition = $input->param('definition');
# my @criteria = split( ',', $crit );
my $query_criteria=$crit;
# split the columns up by ,
my @columns = split( ',', $column );
my @order_by = $input->param('order_by');
my $query_orderby;
foreach my $order (@order_by) {
my $value = $input->param( $order . "_ovalue" );
if ($query_orderby) {
$query_orderby .= ",$order $value";
}
else {
$query_orderby = " ORDER BY $order $value";
}
}
# get the sql
my $sql =
build_query( \@columns, $query_criteria, $query_orderby, $area, $totals, $definition );
$template->param(
'showreport' => 1,
'sql' => $sql,
'type' => $type
);
}
elsif ( $phase eq 'Save' ) {
# Save the report that has just been built
my $sql = $input->param('sql');
my $type = $input->param('type');
$template->param(
'save' => 1,
'sql' => $sql,
'type' => $type
);
}
elsif ( $phase eq 'Save Report' ) {
# save the sql pasted in by a user
my $sql = $input->param('sql');
my $name = $input->param('reportname');
my $type = $input->param('type');
my $notes = $input->param('notes');
save_report( $sql, $name, $type, $notes );
$template->param(
'save_successful' => 1,
);
}
# This condition is not used currently
#elsif ( $phase eq 'Execute' ) {
# # run the sql, and output results in a template
# my $sql = $input->param('sql');
# my $type = $input->param('type');
# my $results = execute_query($sql, $type);
# $template->param(
# 'results' => $results,
# 'sql' => $sql,
# 'execute' => 1,
# );
#}
elsif ($phase eq 'Run this report'){
# execute a saved report
# FIXME: The default limit should not be hardcoded...
my $limit = 20;
my $offset;
my $report = $input->param('reports');
# offset algorithm
if ($input->param('page')) {
$offset = ($input->param('page') - 1) * 20;
} else {
$offset = 0;
}
my ($sql,$type,$name,$notes) = get_saved_report($report);
my ($results, $total) = execute_query($sql, $type, $offset, $limit);
my $totpages = int($total/$limit) + (($total % $limit) > 0 ? 1 : 0);
my $url = "/cgi-bin/koha/reports/guided_reports.pl?reports=$report&phase=Run%20this%20report";
$template->param(
'results' => $results,
'sql' => $sql,
'execute' => 1,
'name' => $name,
'notes' => $notes,
'pagination_bar' => pagination_bar($url, $totpages, $input->param('page'), "page"),
);
}
elsif ($phase eq 'Export'){
# export results to tab separated text
my $sql = $input->param('sql');
$no_html=1;
print $input->header( -type => 'application/octet-stream',
-attachment=>'reportresults.csv');
my $format=$input->param('format');
my $results = execute_query($sql,1,0,0,$format);
print $results;
}
elsif ($phase eq 'Create report from SQL'){
# alllow the user to paste in sql
$template->param('create' => 1);
my $types = C4::Reports::get_report_types();
$template->param( 'types' => $types );
}
elsif ($phase eq 'Create Compound Report'){
my $reports = get_saved_reports();
$template->param( 'savedreports' => $reports,
'compound' => 1,
);
}
elsif ($phase eq 'Save Compound'){
my $master = $input->param('master');
my $subreport = $input->param('subreport');
# my $compound_report = create_compound($master,$subreport);
# my $results = run_compound($compound_report);
my ($mastertables,$subtables) = create_compound($master,$subreport);
$template->param( 'save_compound' => 1,
master=>$mastertables,
subsql=>$subtables
);
}
$template->param( 'referer' => $referer,
'DHTMLcalendar_dateformat' => C4::Dates->DHTMLcalendar(),
);
if (!$no_html){
output_html_with_http_headers $input, $cookie, $template->output;
}