MT 1443 : better reports on items
[koha.git] / C4 / Reports / Guided.pm
1 package C4::Reports::Guided;
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
20 use strict;
21 # use warnings;  # FIXME: this module needs a lot of repair to run clean under warnings
22 use CGI;
23 use Carp;
24
25 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
26 use C4::Context;
27 use C4::Dates qw/format_date/;
28 use C4::Output;
29 use C4::Dates;
30 use XML::Simple;
31 use XML::Dumper;
32 use Switch;
33 use C4::Debug;
34 # use Smart::Comments;
35 # use Data::Dumper;
36
37 BEGIN {
38         # set the version for version checking
39         $VERSION = 0.12;
40         require Exporter;
41         @ISA = qw(Exporter);
42         @EXPORT = qw(
43                 get_report_types get_report_areas get_columns build_query get_criteria
44             save_report get_saved_reports execute_query get_saved_report create_compound run_compound
45                 get_column_type get_distinct_values save_dictionary get_from_dictionary
46                 delete_definition delete_report format_results get_sql
47         select_2_select_count_value update_sql
48         );
49 }
50
51 our %table_areas;
52 $table_areas{'1'} =
53   [ 'borrowers', 'statistics','items', 'biblioitems' ];    # circulation
54 $table_areas{'2'} = [ 'items', 'biblioitems', 'biblio' ];   # catalogue
55 $table_areas{'3'} = [ 'borrowers' ];        # patrons
56 $table_areas{'4'} = ['aqorders', 'biblio', 'items'];        # acquisitions
57 $table_areas{'5'} = [ 'borrowers', 'accountlines' ];        # accounts
58 our %keys;
59 $keys{'1'} = [
60     'statistics.borrowernumber=borrowers.borrowernumber',
61     'items.itemnumber = statistics.itemnumber',
62     'biblioitems.biblioitemnumber = items.biblioitemnumber'
63 ];
64 $keys{'2'} = [
65     'items.biblioitemnumber=biblioitems.biblioitemnumber',
66     'biblioitems.biblionumber=biblio.biblionumber'
67 ];
68 $keys{'3'} = [ ];
69 $keys{'4'} = [
70         'aqorders.biblionumber=biblio.biblionumber',
71         'biblio.biblionumber=items.biblionumber'
72 ];
73 $keys{'5'} = ['borrowers.borrowernumber=accountlines.borrowernumber'];
74
75 # have to do someting here to know if its dropdown, free text, date etc
76
77 our %criteria;
78 $criteria{'1'} = [
79     'statistics.type',   'borrowers.categorycode',
80     'statistics.branch',
81     'biblioitems.publicationyear|date',
82     'items.dateaccessioned|date'
83 ];
84 $criteria{'2'} =
85   [ 'items.itemnumber|textrange', 'items.biblionumber|textrange', 'items.barcode|textrange', 'items.holdingbranch', 'items.homebranch', 'items.onloan|daterange', 'items.ccode', 'items.itemcallnumber|textrange', 'items.itype', 'items.itemlost', 'items.location' ];
86 $criteria{'3'} = ['borrowers.branchcode'];
87 $criteria{'4'} = ['aqorders.datereceived|date'];
88 $criteria{'5'} = ['borrowers.branchcode'];
89
90 if (C4::Context->preference('item-level_itypes')) {
91     unshift @{ $criteria{'1'} }, 'items.itype';
92     unshift @{ $criteria{'2'} }, 'items.itype';
93 } else {
94     unshift @{ $criteria{'1'} }, 'biblioitems.itemtype';
95     unshift @{ $criteria{'2'} }, 'biblioitems.itemtype';
96 }
97
98 =head1 NAME
99    
100 C4::Reports::Guided - Module for generating guided reports 
101
102 =head1 SYNOPSIS
103
104   use C4::Reports::Guided;
105
106 =head1 DESCRIPTION
107
108
109 =head1 METHODS
110
111 =over 2
112
113 =cut
114
115 =item get_report_types()
116
117 This will return a list of all the available report types
118
119 =cut
120
121 sub get_report_types {
122     my $dbh = C4::Context->dbh();
123
124     # FIXME these should be in the database perhaps
125     my @reports = ( 'Tabular', 'Summary', 'Matrix' );
126     my @reports2;
127     for ( my $i = 0 ; $i < 3 ; $i++ ) {
128         my %hashrep;
129         $hashrep{id}   = $i + 1;
130         $hashrep{name} = $reports[$i];
131         push @reports2, \%hashrep;
132     }
133     return ( \@reports2 );
134
135 }
136
137 =item get_report_areas()
138
139 This will return a list of all the available report areas
140
141 =cut
142
143 sub get_report_areas {
144     my $dbh = C4::Context->dbh();
145
146     # FIXME these should be in the database
147     my @reports = ( 'Circulation', 'Catalog', 'Patrons', 'Acquisitions', 'Accounts');
148     my @reports2;
149     for ( my $i = 0 ; $i < 5 ; $i++ ) {
150         my %hashrep;
151         $hashrep{id}   = $i + 1;
152         $hashrep{name} = $reports[$i];
153         push @reports2, \%hashrep;
154     }
155     return ( \@reports2 );
156
157 }
158
159 =item get_all_tables()
160
161 This will return a list of all tables in the database 
162
163 =cut
164
165 sub get_all_tables {
166     my $dbh   = C4::Context->dbh();
167     my $query = "SHOW TABLES";
168     my $sth   = $dbh->prepare($query);
169     $sth->execute();
170     my @tables;
171     while ( my $data = $sth->fetchrow_arrayref() ) {
172         push @tables, $data->[0];
173     }
174     $sth->finish();
175     return ( \@tables );
176
177 }
178
179 =item get_columns($area)
180
181 This will return a list of all columns for a report area
182
183 =cut
184
185 sub get_columns {
186
187     # this calls the internal fucntion _get_columns
188     my ($area,$cgi) = @_;
189     my $tables = $table_areas{$area};
190     my @allcolumns;
191     my $first = 1;
192     foreach my $table (@$tables) {
193         my @columns = _get_columns($table,$cgi, $first);
194         $first = 0;
195         push @allcolumns, @columns;
196     }
197     return ( \@allcolumns );
198 }
199
200 sub _get_columns {
201     my ($tablename,$cgi, $first) = @_;
202     my $dbh         = C4::Context->dbh();
203     my $sth         = $dbh->prepare("show columns from $tablename");
204     $sth->execute();
205     my @columns;
206         my $column_defs = _get_column_defs($cgi);
207         my %tablehash;
208         $tablehash{'table'}=$tablename;
209     $tablehash{'__first__'} = $first;
210         push @columns, \%tablehash;
211     while ( my $data = $sth->fetchrow_arrayref() ) {
212         my %temphash;
213         $temphash{'name'}        = "$tablename.$data->[0]";
214         $temphash{'description'} = $column_defs->{"$tablename.$data->[0]"};
215         push @columns, \%temphash;
216     }
217     $sth->finish();
218     return (@columns);
219 }
220
221 =item build_query($columns,$criteria,$orderby,$area)
222
223 This will build the sql needed to return the results asked for, 
224 $columns is expected to be of the format tablename.columnname.
225 This is what get_columns returns.
226
227 =cut
228
229 sub build_query {
230     my ( $columns, $criteria, $orderby, $area, $totals, $definition ) = @_;
231 ### $orderby
232     my $keys   = $keys{$area};
233     my $tables = $table_areas{$area};
234
235     my $sql =
236       _build_query( $tables, $columns, $criteria, $keys, $orderby, $totals, $definition );
237     return ($sql);
238 }
239
240 sub _build_query {
241     my ( $tables, $columns, $criteria, $keys, $orderby, $totals, $definition) = @_;
242 ### $orderby
243     # $keys is an array of joining constraints
244     my $dbh           = C4::Context->dbh();
245     my $joinedtables  = join( ',', @$tables );
246     my $joinedcolumns = join( ',', @$columns );
247     my $joinedkeys    = join( ' AND ', @$keys );
248     my $query =
249       "SELECT $totals $joinedcolumns FROM $tables->[0] ";
250         for (my $i=1;$i<@$tables;$i++){
251                 $query .= "LEFT JOIN $tables->[$i] on ($keys->[$i-1]) ";
252         }
253
254     if ($criteria) {
255                 $criteria =~ s/AND/WHERE/;
256         $query .= " $criteria";
257     }
258         if ($definition){
259                 my @definitions = split(',',$definition);
260                 my $deftext;
261                 foreach my $def (@definitions){
262                         my $defin=get_from_dictionary('',$def);
263                         $deftext .=" ".$defin->[0]->{'saved_sql'};
264                 }
265                 if ($query =~ /WHERE/i){
266                         $query .= $deftext;
267                 }
268                 else {
269                         $deftext  =~ s/AND/WHERE/;
270                         $query .= $deftext;                     
271                 }
272         }
273     if ($totals) {
274         my $groupby;
275         my @totcolumns = split( ',', $totals );
276         foreach my $total (@totcolumns) {
277             if ( $total =~ /\((.*)\)/ ) {
278                 if ( $groupby eq '' ) {
279                     $groupby = " GROUP BY $1";
280                 }
281                 else {
282                     $groupby .= ",$1";
283                 }
284             }
285         }
286         $query .= $groupby;
287     }
288     if ($orderby) {
289         $query .= $orderby;
290     }
291     return ($query);
292 }
293
294 =item get_criteria($area,$cgi);
295
296 Returns an arraref to hashrefs suitable for using in a tmpl_loop. With the criteria and available values.
297
298 =cut
299
300 sub get_criteria {
301     my ($area,$cgi) = @_;
302     my $dbh    = C4::Context->dbh();
303     my $crit   = $criteria{$area};
304         my $column_defs = _get_column_defs($cgi);
305     my @criteria_array;
306     foreach my $localcrit (@$crit) {
307         my ( $value, $type )   = split( /\|/, $localcrit );
308         my ( $table, $column ) = split( /\./, $value );
309         switch ($type) {
310             case 'textrange' {
311                 my %temp;
312                 $temp{'name'}        = $value;
313                 $temp{'from'}        = "from_" . $value;
314                 $temp{'to'}          = "to_" . $value;
315                 $temp{'textrange'}   = 1;
316                 $temp{'description'} = $column_defs->{$value};
317                 push @criteria_array, \%temp;
318             }
319
320             case 'date' {
321                 my %temp;
322                 $temp{'name'}        = $value;
323                 $temp{'date'}        = 1;
324                 $temp{'description'} = $column_defs->{$value};
325                 push @criteria_array, \%temp;
326             }
327
328             case 'daterange' {
329                 my %temp;
330                 $temp{'name'}        = $value;
331                 $temp{'from'}        = "from_" . $value;
332                 $temp{'to'}          = "to_" . $value;
333                 $temp{'daterange'}   = 1;
334                 $temp{'description'} = $column_defs->{$value};
335                 push @criteria_array, \%temp;
336             }
337
338
339             else {
340                 my $query =
341                   "SELECT distinct($column) as availablevalues FROM $table";
342                 my $sth = $dbh->prepare($query);
343                 $sth->execute();
344                 my @values;
345                 while ( my $row = $sth->fetchrow_hashref() ) {
346                     push @values, $row;
347                 }
348                 $sth->finish();
349
350                 my %temp;
351                 $temp{'name'}        = $value;
352                 $temp{'description'} = $column_defs->{$value};
353                 $temp{'values'}      = \@values;
354                 
355                 push @criteria_array, \%temp;
356      
357             }
358
359         }
360     }
361     return ( \@criteria_array );
362 }
363
364 =item execute_query
365
366 =over
367
368 ($results, $total, $error) = execute_query($sql, $offset, $limit)
369
370 =back
371
372     When passed C<$sql>, this function returns an array ref containing a result set
373     suitably formatted for display in html or for output as a flat file when passed in
374     C<$format> and C<$id>. It also returns the C<$total> records available for the
375     supplied query. If passed any query other than a SELECT, or if there is a db error,
376     C<$errors> an array ref is returned containing the error after this manner:
377
378     C<$error->{'sqlerr'}> contains the offending SQL keyword.
379     C<$error->{'queryerr'}> contains the native db engine error returned for the query.
380     
381     Valid values for C<$format> are 'text,' 'tab,' 'csv,' or 'url. C<$sql>, C<$type>,
382     C<$offset>, and C<$limit> are required parameters. If a valid C<$format> is passed
383     in, C<$offset> and C<$limit> are ignored for obvious reasons. A LIMIT specified by
384     the user in a user-supplied SQL query WILL apply in any case.
385
386 =cut
387
388 # returns $sql, $offset, $limit
389 # $sql returned will be transformed to:
390 #  ~ remove any LIMIT clause
391 #  ~ repace SELECT clause w/ SELECT count(*)
392
393 sub select_2_select_count_value ($) {
394     my $sql = shift or return;
395     my $countsql = select_2_select_count($sql);
396     $debug and warn "original query: $sql\ncount query: $countsql\n";
397     my $sth1 = C4::Context->dbh->prepare($countsql);
398     $sth1->execute();
399     my $total = $sth1->fetchrow();
400     $debug and warn "total records for this query: $total\n";
401     return $total;
402 }
403 sub select_2_select_count ($) {
404     # Modify the query passed in to create a count query... (I think this covers all cases -crn)
405     my ($sql) = strip_limit(shift) or return;
406     $sql =~ s/\bSELECT\W+(?:\w+\W+){1,}?FROM\b|\bSELECT\W\*\WFROM\b/SELECT count(*) FROM /ig;
407     return $sql;
408 }
409 sub strip_limit ($) {
410     my $sql = shift or return;
411     ($sql =~ /\bLIMIT\b/i) or return ($sql, 0, undef);
412     $sql =~ s/\bLIMIT\b\s*\d+(\,\s*\d+)?\s*/ /ig;
413     return ($sql, (defined $1 ? $1 : 0), $2);   # offset can default to 0, LIMIT cannot!
414 }
415
416 sub execute_query ($;$$$) {
417
418     my ( $sql, $offset, $limit, $no_count ) = @_;
419
420     # check parameters
421     unless ($sql) {
422         carp "execute_query() called without SQL argument";
423         return;
424     }
425     $offset = 0    unless $offset;
426     $limit  = 9999 unless $limit;
427     $debug and print STDERR "execute_query($sql, $offset, $limit)\n";
428     if ($sql =~ /;?\W?(UPDATE|DELETE|DROP|INSERT|SHOW|CREATE)\W/i) {
429         return (undef, {  sqlerr => $1} );
430     } elsif ($sql !~ /^\s*SELECT\b\s*/i) {
431         return (undef, { queryerr => 'Missing SELECT'} );
432     }
433
434     my ($useroffset, $userlimit);
435
436     # Grab offset/limit from user supplied LIMIT and drop the LIMIT so we can control pagination
437     ($sql, $useroffset, $userlimit) = strip_limit($sql);
438     $debug and warn sprintf "User has supplied (OFFSET,) LIMIT = %s, %s",
439         $useroffset,
440         (defined($userlimit ) ? $userlimit  : 'UNDEF');
441     $offset += $useroffset;
442     my $total;
443     if (defined($userlimit)) {
444         if ($offset + $limit > $userlimit ) {
445             $limit = $userlimit - $offset;
446         }
447         $total = $userlimit if $userlimit < $total;     # we will never exceed a user defined LIMIT and...
448         $userlimit = $total if $userlimit > $total;     # we will never exceed the total number of records available to satisfy the query
449     }
450     $sql .= " LIMIT ?, ?";
451
452     my $sth = C4::Context->dbh->prepare($sql);
453     $sth->execute($offset, $limit);
454     return ( $sth );
455     # my @xmlarray = ... ;
456     # my $url = "/cgi-bin/koha/reports/guided_reports.pl?phase=retrieve%20results&id=$id";
457     # my $xml = XML::Dumper->new()->pl2xml( \@xmlarray );
458     # store_results($id,$xml);
459 }
460
461 =item save_report($sql,$name,$type,$notes)
462
463 Given some sql and a name this will saved it so that it can resued
464
465 =cut
466
467 sub save_report {
468     my ( $borrowernumber, $sql, $name, $type, $notes ) = @_;
469     my $dbh = C4::Context->dbh();
470     $sql =~ s/(\s*\;\s*)$//; # removes trailing whitespace and /;/
471     my $query =
472 "INSERT INTO saved_sql (borrowernumber,date_created,last_modified,savedsql,report_name,type,notes)  VALUES (?,now(),now(),?,?,?,?)";
473     my $sth = $dbh->prepare($query);
474     $sth->execute( $borrowernumber, $sql, $name, $type, $notes );
475 }
476
477 sub update_sql {
478     my $id = shift || croak "No Id given";
479     my $sql = shift;
480     my $reportname = shift;
481     my $notes = shift;
482     my $dbh = C4::Context->dbh();
483     $sql =~ s/(\s*\;\s*)$//; # removes trailing whitespace and /;/
484     my $query = "UPDATE saved_sql SET savedsql = ?, last_modified = now(), report_name = ?, notes = ? WHERE id = ? ";
485     my $sth = $dbh->prepare($query);
486     $sth->execute( $sql, $reportname, $notes, $id );
487     $sth->finish();
488 }
489
490 sub store_results {
491         my ($id,$xml)=@_;
492         my $dbh = C4::Context->dbh();
493         my $query = "SELECT * FROM saved_reports WHERE report_id=?";
494         my $sth = $dbh->prepare($query);
495         $sth->execute($id);
496         if (my $data=$sth->fetchrow_hashref()){
497                 my $query2 = "UPDATE saved_reports SET report=?,date_run=now() WHERE report_id=?";
498                 my $sth2 = $dbh->prepare($query2);
499             $sth2->execute($xml,$id);
500         }
501         else {
502                 my $query2 = "INSERT INTO saved_reports (report_id,report,date_run) VALUES (?,?,now())";
503                 my $sth2 = $dbh->prepare($query2);
504                 $sth2->execute($id,$xml);
505         }
506 }
507
508 sub format_results {
509         my ($id) = @_;
510         my $dbh = C4::Context->dbh();
511         my $query = "SELECT * FROM saved_reports WHERE report_id = ?";
512         my $sth = $dbh->prepare($query);
513         $sth->execute($id);
514         my $data = $sth->fetchrow_hashref();
515         my $dump = new XML::Dumper;
516         my $perl = $dump->xml2pl( $data->{'report'} );
517         foreach my $row (@$perl) {
518                 my $htmlrow="<tr>";
519                 foreach my $key (keys %$row){
520                         $htmlrow .= "<td>$row->{$key}</td>";
521                 }
522                 $htmlrow .= "</tr>";
523                 $row->{'row'} = $htmlrow;
524         }
525         $sth->finish;
526         $query = "SELECT * FROM saved_sql WHERE id = ?";
527         $sth = $dbh->prepare($query);
528         $sth->execute($id);
529         $data = $sth->fetchrow_hashref();
530         return ($perl,$data->{'report_name'},$data->{'notes'}); 
531 }       
532
533 sub delete_report {
534         my ( $id ) = @_;
535         my $dbh = C4::Context->dbh();
536         my $query = "DELETE FROM saved_sql WHERE id = ?";
537         my $sth = $dbh->prepare($query);
538         $sth->execute($id);
539 }       
540
541 sub get_saved_reports {
542     my $dbh   = C4::Context->dbh();
543     my $query = "SELECT *,saved_sql.id AS id FROM saved_sql 
544     LEFT JOIN saved_reports ON saved_reports.report_id = saved_sql.id
545     ORDER by date_created";
546     my $sth   = $dbh->prepare($query);
547     $sth->execute();
548     
549     my $result = $sth->fetchall_arrayref({});
550     foreach (@$result){
551         $_->{date_created} = format_date($_->{date_created}); 
552         
553         my $member = C4::Members::GetMember(borrowernumber=>$_->{borrowernumber});
554         $_->{borrowerfirstname} = $member->{firstname};
555         $_->{borrowersurname}   = $member->{surname};
556     }
557     return $result;
558 }
559
560 sub get_saved_report {
561     my ($id)  = @_;
562     my $dbh   = C4::Context->dbh();
563     my $query = " SELECT * FROM saved_sql WHERE id = ?";
564     my $sth   = $dbh->prepare($query);
565     $sth->execute($id);
566     my $data = $sth->fetchrow_hashref();
567     return ( $data->{'savedsql'}, $data->{'type'}, $data->{'report_name'}, $data->{'notes'} );
568 }
569
570 =item create_compound($masterID,$subreportID)
571
572 This will take 2 reports and create a compound report using both of them
573
574 =cut
575
576 sub create_compound {
577         my ($masterID,$subreportID) = @_;
578         my $dbh = C4::Context->dbh();
579         # get the reports
580         my ($mastersql,$mastertype) = get_saved_report($masterID);
581         my ($subsql,$subtype) = get_saved_report($subreportID);
582         
583         # now we have to do some checking to see how these two will fit together
584         # or if they will
585         my ($mastertables,$subtables);
586         if ($mastersql =~ / from (.*) where /i){ 
587                 $mastertables = $1;
588         }
589         if ($subsql =~ / from (.*) where /i){
590                 $subtables = $1;
591         }
592         return ($mastertables,$subtables);
593 }
594
595 =item get_column_type($column)
596
597 This takes a column name of the format table.column and will return what type it is
598 (free text, set values, date)
599
600 =cut
601
602 sub get_column_type {
603         my ($tablecolumn) = @_;
604         my ($table,$column) = split(/\./,$tablecolumn);
605         my $dbh = C4::Context->dbh();
606         my $catalog;
607         my $schema;
608
609         # mysql doesnt support a column selection, set column to %
610         my $tempcolumn='%';
611         my $sth = $dbh->column_info( $catalog, $schema, $table, $tempcolumn ) || die $dbh->errstr;
612         while (my $info = $sth->fetchrow_hashref()){
613                 if ($info->{'COLUMN_NAME'} eq $column){
614                         #column we want
615                         if ($info->{'TYPE_NAME'} eq 'CHAR' || $info->{'TYPE_NAME'} eq 'VARCHAR'){
616                                 $info->{'TYPE_NAME'} = 'distinct';
617                         }
618                         return $info->{'TYPE_NAME'};            
619                 }
620         }
621 }
622
623 =item get_distinct_values($column)
624
625 Given a column name, return an arrary ref of hashrefs suitable for use as a tmpl_loop 
626 with the distinct values of the column
627
628 =cut
629
630 sub get_distinct_values {
631         my ($tablecolumn) = @_;
632         my ($table,$column) = split(/\./,$tablecolumn);
633         my $dbh = C4::Context->dbh();
634         my $query =
635           "SELECT distinct($column) as availablevalues FROM $table";
636         my $sth = $dbh->prepare($query);
637         $sth->execute();
638     return $sth->fetchall_arrayref({});
639 }       
640
641 sub save_dictionary {
642         my ($name,$description,$sql,$area) = @_;
643         my $dbh = C4::Context->dbh();
644         my $query = "INSERT INTO reports_dictionary (name,description,saved_sql,area,date_created,date_modified)
645   VALUES (?,?,?,?,now(),now())";
646     my $sth = $dbh->prepare($query);
647     $sth->execute($name,$description,$sql,$area) || return 0;
648     return 1;
649 }
650
651 sub get_from_dictionary {
652         my ($area,$id) = @_;
653         my $dbh = C4::Context->dbh();
654         my $query = "SELECT * FROM reports_dictionary";
655         if ($area){
656                 $query.= " WHERE area = ?";
657         }
658         elsif ($id){
659                 $query.= " WHERE id = ?"
660         }
661         my $sth = $dbh->prepare($query);
662         if ($id){
663                 $sth->execute($id);
664         }
665         elsif ($area) {
666                 $sth->execute($area);
667         }
668         else {
669                 $sth->execute();
670         }
671         my @loop;
672         my @reports = ( 'Circulation', 'Catalog', 'Patrons', 'Acquisitions', 'Accounts');
673         while (my $data = $sth->fetchrow_hashref()){
674                 $data->{'areaname'}=$reports[$data->{'area'}-1];
675                 push @loop,$data;
676                 
677         }
678         return (\@loop);
679 }
680
681 sub delete_definition {
682         my ($id) = @_ or return;
683         my $dbh = C4::Context->dbh();
684         my $query = "DELETE FROM reports_dictionary WHERE id = ?";
685         my $sth = $dbh->prepare($query);
686         $sth->execute($id);
687 }
688
689 sub get_sql {
690         my ($id) = @_ or return;
691         my $dbh = C4::Context->dbh();
692         my $query = "SELECT * FROM saved_sql WHERE id = ?";
693         my $sth = $dbh->prepare($query);
694         $sth->execute($id);
695         my $data=$sth->fetchrow_hashref();
696         return $data->{'savedsql'};
697 }
698
699 sub _get_column_defs {
700         my ($cgi) = @_;
701         my %columns;
702         my $columns_def_file = "columns.def";
703         my $htdocs = C4::Context->config('intrahtdocs');                       
704         my $section='intranet';
705         my ($theme, $lang) = themelanguage($htdocs, $columns_def_file, $section,$cgi);
706
707         my $full_path_to_columns_def_file="$htdocs/$theme/$lang/$columns_def_file";    
708         open (COLUMNS,$full_path_to_columns_def_file);
709         while (my $input = <COLUMNS>){
710                 my @row =split(/\t/,$input);
711                 $columns{$row[0]}=$row[1];
712         }
713
714         close COLUMNS;
715         return \%columns;
716 }
717 1;
718 __END__
719
720 =back
721
722 =head1 AUTHOR
723
724 Chris Cormack <crc@liblime.com>
725
726 =cut