Bug 7683: Cataloguing statistics wizard improvements

- Add 3 options for cells value
  - Titles count "COUNT (biblionumber)"
  - Items count "COUNT (itemnumber)" (current behavior)
  - Deleted items count "COUNT (deleteditems.itemnumber)"

- Add to selectable rows, colums and filters:
  - items.notforloan
  - items.materials

  For each of these fields, retrieve the label in the default cataloging
  framework.
  If no MARC field is mapped to the field in question, it does not show
  this line in the wizard.
  If the MARC field is associated with a list of authorized values, it
  displays a dropdown list for the filter, otherwise it displays a text
  field.

- Add to selectable rows, columns and filters:
  - items.dateaccessioned (creation date)
  - deleteditems.timestamp (deletion date) (Only if the third option (eg
    count deleted items) is selected)

- Add unit tests for GetMarcSubfieldStructureFromKohaField

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Paul Poulain <paul.poulain@biblibre.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com>

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>

Signed-off-by: Brendan A Gallagher <brendan@bywatersolutions.com>
This commit is contained in:
Julian Maurice 2012-02-27 17:11:29 +01:00 committed by Brendan A Gallagher
parent e5f4a0e3d5
commit 84ea840232
3 changed files with 620 additions and 408 deletions

View file

@ -4,21 +4,22 @@
[% INCLUDE 'calendar.inc' %]
<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {
// http://jqueryui.com/demos/datepicker/#date-range
var dates = $( "#from, #to" ).datepicker({
changeMonth: true,
numberOfMonths: 1,
onSelect: function( selectedDate ) {
var option = this.id == "from" ? "minDate" : "maxDate",
instance = $( this ).data( "datepicker" );
date = $.datepicker.parseDate(
instance.settings.dateFormat ||
$.datepicker._defaults.dateFormat,
selectedDate, instance.settings );
dates.not( this ).datepicker( "option", option, date );
}
});
function changeRemovedDateTrStatus() {
var Cellvalue = $("input[name='Cellvalue']:checked").val();
if(Cellvalue == "deleteditems") {
$("#removeddatetr").show();
$("input[value='deleteditems.timestamp']").attr('disabled', false);
$("#deldateFrom").attr('disabled', false);
$("#deldateTo").attr('disabled', false);
} else {
$("#removeddatetr").hide();
$("input[value='deleteditems.timestamp']").attr('disabled', true).attr('checked', false);
$("#deldateFrom").attr('disabled', true).val('');
$("#deldateTo").attr('disabled', true).val('');
}
}
$(document).ready(function() {
var datesRO = $( "#fromRO, #toRO" ).datepicker({
changeMonth: true,
numberOfMonths: 1,
@ -32,7 +33,11 @@
datesRO.not( this ).datepicker( "option", option, date );
}
});
$("input[name='Cellvalue']").change(function() {
changeRemovedDateTrStatus();
});
changeRemovedDateTrStatus();
});
//]]>
</script>
</head>
@ -218,6 +223,56 @@
</select>
</td>
</tr>
[% IF (notforloan) %]
<tr>
<td>[% notforloan_label %]</td>
<td><input type="radio" name="Line" value="items.notforloan" /></td>
<td><input type="radio" name="Column" value="items.notforloan" /></td>
<td>
[% IF (notforloan_avlist) %]
<select name="Filter" id="notforloan">
<option value="">&nbsp;</option>
[% FOREACH av IN notforloan_avlist %]
<option value="[% av.authorised_value %]">
[% av.lib %]
</option>
[% END %]
</select>
[% ELSE %]
<input type="text" name="Filter" id="notforloan" />
[% END %]
</td>
</tr>
[% ELSE %]
<tr style="display:none">
<td colspan="4"><input type="hidden" name="Filter" /></td>
</tr>
[% END %]
[% IF (materials) %]
<tr>
<td>[% materials_label %]</td>
<td><input type="radio" name="Line" value="items.materials" /></td>
<td><input type="radio" name="Column" value="items.materials" /></td>
<td>
[% IF (materials_avlist) %]
<select name="Filter" id="materials">
<option value="">&nbsp;</option>
[% FOREACH av IN materials_avlist %]
<option value="[% av.authorised_value %]">
[% av.lib %]
</option>
[% END %]
</select>
[% ELSE %]
<input type="text" name="Filter" id="materials" />
[% END %]
</td>
</tr>
[% ELSE %]
<tr style="display:none">
<td colspan="4"><input type="hidden" name="Filter" /></td>
</tr>
[% END %]
<tr>
<td colspan="3">Filter barcode</td>
<td>
@ -228,10 +283,50 @@
<input type="text" name="Filter" id="barcode" />
(use * to do a fuzzy search)
</td>
</tr>
<tr>
<td>Acquired date</td>
<td><input type="radio" name="Line" value="items.dateaccessioned" /></td>
<td><input type="radio" name="Column" value="items.dateaccessioned" /></td>
<td>
<label for="acqdateFrom">From:</label>
<input type="text" name="Filter" id="acqdateFrom" class="datepicker" />
<label for="acqdateTo">To:</label>
<input type="text" name="Filter" id="acqdateTo" class="datepicker" />
</td>
</tr>
<tr id="removeddatetr">
<td>Removed date</td>
<td><input type="radio" name="Line" value="deleteditems.timestamp" /></td>
<td><input type="radio" name="Column" value="deleteditems.timestamp" /></td>
<td>
<label for="deldateFrom">From:</label>
<input type="text" name="Filter" id="deldateFrom" class="datepicker" />
<label for="deldateTo">To:</label>
<input type="text" name="Filter" id="deldateTo" class="datepicker"/>
</td>
</tr>
</tbody>
</table><br /></fieldset>
<fieldset class="rows">
<legend>Cell value</legend>
<ol>
<li>
<label for="cellvalue_items">Count total items</label>
<input type="radio" name="Cellvalue" value="items" id="cellvalue_items" checked="checked" />
</li>
<li>
<label for="cellvalue_biblios">Count unique biblios</label>
<input type="radio" name="Cellvalue" value="biblios" id="cellvalue_biblios" />
</li>
<li>
<label for="cellvalue_deleteditems">Count deleted items</label>
<input type="radio" name="Cellvalue" value="deleteditems" id="cellvalue_deleteditems" />
</li>
</ol>
</fieldset>
<fieldset class="rows">
<legend>Output</legend>
<ol><li><label for="outputscreen">To screen into the browser: </label><input type="radio" checked="checked" name="output" id="outputscreen" value="screen" /></li>

View file

@ -28,6 +28,7 @@ use C4::Output;
use C4::Koha;
use C4::Reports;
use C4::Circulation;
use C4::Biblio qw/GetMarcSubfieldStructureFromKohaField/;
=head1 NAME
@ -35,8 +36,6 @@ plugin that shows a stats on borrowers
=head1 DESCRIPTION
=over 2
=cut
our $debug = 0;
@ -45,6 +44,7 @@ my $fullreportname = "reports/catalogue_stats.tt";
my $do_it = $input->param('do_it');
my $line = $input->param("Line");
my $column = $input->param("Column");
my $cellvalue = $input->param("Cellvalue"); # one of 'items', 'biblios', 'deleteditems'
my @filters = $input->param("Filter");
my $deweydigits = $input->param("deweydigits");
my $lccndigits = $input->param("lccndigits");
@ -76,40 +76,42 @@ my ($template, $borrowernumber, $cookie)
});
$template->param(do_it => $do_it);
if ($do_it) {
my $results = calculate($line, $column, $deweydigits, $lccndigits, $cotedigits, \@filters);
if ($output eq "screen"){
$template->param(mainloop => $results);
output_html_with_http_headers $input, $cookie, $template->output;
exit;
} else {
print $input->header(-type => 'application/vnd.sun.xml.calc',
-encoding => 'utf-8',
-attachment=>"$basename.csv",
-name=>"$basename.csv" );
my $cols = @$results[0]->{loopcol};
my $lines = @$results[0]->{looprow};
print @$results[0]->{line} ."/". @$results[0]->{column} .$sep;
foreach my $col ( @$cols ) {
print $col->{coltitle}.$sep;
}
print "Total\n";
foreach my $line ( @$lines ) {
my $x = $line->{loopcell};
print $line->{rowtitle}.$sep;
foreach my $cell (@$x) {
print $cell->{value}.$sep;
}
print $line->{totalrow};
print "\n";
}
print "TOTAL";
$cols = @$results[0]->{loopfooter};
foreach my $col ( @$cols ) {
print $sep.$col->{totalcol};
}
print $sep.@$results[0]->{total};
exit;
}
my $results = calculate( $line, $column, $cellvalue, $deweydigits, $lccndigits, $cotedigits, \@filters );
if ( $output eq "screen" ) {
$template->param( mainloop => $results );
output_html_with_http_headers $input, $cookie, $template->output;
exit;
} else {
print $input->header(
-type => 'application/vnd.sun.xml.calc',
-encoding => 'utf-8',
-attachment => "$basename.csv",
-name => "$basename.csv"
);
my $cols = @$results[0]->{loopcol};
my $lines = @$results[0]->{looprow};
print @$results[0]->{line} . "/" . @$results[0]->{column} . $sep;
foreach my $col (@$cols) {
print $col->{coltitle} . $sep;
}
print "Total\n";
foreach my $line (@$lines) {
my $x = $line->{loopcell};
print $line->{rowtitle} . $sep;
foreach my $cell (@$x) {
print $cell->{value} . $sep;
}
print $line->{totalrow};
print "\n";
}
print "TOTAL";
$cols = @$results[0]->{loopfooter};
foreach my $col (@$cols) {
print $sep. $col->{totalcol};
}
print $sep. @$results[0]->{total};
exit;
}
} else {
my $dbh = C4::Context->dbh;
my @values;
@ -148,31 +150,50 @@ if ($do_it) {
my $itemtypes = GetItemTypes( style => 'array' );
my $authvals = GetKohaAuthorisedValues("items.ccode");
my @authvals;
foreach (sort {$authvals->{$a} cmp $authvals->{$b} || $a cmp $b} keys %$authvals) {
push @authvals, { code => $_, description => $authvals->{$_} };
}
my $authvals = GetKohaAuthorisedValues("items.ccode");
my @authvals;
foreach ( sort { $authvals->{$a} cmp $authvals->{$b} || $a cmp $b } keys %$authvals ) {
push @authvals, { code => $_, description => $authvals->{$_} };
}
my $locations = GetKohaAuthorisedValues("items.location");
my @locations;
foreach (sort keys %$locations) {
push @locations, { code => $_, description => "$_ - " . $locations->{$_} };
}
my $locations = GetKohaAuthorisedValues("items.location");
my @locations;
foreach ( sort keys %$locations ) {
push @locations, { code => $_, description => "$_ - " . $locations->{$_} };
}
my @mime = ( map { +{type =>$_} } (split /[;:]/, 'CSV') ); # FIXME translation
foreach my $kohafield (qw(items.notforloan items.materials)) {
my $subfield_structure = GetMarcSubfieldStructureFromKohaField($kohafield);
if($subfield_structure) {
my $avlist;
my $avcategory = $subfield_structure->{authorised_value};
if($avcategory) {
$avlist = GetAuthorisedValues($avcategory);
}
my $kf = $kohafield;
$kf =~ s/^items\.//;
$template->param(
$kf => 1,
$kf."_label" => $subfield_structure->{liblibrarian},
$kf."_avlist" => $avlist
);
}
}
$template->param(hasdewey=>$hasdewey,
haslccn => $haslccn,
hascote => $hascote,
itemtypes => $itemtypes,
CGIBranch => GetBranchesLoop(C4::Context->userenv->{'branch'}),
locationloop => \@locations,
authvals => \@authvals,
CGIextChoice => \@mime,
CGIsepChoice => GetDelimiterChoices,
item_itype => $item_itype
);
my @mime = ( map { +{type =>$_} } (split /[;:]/, 'CSV') ); # FIXME translation
$template->param(
hasdewey => $hasdewey,
haslccn => $haslccn,
hascote => $hascote,
itemtypes => $itemtypes,
CGIBranch => GetBranchesLoop( C4::Context->userenv->{'branch'} ),
locationloop => \@locations,
authvals => \@authvals,
CGIextChoice => \@mime,
CGIsepChoice => GetDelimiterChoices,
item_itype => $item_itype,
);
}
output_html_with_http_headers $input, $cookie, $template->output;
@ -181,356 +202,428 @@ output_html_with_http_headers $input, $cookie, $template->output;
sub calculate {
my ($line, $column, $deweydigits, $lccndigits, $cotedigits, $filters) = @_;
my @mainloop;
my @loopfooter;
my @loopcol;
my @loopline;
my @looprow;
my %globalline;
my $grantotal =0;
my $barcodelike = @$filters[13];
my $barcodefilter = @$filters[14];
my ( $line, $column, $cellvalue, $deweydigits, $lccndigits, $cotedigits, $filters ) = @_;
my @mainloop;
my @loopfooter;
my @loopcol;
my @loopline;
my @looprow;
my %globalline;
my $grantotal = 0;
my $barcodelike = @$filters[16];
my $barcodefilter = @$filters[17];
my $not;
my $itemstable = ($cellvalue eq 'deleteditems') ? 'deleteditems' : 'items';
# extract parameters
my $dbh = C4::Context->dbh;
my $dbh = C4::Context->dbh;
# if barcodefilter is empty set as %
if($barcodefilter){
# Check if barcodefilter is "like" or "not like"
if(!$barcodelike){
$not = "not";
# if barcodefilter is empty set as %
if ($barcodefilter) {
# Check if barcodefilter is "like" or "not like"
if ( !$barcodelike ) {
$not = "not";
}
# Change * to %
$barcodefilter =~ s/\*/%/g;
}
# Change * to %
$barcodefilter =~ s/\*/%/g;
}
# Filters
# Checking filters
#
my @loopfilter;
for (my $i=0;$i<=12;$i++) {
my %cell;
if ( @$filters[$i] ) {
if ((($i==1) or ($i==3) or ($i==5) or ($i==9)) and (@$filters[$i-1])) {
$cell{err} = 1 if (@$filters[$i]<@$filters[$i-1]) ;
}
$cell{filter} .= @$filters[$i];
$cell{crit} .=
($i== 0) ? "Dewey Classification From" :
($i== 1) ? "Dewey Classification To" :
($i== 2) ? "Lccn Classification From" :
($i== 3) ? "Lccn Classification To" :
($i== 4) ? "Item CallNumber From" :
($i== 5) ? "Item CallNumber To" :
($i== 6) ? "Item type" :
($i== 7) ? "Publisher" :
($i== 8) ? "Publication year From" :
($i== 9) ? "Publication year To" :
($i==10) ? "Library :" :
($i==11) ? "Shelving Location :" :
($i==12) ? "Collection Code :" : '';
push @loopfilter, \%cell;
}
}
# Filters
# Checking filters
#
my @loopfilter;
for ( my $i = 0 ; $i <= @$filters ; $i++ ) {
my %cell;
if ( defined @$filters[$i] and @$filters[$i] ne '' and $i != 15 ) {
if ( ( ( $i == 1 ) or ( $i == 3 ) or ( $i == 5 ) or ( $i == 9 ) ) and ( @$filters[ $i - 1 ] ) ) {
$cell{err} = 1 if ( @$filters[$i] < @$filters[ $i - 1 ] );
}
$cell{filter} .= @$filters[$i];
$cell{crit} .=
( $i == 0 ) ? "Dewey Classification From"
: ( $i == 1 ) ? "Dewey Classification To"
: ( $i == 2 ) ? "Lccn Classification From"
: ( $i == 3 ) ? "Lccn Classification To"
: ( $i == 4 ) ? "Item CallNumber From"
: ( $i == 5 ) ? "Item CallNumber To"
: ( $i == 6 ) ? "Item type"
: ( $i == 7 ) ? "Publisher"
: ( $i == 8 ) ? "Publication year From"
: ( $i == 9 ) ? "Publication year To"
: ( $i == 10 ) ? "Library"
: ( $i == 11 ) ? "Shelving Location"
: ( $i == 12 ) ? "Collection Code"
: ( $i == 13 ) ? "Status"
: ( $i == 14 ) ? "Materials"
: ( $i == 16 and $filters->[15] == 0 ) ? "Barcode (not like)"
: ( $i == 16 and $filters->[15] == 1 ) ? "Barcode (like)"
: ( $i == 17 ) ? "Acquired date from"
: ( $i == 18 ) ? "Acquired date to"
: ( $i == 19 ) ? "Removed date from"
: ( $i == 20 ) ? "Removed date to"
: '';
# warn map {"filtres $_\n"} @filters[0..3];
push @loopfilter, \%cell;
}
}
my @linefilter;
$linefilter[0] = @$filters[0] if ($line =~ /dewey/ ) ;
$linefilter[1] = @$filters[1] if ($line =~ /dewey/ ) ;
$linefilter[0] = @$filters[2] if ($line =~ /lccn/ ) ;
$linefilter[1] = @$filters[3] if ($line =~ /lccn/ ) ;
$linefilter[0] = @$filters[4] if ($line =~ /items\.itemcallnumber/ ) ;
$linefilter[1] = @$filters[5] if ($line =~ /items\.itemcallnumber/ ) ;
if (C4::Context->preference('item-level_itypes')) {
$linefilter[0] = @$filters[6] if ($line =~ /items\.itype/ ) ;
} else {
$linefilter[0] = @$filters[6] if ($line =~ /itemtype/ ) ;
}
$linefilter[0] = @$filters[7] if ($line =~ /publishercode/ ) ;
$linefilter[0] = @$filters[8] if ($line =~ /publicationyear/ ) ;
$linefilter[1] = @$filters[9] if ($line =~ /publicationyear/ ) ;
$linefilter[0] = @$filters[10] if ($line =~ /items\.homebranch/ ) ;
$linefilter[0] = @$filters[11] if ($line =~ /items\.location/ ) ;
$linefilter[0] = @$filters[12] if ($line =~ /items\.ccode/ ) ;
@$filters[18] = C4::Dates->new(@$filters[18])->output('iso') if @$filters[18];
@$filters[19] = C4::Dates->new(@$filters[19])->output('iso') if @$filters[19];
@$filters[20] = C4::Dates->new(@$filters[20])->output('iso') if @$filters[20];
@$filters[21] = C4::Dates->new(@$filters[21])->output('iso') if @$filters[21];
my @colfilter ;
$colfilter[0] = @$filters[0] if ($column =~ /dewey/ ) ;
$colfilter[1] = @$filters[1] if ($column =~ /dewey/ ) ;
$colfilter[0] = @$filters[2] if ($column =~ /lccn/ ) ;
$colfilter[1] = @$filters[3] if ($column =~ /lccn/ ) ;
$colfilter[0] = @$filters[4] if ($column =~ /items\.itemcallnumber/ ) ;
$colfilter[1] = @$filters[5] if ($column =~ /items\.itemcallnumber/ ) ;
if (C4::Context->preference('item-level_itypes')) {
$colfilter[0] = @$filters[6] if ($column =~ /items\.itype/ ) ;
} else {
$colfilter[0] = @$filters[6] if ($column =~ /itemtype/ ) ;
}
$colfilter[0] = @$filters[7] if ($column =~ /publishercode/ ) ;
$colfilter[0] = @$filters[8] if ($column =~ /publicationyear/ ) ;
$colfilter[1] = @$filters[9] if ($column =~ /publicationyear/ ) ;
$colfilter[0] = @$filters[10] if ($column =~ /items\.homebranch/ ) ;
$colfilter[0] = @$filters[11] if ($column =~ /items\.location/ ) ;
$colfilter[0] = @$filters[12] if ($column =~ /items\.ccode/ ) ;
my @linefilter;
$linefilter[0] = @$filters[0] if ( $line =~ /dewey/ );
$linefilter[1] = @$filters[1] if ( $line =~ /dewey/ );
$linefilter[0] = @$filters[2] if ( $line =~ /lccn/ );
$linefilter[1] = @$filters[3] if ( $line =~ /lccn/ );
$linefilter[0] = @$filters[4] if ( $line =~ /items\.itemcallnumber/ );
$linefilter[1] = @$filters[5] if ( $line =~ /items\.itemcallnumber/ );
if ( C4::Context->preference('item-level_itypes') ) {
$linefilter[0] = @$filters[6] if ( $line =~ /items\.itype/ );
} else {
$linefilter[0] = @$filters[6] if ( $line =~ /itemtype/ );
}
$linefilter[0] = @$filters[7] if ( $line =~ /publishercode/ );
$linefilter[0] = @$filters[8] if ( $line =~ /publicationyear/ );
$linefilter[1] = @$filters[9] if ( $line =~ /publicationyear/ );
# 1st, loop rows.
my $linefield;
if (($line =~/dewey/) and ($deweydigits)) {
$linefield .="left($line,$deweydigits)";
} elsif (($line=~/lccn/) and ($lccndigits)) {
$linefield .="left($line,$lccndigits)";
} elsif (($line=~/items.itemcallnumber/) and ($cotedigits)) {
$linefield .="left($line,$cotedigits)";
}else {
$linefield .= $line;
}
$linefilter[0] = @$filters[10] if ( $line =~ /items\.homebranch/ );
$linefilter[0] = @$filters[11] if ( $line =~ /items\.location/ );
$linefilter[0] = @$filters[12] if ( $line =~ /items\.ccode/ );
$linefilter[0] = @$filters[13] if ( $line =~ /items\.notforloan/ );
$linefilter[0] = @$filters[14] if ( $line =~ /items\.materials/ );
$linefilter[0] = @$filters[17] if ( $line =~ /items\.dateaccessioned/ );
$linefilter[1] = @$filters[18] if ( $line =~ /items\.dateaccessioned/ );
$linefilter[0] = @$filters[19] if ( $line =~ /deleteditems\.timestamp/ );
$linefilter[1] = @$filters[20] if ( $line =~ /deleteditems\.timestamp/ );
my $strsth = "SELECT DISTINCTROW $linefield FROM biblioitems
INNER JOIN items USING (biblioitemnumber)
INNER JOIN biblio ON (biblioitems.biblionumber = biblio.biblionumber)
WHERE $line IS NOT NULL ";
my @colfilter;
$colfilter[0] = @$filters[0] if ( $column =~ /dewey/ );
$colfilter[1] = @$filters[1] if ( $column =~ /dewey/ );
$colfilter[0] = @$filters[2] if ( $column =~ /lccn/ );
$colfilter[1] = @$filters[3] if ( $column =~ /lccn/ );
$colfilter[0] = @$filters[4] if ( $column =~ /items\.itemcallnumber/ );
$colfilter[1] = @$filters[5] if ( $column =~ /items\.itemcallnumber/ );
if ( C4::Context->preference('item-level_itypes') ) {
$colfilter[0] = @$filters[6] if ( $column =~ /items\.itype/ );
} else {
$colfilter[0] = @$filters[6] if ( $column =~ /itemtype/ );
}
$colfilter[0] = @$filters[7] if ( $column =~ /publishercode/ );
$colfilter[0] = @$filters[8] if ( $column =~ /publicationyear/ );
$colfilter[1] = @$filters[9] if ( $column =~ /publicationyear/ );
$colfilter[0] = @$filters[10] if ( $column =~ /items\.homebranch/ );
$colfilter[0] = @$filters[11] if ( $column =~ /items\.location/ );
$colfilter[0] = @$filters[12] if ( $column =~ /items\.ccode/ );
$colfilter[0] = @$filters[13] if ( $column =~ /items\.notforloan/ );
$colfilter[0] = @$filters[14] if ( $column =~ /items\.materials/ );
$colfilter[0] = @$filters[17] if ( $column =~ /items.dateaccessioned/ );
$colfilter[1] = @$filters[18] if ( $column =~ /items\.dateaccessioned/ );
$colfilter[0] = @$filters[19] if ( $column =~ /deleteditems\.timestamp/ );
$colfilter[1] = @$filters[20] if ( $column =~ /deleteditems\.timestamp/ );
# 1st, loop rows.
my $origline = $line;
$line =~ s/^items\./deleteditems./ if($cellvalue eq "deleteditems");
my $linefield;
if ( ( $line =~ /dewey/ ) and ($deweydigits) ) {
$linefield = "left($line,$deweydigits)";
} elsif ( ( $line =~ /lccn/ ) and ($lccndigits) ) {
$linefield = "left($line,$lccndigits)";
} elsif ( ( $line =~ /itemcallnumber/ ) and ($cotedigits) ) {
$linefield = "left($line,$cotedigits)";
} elsif ( $line =~ /^deleteditems\.timestamp$/ ) {
$linefield = "DATE($line)";
} else {
$linefield = $line;
}
my $strsth = "SELECT DISTINCTROW $linefield FROM $itemstable
LEFT JOIN biblioitems USING (biblioitemnumber)
LEFT JOIN biblio ON (biblioitems.biblionumber = biblio.biblionumber)
WHERE 1 ";
$strsth .= " AND barcode $not LIKE ? " if ($barcodefilter);
if ( @linefilter ) {
if ($linefilter[1]){
$strsth .= " AND $line >= ? " ;
$strsth .= " AND $line <= ? " ;
} elsif ($linefilter[0]) {
$linefilter[0] =~ s/\*/%/g;
$strsth .= " AND $line LIKE ? " ;
}
}
$strsth .=" ORDER BY $linefield";
$debug and print STDERR "catalogue_stats SQL: $strsth\n";
if (@linefilter) {
if ( $linefilter[1] ) {
$strsth .= " AND $line >= ? ";
$strsth .= " AND $line <= ? ";
} elsif ( defined $linefilter[0] and $linefilter[0] ne '' ) {
$linefilter[0] =~ s/\*/%/g;
$strsth .= " AND $line LIKE ? ";
}
}
$strsth .= " ORDER BY $linefield";
$debug and print STDERR "catalogue_stats SQL: $strsth\n";
my $sth = $dbh->prepare( $strsth );
if (( @linefilter ) and ($linefilter[1])){
$sth->execute($barcodefilter,$linefilter[0],$linefilter[1]);
} elsif ($barcodefilter,$linefilter[0]) {
$sth->execute($barcodefilter,$linefilter[0]);
} elsif ($barcodefilter) {
$sth->execute($barcodefilter);
}else{
$sth->execute();
}
while ( my ($celvalue) = $sth->fetchrow) {
my %cell;
if ($celvalue) {
$cell{rowtitle} = $celvalue;
# } else {
# $cell{rowtitle} = "";
}
$cell{totalrow} = 0;
push @loopline, \%cell;
}
my $sth = $dbh->prepare($strsth);
if ( $barcodefilter and (@linefilter) and ( $linefilter[1] ) ) {
$sth->execute( $barcodefilter, $linefilter[0], $linefilter[1] );
} elsif ( (@linefilter) and ( $linefilter[1] ) ) {
$sth->execute( $linefilter[0], $linefilter[1] );
} elsif ( $barcodefilter and $linefilter[0] ) {
$sth->execute( $barcodefilter, $linefilter[0] );
} elsif ( $linefilter[0] ) {
$sth->execute($linefilter[0]);
} elsif ($barcodefilter) {
$sth->execute($barcodefilter);
} else {
$sth->execute();
}
my $rowauthvals = GetKohaAuthorisedValues($origline);
while ( my ($celvalue) = $sth->fetchrow ) {
my %cell;
if (defined $celvalue and $celvalue ne '') {
if($rowauthvals and $rowauthvals->{$celvalue}) {
$cell{rowtitle} = $rowauthvals->{$celvalue};
} else {
$cell{rowtitle} = $celvalue;
}
$cell{value} = $celvalue;
}
else {
$cell{rowtitle} = "NULL";
$cell{value} = "zzEMPTY";
}
$cell{totalrow} = 0;
push @loopline, \%cell;
}
# 2nd, loop cols.
my $colfield;
if (($column =~/dewey/) and ($deweydigits)) {
$colfield = "left($column,$deweydigits)";
}elsif (($column=~/lccn/) and ($lccndigits)) {
$colfield = "left($column,$lccndigits)";
}elsif (($column=~/itemcallnumber/) and ($cotedigits)) {
$colfield = "left($column,$cotedigits)";
}else {
$colfield = $column;
}
# 2nd, loop cols.
my $origcolumn = $column;
$column =~ s/^items\./deleteditems./ if($cellvalue eq "deleteditems");
my $colfield;
if ( ( $column =~ /dewey/ ) and ($deweydigits) ) {
$colfield = "left($column,$deweydigits)";
} elsif ( ( $column =~ /lccn/ ) and ($lccndigits) ) {
$colfield = "left($column,$lccndigits)";
} elsif ( ( $column =~ /itemcallnumber/ ) and ($cotedigits) ) {
$colfield = "left($column,$cotedigits)";
} elsif ( $column =~ /^deleteditems\.timestamp$/ ) {
$colfield = "DATE($column)";
} else {
$colfield = $column;
}
my $strsth2 = "
SELECT distinctrow $colfield
FROM biblioitems
INNER JOIN items
USING (biblioitemnumber)
INNER JOIN biblio
ON (biblioitems.biblionumber = biblio.biblionumber)
WHERE $column IS NOT NULL ";
$strsth2 .= " AND barcode $not LIKE ?" if $barcodefilter;
if (( @colfilter ) and ($colfilter[1])) {
$strsth2 .= " AND $column> ? AND $column< ?";
}elsif ($colfilter[0]){
$colfilter[0] =~ s/\*/%/g;
$strsth2 .= " AND $column LIKE ? ";
}
$strsth2 .= " ORDER BY $colfield";
$debug and print STDERR "SQL: $strsth2";
my $sth2 = $dbh->prepare( $strsth2 );
if ((@colfilter) and ($colfilter[1])) {
$sth2->execute($barcodefilter,$colfilter[0],$colfilter[1]);
} elsif ($colfilter[0]){
$sth2->execute($barcodefilter,$colfilter[0]);
} elsif ($barcodefilter){
$sth2->execute($barcodefilter);
} else {
$sth2->execute();
}
while (my ($celvalue) = $sth2->fetchrow) {
my %cell;
my %ft;
if ($celvalue) {
$cell{coltitle} = $celvalue;
# } else {
# $cell{coltitle} = "";
}
$ft{totalcol} = 0;
push @loopcol, \%cell;
}
my $i=0;
my @totalcol;
my $hilighted=-1;
#Initialization of cell values.....
my %table;
# warn "init table";
foreach my $row ( @loopline ) {
foreach my $col ( @loopcol ) {
# warn " init table : $row->{rowtitle} / $col->{coltitle} ";
$table{$row->{rowtitle}}->{$col->{coltitle}}=0;
}
$table{$row->{rowtitle}}->{totalrow}=0;
}
# preparing calculation
my $strcalc = "
SELECT $linefield, $colfield, count(*)
FROM biblioitems
INNER JOIN items ON (items.biblioitemnumber = biblioitems.biblioitemnumber)
INNER JOIN biblio ON (biblioitems.biblionumber = biblio.biblionumber)
my $strsth2 = "
SELECT distinctrow $colfield
FROM $itemstable
LEFT JOIN biblioitems
USING (biblioitemnumber)
LEFT JOIN biblio
ON (biblioitems.biblionumber = biblio.biblionumber)
WHERE 1 ";
$strcalc .= "AND barcode $not like ? " if ($barcodefilter);
$strsth2 .= " AND barcode $not LIKE ?" if $barcodefilter;
if (@$filters[0]){
@$filters[0]=~ s/\*/%/g;
$strcalc .= " AND dewey >" . @$filters[0];
}
if (@$filters[1]){
@$filters[1]=~ s/\*/%/g ;
$strcalc .= " AND dewey <" . @$filters[1];
}
if (@$filters[2]){
@$filters[2]=~ s/\*/%/g ;
$strcalc .= " AND lccn >" . @$filters[2];
}
if (@$filters[3]){
@$filters[3]=~ s/\*/%/g;
$strcalc .= " AND lccn <" . @$filters[3];
}
if (@$filters[4]){
@$filters[4]=~ s/\*/%/g ;
$strcalc .= " AND items.itemcallnumber >=" . $dbh->quote(@$filters[4]);
}
if ( (@colfilter) and ( $colfilter[1] ) ) {
$strsth2 .= " AND $column >= ? AND $column <= ?";
} elsif ( defined $colfilter[0] and $colfilter[0] ne '' ) {
$colfilter[0] =~ s/\*/%/g;
$strsth2 .= " AND $column LIKE ? ";
}
$strsth2 .= " ORDER BY $colfield";
$debug and print STDERR "SQL: $strsth2";
my $sth2 = $dbh->prepare($strsth2);
if ( $barcodefilter and (@colfilter) and ( $colfilter[1] ) ) {
$sth2->execute( $barcodefilter, $colfilter[0], $colfilter[1] );
} elsif ( (@colfilter) and ( $colfilter[1] ) ) {
$sth2->execute( $colfilter[0], $colfilter[1] );
} elsif ( $barcodefilter && $colfilter[0] ) {
$sth2->execute( $barcodefilter , $colfilter[0] );
} elsif ( $colfilter[0]) {
$sth2->execute( $colfilter[0] );
} elsif ($barcodefilter) {
$sth2->execute($barcodefilter);
} else {
$sth2->execute();
}
my $colauthvals = GetKohaAuthorisedValues($origcolumn);
while ( my ($celvalue) = $sth2->fetchrow ) {
my %cell;
if (defined $celvalue and $celvalue ne '') {
if($colauthvals and $colauthvals->{$celvalue}) {
$cell{coltitle} = $colauthvals->{$celvalue};
} else {
$cell{coltitle} = $celvalue;
}
$cell{value} = $celvalue;
}
else {
$cell{coltitle} = "NULL";
$cell{value} = "zzEMPTY";
}
$cell{totalcol} = 0;
push @loopcol, \%cell;
}
if (@$filters[5]){
@$filters[5]=~ s/\*/%/g;
$strcalc .= " AND items.itemcallnumber <=" . $dbh->quote(@$filters[5]);
}
my $i = 0;
my @totalcol;
my $hilighted = -1;
if (@$filters[6]){
@$filters[6]=~ s/\*/%/g;
$strcalc .= " AND " .
(C4::Context->preference('item-level_itypes') ? 'items.itype' : 'biblioitems.itemtype')
. " LIKE '" . @$filters[6] ."'";
}
#Initialization of cell values.....
my %table;
if (@$filters[7]){
@$filters[7]=~ s/\*/%/g;
@$filters[7].="%" unless @$filters[7]=~/%/;
$strcalc .= " AND biblioitems.publishercode LIKE \"" . @$filters[7] ."\"";
}
if (@$filters[8]){
@$filters[8]=~ s/\*/%/g;
foreach my $row (@loopline) {
foreach my $col (@loopcol) {
$table{ $row->{value} }->{ $col->{value} } = 0;
}
$table{ $row->{value} }->{totalrow} = 0;
}
# preparing calculation
my $select_cellvalue = " COUNT(*) ";
$select_cellvalue = " COUNT(DISTINCT biblioitems.biblionumber) " if($cellvalue eq 'biblios');
my $strcalc = "
SELECT $linefield, $colfield, $select_cellvalue
FROM $itemstable
LEFT JOIN biblioitems ON ($itemstable.biblioitemnumber = biblioitems.biblioitemnumber)
LEFT JOIN biblio ON (biblioitems.biblionumber = biblio.biblionumber)
WHERE 1 ";
$strcalc .= "AND barcode $not like ? " if ($barcodefilter);
if ( @$filters[0] ) {
@$filters[0] =~ s/\*/%/g;
$strcalc .= " AND dewey >" . @$filters[0];
}
if ( @$filters[1] ) {
@$filters[1] =~ s/\*/%/g;
$strcalc .= " AND dewey <" . @$filters[1];
}
if ( @$filters[2] ) {
@$filters[2] =~ s/\*/%/g;
$strcalc .= " AND lccn >" . @$filters[2];
}
if ( @$filters[3] ) {
@$filters[3] =~ s/\*/%/g;
$strcalc .= " AND lccn <" . @$filters[3];
}
if ( @$filters[4] ) {
@$filters[4] =~ s/\*/%/g;
$strcalc .= " AND $itemstable.itemcallnumber >=" . $dbh->quote( @$filters[4] );
}
if ( @$filters[5] ) {
@$filters[5] =~ s/\*/%/g;
$strcalc .= " AND $itemstable.itemcallnumber <=" . $dbh->quote( @$filters[5] );
}
if ( @$filters[6] ) {
@$filters[6] =~ s/\*/%/g;
$strcalc .= " AND " . ( C4::Context->preference('item-level_itypes') ? "$itemstable.itype" : 'biblioitems.itemtype' ) . " LIKE '" . @$filters[6] . "'";
}
if ( @$filters[7] ) {
@$filters[7] =~ s/\*/%/g;
@$filters[7] .= "%" unless @$filters[7] =~ /%/;
$strcalc .= " AND biblioitems.publishercode LIKE \"" . @$filters[7] . "\"";
}
if ( @$filters[8] ) {
@$filters[8] =~ s/\*/%/g;
$strcalc .= " AND " .
(C4::Context->preference('marcflavour') eq 'UNIMARC' ? 'publicationyear' : 'copyrightdate')
. ">" . @$filters[8];
}
if (@$filters[9]){
@$filters[9]=~ s/\*/%/g;
}
if ( @$filters[9] ) {
@$filters[9] =~ s/\*/%/g;
$strcalc .= " AND " .
(C4::Context->preference('marcflavour') eq 'UNIMARC' ? 'publicationyear' : 'copyrightdate')
. "<" . @$filters[9];
}
if (@$filters[10]){
@$filters[10]=~ s/\*/%/g;
$strcalc .= " AND items.homebranch LIKE '" . @$filters[10] ."'";
}
if (@$filters[11]){
@$filters[11]=~ s/\*/%/g;
$strcalc .= " AND items.location LIKE '" . @$filters[11] ."'";
}
if (@$filters[12]){
@$filters[12]=~ s/\*/%/g;
$strcalc .= " AND items.ccode LIKE '" . @$filters[12] ."'";
}
}
if ( @$filters[10] ) {
@$filters[10] =~ s/\*/%/g;
$strcalc .= " AND $itemstable.homebranch LIKE '" . @$filters[10] . "'";
}
if ( @$filters[11] ) {
@$filters[11] =~ s/\*/%/g;
$strcalc .= " AND $itemstable.location LIKE '" . @$filters[11] . "'";
}
if ( @$filters[12] ) {
@$filters[12] =~ s/\*/%/g;
$strcalc .= " AND $itemstable.ccode LIKE '" . @$filters[12] . "'";
}
if ( defined @$filters[13] and @$filters[13] ne '' ) {
@$filters[13] =~ s/\*/%/g;
$strcalc .= " AND $itemstable.notforloan LIKE '" . @$filters[13] . "'";
}
if ( defined @$filters[14] and @$filters[14] ne '' ) {
@$filters[14] =~ s/\*/%/g;
$strcalc .= " AND $itemstable.materials LIKE '" . @$filters[14] . "'";
}
if ( @$filters[17] ) {
@$filters[17] =~ s/\*/%/g;
$strcalc .= " AND $itemstable.dateaccessioned >= '@$filters[17]' ";
}
if ( @$filters[18] ) {
@$filters[18] =~ s/\*/%/g;
$strcalc .= " AND $itemstable.dateaccessioned <= '@$filters[18]' ";
}
if ( $cellvalue eq 'deleteditems' and @$filters[19] ) {
@$filters[19] =~ s/\*/%/g;
$strcalc .= " AND DATE(deleteditems.timestamp) >= '@$filters[19]' ";
}
if ( $cellvalue eq 'deleteditems' and @$filters[20] ) {
@$filters[20] =~ s/\*/%/g;
$strcalc .= " AND DATE(deleteditems.timestamp) <= '@$filters[20]' ";
}
$strcalc .= " group by $linefield, $colfield order by $linefield,$colfield";
$debug and warn "SQL: $strcalc";
my $dbcalc = $dbh->prepare($strcalc);
if ($barcodefilter) {
$dbcalc->execute($barcodefilter);
} else {
$dbcalc->execute();
}
$strcalc .= " group by $linefield, $colfield order by $linefield,$colfield";
$debug and warn "SQL: $strcalc";
my $dbcalc = $dbh->prepare($strcalc);
if($barcodefilter){
$dbcalc->execute($barcodefilter);
}else{
$dbcalc->execute();
}
# warn "filling table";
my $emptycol;
while (my ($row, $col, $value) = $dbcalc->fetchrow) {
# warn "filling table $row / $col / $value ";
$emptycol = 1 if (!defined($col));
$col = "zzEMPTY" if (!defined($col));
$row = "zzEMPTY" if (!defined($row));
while ( my ( $row, $col, $value ) = $dbcalc->fetchrow ) {
$table{$row}->{$col}+=$value;
$table{$row}->{totalrow}+=$value;
$grantotal += $value;
}
$col = "zzEMPTY" if ( !defined($col) );
$row = "zzEMPTY" if ( !defined($row) );
# my %cell = {rowtitle => 'zzROWEMPTY'};
# push @loopline,\%cell;
# undef %cell;
# my %cell;
# %cell = {coltitle => "zzEMPTY"};
push @loopcol,{coltitle => "NULL"} if ($emptycol);
$table{$row}->{$col} += $value;
$table{$row}->{totalrow} += $value;
$grantotal += $value;
}
foreach my $row ( sort keys %table ) {
my @loopcell;
#@loopcol ensures the order for columns is common with column titles
# and the number matches the number of columns
foreach my $col ( @loopcol ) {
my $value =$table{$row}->{($col->{coltitle} eq "NULL")?"zzEMPTY":$col->{coltitle}};
push @loopcell, {value => $value } ;
}
push @looprow,{ 'rowtitle' => ($row eq "zzEMPTY")?"NULL":$row,
'loopcell' => \@loopcell,
'hilighted' => ($hilighted *= -1 > 0),
'totalrow' => $table{$row}->{totalrow}
};
}
foreach my $row ( @loopline ) {
my @loopcell;
# warn "footer processing";
foreach my $col ( @loopcol ) {
my $total=0;
foreach my $row ( @looprow ) {
$total += $table{($row->{rowtitle} eq "NULL")?"zzEMPTY":$row->{rowtitle}}->{($col->{coltitle} eq "NULL")?"zzEMPTY":$col->{coltitle}};
# warn "value added ".$table{$row->{rowtitle}}->{$col->{coltitle}}. "for line ".$row->{rowtitle};
}
# warn "summ for column ".$col->{coltitle}." = ".$total;
push @loopfooter, {'totalcol' => $total};
}
#@loopcol ensures the order for columns is common with column titles
# and the number matches the number of columns
foreach my $col (@loopcol) {
my $value = $table{$row->{value}}->{ $col->{value} };
push @loopcell, { value => $value };
}
push @looprow,
{ 'rowtitle' => $row->{rowtitle},
'value' => $row->{value},
'loopcell' => \@loopcell,
'hilighted' => ( $hilighted *= -1 > 0 ),
'totalrow' => $table{$row->{value}}->{totalrow}
};
}
foreach my $col (@loopcol) {
my $total = 0;
foreach my $row (@looprow) {
$total += $table{ $row->{value} }->{ $col->{value} };
}
# the header of the table
$globalline{loopfilter}=\@loopfilter;
# the core of the table
$globalline{looprow} = \@looprow;
$globalline{loopcol} = \@loopcol;
# # the foot (totals by borrower type)
$globalline{loopfooter} = \@loopfooter;
$globalline{total}= $grantotal;
$globalline{line} = $line;
$globalline{column} = $column;
push @mainloop,\%globalline;
return \@mainloop;
push @loopfooter, { 'totalcol' => $total };
}
# the header of the table
$globalline{loopfilter} = \@loopfilter;
# the core of the table
$globalline{looprow} = \@looprow;
$globalline{loopcol} = \@loopcol;
# the foot (totals by borrower type)
$globalline{loopfooter} = \@loopfooter;
$globalline{total} = $grantotal;
$globalline{line} = $line;
$globalline{column} = $column;
push @mainloop, \%globalline;
return \@mainloop;
}
1;

View file

@ -17,7 +17,7 @@
use Modern::Perl;
use Test::More tests => 4;
use Test::More tests => 5;
use Test::MockModule;
use MARC::Record;
@ -290,5 +290,29 @@ subtest 'NORMARC' => sub {
$dbh->rollback;
};
subtest 'GetMarcSubfieldStructureFromKohaField' => sub {
plan tests => 23;
my @columns = qw(
tagfield tagsubfield liblibrarian libopac repeatable mandatory kohafield tab
authorised_value authtypecode value_builder isurl hidden frameworkcode
seealso link defaultvalue maxlength
);
# biblio.biblionumber must be mapped so this should return something
my $marc_subfield_structure = GetMarcSubfieldStructureFromKohaField('biblio.biblionumber', '');
ok(defined $marc_subfield_structure, "There is a result");
is(ref $marc_subfield_structure, "HASH", "Result is a hashref");
foreach my $col (@columns) {
ok(exists $marc_subfield_structure->{$col}, "Hashref contains key '$col'");
}
is($marc_subfield_structure->{kohafield}, 'biblio.biblionumber', "Result is the good result");
like($marc_subfield_structure->{tagfield}, qr/^\d{3}$/, "tagfield is a valid tagfield");
# foo.bar does not exist so this should return undef
$marc_subfield_structure = GetMarcSubfieldStructureFromKohaField('foo.bar', '');
is($marc_subfield_structure, undef, "invalid kohafield returns undef");
};
1;