# Suite 330, Boston, MA 02111-1307 USA
use strict;
-# use warnings; # FIXME
+use warnings;
use C4::Context;
use C4::Output;
-use CGI;
+use CGI qw(-oldstyle_urls);
use C4::Auth;
use C4::Branch;
+use C4::Debug;
use C4::Dates qw/format_date/;
use Date::Calc qw/Today/;
+use Text::CSV_XS;
my $input = new CGI;
-my $order = $input->param( 'order' ) || '';
-my $showall = $input->param('showall');
-
-my $bornamefilter = $input->param( 'borname');
-my $borcatfilter = $input->param( 'borcat' );
-my $itemtypefilter = $input->param('itemtype');
-my $borflagsfilter = $input->param('borflags') || "";
-my $branchfilter = $input->param( 'branch' );
-my $op = $input->param( 'op' ) || '';
+my $order = $input->param('order') || '';
+my $showall = $input->param('showall');
+my $bornamefilter = $input->param('borname') || '';
+my $borcatfilter = $input->param('borcat') || '';
+my $itemtypefilter = $input->param('itemtype') || '';
+my $borflagsfilter = $input->param('borflag') || '';
+my $branchfilter = $input->param('branch') || '';
+my $op = $input->param('op') || '';
+my $isfiltered = $op =~ /apply/i && $op =~ /filter/i;
+my $noreport = C4::Context->preference('FilterBeforeOverdueReport') && ! $isfiltered && $op ne "csv";
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
{
my $dbh = C4::Context->dbh;
-# download the complete CSV
-if ($op eq 'csv') {
-warn "BRANCH : $branchfilter";
- my $lib = $branchfilter ? "-library $branchfilter" :'';
- my $csv = `../misc/cronjobs/overdue_notices.pl -csv -n $lib`;
- print $input->header(-type => 'application/vnd.sun.xml.calc',
- -encoding => 'utf-8',
- -attachment=>"overdues.csv",
- -filename=>"overdues.csv" );
- print $csv;
- exit;
-}
my $req;
$req = $dbh->prepare( "select categorycode, description from categories order by description");
$req->execute;
};
}
my $onlymine=C4::Context->preference('IndependantBranches') &&
- C4::Context->userenv &&
- C4::Context->userenv->{flags} % 2 !=1 &&
+ C4::Context->userenv &&
+ C4::Context->userenv->{flags} % 2 !=1 &&
C4::Context->userenv->{branch};
$branchfilter = C4::Context->userenv->{'branch'} if ($onlymine && !$branchfilter);
-$template->param(
- branchloop => GetBranchesLoop($branchfilter, $onlymine),
- branchfilter => $branchfilter,
- borcatloop => \@borcatloop,
- itemtypeloop => \@itemtypeloop,
- borname => $bornamefilter,
- order => $order,
- showall => $showall,
-);
+# Filtering by Patron Attributes
+# @patron_attr_filter_loop is non empty if there are any patron attribute filters
+# %cgi_attrcode_to_attrvalues contains the patron attribute filter values, as returned by the CGI
+# %borrowernumber_to_attributes is populated by those borrowernumbers matching the patron attribute filters
+
+my %cgi_attrcode_to_attrvalues; # ( patron_attribute_code => [ zero or more attribute filter values from the CGI ] )
+for my $attrcode (grep { /^patron_attr_filter_/ } $input->param) {
+ if (my @attrvalues = grep { length($_) > 0 } $input->param($attrcode)) {
+ $attrcode =~ s/^patron_attr_filter_//;
+ $cgi_attrcode_to_attrvalues{$attrcode} = \@attrvalues;
+ print STDERR ">>>param($attrcode)[@{[scalar @attrvalues]}] = '@attrvalues'\n" if $debug;
+ }
+}
+my $have_pattr_filter_data = keys(%cgi_attrcode_to_attrvalues) > 0;
+
+my @patron_attr_filter_loop; # array of [ domid cgivalue ismany isclone ordinal code description repeatable authorised_value_category ]
+my @patron_attr_order_loop; # array of { label => $patron_attr_label, value => $patron_attr_order }
my @sort_roots = qw(borrower title barcode date_due);
push @sort_roots, map {$_ . " desc"} @sort_roots;
push @order_loop, {
selected => $order eq $_ ? 1 : 0,
ordervalue => $_,
- foo => $tmpl_name,
'order_' . $tmpl_name => 1,
};
}
-$template->param(ORDER_LOOP => \@order_loop);
-my $todaysdate = sprintf("%-04.4d-%-02.2d-%02.2d", Today());
-
-$bornamefilter =~s/\*/\%/g;
-$bornamefilter =~s/\?/\_/g;
-
-my $strsth="SELECT date_due,
- concat(surname,' ', firstname) as borrower,
- borrowers.phone,
- borrowers.email,
- issues.itemnumber,
- items.barcode,
- biblio.title,
- biblio.author,
- borrowers.borrowernumber,
- biblio.biblionumber,
- borrowers.branchcode
- FROM issues
-LEFT JOIN borrowers ON (issues.borrowernumber=borrowers.borrowernumber )
-LEFT JOIN items ON (issues.itemnumber=items.itemnumber)
-LEFT JOIN biblioitems ON (biblioitems.biblioitemnumber=items.biblioitemnumber)
-LEFT JOIN biblio ON (biblio.biblionumber=items.biblionumber )
-WHERE 1=1 "; # placeholder, since it is possible that none of the additional
- # conditions will be selected by user
-$strsth.=" AND date_due < '" . $todaysdate . "' " unless ($showall);
-$strsth.=" AND (borrowers.firstname like '".$bornamefilter."%' or borrowers.surname like '".$bornamefilter."%' or borrowers.cardnumber like '".$bornamefilter."%')" if($bornamefilter) ;
-$strsth.=" AND borrowers.categorycode = '" . $borcatfilter . "' " if $borcatfilter;
-$strsth.=" AND biblioitems.itemtype = '" . $itemtypefilter . "' " if $itemtypefilter;
-$strsth.=" AND borrowers.flags = '" . $borflagsfilter . "' " if $borflagsfilter;
-$strsth.=" AND borrowers.branchcode = '" . $branchfilter . "' " if $branchfilter;
-$strsth.=" ORDER BY " . (
- ($order eq "borrower" or $order eq "borrower desc") ? "$order, date_due" :
- ($order eq "title" or $order eq "title desc") ? "$order, date_due, borrower" :
- ($order eq "barcode" or $order eq "barcode desc") ? "items.$order, date_due, borrower" :
- ($order eq "date_due desc") ? "date_due DESC, borrower" :
- "date_due, borrower" # default sort order
-);
-$template->param(sql=>$strsth);
-my $sth=$dbh->prepare($strsth);
-#warn "overdue.pl : query string ".$strsth;
+my $sth = $dbh->prepare('SELECT code,description,repeatable,authorised_value_category
+ FROM borrower_attribute_types
+ WHERE staff_searchable <> 0
+ ORDER BY description');
$sth->execute();
+my $ordinal = 0;
+while (my $row = $sth->fetchrow_hashref) {
+ $row->{ordinal} = $ordinal;
+ my $code = $row->{code};
+ my $cgivalues = $cgi_attrcode_to_attrvalues{$code} || [ '' ];
+ my $isclone = 0;
+ $row->{ismany} = @$cgivalues > 1;
+ my $serial = 0;
+ for (@$cgivalues) {
+ $row->{domid} = $ordinal * 1000 + $serial;
+ $row->{cgivalue} = $_;
+ $row->{isclone} = $isclone;
+ push @patron_attr_filter_loop, { %$row }; # careful: must store a *deep copy* of the modified row
+ } continue { $isclone = 1, ++$serial }
+ foreach my $sortorder ('asc', 'desc') {
+ my $ordervalue = "patron_attr_${sortorder}_${code}";
+ push @order_loop, {
+ selected => $order eq $ordervalue ? 1 : 0,
+ ordervalue => $ordervalue,
+ label => $row->{description},
+ $sortorder => 1,
+ };
+ }
+} continue { ++$ordinal }
+for (@patron_attr_order_loop) { $_->{selected} = 1 if $order eq $_->{value} }
-my @overduedata;
-while (my $data=$sth->fetchrow_hashref) {
- push @overduedata, {
- duedate => format_date($data->{date_due}),
- borrowernumber => $data->{borrowernumber},
- barcode => $data->{barcode},
- itemnum => $data->{itemnumber},
- name => $data->{borrower},
- phone => $data->{phone},
- email => $data->{email},
- biblionumber => $data->{biblionumber},
- title => $data->{title},
- author => $data->{author},
- branchcode => $data->{branchcode},
- };
+$template->param(ORDER_LOOP => \@order_loop);
+
+my %borrowernumber_to_attributes; # hash of { borrowernumber => { attrcode => [ [val,display], [val,display], ... ] } }
+ # i.e. val differs from display when attr is an authorised value
+if (@patron_attr_filter_loop) {
+ # MAYBE FIXME: currently, *all* borrower_attributes are loaded into %borrowernumber_to_attributes
+ # then filtered and honed down to match the patron attribute filters. If this is
+ # too resource intensive, MySQL can be used to do the filtering, i.e. rewire the
+ # SQL below to select only those attribute values that match the filters.
+
+ my $sql = q(SELECT borrowernumber AS bn, b.code, attribute AS val, category AS avcategory, lib AS avdescription
+ FROM borrower_attributes b
+ JOIN borrower_attribute_types bt ON (b.code = bt.code)
+ LEFT JOIN authorised_values a ON (a.category = bt.authorised_value_category AND a.authorised_value = b.attribute));
+ my $sth = $dbh->prepare($sql);
+ $sth->execute();
+ while (my $row = $sth->fetchrow_hashref) {
+ my $pattrs = $borrowernumber_to_attributes{$row->{bn}} ||= { };
+ push @{ $pattrs->{$row->{code}} }, [
+ $row->{val},
+ defined $row->{avdescription} ? $row->{avdescription} : $row->{val},
+ ];
+ }
+
+ for my $bn (keys %borrowernumber_to_attributes) {
+ my $pattrs = $borrowernumber_to_attributes{$bn};
+ my $keep = 1;
+ for my $code (keys %cgi_attrcode_to_attrvalues) {
+ # discard patrons that do not match (case insensitive) at least one of each attribute filter value
+ my $discard = 1;
+ for my $attrval (map { lc $_ } @{ $cgi_attrcode_to_attrvalues{$code} }) {
+ ## if (grep { $attrval eq lc($_->[0]) } @{ $pattrs->{$code} })
+ if (grep { $attrval eq lc($_->[1]) } @{ $pattrs->{$code} }) {
+ $discard = 0;
+ last;
+ }
+ }
+ if ($discard) {
+ $keep = 0;
+ last;
+ }
+ }
+ if ($debug) {
+ my $showkeep = $keep ? 'keep' : 'do NOT keep';
+ print STDERR ">>> patron $bn: $showkeep attributes: ";
+ for (sort keys %$pattrs) { my @a=map { "$_->[0]/$_->[1] " } @{$pattrs->{$_}}; print STDERR "attrcode $_ = [@a] " }
+ print STDERR "\n";
+ }
+ delete $borrowernumber_to_attributes{$bn} if !$keep;
+ }
}
+
$template->param(
- todaysdate => format_date($todaysdate),
- overdueloop => \@overduedata
-);
+ patron_attr_header_loop => [ map { { header => $_->{description} } } grep { ! $_->{isclone} } @patron_attr_filter_loop ],
+ branchloop => GetBranchesLoop($branchfilter, $onlymine),
+ branchfilter => $branchfilter,
+ borcatloop=> \@borcatloop,
+ itemtypeloop => \@itemtypeloop,
+ patron_attr_filter_loop => \@patron_attr_filter_loop,
+ borname => $bornamefilter,
+ order => $order,
+ showall => $showall);
+
+if ($noreport) {
+ # la de dah ... page comes up presto-quicko
+ $template->param( noreport => $noreport );
+} else {
+ # FIXME : the left joins + where clauses make the following SQL query really slow with large datasets :(
+ #
+ # FIX 1: use the table with the least rows as first in the join, second least second, etc
+ # ref: http://www.fiftyfoureleven.com/weblog/web-development/programming-and-scripts/mysql-optimization-tip
+ #
+ # FIX 2: ensure there are indexes for columns participating in the WHERE clauses, where feasible/reasonable
+
+
+ my $todaysdate = sprintf("%-04.4d-%-02.2d-%02.2d", Today());
+
+ $bornamefilter =~s/\*/\%/g;
+ $bornamefilter =~s/\?/\_/g;
+
+ my $strsth="SELECT date_due,
+ concat(surname,' ', firstname) as borrower,
+ borrowers.phone,
+ borrowers.email,
+ issues.itemnumber,
+ items.barcode,
+ biblio.title,
+ biblio.author,
+ borrowers.borrowernumber,
+ biblio.biblionumber,
+ borrowers.branchcode,
+ items.itemcallnumber,
+ items.replacementprice
+ FROM issues
+ LEFT JOIN borrowers ON (issues.borrowernumber=borrowers.borrowernumber )
+ LEFT JOIN items ON (issues.itemnumber=items.itemnumber)
+ LEFT JOIN biblioitems ON (biblioitems.biblioitemnumber=items.biblioitemnumber)
+ LEFT JOIN biblio ON (biblio.biblionumber=items.biblionumber )
+ WHERE 1=1 "; # placeholder, since it is possible that none of the additional
+ # conditions will be selected by user
+ $strsth.=" AND date_due < '" . $todaysdate . "' " unless ($showall);
+ $strsth.=" AND (borrowers.firstname like '".$bornamefilter."%' or borrowers.surname like '".$bornamefilter."%' or borrowers.cardnumber like '".$bornamefilter."%')" if($bornamefilter) ;
+ $strsth.=" AND borrowers.categorycode = '" . $borcatfilter . "' " if $borcatfilter;
+ $strsth.=" AND biblioitems.itemtype = '" . $itemtypefilter . "' " if $itemtypefilter;
+ $strsth.=" AND borrowers.flags = '" . $borflagsfilter . "' " if $borflagsfilter;
+ $strsth.=" AND borrowers.branchcode = '" . $branchfilter . "' " if $branchfilter;
+ # restrict patrons (borrowers) to those matching the patron attribute filter(s), if any
+ my $bnlist = $have_pattr_filter_data ? join(',',keys %borrowernumber_to_attributes) : '';
+ $strsth =~ s/WHERE 1=1/WHERE 1=1 AND borrowers.borrowernumber IN ($bnlist)/ if $bnlist;
+ $strsth =~ s/WHERE 1=1/WHERE 0=1/ if $have_pattr_filter_data && !$bnlist; # no match if no borrowers matched patron attrs
+ $strsth.=" ORDER BY " . (
+ ($order eq "borrower" or $order eq "borrower desc") ? "$order, date_due" :
+ ($order eq "title" or $order eq "title desc") ? "$order, date_due, borrower" :
+ ($order eq "barcode" or $order eq "barcode desc") ? "items.$order, date_due, borrower" :
+ ($order eq "date_due desc") ? "date_due DESC, borrower" :
+ "date_due, borrower" # default sort order
+ );
+ $template->param(sql=>$strsth);
+ my $sth=$dbh->prepare($strsth);
+ #warn "overdue.pl : query string ".$strsth;
+ $sth->execute();
+
+ my @overduedata;
+ while (my $data = $sth->fetchrow_hashref) {
+
+ # most of the overdue report data is linked to the database schema, i.e. things like borrowernumber and phone
+ # but the patron attributes (patron_attr_value_loop) are unnormalised and varies dynamically from one db to the next
+
+ my $pattrs = $borrowernumber_to_attributes{$data->{borrowernumber}} || {}; # patron attrs for this borrower
+ # $pattrs is a hash { attrcode => [ [value,displayvalue], [value,displayvalue]... ] }
+
+ my @patron_attr_value_loop; # template array [ {value=>v1}, {value=>v2} ... } ]
+ for my $pattr_filter (grep { ! $_->{isclone} } @patron_attr_filter_loop) {
+ my @displayvalues = map { $_->[1] } @{ $pattrs->{$pattr_filter->{code}} }; # grab second value from each subarray
+ push @patron_attr_value_loop, { value => join(', ', sort { lc $a cmp lc $b } @displayvalues) };
+ }
+
+ push @overduedata, {
+ duedate => format_date($data->{date_due}),
+ borrowernumber => $data->{borrowernumber},
+ barcode => $data->{barcode},
+ itemnum => $data->{itemnumber},
+ name => $data->{borrower},
+ phone => $data->{phone},
+ email => $data->{email},
+ biblionumber => $data->{biblionumber},
+ title => $data->{title},
+ author => $data->{author},
+ branchcode => $data->{branchcode},
+ itemcallnumber => $data->{itemcallnumber},
+ replacementprice => $data->{replacementprice},
+ patron_attr_value_loop => \@patron_attr_value_loop,
+ };
+ }
+
+ my ($attrorder) = $order =~ /patron_attr_(.*)$/;
+ my $patrorder = '';
+ my $sortorder = 'asc';
+ if (defined $attrorder) {
+ ($sortorder, $patrorder) = split /_/, $attrorder, 2;
+ }
+ print STDERR ">>> order is $order, patrorder is $patrorder, sortorder is $sortorder\n" if $debug;
+
+ if (my @attrtype = grep { $_->{'code'} eq $patrorder } @patron_attr_filter_loop) { # sort by patron attrs perhaps?
+ my $ordinal = $attrtype[0]{ordinal};
+ print STDERR ">>> sort ordinal is $ordinal\n" if $debug;
+
+ sub patronattr_sorter_asc {
+ lc $a->{patron_attr_value_loop}[$ordinal]{value}
+ cmp
+ lc $b->{patron_attr_value_loop}[$ordinal]{value} }
+
+ sub patronattr_sorter_des { -patronattr_sorter_asc() }
+
+ my $sorter = $sortorder eq 'desc' ? \&patronattr_sorter_des : \&patronattr_sorter_asc;
+ @overduedata = sort $sorter @overduedata;
+ }
+
+ if ($op eq 'csv') {
+ binmode(STDOUT, ":utf8");
+ my $csv = build_csv(\@overduedata);
+ print $input->header(-type => 'application/vnd.sun.xml.calc',
+ -encoding => 'utf-8',
+ -attachment=>"overdues.csv",
+ -filename=>"overdues.csv" );
+ print $csv;
+ exit;
+ }
+
+ # generate parameter list for CSV download link
+ my $new_cgi = CGI->new($input);
+ $new_cgi->delete('op');
+ my $csv_param_string = $new_cgi->query_string();
+
+ $template->param(
+ csv_param_string => $csv_param_string,
+ todaysdate => format_date($todaysdate),
+ overdueloop => \@overduedata,
+ nnoverdue => scalar(@overduedata),
+ noverdue_is_plural => scalar(@overduedata) != 1,
+ noreport => $noreport,
+ isfiltered => $isfiltered,
+ borflag_gonenoaddress => $borflagsfilter eq 'gonenoaddress',
+ borflag_debarred => $borflagsfilter eq 'debarred',
+ borflag_lost => $borflagsfilter eq 'lost',
+ );
+
+}
output_html_with_http_headers $input, $cookie, $template->output;
+
+
+sub build_csv {
+ my $overdues = shift;
+
+ return "" if scalar(@$overdues) == 0;
+
+ my @lines = ();
+
+ # build header ...
+ my @keys = grep { $_ ne 'patron_attr_value_loop' } sort keys %{ $overdues->[0] };
+ my $csv = Text::CSV_XS->new();
+ $csv->combine(@keys);
+ push @lines, $csv->string();
+
+ # ... and rest of report
+ foreach my $overdue ( @{ $overdues } ) {
+ push @lines, $csv->string() if $csv->combine(map { $overdue->{$_} } @keys);
+ }
+
+ return join("\n", @lines) . "\n";
+}
<!-- TMPL_INCLUDE NAME="doc-head-open.inc" -->
<title>Koha › Circulation › Items Overdue as of <!-- TMPL_VAR NAME="todaysdate" --></title>
<!-- TMPL_INCLUDE NAME="doc-head-close.inc" -->
+<script type="text/JavaScript" language="JavaScript">
+//<![CDATA[
+ function clone_parent(node) {
+ var parent = node.parentNode;
+ var clone = parent.cloneNode(true);
+ $("a", clone).attr("style", "visibility: visible");
+ $("input", clone).attr("value", "");
+
+ var theid = $("span", clone).attr("id") || "";
+ var parts = theid.match(/^pattrodue-getready-(.*)$/);
+ if (parts && parts.length > 1)
+ {
+ var appendid = "-" + Math.floor(Math.random()*1000+1);
+ $("span", clone).attr("id",theid+appendid);
+
+ theid = $("input", clone).attr("id");
+ $("input", clone).attr("id",theid+appendid);
+
+ theid = $("div[id]", clone).attr("id");
+ $("div[id]", clone).attr("id",theid+appendid);
+
+ var attrcode = $("script", clone).attr("x-code");
+ var newsuffix = parts[1] + appendid;
+ create_auto_completion_responder(newsuffix,attrcode);
+ }
+
+ parent.parentNode.insertBefore(clone, parent.nextSibling);
+ }
+ function delete_parent(node) {
+ var parent = node.parentNode;
+ parent.parentNode.removeChild(parent);
+ }
+ function create_auto_completion_responder(uniqueid,attrcode) {
+ YAHOO.util.Event.onContentReady("pattrodue-getready-"+uniqueid, function() {
+ new function() {
+ // Define a custom formatter function
+ this.fnCustomFormatter = function(oResultItem, sQuery) {
+ var description = oResultItem[0];
+ var authorised_value = oResultItem[1];
+ var aMarkup = [
+ "<div class='pattrodue-result'>",
+ description,
+ " (",
+ authorised_value,
+ ")",
+ "</div>"];
+ return (aMarkup.join(""));
+ };
+
+ // Instantiate an XHR DataSource
+ this.oACDS = new YAHOO.widget.DS_XHR("/cgi-bin/koha/circ/ypattrodue-attr-search-authvalue.pl/"+attrcode, ["\n", "\t"]);
+ this.oACDS.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT;
+ this.oACDS.maxCacheEntries = 60;
+ this.oACDS.queryMatchSubset = true;
+
+ // Instantiate an AutoComplete Widget with uniqueid
+ var myInput = document.getElementById('pattrodue-input-'+uniqueid);
+ var myContainer = document.getElementById('pattrodue-container-'+uniqueid);
+ this.oAutoComp = new YAHOO.widget.AutoComplete(myInput,myContainer,this.oACDS);
+ this.oAutoComp.formatResult = this.fnCustomFormatter;
+ }
+ });
+ }
+//]]>
+</script>
<style type="text/css">
.sql {display:none;}
</style>
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/circ/circulation-home.pl">Circulation</a> › Overdues as of <!-- TMPL_VAR NAME="todaysdate" --></div>
<div id="doc3" class="yui-t2">
-
+
<div id="bd">
<div id="yui-main">
<div class="yui-b">
-<h2>Items Overdue as of <!-- TMPL_VAR NAME="todaysdate" --></h2>
-<p><a href="overdue.pl?op=csv&branch=<!-- TMPL_VAR name="branchfilter" -->">Download file of all overdues</a> (for <!-- TMPL_IF name="branchfilter" -->branch <!-- TMPL_VAR name="branchfilter" --><!-- TMPL_ELSE -->all branches<!-- /TMPL_IF -->. Other filters are ignored)</p>
+<!-- TMPL_IF name="noreport" -->
+
+<h2>Overdue Report</h2>
+
+<p>Please choose one or more filters to proceed.</p>
+
+<!-- TMPL_ELSE -->
+
+<h2><!-- TMPL_VAR NAME="nnoverdue" --> Item<!-- TMPL_IF NAME="noverdue_is_plural" -->s<!-- /TMPL_IF -->
+ Overdue as of <!-- TMPL_VAR NAME="todaysdate" --><!-- TMPL_IF NAME="isfiltered" --> (filtered)<!-- /TMPL_IF --></h2>
+
+<p>
+ <!-- TMPL_IF NAME="isfiltered" -->
+ <a href="overdue.pl?op=csv&<!-- TMPL_VAR name="csv_param_string" escape="HTML" -->">Download file of displayed overdues</a>
+ <!-- TMPL_ELSE -->
+ <a href="overdue.pl?op=csv">Download file of all overdues</a>
+ <!-- /TMPL_IF -->
+</p>
<div class="sql"><pre><!-- TMPL_VAR NAME="sql" ESCAPE="HTML" --></pre></div>
<div class="searchresults">
<table id="overduest">
<th>Patron</th>
<th>Library</th>
<th>Title</th>
+ <th>Barcode</th>
+ <th>Call number</th>
</tr></thead>
<tbody><!-- TMPL_LOOP NAME="overdueloop" -->
<!-- TMPL_ELSE -->
<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=<!-- TMPL_VAR NAME="biblionumber" ESCAPE="URL" -->"><!-- TMPL_VAR NAME="title" escape="html" --> <!-- TMPL_VAR NAME="subtitle" --></a><!-- /TMPL_IF --> <!-- TMPL_IF NAME="author" -->, by <!-- TMPL_VAR NAME="author" --><!-- /TMPL_IF -->
</td>
- </tr>
+ <td><a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=<!-- TMPL_VAR NAME="biblionumber" -->&itemnumber=<!-- TMPL_VAR NAME="itemnum" -->#item<!-- TMPL_VAR NAME="itemnum" -->"><!-- TMPL_VAR name="barcode" --></a></td>
+ <td><!-- TMPL_VAR name="itemcallnumber" --></td>
+ </tr>
<!-- /TMPL_LOOP --></tbody>
</table>
+
</div>
+<!-- /TMPL_IF --> <!-- noreport -->
+
</div>
</div>
<div class="yui-b">
<fieldset class="brief">
<h4>Filter On:</h4>
<ol>
- <li><label>Name or cardnumber:</label><input type="text" name="borname" value="<!--TMPL_VAR Name="borname"-->" /></li>
+ <li><label>Name or cardnumber:</label><input type="text" name="borname" value="<!--TMPL_VAR Name="borname" escape="html" -->" /></li>
<li><label>Patron category:</label><select name="borcat" id="borcat"><option value="">Any</option>
<!-- TMPL_LOOP name="borcatloop" -->
- <!-- TMPL_IF NAME="selected" --><option value="<!-- TMPL_VAR name="value" -->" selected="selected"><!-- TMPL_VAR name="catname" --></option><!-- TMPL_ELSE --><option value="<!-- TMPL_VAR name="value" -->"><!-- TMPL_VAR name="catname" --></option><!-- /TMPL_IF -->
+ <!-- TMPL_IF NAME="selected" --><option value="<!-- TMPL_VAR name="value" escape="html" -->" selected="selected"><!-- TMPL_VAR name="catname" --></option><!-- TMPL_ELSE --><option value="<!-- TMPL_VAR name="value" escape="html" -->"><!-- TMPL_VAR name="catname" --></option><!-- /TMPL_IF -->
<!-- /TMPL_LOOP -->
</select>
</li>
<li><label>Patron flags:</label>
- <select name="borflags" size="1" id="borflags">
- <option value=""></option>
- <option value="gonenoaddress">Address in question</option>
- <option value="debarred">Debarred</option>
- <option value="lost">Lost Card</option>
+ <select name="borflag" size="1" id="borflag">
+ <option value="">None</option>
+ <option value="gonenoaddress"<!-- TMPL_IF NAME="borflag_gonenoaddress" --> selected="selected"<!-- /TMPL_IF -->>Address in question</option>
+ <option value="debarred"<!-- TMPL_IF NAME="borflag_debarred" --> selected="selected"<!-- /TMPL_IF -->>Debarred</option>
+ <option value="lost"<!-- TMPL_IF NAME="borflag_lost" --> selected="selected"<!-- /TMPL_IF -->>Lost Card</option>
</select>
</li>
+ <!-- TMPL_LOOP name="patron_attr_filter_loop" -->
+ <!-- domid cgivalue ismany isclone ordinal code description repeatable authorised_value_category -->
+ <li>
+ <label><!-- TMPL_VAR name="description" -->:</label>
+ <!-- TMPL_IF NAME="authorised_value_category"-->
+ <script type="text/JavaScript" language="JavaScript" x-code="<!-- TMPL_VAR name="code" escape="html" -->">create_auto_completion_responder(<!-- TMPL_VAR name="domid" -->,"<!-- TMPL_VAR name="code" escape="html" -->");</script>
+ <span id="pattrodue-getready-<!-- TMPL_VAR name="domid" -->">
+ <div class="pattrodue-autocomplete">
+ <input autocomplete="off" id="pattrodue-input-<!-- TMPL_VAR name="domid" -->" name="patron_attr_filter_<!-- TMPL_VAR name="code" escape="html" -->" value="<!-- TMPL_VAR name="cgivalue" escape="html" -->" class="pattrodue-input" type="text" />
+ <div id="pattrodue-container-<!-- TMPL_VAR name="domid" -->" class="pattrodue-container"></div>
+ </div>
+ </span>
+ <!-- TMPL_ELSE -->
+ <input name="patron_attr_filter_<!-- TMPL_VAR name="code" escape="html" -->" value="<!-- TMPL_VAR name="cgivalue" escape="html" -->"/>
+ <!-- /TMPL_IF -->
+ <!-- TMPL_IF NAME="repeatable"-->
+ <a href="#" onclick="clone_parent(this); return false;">Add</a>
+ <!-- TMPL_IF NAME="isclone" -->
+ <a href="#" onclick="delete_parent(this); return false;" style="visibility: visible">Delete</a>
+ <!-- TMPL_ELSIF NAME="ismany" -->
+ <a href="#" onclick="delete_parent(this); return false;" style="visibility: visible">Delete</a>
+ <!-- TMPL_ELSE -->
+ <a href="#" onclick="delete_parent(this); return false;" style="visibility: hidden">Delete</a>
+ <!-- /TMPL_IF -->
+ <!-- /TMPL_IF -->
+ </li>
+ <!-- /TMPL_LOOP -->
+
<li><label>Item type:</label><select name="itemtype" id="itemtype"><option value="">Any</option>
<!-- TMPL_LOOP name="itemtypeloop" --><!-- TMPL_IF NAME="selected" -->
- <option value="<!-- TMPL_VAR name="value" -->" selected="selected"><!-- TMPL_VAR name="itemtypename" --></option><!-- TMPL_ELSE -->
- <option value="<!-- TMPL_VAR name="value" -->"><!-- TMPL_VAR name="itemtypename" --></option><!-- /TMPL_IF -->
+ <option value="<!-- TMPL_VAR name="value" escape="html" -->" selected="selected"><!-- TMPL_VAR name="itemtypename" --></option><!-- TMPL_ELSE -->
+ <option value="<!-- TMPL_VAR name="value" escape="html" -->"><!-- TMPL_VAR name="itemtypename" --></option><!-- /TMPL_IF -->
<!-- /TMPL_LOOP -->
</select>
</li>
+
<li>
<label>Library of the patron:</label><select name="branch" id="branch">
<option value="">Any</option>
<!-- TMPL_LOOP name="branchloop" -->
<!-- TMPL_IF NAME="selected" -->
- <option value="<!-- TMPL_VAR name="value" -->" selected="selected"><!-- TMPL_VAR name="branchname" --></option><!-- TMPL_ELSE -->
- <option value="<!-- TMPL_VAR name="value" -->"><!-- TMPL_VAR name="branchname" --></option><!-- /TMPL_IF -->
+ <option value="<!-- TMPL_VAR name="value" escape="html" -->" selected="selected"><!-- TMPL_VAR name="branchname" --></option><!-- TMPL_ELSE -->
+ <option value="<!-- TMPL_VAR name="value" escape="html" -->"><!-- TMPL_VAR name="branchname" --></option><!-- /TMPL_IF -->
<!-- /TMPL_LOOP -->
</select>
</li>
-
+
<li><label for="order">Sort By:</label> <select name="order" id="order">
<!-- TMPL_LOOP NAME="ORDER_LOOP" -->
<!-- TMPL_IF NAME="selected" -->
<option value="<!-- TMPL_VAR NAME="ordervalue" DEFAULT="" -->" selected="selected">
<!-- TMPL_ELSE -->
<option value="<!-- TMPL_VAR NAME="ordervalue" DEFAULT="" -->">
- <!-- /TMPL_IF -->[<!-- TMPL_VAR name="foo" -->]
+ <!-- /TMPL_IF -->
<!-- TMPL_IF NAME="order_date_due" -->Due Date
<!-- TMPL_ELSIF NAME="order_borrower" -->Patron
<!-- TMPL_ELSIF NAME="order_barcode" -->Barcode
<!-- TMPL_ELSIF NAME="order_borrower_desc" -->Patron desc
<!-- TMPL_ELSIF NAME="order_barcode_desc" -->Barcode desc
<!-- TMPL_ELSIF NAME="order_title_desc" -->Title desc
+ <!-- TMPL_ELSE --><!-- TMPL_VAR NAME="label" -->
+ <!-- TMPL_IF NAME="desc" -->desc<!-- /TMPL_IF -->
<!-- /TMPL_IF -->
</option>
<!-- /TMPL_LOOP -->
+ <!-- TMPL_LOOP name="patron_attr_order_loop" -->
+ <option value="<!-- TMPL_VAR name="value" escape="html" -->"<!-- TMPL_IF NAME="selected" --> selected="selected"<!-- /TMPL_IF -->><!-- TMPL_VAR name="label" --></option>
+ <!-- /TMPL_LOOP -->
</select></li>
+
<li class="radio"><label for="showall">Show any items currently issued:</label>
- <!-- TMPL_IF NAME="showall" --><input type="checkbox" id="showall" name="showall" value="show" checked="checked" /><!-- TMPL_ELSE --><input type="checkbox" id="showall" name="showall" value="show" /><!-- /TMPL_IF -->
+ <!-- TMPL_IF NAME="showall" -->
+ <input type="checkbox" id="showall" name="showall" value="show" checked="checked" />
+ <!-- TMPL_ELSE -->
+ <input type="checkbox" id="showall" name="showall" value="show" />
+ <!-- /TMPL_IF -->
</li>
</ol>
<fieldset class="action">
- <input type="submit" value="Apply Filter" class="submit" />
- </fieldset>
- </fieldset>
+ <input type="submit" name="op" value="Apply Filter" class="submit" />
+ </fieldset>
+ </fieldset>
</form>
</div>
</div>
+
<!-- TMPL_INCLUDE NAME="intranet-bottom.inc" -->