@@ -, +, @@
- 1 module C4/Utils/DataTables/Members.pm
- 2 services svc/members/search and svc/members/add_to_list
- 1 template members/tables/members_results.tt
- 1 new practice which is to add template for DataTables in a
subdirectory named 'tables'.
- 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.
- Verify this feature does not break the patron list feature (cf bug
10565).
- removes 2 tabs
- removes mysqlisms
- add sort on borrowernotes
- fix wrong capitalization
- cat => Category
- perform a member search that does not return a borrower with a circ note
- edit one of the borrowers returned by this search
- enter serveral lines of text in "Circulation note" and save
- reperform the member search
-------------
-TEST REPORT-
-------------
efficient (using LIMIT clause) to not stress DB needlessly.
---
C4/Members.pm | 2 +-
C4/Utils/DataTables/Members.pm | 213 +++++++
.../intranet-tmpl/prog/en/includes/home-search.inc | 3 +-
.../prog/en/includes/patron-search.inc | 147 +++--
.../prog/en/includes/patron-title.inc | 44 +-
koha-tmpl/intranet-tmpl/prog/en/js/datatables.js | 2 +-
.../prog/en/modules/members/member.tt | 603 ++++++++++++++------
.../en/modules/members/tables/members_results.tt | 35 ++
members/member.pl | 230 ++------
members/members-home.pl | 27 +-
members/moremember.pl | 20 +-
svc/members/add_to_list | 63 ++
svc/members/search | 119 ++++
t/DataTables/Members.t | 14 +
14 files changed, 1078 insertions(+), 444 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/add_to_list
create mode 100755 svc/members/search
create mode 100644 t/DataTables/Members.t
--- a/C4/Members.pm
+++ a/C4/Members.pm
@@ -273,7 +273,7 @@ sub Search {
else {
$filter = { '' => $filter, branchcode => $branch };
}
- }
+ }
}
}
--- a/C4/Utils/DataTables/Members.pm
+++ a/C4/Utils/DataTables/Members.pm
@@ -0,0 +1,213 @@
+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
+ 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',
+ sort1 => 'sort1',
+ sort2 => 'sort2',
+ };
+ 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 iDisplayLength == -1, we want to display all patrons
+ if ( $dt_params->{iDisplayLength} > -1 ) {
+ # In order to avoid sql injection
+ $dt_params->{iDisplayStart} =~ s/\D//g;
+ $dt_params->{iDisplayLength} =~ s/\D//g;
+ $dt_params->{iDisplayStart} //= 0;
+ $dt_params->{iDisplayLength} //= 20;
+ $limit = "LIMIT $dt_params->{iDisplayStart},$dt_params->{iDisplayLength}";
+ }
+
+ my $query = join(
+ " ",
+ ($select ? $select : ""),
+ ($from ? $from : ""),
+ ($where ? $where : ""),
+ ($orderby ? $orderby : ""),
+ ($limit ? $limit : "")
+ );
+ my $sth = $dbh->prepare($query);
+ $sth->execute(@where_args);
+ my $patrons = $sth->fetchall_arrayref({});
+
+ # Get the iTotalDisplayRecords DataTable variable
+ $query = "SELECT COUNT(borrowers.borrowernumber) " . $from . ($where ? $where : "");
+ $sth = $dbh->prepare($query);
+ $sth->execute(@where_args);
+ ($iTotalDisplayRecords) = $sth->fetchrow_array;
+
+ # Get the iTotalRecords DataTable variable
+ $query = "SELECT COUNT(borrowers.borrowernumber) 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', 'sort1', 'sort2'
+
+=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.
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/home-search.inc
+++ a/koha-tmpl/intranet-tmpl/prog/en/includes/home-search.inc
@@ -15,7 +15,8 @@
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc
+++ a/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 %]
+[%- 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 -%]
--- a/koha-tmpl/intranet-tmpl/prog/en/js/datatables.js
+++ a/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>',
"aLengthMenu": [[10, 20, 50, 100, -1], [10, 20, 50, 100, window.MSG_DT_ALL || "All"]],
"iDisplayLength": 20
};
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt
@@ -1,7 +1,8 @@
[% INCLUDE 'doc-head-open.inc' %]
Koha › Patrons [% IF ( searching ) %]› Search results[% END %]
[% INCLUDE 'doc-head-close.inc' %]
-
+
+[% INCLUDE 'datatables.inc' %]
-
[% INCLUDE 'header.inc' %]
@@ -75,163 +281,204 @@ function CheckForm() {
Home › [% IF ( searching ) %]Patrons › Search results[% ELSE %]Patrons[% END %]
-
+
+
+
+
+
+ [% IF CAN_user_tools_manage_patron_lists %]
+
+ Added patrons to .
+
+ [% END %]
-
-
-
-
+ [% INCLUDE 'patron-toolbar.inc' %]
+ [% IF ( no_add ) %]
+
+
Cannot add patron
+ [% IF ( no_branches ) %]
+
There are no libraries defined. [% IF ( CAN_user_parameters ) %]Please add a library.[% ELSE %]An administrator must define at least one library.[% END %]
+ [% END %]
+ [% IF ( no_categories ) %]
+
There are no patron categories defined. [% IF ( CAN_user_parameters ) %]Please add a patron category.[% ELSE %]An administrator must define at least one patron category.[% END %]
+ [% END %]
+
+ [% END %]
+
+ Browse by last name:
+ [% FOREACH letter IN alphabet.split(' ') %]
+ [% letter %]
+ [% END %]
+
Results found [% IF searchmember %] for '[% searchmember %]'[% END %]
+
+ [% IF CAN_user_tools_manage_patron_lists %]
+
+
+ Select all
+ |
+ Clear all
+ |
+
+ Add selected patrons
+
+
+
+
- [% INCLUDE 'patron-toolbar.inc' %]
-
- [% IF ( no_add ) %]
Cannot add patron
- [% IF ( no_branches ) %]
There are no libraries defined. [% IF ( CAN_user_parameters ) %]Please add a library.[% ELSE %]An administrator must define at least one library.[% END %]
[% END %]
- [% IF ( no_categories ) %]
There are no patron categories defined. [% IF ( CAN_user_parameters ) %]Please add a patron category.[% ELSE %]An administrator must define at least one patron category.[% END %]
[% END %]
- [% END %]
-
-
- Browse by last name:
- [% FOREACH letter IN alphabet.split(' ') %]
- [% letter %]
- [% END %]
-