Bugzilla – Attachment 19056 Details for
Bug 9811
Patrons search improvements
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 9811: Patron search improvement
Bug-9811-Patron-search-improvement.patch (text/plain), 59.71 KB, created by
Jonathan Druart
on 2013-06-17 08:48:24 UTC
(
hide
)
Description:
Bug 9811: Patron search improvement
Filename:
MIME Type:
Creator:
Jonathan Druart
Created:
2013-06-17 08:48:24 UTC
Size:
59.71 KB
patch
obsolete
>From 2155eb21fa02798c799fff9d17306611bb201f3d Mon Sep 17 00:00:00 2001 >From: Jonathan Druart <jonathan.druart@biblibre.com> >Date: Tue, 19 Mar 2013 11:12:26 +0100 >Subject: [PATCH] Bug 9811: Patron search improvement > >This patch add DataTables using server-side processing for the patrons >search. > >It adds: >- 1 module C4/Utils/DataTables/Members.pm >- 1 service svc/members/search >- 1 template members/tables/members_results.tt >- 1 new practice which is to add template for DataTables in a > subdirectory named 'tables'. > >Impacted scripts: members/members-home.pl and members/members.pl > >To go further: We can imagine that all patrons searches use the same >service with no big changes: 1 little template creates a JSON file and >to implement DataTables on the template page, that's all. > >Test plan: >- Check that there is no regression on searching patrons. >- Try filters on the left of the screen >- Try to sort each column >- Try the "Browse by last name" links. >- Check that the "Clear" button clears yours filters. >- Try with IndependantBranches ON and OFF > >Signed-off-by: Cedric Vita <cedric.vita@dracenie.com> >--- > C4/Members.pm | 6 +- > C4/Utils/DataTables/Members.pm | 201 ++++++++++ > .../prog/en/includes/patron-search.inc | 143 ++++--- > .../prog/en/includes/patron-title.inc | 44 +-- > koha-tmpl/intranet-tmpl/prog/en/js/datatables.js | 5 +- > .../prog/en/modules/members/member.tt | 401 +++++++++++++++----- > .../en/modules/members/tables/members_results.tt | 31 ++ > members/member.pl | 179 +++------ > members/members-home.pl | 27 +- > members/moremember.pl | 19 +- > svc/members/search | 119 ++++++ > 11 files changed, 848 insertions(+), 327 deletions(-) > create mode 100644 C4/Utils/DataTables/Members.pm > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/tables/members_results.tt > create mode 100755 svc/members/search > >diff --git a/C4/Members.pm b/C4/Members.pm >index 3221f53..28a50e2 100644 >--- a/C4/Members.pm >+++ b/C4/Members.pm >@@ -250,7 +250,7 @@ sub Search { > $filter = [ $filter ]; > push @$filter, {"borrowernumber"=>$matching_records}; > } >- } >+ } > } > > # $showallbranches was not used at the time SearchMember() was mainstreamed into Search(). >@@ -274,7 +274,7 @@ sub Search { > else { > $filter = { '' => $filter, branchcode => $branch }; > } >- } >+ } > } > } > >@@ -283,7 +283,7 @@ sub Search { > } > $searchtype ||= "start_with"; > >- return SearchInTable( "borrowers", $filter, $orderby, $limit, $columns_out, $search_on_fields, $searchtype ); >+ return SearchInTable( "borrowers", $filter, $orderby, $limit, $columns_out, $search_on_fields, $searchtype ); > } > > =head2 GetMemberDetails >diff --git a/C4/Utils/DataTables/Members.pm b/C4/Utils/DataTables/Members.pm >new file mode 100644 >index 0000000..b49a931 >--- /dev/null >+++ b/C4/Utils/DataTables/Members.pm >@@ -0,0 +1,201 @@ >+package C4::Utils::DataTables::Members; >+ >+use C4::Branch qw/onlymine/; >+use C4::Context; >+use C4::Members qw/GetMemberIssuesAndFines/; >+use C4::Utils::DataTables; >+use Modern::Perl; >+ >+sub search { >+ my ( $params ) = @_; >+ my $searchmember = $params->{searchmember}; >+ my $firstletter = $params->{firstletter}; >+ my $categorycode = $params->{categorycode}; >+ my $branchcode = $params->{branchcode}; >+ my $searchtype = $params->{searchtype}; >+ my $searchfieldstype = $params->{searchfieldstype}; >+ my $dt_params = $params->{dt_params}; >+ >+ my ($iTotalRecords, $iTotalDisplayRecords); >+ >+ # If branches are independant and user is not superlibrarian >+ # The search has to be only on the user branch >+ if ( C4::Branch::onlymine ) { >+ my $userenv = C4::Context->userenv; >+ $branchcode = $userenv->{'branch'}; >+ >+ } >+ >+ my $dbh = C4::Context->dbh; >+ my $select = "SELECT SQL_CALC_FOUND_ROWS >+ borrowers.borrowernumber, borrowers.surname, borrowers.firstname, borrowers.address, >+ borrowers.address2, borrowers.city, borrowers.zipcode, borrowers.country, >+ CAST(borrowers.cardnumber AS UNSIGNED) AS cardnumber, borrowers.dateexpiry, >+ borrowers.borrowernotes, borrowers.branchcode, >+ categories.description AS category_description, categories.category_type, >+ branches.branchname"; >+ my $from = "FROM borrowers >+ LEFT JOIN branches ON borrowers.branchcode = branches.branchcode >+ LEFT JOIN categories ON borrowers.categorycode = categories.categorycode"; >+ my @where_args; >+ my @where_strs; >+ if(defined $firstletter and $firstletter ne '') { >+ push @where_strs, "borrowers.surname LIKE ?"; >+ push @where_args, "$firstletter%"; >+ } >+ if(defined $categorycode and $categorycode ne '') { >+ push @where_strs, "borrowers.categorycode = ?"; >+ push @where_args, $categorycode; >+ } >+ if(defined $branchcode and $branchcode ne '') { >+ push @where_strs, "borrowers.branchcode = ?"; >+ push @where_args, $branchcode; >+ } >+ >+ # split on coma >+ $searchmember =~ s/,/ /g if $searchmember; >+ my @where_strs_or; >+ my $searchfields = { >+ standard => 'surname,firstname,othernames,cardnumber', >+ email => 'email,emailpro,B_email', >+ borrowernumber => 'borrowernumber', >+ phone => 'phone,phonepro,B_phone,altcontactphone,mobile', >+ address => 'streettype,address,address2,city,state,zipcode,country', >+ dateofbirth => 'dateofbirth', >+ }; >+ for my $searchfield ( split /,/, $searchfields->{$searchfieldstype} ) { >+ foreach my $term ( split / /, $searchmember) { >+ next unless $term; >+ $searchmember =~ s/\*/%/g; # * is replaced with % for sql >+ $term .= '%' # end with anything >+ if $term !~ /%$/; >+ $term = "%$term" # begin with anythin unless start_with >+ if $term !~ /^%/ >+ and $searchtype eq "contain"; >+ push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfield) . " LIKE ?"; >+ push @where_args, $term; >+ } >+ } >+ push @where_strs, '('. join (' OR ', @where_strs_or) . ')' >+ if @where_strs_or; >+ >+ my $where; >+ $where = "WHERE " . join (" AND ", @where_strs) if @where_strs; >+ my $orderby = dt_build_orderby($dt_params); >+ >+ my $limit; >+ if(defined $dt_params->{iDisplayStart} and defined $dt_params->{iDisplayLength}) { >+ # In order to avoir sql injection >+ $dt_params->{iDisplayStart} =~ s/\D//g; >+ $dt_params->{iDisplayLength} =~ s/\D//g; >+ $limit = "LIMIT $dt_params->{iDisplayStart},$dt_params->{iDisplayLength}"; >+ } >+ >+ my $query = join(" ", $select, $from, $where, $orderby, $limit); >+ my $sth = $dbh->prepare($query); >+ $sth->execute(@where_args); >+ my $patrons = $sth->fetchall_arrayref({}); >+ >+ # Get the iTotalDisplayRecords DataTable variable >+ $query = "SELECT FOUND_ROWS()"; >+ $sth = $dbh->prepare($query); >+ $sth->execute; >+ ($iTotalDisplayRecords) = $sth->fetchrow_array; >+ >+ # Get the iTotalRecords DataTable variable >+ $query = "SELECT COUNT(*) FROM borrowers"; >+ $sth = $dbh->prepare($query); >+ $sth->execute; >+ ($iTotalRecords) = $sth->fetchrow_array; >+ >+ # Get some information on patrons >+ foreach my $patron (@$patrons) { >+ ($patron->{overdues}, $patron->{issues}, $patron->{fines}) = >+ GetMemberIssuesAndFines($patron->{borrowernumber}); >+ if($patron->{dateexpiry} and $patron->{dateexpiry} ne '0000-00-00') { >+ $patron->{dateexpiry} = C4::Dates->new($patron->{dateexpiry}, "iso")->output(); >+ } else { >+ $patron->{dateexpiry} = ''; >+ } >+ $patron->{fines} = sprintf("%.2f", $patron->{fines} || 0); >+ } >+ >+ return { >+ iTotalRecords => $iTotalRecords, >+ iTotalDisplayRecords => $iTotalDisplayRecords, >+ patrons => $patrons >+ } >+} >+ >+1; >+__END__ >+ >+=head1 NAME >+ >+C4::Utils::DataTables::Members - module for using DataTables with patrons >+ >+=head1 SYNOPSIS >+ >+This module provides (one for the moment) routines used by the patrons search >+ >+=head2 FUNCTIONS >+ >+=head3 search >+ >+ my $dt_infos = C4::Utils::DataTables::Members->search($params); >+ >+$params is a hashref with some keys: >+ >+=over 4 >+ >+=item searchmember >+ >+ String to search in the borrowers sql table >+ >+=item firstletter >+ >+ Introduced to contain 1 letter but can contain more. >+ The search will done on the borrowers.surname field >+ >+=item categorycode >+ >+ Search patrons with this categorycode >+ >+=item branchcode >+ >+ Search patrons with this branchcode >+ >+=item searchtype >+ >+ Can be 'contain' or 'start_with'. Used for the searchmember parameter. >+ >+=item searchfieldstype >+ >+ Can be 'standard', 'email', 'borrowernumber', 'phone', 'address' or 'dateofbirth' >+ >+=item dt_params >+ >+ Is the reference of C4::Utils::DataTables::dt_get_params($input); >+ >+=cut >+ >+=back >+ >+=head1 LICENSE >+ >+Copyright 2013 BibLibre >+ >+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., >+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc >index be49b95..722fec8 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc >@@ -5,73 +5,94 @@ > <div id="patron_search" class="residentsearch"> > <p class="tip">Enter patron card number or partial name:</p> > <form action="/cgi-bin/koha/members/member.pl" method="post"> >- <input id="searchmember" size="25" class="focus" name="member" type="text" value="[% member %]"/> >+ <input id="searchmember" size="25" class="focus" name="searchmember" type="text" value="[% searchmember %]"/> > <span class="filteraction" id="filteraction_off"> <a href="#" onclick="$('#filters').toggle();$('.filteraction').toggle();">[-]</a></span> > <span class="filteraction" id="filteraction_on"> <a href="#" onclick="$('#filters').toggle();$('.filteraction').toggle();">[+]</a></span> > >- <input value="Search" class="submit" type="submit" /> >+ <label for="searchfieldstype">Search fields:</label> >+ <select name="searchfieldstype" id="searchfieldstype"> >+ [% IF searchfieldstype == "standard" %] >+ <option selected="selected" value='standard'>Standard</option> >+ [% ELSE %] >+ <option value='standard'>Standard</option> >+ [% END %] >+ [% IF searchfieldstype == "email" %] >+ <option selected="selected" value='email'>Email</option> >+ [% ELSE %] >+ <option value='email'>Email</option> >+ [% END %] >+ [% IF searchfieldstype == "borrowernumber" %] >+ <option selected="selected" value='borrowernumber'>Borrower number</option> >+ [% ELSE %] >+ <option value='borrowernumber'>Borrower number</option> >+ [% END %] >+ [% IF searchfieldstype == "phone" %] >+ <option selected="selected" value='phone'>Phone number</option> >+ [% ELSE %] >+ <option value='phone'>Phone number</option> >+ [% END %] >+ [% IF searchfieldstype == "address" %] >+ <option selected="selected" value='address'>Street Address</option> >+ [% ELSE %] >+ <option value='address'>Street Address</option> >+ [% END %] >+ [% IF searchfieldstype == "dateofbirth" %] >+ <option selected="selected" value='dateofbirth'>Date of birth</option> >+ [% ELSE %] >+ <option value='dateofbirth'>Date of birth</option> >+ [% END %] >+ </select> >+ >+ <script type="text/javascript"> >+ [% SET dateformat = Koha.Preference('dateformat') %] >+ $("#searchfieldstype").change(function() { >+ if ( $(this).val() == 'dateofbirth' ) { >+ [% IF dateformat == 'us' %] >+ [% SET format = 'MM/DD/YYYY' %] >+ [% ELSIF dateformat == 'iso' %] >+ [% SET format = 'YYYY-MM-DD' %] >+ [% ELSIF dateformat == 'metric' %] >+ [% SET format = 'DD/MM/YYYY' %] >+ [% END %] > >- <div id="filters"> >- <p><label for="searchfields">Search fields:</label> >- <select name="searchfields" id="searchfields"> >- <option selected="selected" value=''>Standard</option> >- <option value='email,emailpro,B_email,'>Email</option> >- <option value='borrowernumber'>Borrower number</option> >- <option value='phone,phonepro,B_phone,altcontactphone,mobile'>Phone number</option> >- <option value='streettype,address,address2,city,state,zipcode,country'>Street Address</option> >- <option value='dateofbirth'>Date of birth</option> >- </select> >- <script type="text/javascript"> >- [% SET dateformat = Koha.Preference('dateformat') %] >- $("#searchfields").change(function() { >- if ( $(this).val() == 'dateofbirth' ) { >- [% IF dateformat == 'us' %] >- [% SET format = 'MM/DD/YYYY' %] >- [% ELSIF dateformat == 'iso' %] >- [% SET format = 'YYYY-MM-DD' %] >- [% ELSIF dateformat == 'metric' %] >- [% SET format = 'DD/MM/YYYY' %] >- [% END %] >+ $('#searchmember').qtip({ >+ content: 'Dates of birth should be entered in the format "[% format %]"', >+ style: { >+ tip: 'topLeft' >+ } >+ }) >+ } else { >+ $('#searchmember').qtip('destroy'); >+ } >+ }); >+ </script> > >- $('#searchmember').qtip({ >- content: 'Dates of birth should be entered in the format "[% format %]"', >- style: { >- tip: 'topLeft' >- } >- }) >- } else { >- $('#searchmember').qtip('destroy'); >- } >- }); >- </script> >- </p> >- <p><label for="searchtype">Search type:</label> >- <select name="searchtype" id="searchtype"> >- <option selected="selected" value=''>Starts with</option> >- <option value='contain'>Contains</option> >- </select></p> >+ <label for="searchtype">Search type:</label> >+ <select name="searchtype" id="searchtype"> >+ <option selected="selected" value='start_with'>Starts with</option> >+ <option value='contain'>Contains</option> >+ </select> > >- <p><label for="searchorderby">Order by:</label> >- <select name="orderby" id="searchorderby"> >- <option value="">Surname, Firstname</option> >- <option value="cardnumber,0">Cardnumber</option> >- </select></p> >- [% IF ( branchloop ) %] <p><label for="branchcode">Library: </label><select name="branchcode" id="branchcode"> >- <option value="">Any</option>[% FOREACH branchloo IN branchloop %] >- [% IF ( branchloo.selected ) %] >- <option value="[% branchloo.value %]" selected="selected">[% branchloo.branchname %]</option>[% ELSE %] >- <option value="[% branchloo.value %]">[% branchloo.branchname %]</option>[% END %] >- [% END %]</select></p> >- [% END %] >- [% IF ( categories ) %] >- <p><label for="categorycode">Category: </label><select name="categorycode" id="categorycode"> >- <option value="">Any</option>[% FOREACH categorie IN categories %] >- [% IF ( categorie.selected ) %] >- <option value="[% categorie.categorycode %]" selected="selected">[% categorie.description %]</option>[% ELSE %] >- <option value="[% categorie.categorycode %]">[% categorie.description %]</option>[% END %] >- [% END %]</select></p> >- [% END %] >- </div> >+ <input value="Search" class="submit" type="submit" /> >+ [% IF ( branchloop ) %] >+ <p id="filters"> <label for="branchcode">Library: </label> >+ <select name="branchcode" id="branchcode"> >+ [% IF branchloop.size != 1 %] >+ <option value="">Any</option> >+ [% END %] >+ [% FOREACH branchloo IN branchloop %] >+ [% IF ( branchloo.selected ) %] >+ <option value="[% branchloo.value %]" selected="selected">[% branchloo.branchname %]</option>[% ELSE %] >+ <option value="[% branchloo.value %]">[% branchloo.branchname %]</option>[% END %] >+ [% END %]</select> >+ <label for="categorycode">Category: </label><select name="categorycode" id="categorycode"> >+ <option value="">Any</option>[% FOREACH categorie IN categories %] >+ [% IF ( categorie.selected ) %] >+ <option value="[% categorie.categorycode %]" selected="selected">[% categorie.description %]</option>[% ELSE %] >+ <option value="[% categorie.categorycode %]">[% categorie.description %]</option>[% END %] >+ [% END %]</select> >+ </p> >+ [% END %] > </form> > </div> > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc >index ac2f388..3a3b90c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc >@@ -1,23 +1,23 @@ >-[% IF ( borrower.borrowernumber ) %] >- [% IF borrower.category_type == 'I' %] >- [% borrower.surname %] [% IF borrower.othernames %] ([% borrower.othernames %]) [% END %] >- [% ELSE %] >- [% IF invert_name %] >- [% borrower.surname %], [% borrower.firstname %] [% IF borrower.othernames %] ([% borrower.othernames %]) [% END %] >- [% ELSE %] >- [% borrower.firstname %] [% IF borrower.othernames %] ([% borrower.othernames %]) [% END %] [% borrower.surname %] >- [% END %] >- [% END %] >+[%- IF ( borrower.borrowernumber ) %] >+ [%- IF borrower.category_type == 'I' %] >+ [%- borrower.surname %] [% IF borrower.othernames %] ([% borrower.othernames %]) [% END %] >+ [%- ELSE %] >+ [%- IF invert_name %] >+ [%- borrower.surname %], [% borrower.firstname %] [% IF borrower.othernames %] ([% borrower.othernames %]) [% END %] >+ [%- ELSE %] >+ [%- borrower.firstname %] [% IF borrower.othernames %] ([% borrower.othernames %]) [% END %] [% borrower.surname %] >+ [%- END -%] >+ [%- END -%] > ([% borrower.cardnumber %]) >-[% ELSIF ( borrowernumber ) %] >- [% IF category_type == 'I' %] >- [% surname %] [% IF othernames %] ([% othernames %]) [% END %] >- [% ELSE %] >- [% IF invert_name %] >- [% surname %], [% firstname %] [% IF othernames %] ([% othernames %]) [% END %] >- [% ELSE %] >- [% firstname %] [% IF othernames %] ([% othernames %]) [% END %] [% surname %] >- [% END %] >- [% END %] >- ([% cardnumber %]) >-[% END %] >\ No newline at end of file >+[%- ELSIF ( borrowernumber ) %] >+ [%- IF category_type == 'I' %] >+ [%- surname %] [% IF othernames %] ([% othernames %]) [% END %] >+ [%- ELSE %] >+ [%- IF invert_name %] >+ [%- surname %], [% firstname %] [% IF othernames %] ([% othernames %]) [% END %] >+ [%- ELSE %] >+ [%- firstname %] [% IF othernames %] ([% othernames %]) [% END %] [% surname %] >+ [%- END %] >+ [%- END -%] >+ ([% cardnumber -%]) >+[%- END -%] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/js/datatables.js b/koha-tmpl/intranet-tmpl/prog/en/js/datatables.js >index 703944e..89e25c5 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/js/datatables.js >+++ b/koha-tmpl/intranet-tmpl/prog/en/js/datatables.js >@@ -23,7 +23,7 @@ var dataTablesDefaults = { > "sSearch" : window.MSG_DT_SEARCH || "Search:", > "sZeroRecords" : window.MSG_DT_ZERO_RECORDS || "No matching records found" > }, >- "sDom": '<"top pager"ilpf>t<"bottom pager"ip>' >+ "sDom": '<"top pager"ilpf>tr<"bottom pager"ip>' > }; > > >@@ -471,6 +471,7 @@ jQuery.extend( jQuery.fn.dataTableExt.oSort, { > } ); > > }()); >+ > /* Plugin to allow sorting on data stored in a span's title attribute > * > * Ex: <td><span title="[% ISO_date %]">[% formatted_date %]</span></td> >@@ -493,4 +494,4 @@ jQuery.extend( jQuery.fn.dataTableExt.oSort, { > "title-string-desc": function ( a, b ) { > return ((a < b) ? 1 : ((a > b) ? -1 : 0)); > } >-} ); >\ No newline at end of file >+} ); >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt >index f44754a..b8a7ce0 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt >@@ -1,110 +1,327 @@ > [% INCLUDE 'doc-head-open.inc' %] > <title>Koha › Patrons [% IF ( searching ) %]› Search results[% END %]</title> > [% INCLUDE 'doc-head-close.inc' %] >-</head> >-<body id="pat_member" class="pat"> >-[% INCLUDE 'header.inc' %] >-[% INCLUDE 'patron-search.inc' %] >+<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.min.js"></script> >+<script type="text/javascript" src="[% themelang %]/js/datatables.js"></script> >+<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" /> >+<script type="text/javascript"> >+//<![CDATA[ >+ var dtMemberResults; > >-<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › [% IF ( searching ) %]<a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › Search results[% ELSE %]Patrons[% END %]</div> >+ $(document).ready(function() { >+ [% IF searchmember %] >+ $("#searchmember_filter").val("[% searchmember %]"); >+ [% END %] >+ [% IF searchfieldstype %] >+ $("searchfieldstype_filter").val("[% searchfieldstype %]"); >+ [% END %] >+ [% IF searchtype %] >+ $("#searchtype_filter").val("[% searchtype %]"); >+ [% END %] >+ [% IF categorycode %] >+ $("#categorycode_filter").val("[% categorycode %]"); >+ [% END %] >+ [% IF branchcode %] >+ $("#branchcode_filter").val("[% branchcode %]"); >+ [% END %] > >-<div id="doc2" class="yui-t7"> >+ // Build the aLengthMenu >+ var aLengthMenu = [ >+ [%PatronsPerPage %], 10, 20, 50, 100 >+ ]; >+ jQuery.unique(aLengthMenu); >+ aLengthMenu.sort(function(a,b){return parseInt(a) < parseInt(b) ? -1 : 1;}); > >- <div id="bd"> >- <div id="yui-main"> >- <div class="yui-b"> >- <div class="yui-g"> >+ // Apply DataTables on the results table >+ dtMemberResults = $("#memberresultst").dataTable($.extend(true, {}, dataTablesDefaults, { >+ 'bServerSide': true, >+ 'sAjaxSource': "/cgi-bin/koha/svc/members/search", >+ 'fnServerData': function(sSource, aoData, fnCallback) { >+ aoData.push({ >+ 'name': 'searchmember', >+ 'value': $("#searchmember_filter").val() >+ },{ >+ 'name': 'firstletter', >+ 'value': $("#firstletter_filter").val() >+ },{ >+ 'name': 'searchfieldstype', >+ 'value': $("#searchfieldstype_filter").val() >+ },{ >+ 'name': 'searchtype', >+ 'value': $("#searchtype_filter").val() >+ },{ >+ 'name': 'categorycode', >+ 'value': $("#categorycode_filter").val() >+ },{ >+ 'name': 'branchcode', >+ 'value': $("#branchcode_filter").val() >+ },{ >+ 'name': 'name_sorton', >+ 'value': 'borrowers.surname borrowers.firstname' >+ },{ >+ 'name': 'category_sorton', >+ 'value': 'categories.description', >+ },{ >+ 'name': 'branch_sorton', >+ 'value': 'branches.branchname' >+ },{ >+ 'name': 'template_path', >+ 'value': 'members/tables/members_results.tt', >+ }); >+ $.ajax({ >+ 'dataType': 'json', >+ 'type': 'POST', >+ 'url': sSource, >+ 'data': aoData, >+ 'success': function(json){ >+ // redirect if there is only 1 result. >+ if ( json.aaData.length == 1 ) { >+ var borrowernumber = json.aaData[0].borrowernumber; >+ document.location.href="/cgi-bin/koha/members/moremember.pl?borrowernumber="+borrowernumber; >+ return false; >+ } >+ fnCallback(json); >+ } >+ }); >+ }, >+ 'aoColumns': [ >+ { 'mDataProp': 'dt_cardnumber' }, >+ { 'mDataProp': 'dt_name' }, >+ { 'mDataProp': 'dt_category' }, >+ { 'mDataProp': 'dt_branch' }, >+ { 'mDataProp': 'dt_dateexpiry' }, >+ { 'mDataProp': 'dt_od_checkouts', 'bSortable': false }, >+ { 'mDataProp': 'dt_fines', 'bSortable': false }, >+ { 'mDataProp': 'dt_borrowernotes', 'bSortable': false }, >+ { 'mDataProp': 'dt_action', 'bSortable': false } >+ ], >+ 'fnRowCallback': function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { >+ /* Center text for 6th column */ >+ $("td:eq(5)", nRow).css("text-align", "center"); > >- [% INCLUDE 'patron-toolbar.inc' %] >+ return nRow; >+ }, >+ 'bFilter': false, >+ 'bAutoWidth': false, >+ 'bProcessing': true, >+ [% IF orderby_cardnumber_0 %] >+ 'aaSorting': [[0, 'asc']], >+ [% ELSE %] >+ 'aaSorting': [[1, 'asc']], >+ [% END %] >+ "aLengthMenu": [aLengthMenu, aLengthMenu], >+ 'sPaginationType': 'full_numbers', >+ "iDisplayLength": [% PatronsPerPage %], >+ })); >+ }); > >- [% IF ( no_add ) %]<div class="dialog alert"><h3>Cannot add patron</h3> >- [% IF ( no_branches ) %]<p>There are <strong>no libraries defined</strong>. [% IF ( CAN_user_parameters ) %]Please <a href="/cgi-bin/koha/admin/branches.pl">add a library</a>.[% ELSE %]An administrator must define at least one library.[% END %]</p>[% END %] >- [% IF ( no_categories ) %]<p>There are <strong>no patron categories defined</strong>. [% IF ( CAN_user_parameters ) %]Please <a href="/cgi-bin/koha/admin/categorie.pl">add a patron category</a>.[% ELSE %]An administrator must define at least one patron category.[% END %]</p>[% END %]</div> >- [% END %] >+ // Update the string "Results found ..." >+ function update_searched(){ >+ var searched = ""; >+ searched += "on " + $("#searchfieldstype_filter").find("option:selected").text().toLowerCase() + " fields"; >+ if ( $("#searchmember_filter").val() ) { >+ if ( $("#searchtype_filter").val() == 'start_with' ) { >+ searched += _(" starting with "); >+ } else { >+ searched += _(" containing "); >+ } >+ searched += $("#searchmember_filter").val(); >+ } >+ if ( $("#firstletter_filter").val() ) { >+ searched += _(" begin with ") + $("#firstletter_filter").val(); >+ } >+ if ( $("#categorycode_filter").val() ) { >+ searched += _(" with category ") + $("#categorycode_filter").find("option:selected").text(); >+ } >+ if ( $("#branchcode_filter").val() ) { >+ searched += _(" in library ") + $("#branchcode_filter").find("option:selected").text(); >+ } >+ $("#searchpattern").text("for patron " + searched); >+ } > >- <div class="browse"> >- Browse by last name: >- [% FOREACH letter IN alphabet.split(' ') %] >- <a href="/cgi-bin/koha/members/member.pl?quicksearch=1&surname=[% letter %]">[% letter %]</a> >- [% END %] >- </div> >+ // Redraw the table >+ function filter() { >+ $("#firstletter_filter").val(''); >+ update_searched(); >+ dtMemberResults.fnDraw(); >+ return false; >+ } > >- [% IF ( CAN_user_borrowers && pending_borrower_modifications ) %] >- <div class="pending-info" id="patron_updates_pending"> >- <a href="/cgi-bin/koha/members/members-update.pl">Patrons requesting modifications</a>: >- <span class="holdcount"><a href="/cgi-bin/koha/members/members-update.pl">[% pending_borrower_modifications %]</a></span> >- </div> >- [% END %] >+ // User has clicked on the Clear button >+ function clearFilters(redraw) { >+ $("#searchform select").val(''); >+ $("#firstletter_filter").val(''); >+ $("#searchmember_filter").val(''); >+ if(redraw) { >+ dtMemberResults.fnDraw(); >+ } >+ } > >- [% IF ( resultsloop ) %] >- <div id="searchheader"> <h3>Results [% from %] to [% to %] of [% numresults %] found for [% IF ( member ) %]'<span class="ex">[% member %]</span>'[% END %][% IF ( surname ) %]'<span class="ex">[% surname %]</span>'[% END %]</h3></div> >- <div class="searchresults"> >+ // User has clicked on a letter >+ function filterByFirstLetterSurname(letter) { >+ clearFilters(false); >+ $("#firstletter_filter").val(letter); >+ dtMemberResults.fnDraw(); >+ } >+//]]> >+</script> >+</head> >+<body id="pat_member" class="pat"> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'patron-search.inc' %] > >- <table id="memberresultst"> >- <thead> >- <tr> >- <th>Card</th> >- <th>Name</th> >- <th>Cat</th> >- <th>Library</th> >- <th>Expires on</th> >- <th>OD/Checkouts</th> >- <th>Fines</th> >- <th>Circ note</th> >- <th> </th> >- </tr> >- </thead> >- <tbody> >- [% FOREACH resultsloo IN resultsloop %] >- [% IF ( resultsloo.overdue ) %] >- <tr class="problem"> >- [% ELSE %] >- [% UNLESS ( loop.odd ) %] >- <tr class="highlight"> >- [% ELSE %] >- <tr> >- [% END %] >- [% END %] >- <td>[% resultsloo.cardnumber %]</td> >- <td style="white-space: nowrap;"> >- <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% resultsloo.borrowernumber %]"> >- [% INCLUDE 'patron-title.inc' borrowernumber = resultsloo.borrowernumber category_type = resultsloo.category_type firstname = resultsloo.firstname surname = resultsloo.surname othernames = resultsloo.othernames cardnumber = resultsloo.cardnumber invert_name = 1%] >- </a> <br /> >- [% IF ( resultsloo.streetnumber ) %][% resultsloo.streetnumber %] [% END %][% resultsloo.address %][% IF ( resultsloo.address2 ) %]<br />[% resultsloo.address2 %][% END %][% IF ( resultsloo.city ) %]<br />[% resultsloo.city %][% IF ( resultsloo.state ) %],[% END %][% END %][% IF ( resultsloo.state ) %] [% resultsloo.state %][% END %] [% IF ( resultsloo.zipcode ) %] [% resultsloo.zipcode %][% END %][% IF ( resultsloo.country ) %], [% resultsloo.country %][% END %]</td> >- <td>[% resultsloo.category_description %] ([% resultsloo.category_type %])</td> >- <td>[% resultsloo.branchname %]</td> >- <td>[% resultsloo.dateexpiry %]</td> >- <td>[% IF ( resultsloo.overdues ) %]<span class="overdue"><strong>[% resultsloo.overdues %]</strong></span>[% ELSE %][% resultsloo.overdues %][% END %]/[% resultsloo.issues %]</td> >- <td>[% IF ( resultsloo.fines < 0 ) %]<span class="credit">[% resultsloo.fines %]</span> [% ELSIF resultsloo.fines > 0 %] <span class="debit"><strong>[% resultsloo.fines %]</strong></span> [% ELSE %] [% resultsloo.fines %] [% END %]</td> >- <td>[% resultsloo.borrowernotes %]</td> >- <td>[% IF ( resultsloo.category_type ) %] >- <a href="/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% resultsloo.borrowernumber %]&category_type=[% resultsloo.category_type %]">Edit</a> >- [% ELSE %] <!-- try with categorycode if no category_type --> >- [% IF ( resultsloo.categorycode ) %] >- <a href="/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% resultsloo.borrowernumber %]&categorycode=[% resultsloo.categorycode %]">Edit</a> >- [% ELSE %] <!-- if no categorycode, set category_type to A by default --> >- <a href="/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% resultsloo.borrowernumber %]&category_type=A">Edit</a> >- [% END %] >- [% END %]</td> >- </tr> >- [% END %] >- </tbody> >- </table> >- <div class="pages">[% IF ( multipage ) %][% paginationbar %][% END %]</div> >- </div> >- [% ELSE %] >- [% IF ( searching ) %] >- <div class="dialog alert">No results found</div> >- [% END %] >- [% END %] >+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › [% IF ( searching ) %]<a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › Search results[% ELSE %]Patrons[% END %]</div> > >- </div> >- </div> >+<div id="doc3" class="yui-t2"> >+ <div id="bd"> >+ <div id="yui-main"> >+ <div class="yui-b"> >+ <div class="yui-g"> >+ [% INCLUDE 'patron-toolbar.inc' %] >+ [% IF ( no_add ) %] >+ <div class="dialog alert"> >+ <h3>Cannot add patron</h3> >+ [% IF ( no_branches ) %] >+ <p>There are <strong>no libraries defined</strong>. [% IF ( CAN_user_parameters ) %]Please <a href="/cgi-bin/koha/admin/branches.pl">add a library</a>.[% ELSE %]An administrator must define at least one library.[% END %]</p> >+ [% END %] >+ [% IF ( no_categories ) %] >+ <p>There are <strong>no patron categories defined</strong>. [% IF ( CAN_user_parameters ) %]Please <a href="/cgi-bin/koha/admin/categorie.pl">add a patron category</a>.[% ELSE %]An administrator must define at least one patron category.[% END %]</p> >+ [% END %] >+ </div> >+ [% END %] >+ <div class="browse"> >+ Browse by last name: >+ [% FOREACH letter IN alphabet.split(' ') %] >+ <a style="cursor:pointer" onclick="filterByFirstLetterSurname('[% letter %]');">[% letter %]</a> >+ [% END %] >+ </div> > >- <div class="yui-g"> >- [% INCLUDE 'members-menu.inc' %] >- </div> >+ [% IF ( CAN_user_borrowers && pending_borrower_modifications ) %] >+ <div class="pending-info" id="patron_updates_pending"> >+ <a href="/cgi-bin/koha/members/members-update.pl">Patrons requesting modifications</a>: >+ <span class="holdcount"><a href="/cgi-bin/koha/members/members-update.pl">[% pending_borrower_modifications %]</a></span> >+ </div> >+ [% END %] > >+ <div id="searchheader"> >+ <h3>Results found <span id="searchpattern">[% IF searchmember %] for '[% searchmember %]'[% END %]</span></h3> >+ </div> >+ <div class="searchresults"> >+ <table id="memberresultst"> >+ <thead> >+ <tr> >+ <th>Card</th> >+ <th>Name</th> >+ <th>Cat</th> >+ <th>Library</th> >+ <th>Expires on</th> >+ <th>OD/Checkouts</th> >+ <th>Fines</th> >+ <th>Circ note</th> >+ <th> </th> >+ </tr> >+ </thead> >+ <tbody></tbody> >+ </table> >+ </div> >+ </div> >+ </div> >+ </div> >+ <div class="yui-b"> >+ <form onsubmit="return filter();" id="searchform"> >+ <input type="hidden" id="firstletter_filter" value="" /> >+ <fieldset class="brief"> >+ <h3>Filters</h3> >+ <ol> >+ <li> >+ <label for="searchmember_filter">Search:</label> >+ <input type="text" id="searchmember_filter" value="[% searchmember %]"/> >+ </li> >+ <li> >+ <label for="searchfieldstype_filter">Search fields:</label> >+ <select name="searchfieldstype" id="searchfieldstype_filter"> >+ [% IF searchfieldstype == "standard" %] >+ <option selected="selected" value='standard'>Standard</option> >+ [% ELSE %] >+ <option value='standard'>Standard</option> >+ [% END %] >+ [% IF searchfieldstype == "email" %] >+ <option selected="selected" value='email'>Email</option> >+ [% ELSE %] >+ <option value='email'>Email</option> >+ [% END %] >+ [% IF searchfieldstype == "borrowernumber" %] >+ <option selected="selected" value='borrowernumber'>Borrower number</option> >+ [% ELSE %] >+ <option value='borrowernumber'>Borrower number</option> >+ [% END %] >+ [% IF searchfieldstype == "phone" %] >+ <option selected="selected" value='phone'>Phone number</option> >+ [% ELSE %] >+ <option value='phone'>Phone number</option> >+ [% END %] >+ [% IF searchfieldstype == "address" %] >+ <option selected="selected" value='address'>Street Address</option> >+ [% ELSE %] >+ <option value='address'>Street Address</option> >+ [% END %] >+ [% IF searchfieldstype == "dateofbirth" %] >+ <option selected="selected" value='dateofbirth'>Date of birth</option> >+ [% ELSE %] >+ <option value='dateofbirth'>Date of birth</option> >+ [% END %] >+ </select> >+ </li> >+ <li> >+ <label for="searchtype_filter">Search type:</label> >+ <select name="searchtype" id="searchtype_filter"> >+ <option value='start_with'>Starts with</option> >+ [% IF searchtype == "contain" %] >+ <option value="contain" selected="selected">Contains</option> >+ [% ELSE %] >+ <option value="contain" selected="selected">Contains</option> >+ [% END %] >+ </select> >+ </li> >+ <li> >+ <label for="categorycode_filter">Category:</label> >+ <select id="categorycode_filter"> >+ <option value="">Any</option> >+ [% FOREACH cat IN categories %] >+ [% IF cat.selected %] >+ <option selected="selected" value="[% cat.categorycode %]">[% cat.description %]</option> >+ [% ELSE %] >+ <option value="[% cat.categorycode %]">[% cat.description %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ </li> >+ <li> >+ <label for="branchcode_filter">Branch:</label> >+ <select id="branchcode_filter"> >+ [% IF branchloop.size != 1 %] >+ <option value="">Any</option> >+ [% END %] >+ [% FOREACH b IN branchloop %] >+ [% IF b.selected %] >+ <option selected="selected" value="[% b.branchcode %]">[% b.branchname %]</option> >+ [% ELSE %] >+ <option value="[% b.branchcode %]">[% b.branchname %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ </li> >+ </ol> >+ <fieldset class="action"> >+ <input type="submit" value="Search" /> >+ <input type="button" value="Clear" onclick="clearFilters(true);" /> >+ </fieldset> >+ </fieldset> >+ </form> > </div> >+ </div> >+ <div class="yui-g"> >+ [% INCLUDE 'members-menu.inc' %] >+ </div> > </div> > [% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/tables/members_results.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/tables/members_results.tt >new file mode 100644 >index 0000000..debf16b >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/tables/members_results.tt >@@ -0,0 +1,31 @@ >+{ >+ "sEcho": [% sEcho %], >+ "iTotalRecords": [% iTotalRecords %], >+ "iTotalDisplayRecords": [% iTotalDisplayRecords %], >+ "aaData": [ >+ [% FOREACH data IN aaData %] >+ { >+ "dt_cardnumber": >+ "[% data.cardnumber %]", >+ "dt_name": >+ "<span style='white-space:nowrap'><a href='/cgi-bin/koha/members/moremember.pl?borrowernumber=[% data.borrowernumber %]'>[% INCLUDE 'patron-title.inc' borrowernumber = data.borrowernumber category_type = data.category_type firstname = data.firstname surname = data.surname othernames = data.othernames cardnumber = data.cardnumber invert_name = 1%]</a><br />[% IF ( data.streetnumber ) %][% data.streetnumber %] [% END %][% data.address %][% IF ( data.address2 ) %]<br />[% data.address2 %][% END %][% IF ( data.city ) %]<br />[% data.city %][% IF ( data.state ) %],[% END %][% END %][% IF ( data.state ) %] [% data.state %][% END %] [% IF ( data.zipcode ) %] [% data.zipcode %][% END %][% IF ( data.country ) %], [% data.country %][% END %]</span>", >+ "dt_category": >+ "[% data.category_description |html %]([% data.category_type |html %])", >+ "dt_branch": >+ "[% data.branchname |html %]", >+ "dt_dateexpiry": >+ "[% data.dateexpiry %]", >+ "dt_od_checkouts": >+ "[% IF data.overdues %]<span class='overdue'><strong>[% data.overdues %]</strong></span>[% ELSE %][% data.overdues %][% END %] / [% data.issues %]", >+ "dt_fines": >+ "[% IF data.fines < 0 %]<span class='credit'>[% data.fines |html %]</span> [% ELSIF data.fines > 0 %] <span class='debit'><strong>[% data.fines |html %]</strong></span> [% ELSE %] [% data.fines |html%] [% END %]</td>", >+ "dt_borrowernotes": >+ "[% data.borrowernotes |html %]", >+ "dt_action": >+ "[% IF data.category_type %]<a href='/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% data.borrowernumber %]&category_type=[% data.category_type %]'>Edit</a>[% ELSE %][% IF data.categorycode %]<a href='/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% data.borrowernumber %]&categorycode=[% data.categorycode %]'>Edit</a>[% ELSE %]<a href='/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% data.borrowernumber %]&category_type=A'>Edit</a>[% END %][% END %]", >+ "borrowernumber": >+ "[% data.borrowernumber %]" >+ }[% UNLESS loop.last %],[% END %] >+ [% END %] >+ ] >+} >diff --git a/members/member.pl b/members/member.pl >index 47f7cb7..bc23c84 100755 >--- a/members/member.pl >+++ b/members/member.pl >@@ -6,7 +6,7 @@ > > > # Copyright 2000-2002 Katipo Communications >-# Copyright 2010 BibLibre >+# Copyright 2013 BibLibre > # > # This file is part of Koha. > # >@@ -23,21 +23,16 @@ > # with Koha; if not, write to the Free Software Foundation, Inc., > # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > >-use strict; >-#use warnings; FIXME - Bug 2505 >+use Modern::Perl; > use C4::Auth; > use C4::Output; > use CGI; >-use C4::Members; > use C4::Branch; > use C4::Category; > use Koha::DateUtils; > use File::Basename; > > my $input = new CGI; >-my $quicksearch = $input->param('quicksearch'); >-my $startfrom = $input->param('startfrom')||1; >-my $resultsperpage = $input->param('resultsperpage')||C4::Context->preference("PatronsPerPage")||20; > > my ($template, $loggedinuser, $cookie) > = get_template_and_user({template_name => "members/member.tmpl", >@@ -47,147 +42,69 @@ my ($template, $loggedinuser, $cookie) > flagsrequired => {borrowers => 1}, > }); > >-my $theme = $input->param('theme') || "default"; >- > my $patron = $input->Vars; > foreach (keys %$patron){ >- delete $$patron{$_} unless($$patron{$_}); >-} >-my @categories=C4::Category->all; >- >-my $branches = GetBranches; >-my @branchloop; >- >-foreach (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) { >- my $selected; >- $selected = 1 if $branches->{$_}->{branchcode} eq $$patron{branchcode}; >- my %row = ( value => $_, >- selected => $selected, >- branchname => $branches->{$_}->{branchname}, >- ); >- push @branchloop, \%row; >+ delete $patron->{$_} unless($patron->{$_}); > } > >-my %categories_dislay; >- >-foreach my $category (@categories){ >- my $hash={ >- category_description=>$$category{description}, >- category_type=>$$category{category_type} >- }; >- $categories_dislay{$$category{categorycode}} = $hash; >-} > my $AddPatronLists = C4::Context->preference("AddPatronLists") || ''; >-$template->param( >- "AddPatronLists_$AddPatronLists" => "1", >- ); >-if ($AddPatronLists=~/code/){ >- $categories[0]->{'first'}=1; >-} >- >-my $member=$input->param('member'); >-my $orderbyparams=$input->param('orderby'); >-my @orderby; >-if ($orderbyparams){ >- my @orderbyelt=split(/,/,$orderbyparams); >- push @orderby, {$orderbyelt[0]=>$orderbyelt[1]||0}; >-} >-else { >- @orderby = ({surname=>0},{firstname=>0}); >-} >- >-$member =~ s/,//g; #remove any commas from search string >-$member =~ s/\*/%/g; > >-my $from = ( $startfrom - 1 ) * $resultsperpage; >-my $to = $from + $resultsperpage; >+my $searchmember = $input->param('searchmember'); > >-my ($count,$results); >-if ($member || keys %$patron) { >- my $searchfields = $input->param('searchfields'); >- my @searchfields = $searchfields ? split( ',', $searchfields ) : ( "firstname", "surname", "othernames", "cardnumber", "userid", "email" ); >+my $searchfieldstype = $input->param('searchfieldstype') || 'standard'; > >- if ( $searchfields eq "dateofbirth" ) { >- $member = output_pref(dt_from_string($member), 'iso', undef, 1); >- } >- >- my $search_scope = ( $quicksearch ? "field_start_with" : "start_with" ); >- ($results) = Search( $member || $patron, \@orderby, undef, undef, \@searchfields, $search_scope ); >+if ( $searchfieldstype eq "dateofbirth" ) { >+ $searchmember = output_pref(dt_from_string($searchmember), 'iso', undef, 1); > } > >-if ($results) { >- for my $field ('categorycode','branchcode'){ >- next unless ($patron->{$field}); >- @$results = grep { $_->{$field} eq $patron->{$field} } @$results; >- } >- $count = scalar(@$results); >+my $branches = C4::Branch::GetBranches; >+my @branches_loop; >+if ( C4::Branch::onlymine ) { >+ my $userenv = C4::Context->userenv; >+ my $branch = C4::Branch::GetBranchDetail( $userenv->{'branch'} ); >+ push @branches_loop, { >+ value => $branch->{branchcode}, >+ branchcode => $branch->{branchcode}, >+ branchname => $branch->{branchname}, >+ selected => 1 >+ } >+} else { >+ foreach ( sort { lc($branches->{$a}->{branchname}) cmp lc($branches->{$b}->{branchname}) } keys %$branches ) { >+ my $selected = 0; >+ $selected = 1 if($patron->{branchcode} and $patron->{branchcode} eq $_); >+ push @branches_loop, { >+ value => $_, >+ branchcode => $_, >+ branchname => $branches->{$_}->{branchname}, >+ selected => $selected >+ }; >+ } > } > >-if($count == 1){ >- print $input->redirect("/cgi-bin/koha/members/moremember.pl?borrowernumber=" . @$results[0]->{borrowernumber}); >- exit; >+my @categories = C4::Category->all; >+if ( $patron->{categorycode} ) { >+ foreach my $category ( grep { $_->{categorycode} eq $patron->{categorycode} } @categories ) { >+ $category->{selected} = 1; >+ } > } > >-my @resultsdata; >-$to=($count>$to?$to:$count); >-my $index=$from; >-foreach my $borrower(@$results[$from..$to-1]){ >- #find out stats >- my ($od,$issue,$fines)=GetMemberIssuesAndFines($$borrower{'borrowernumber'}); >- >- $$borrower{'dateexpiry'}= C4::Dates->new($$borrower{'dateexpiry'},'iso')->output('syspref'); >- >- my %row = ( >- count => $index++, >- %$borrower, >- (defined $categories_dislay{ $borrower->{categorycode} }? %{ $categories_dislay{ $borrower->{categorycode} } }:()), >- overdues => $od, >- issues => $issue, >- odissue => "$od/$issue", >- fines => sprintf("%.2f",$fines), >- branchname => $branches->{$borrower->{branchcode}}->{branchname}, >- ); >- push(@resultsdata, \%row); >-} >+$template->param( 'alphabet' => C4::Context->preference('alphabet') || join ' ', 'A' .. 'Z' ); > >-if ($$patron{categorycode}){ >- foreach my $category (grep{$_->{categorycode} eq $$patron{categorycode}}@categories){ >- $$category{selected}=1; >- } >+my $orderby = $input->param('orderby') // ''; >+if(defined $orderby and $orderby ne '') { >+ $orderby =~ s/[, ]/_/g; > } >-my %parameters= >- ( %$patron >- , 'orderby' => $orderbyparams >- , 'resultsperpage' => $resultsperpage >- , 'type'=> 'intranet'); >-my $base_url = >- 'member.pl?&' >- . join( >- '&', >- map { "$_=$parameters{$_}" } (keys %parameters) >- ); >- >-my @letters = map { {letter => $_} } ( 'A' .. 'Z'); > > $template->param( >- letters => \@letters, >- paginationbar => pagination_bar( >- $base_url, >- int( $count / $resultsperpage ) + ($count % $resultsperpage ? 1 : 0), >- $startfrom, 'startfrom' >- ), >- startfrom => $startfrom, >- from => ($startfrom-1)*$resultsperpage+1, >- to => $to, >- multipage => ($count != $to || $startfrom!=1), >- advsearch => ($$patron{categorycode} || $$patron{branchcode}), >- branchloop=>\@branchloop, >- categories=>\@categories, >- searching => "1", >- actionname =>basename($0), >- %$patron, >- numresults => $count, >- resultsloop => \@resultsdata, >- ); >+ searchmember => $searchmember, >+ branchloop => \@branches_loop, >+ categories => \@categories, >+ branchcode => $patron->{branchcode}, >+ categorycode => $patron->{categorycode}, >+ searchtype => $input->param('searchtype') || 'start_with', >+ searchfieldstype => $searchfieldstype, >+ "orderby_$orderby" => 1, >+ PatronsPerPage => C4::Context->preference("PatronsPerPage") || 20, >+); > > output_html_with_http_headers $input, $cookie, $template->output; >diff --git a/members/members-home.pl b/members/members-home.pl >index 1d8f1e5..5e816eb 100755 >--- a/members/members-home.pl >+++ b/members/members-home.pl >@@ -45,12 +45,23 @@ my ($template, $loggedinuser, $cookie) > > my $branches = GetBranches; > my @branchloop; >-foreach (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %{$branches}) { >+if ( C4::Branch::onlymine ) { >+ my $userenv = C4::Context->userenv; >+ my $branch = C4::Branch::GetBranchDetail( $userenv->{'branch'} ); > push @branchloop, { >- value => $_, >- selected => ($branches->{$_}->{branchcode} eq $branch), >- branchname => $branches->{$_}->{branchname}, >- }; >+ value => $branch->{branchcode}, >+ branchcode => $branch->{branchcode}, >+ branchname => $branch->{branchname}, >+ selected => 1 >+ } >+} else { >+ foreach (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %{$branches}) { >+ push @branchloop, { >+ value => $_, >+ selected => ($branches->{$_}->{branchcode} eq $branch), >+ branchname => $branches->{$_}->{branchname}, >+ }; >+ } > } > > my @categories; >@@ -86,6 +97,10 @@ $template->param( > no_add => $no_add, > pending_borrower_modifications => $pending_borrower_modifications, > ); >-$template->param( 'alphabet' => C4::Context->preference('alphabet') || join ' ', 'A' .. 'Z' ); >+ >+$template->param( >+ alphabet => C4::Context->preference('alphabet') || join (' ', 'A' .. 'Z'), >+ PatronsPerPage => C4::Context->preference("PatronsPerPage") || 20, >+); > > output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/members/moremember.pl b/members/moremember.pl >index 598b07d..5cebb36 100755 >--- a/members/moremember.pl >+++ b/members/moremember.pl >@@ -53,8 +53,6 @@ use C4::Form::MessagingPreferences; > use List::MoreUtils qw/uniq/; > use C4::Members::Attributes qw(GetBorrowerAttributes); > >-#use Smart::Comments; >-#use Data::Dumper; > use DateTime; > use Koha::DateUtils; > >@@ -82,21 +80,21 @@ my $template_name; > my $quickslip = 0; > > my $flagsrequired; >-if ($print eq "page") { >+if (defined $print and $print eq "page") { > $template_name = "members/moremember-print.tmpl"; > # circ staff who process checkouts but can't edit > # patrons still need to be able to access print view > $flagsrequired = { circulate => "circulate_remaining_permissions" }; >-} elsif ($print eq "slip") { >+} elsif (defined $print and $print eq "slip") { > $template_name = "members/moremember-receipt.tmpl"; > # circ staff who process checkouts but can't edit > # patrons still need to be able to print receipts > $flagsrequired = { circulate => "circulate_remaining_permissions" }; >-} elsif ($print eq "qslip") { >+} elsif (defined $print and $print eq "qslip") { > $template_name = "members/moremember-receipt.tmpl"; > $quickslip = 1; > $flagsrequired = { circulate => "circulate_remaining_permissions" }; >-} elsif ($print eq "brief") { >+} elsif (defined $print and $print eq "brief") { > $template_name = "members/moremember-brief.tmpl"; > $flagsrequired = { borrowers => 1 }; > } else { >@@ -157,7 +155,7 @@ if ($debar) { > } > > $data->{'ethnicity'} = fixEthnicity( $data->{'ethnicity'} ); >-$data->{ "sex_".$data->{'sex'}."_p" } = 1; >+$data->{ "sex_".$data->{'sex'}."_p" } = 1 if defined $data->{sex}; > > my $catcode; > if ( $category_type eq 'C') { >@@ -281,13 +279,13 @@ if ($borrowernumber) { > $getreserv{barcodereserv} = $getiteminfo->{'barcode'}; > $getreserv{itemtype} = $itemtypeinfo->{'description'}; > >- # check if we have a waitin status for reservations >- if ( $num_res->{'found'} eq 'W' ) { >+ # check if we have a waitin status for reservations >+ if ( defined $num_res->{found} and $num_res->{'found'} eq 'W' ) { > $getreserv{color} = 'reserved'; > $getreserv{waiting} = 1; > } > >- # check transfers with the itemnumber foud in th reservation loop >+ # check transfers with the itemnumber foud in th reservation loop > if ($transfertwhen) { > $getreserv{color} = 'transfered'; > $getreserv{transfered} = 1; >@@ -426,6 +424,7 @@ $template->param( > AutoResumeSuspendedHolds => C4::Context->preference('AutoResumeSuspendedHolds'), > SuspendHoldsIntranet => C4::Context->preference('SuspendHoldsIntranet'), > RoutingSerials => C4::Context->preference('RoutingSerials'), >+ PatronsPerPage => C4::Context->preference("PatronsPerPage") || 20, > ); > $template->param( $error => 1 ) if $error; > >diff --git a/svc/members/search b/svc/members/search >new file mode 100755 >index 0000000..56b9e86 >--- /dev/null >+++ b/svc/members/search >@@ -0,0 +1,119 @@ >+#!/usr/bin/perl >+ >+# Copyright 2013 BibLibre >+# >+# 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., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+use CGI; >+ >+use C4::Auth qw( get_template_and_user ); >+use C4::Output qw( output_with_http_headers ); >+use C4::Utils::DataTables qw( dt_get_params ); >+use C4::Utils::DataTables::Members qw( search ); >+ >+my $input = new CGI; >+ >+exit unless $input->param('template_path'); >+ >+my ($template, $user, $cookie) = get_template_and_user({ >+ template_name => $input->param('template_path'), >+ query => $input, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { borrowers => 1 } >+}); >+ >+my $searchmember = $input->param('searchmember'); >+my $firstletter = $input->param('firstletter'); >+my $categorycode = $input->param('categorycode'); >+my $branchcode = $input->param('branchcode'); >+my $searchtype = $input->param('searchtype'); >+my $searchfieldstype = $input->param('searchfieldstype'); >+ >+# variable information for DataTables (id) >+my $sEcho = $input->param('sEcho'); >+ >+my %dt_params = dt_get_params($input); >+foreach (grep {$_ =~ /^mDataProp/} keys %dt_params) { >+ $dt_params{$_} =~ s/^dt_//; >+} >+ >+# Perform the patrons search >+my $results = C4::Utils::DataTables::Members::search( >+ { >+ searchmember => $searchmember, >+ firstletter => $firstletter, >+ categorycode => $categorycode, >+ branchcode => $branchcode, >+ searchtype => $searchtype, >+ searchfieldstype => $searchfieldstype, >+ dt_params => \%dt_params, >+ >+ } >+); >+ >+$template->param( >+ sEcho => $sEcho, >+ iTotalRecords => $results->{iTotalRecords}, >+ iTotalDisplayRecords => $results->{iTotalDisplayRecords}, >+ aaData => $results->{patrons} >+); >+ >+output_with_http_headers $input, $cookie, $template->output, 'json'; >+ >+__END__ >+ >+=head1 NAME >+ >+search - a search script for finding patrons >+ >+=head1 SYNOPSIS >+ >+This script provides a service for template for patron search using DataTables >+ >+=head2 Performing a search >+ >+Call this script from a DataTables table my $searchmember = $input->param('searchmember'); >+All following params are optional: >+ searchmember => the search terms >+ firstletter => search patrons with surname begins with this pattern (currently only used for 1 letter) >+ categorycode and branchcode => search patrons belong to a given categorycode or a branchcode >+ searchtype: can be 'contain' or 'start_with' >+ searchfieldstype: Can be 'standard', 'email', 'borrowernumber', 'phone' or 'address' >+ >+=cut >+ >+=back >+ >+=head1 LICENSE >+ >+Copyright 2013 BibLibre >+ >+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., >+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >-- >1.7.10.4
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 9811
:
16096
|
16111
|
16112
|
16320
|
16362
|
16403
|
16957
|
19056
|
19057
|
19307
|
19633
|
19642
|
20094
|
20095
|
20096
|
20174
|
20266
|
20290
|
20291
|
21169
|
21170
|
21171
|
21172
|
21173
|
21174
|
21175
|
22265
|
23261
|
24095
|
24111
|
26067
|
26068
|
26261
|
26336
|
26337
|
26342
|
26347
|
27642
|
27643
|
27644
|
27645
|
27646
|
27711
|
28738
|
28739
|
28740
|
28741
|
28742
|
28743
|
28744
|
28745
|
28746
|
28747
|
28781
|
28782
|
29019
|
29020
|
29021
|
29022
|
29023
|
29024
|
29025
|
29026
|
29027
|
29028
|
29029
|
29442