@@ -, +, @@ - 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 --- C4/Members.pm | 2 +- C4/Utils/DataTables/Members.pm | 211 +++++++ .../prog/en/includes/patron-search.inc | 143 +++-- .../prog/en/includes/patron-title.inc | 44 +- koha-tmpl/intranet-tmpl/prog/en/js/datatables.js | 2 +- .../prog/en/modules/members/member.tt | 591 ++++++++++++++------ .../en/modules/members/tables/members_results.tt | 35 ++ members/member.pl | 214 ++----- members/members-home.pl | 27 +- members/moremember.pl | 19 +- svc/members/add_to_list | 63 +++ svc/members/search | 119 ++++ t/DataTables/Members.t | 14 + 13 files changed, 1039 insertions(+), 445 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 @@ -274,7 +274,7 @@ sub Search { else { $filter = { '' => $filter, branchcode => $branch }; } - } + } } } --- a/C4/Utils/DataTables/Members.pm +++ a/C4/Utils/DataTables/Members.pm @@ -0,0 +1,211 @@ +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', + }; + 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' + +=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/patron-search.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc @@ -5,73 +5,94 @@
Enter patron card number or partial name:
+ + +
+ [% END %] --- 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>' }; --- 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' %]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 %] +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 %]+ | Card | +Name | +Category | +Library | +Expires on | +OD/Checkouts | +Fines | +Circ note | ++ |
---|