@@ -, +, @@ - 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 @@ [% END %] --- a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc @@ -5,69 +5,100 @@ --- 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() { -
+
+
+
+
+
+ [% 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 %] +
- [% IF patron_list %] -
- Added [% patrons_added_to_list.size %] patrons to [% patron_list.name %]. -
- [% END %] + [% IF ( CAN_user_borrowers && pending_borrower_modifications ) %] + + [% 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 %] -
- - [% IF ( CAN_user_borrowers && pending_borrower_modifications ) %] - - [% END %] - - [% IF ( resultsloop ) %] - [% IF (CAN_user_tools_manage_patron_lists) %] -
- [% END %] -
-

Results [% from %] to [% to %] of [% numresults %] found for [% IF ( member ) %]'[% member %]'[% END %][% IF ( surname ) %]'[% surname %]'[% END %]

- - [% IF (CAN_user_tools_manage_patron_lists) %] -
- Select all - | - Clear all - | - - - - - - - - - - [% FOREACH key IN search_parameters.keys %] - - [% END %] - - - -
- [% END %] -
-
- - - - - [% IF (CAN_user_tools_manage_patron_lists) %] - - [% END %] - - - - - - - - - - - - - [% FOREACH resultsloo IN resultsloop %] - [% IF ( resultsloo.overdue ) %] - - [% ELSE %] - [% UNLESS ( loop.odd ) %] - - [% ELSE %] - - [% END %] - [% END %] - [% IF (CAN_user_tools_manage_patron_lists) %] - - [% END %] - - - - - - - - - - - [% END %] - -
 CardNameCatLibraryExpires onOD/CheckoutsFinesCirc note 
[% resultsloo.cardnumber %] - - [% 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%] -
- [% IF ( resultsloo.streetnumber ) %][% resultsloo.streetnumber %] [% END %][% resultsloo.address %][% IF ( resultsloo.address2 ) %]
[% resultsloo.address2 %][% END %][% IF ( resultsloo.city ) %]
[% 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 %] - [% IF (resultsloo.email ) %]
Email: [% resultsloo.email %][% END %] -
[% resultsloo.category_description %] ([% resultsloo.category_type %])[% resultsloo.branchname %][% resultsloo.dateexpiry %][% IF ( resultsloo.overdues ) %][% resultsloo.overdues %][% ELSE %][% resultsloo.overdues %][% END %]/[% resultsloo.issues %][% IF ( resultsloo.fines < 0 ) %][% resultsloo.fines %] [% ELSIF resultsloo.fines > 0 %] [% resultsloo.fines %] [% ELSE %] [% resultsloo.fines %] [% END %][% resultsloo.borrowernotes %][% IF ( resultsloo.category_type ) %] - Edit - [% ELSE %] - [% IF ( resultsloo.categorycode ) %] - Edit - [% ELSE %] - Edit - [% END %] - [% END %]
-
[% IF ( multipage ) %][% paginationbar %][% END %]
-
- [% IF (CAN_user_tools_manage_patron_lists) %] -
- [% END %] - [% ELSE %] - [% IF ( searching ) %] -
No results found
- [% END %] - [% END %] - -
-
- -
- [% INCLUDE 'members-menu.inc' %] -
+ + +
+
+ [% END %] + + + + + + + + + + + + + + + + +
 CardNameCategoryLibraryExpires onOD/CheckoutsFinesCirc note 
+
+
+
+
+
+
+ +
+

Filters

+
    +
  1. + + +
  2. +
  3. + + +
  4. +
  5. + + +
  6. +
  7. + + +
  8. +
  9. + + +
  10. +
+
+ + +
+
+
+
+
+ [% INCLUDE 'members-menu.inc' %] +
[% INCLUDE 'intranet-bottom.inc' %] --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/tables/members_results.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/members/tables/members_results.tt @@ -0,0 +1,35 @@ +{ + "sEcho": [% sEcho %], + "iTotalRecords": [% iTotalRecords %], + "iTotalDisplayRecords": [% iTotalDisplayRecords %], + "aaData": [ + [% FOREACH data IN aaData %] + { + [% IF CAN_user_tools_manage_patron_lists %] + "dt_borrowernumber": + "", + [% END %] + "dt_cardnumber": + "[% data.cardnumber %]", + "dt_name": + "[% 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%]
[% IF ( data.streetnumber ) %][% data.streetnumber %] [% END %][% data.address %][% IF ( data.address2 ) %]
[% data.address2 %][% END %][% IF ( data.city ) %]
[% 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 %]
", + "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 %][% data.overdues %][% ELSE %][% data.overdues %][% END %] / [% data.issues %]", + "dt_fines": + "[% IF data.fines < 0 %][% data.fines |html %] [% ELSIF data.fines > 0 %] [% data.fines |html %] [% ELSE %] [% data.fines |html%] [% END %]", + "dt_borrowernotes": + "[% data.borrowernotes |html |html_line_break |collapse %]", + "dt_action": + "[% IF data.category_type %]Edit[% ELSE %][% IF data.categorycode %]Edit[% ELSE %]Edit[% END %][% END %]", + "borrowernumber": + "[% data.borrowernumber %]" + }[% UNLESS loop.last %],[% END %] + [% END %] + ] +} --- a/members/member.pl +++ a/members/member.pl @@ -6,7 +6,7 @@ # Copyright 2000-2002 Katipo Communications -# Copyright 2010 BibLibre +# Copyright 2013 BibLibre # # This file is part of Koha. # @@ -27,20 +27,17 @@ use Modern::Perl; use C4::Auth; use C4::Output; use CGI; -use C4::Members; use C4::Branch; use C4::Category; +use C4::Members qw( GetMember ); use Koha::DateUtils; use File::Basename; use Koha::List::Patron; 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", + = get_template_and_user({template_name => "members/member.tt", query => $input, type => "intranet", authnotrequired => 0, @@ -49,189 +46,88 @@ my ($template, $loggedinuser, $cookie) my $theme = $input->param('theme') || "default"; -my $add_to_patron_list = $input->param('add_to_patron_list'); -my $add_to_patron_list_which = $input->param('add_to_patron_list_which'); -my $new_patron_list = $input->param('new_patron_list'); -my @borrowernumbers = $input->param('borrowernumber'); -$input->delete( - 'add_to_patron_list', 'add_to_patron_list_which', - 'new_patron_list', 'borrowernumber', -); - 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 $patron->{branchcode} && $branches->{$_}->{branchcode} eq $patron->{branchcode}; - my %row = ( value => $_, - selected => $selected, - branchname => $branches->{$_}->{branchname}, - ); - push @branchloop, \%row; -} - -my %categories_dislay; - -foreach my $category (@categories){ - my $hash={ - category_description=>$$category{description}, - category_type=>$$category{category_type} - }; - $categories_dislay{$$category{categorycode}} = $hash; + delete $patron->{$_} unless($patron->{$_}); } -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 $quicksearch = $input->param('quicksearch') // 0; -my ($count,$results); -if ($member || keys %$patron) { - my $searchfields = $input->param('searchfields') || ''; - my @searchfields = $searchfields ? split( ',', $searchfields ) : ( "firstname", "surname", "othernames", "cardnumber", "userid", "email" ); - - if ( $searchfields eq "dateofbirth" ) { - $member = output_pref({dt => dt_from_string($member), dateformat => 'iso', dateonly => 1}); +if ( $quicksearch ) { + my $branchcode; + if ( C4::Branch::onlymine ) { + my $userenv = C4::Context->userenv; + $branchcode = $userenv->{'branch'}; + } + my $member = GetMember( + cardnumber => $searchmember, + ( $branchcode ? ( branchcode => $branchcode ) : () ), + ); + if( $member ){ + print $input->redirect("/cgi-bin/koha/members/moremember.pl?borrowernumber=" . $member->{borrowernumber}); + exit; } +} - my $searchtype = $input->param('searchtype'); - my $search_scope = - $quicksearch ? "field_start_with" - : $searchtype ? $searchtype - : "start_with"; +my $searchfieldstype = $input->param('searchfieldstype') || 'standard'; - ($results) = Search( $member || $patron, \@orderby, undef, undef, \@searchfields, $search_scope ); +if ( $searchfieldstype eq "dateofbirth" ) { + $searchmember = output_pref({dt => dt_from_string($searchmember), dateformat => 'iso', dateonly => 1}); } -if ($add_to_patron_list) { - my $patron_list; - - if ( $add_to_patron_list eq 'new' ) { - $patron_list = AddPatronList( { name => $new_patron_list } ); - } - else { - $patron_list = - [ GetPatronLists( { patron_list_id => $add_to_patron_list } ) ]->[0]; +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 } - - if ( $add_to_patron_list_which eq 'all' ) { - @borrowernumbers = map { $_->{borrowernumber} } @$results; +} 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 + }; } - - my @patrons_added_to_list = AddPatronsToList( { list => $patron_list, borrowernumbers => \@borrowernumbers } ); - - $template->param( - patron_list => $patron_list, - patrons_added_to_list => \@patrons_added_to_list, - ) } -if ($results) { - for my $field ('categorycode','branchcode'){ - next unless ($patron->{$field}); - @$results = grep { $_->{$field} eq $patron->{$field} } @$results; - } - $count = scalar(@$results); -} else { - $count = 0; +my @categories = C4::Category->all; +if ( $patron->{categorycode} ) { + foreach my $category ( grep { $_->{categorycode} eq $patron->{categorycode} } @categories ) { + $category->{selected} = 1; + } } -if($count == 1){ - print $input->redirect("/cgi-bin/koha/members/moremember.pl?borrowernumber=" . @$results[0]->{borrowernumber}); - exit; -} +$template->param( 'alphabet' => C4::Context->preference('alphabet') || join ' ', 'A' .. 'Z' ); -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'}); - $fines ||= 0; - $$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); +my $orderby = $input->param('orderby') // ''; +if(defined $orderby and $orderby ne '') { + $orderby =~ s/[, ]/_/g; } -if ($$patron{categorycode}){ - foreach my $category (grep{$_->{categorycode} eq $$patron{categorycode}}@categories){ - $$category{selected}=1; - } -} -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'); +my $view = $input->request_method() eq "GET" ? "show_form" : "show_results"; $template->param( - %$patron, - 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), - numresults => $count, - resultsloop => \@resultsdata, - results_per_page => $resultsperpage, - member => $member, - search_parameters => \%parameters, patron_lists => [ GetPatronLists() ], + 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, + view => $view, ); output_html_with_http_headers $input, $cookie, $template->output; --- a/members/members-home.pl +++ a/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; --- a/members/moremember.pl +++ a/members/moremember.pl @@ -52,8 +52,7 @@ use C4::Form::MessagingPreferences; use List::MoreUtils qw/uniq/; use C4::Members::Attributes qw(GetBorrowerAttributes); use Koha::Borrower::Debarments qw(GetDebarments); -#use Smart::Comments; -#use Data::Dumper; + use DateTime; use Koha::DateUtils; @@ -81,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 { @@ -156,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') { @@ -283,13 +282,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; @@ -436,6 +435,7 @@ $template->param( SuspendHoldsIntranet => C4::Context->preference('SuspendHoldsIntranet'), RoutingSerials => C4::Context->preference('RoutingSerials'), debarments => GetDebarments({ borrowernumber => $borrowernumber }), + PatronsPerPage => C4::Context->preference("PatronsPerPage") || 20, ); $template->param( $error => 1 ) if $error; --- a/svc/members/add_to_list +++ a/svc/members/add_to_list @@ -0,0 +1,63 @@ +#!/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( check_cookie_auth ); +use JSON qw( to_json ); +use Koha::List::Patron; + +my $input = new CGI; + +my ( $auth_status, $sessionID ) = check_cookie_auth( + $input->cookie('CGISESSID'), + { tools => 'manage_patron_lists' }, +); + +exit 0 if $auth_status ne "ok"; +my $add_to_patron_list = $input->param('add_to_patron_list'); +my $new_patron_list = $input->param('new_patron_list'); +my @borrowernumbers = $input->param('borrowernumbers[]'); + +my $response; +if ($add_to_patron_list) { + my $patron_list = []; + + if ( $add_to_patron_list eq 'new' ) { + $patron_list = AddPatronList( { name => $new_patron_list } ); + } + else { + $patron_list = + [ GetPatronLists( { patron_list_id => $add_to_patron_list } ) ]->[0]; + } + + my @patrons_added_to_list = AddPatronsToList( { list => $patron_list, borrowernumbers => \@borrowernumbers } ); + + $response->{patron_list} = { patron_list_id => $patron_list->patron_list_id, name => $patron_list->name }; + $response->{patrons_added_to_list} = scalar( @patrons_added_to_list ); +} + +binmode STDOUT, ":encoding(UTF-8)"; +print $input->header( + -type => 'application/json', + -charset => 'UTF-8' +); + +print to_json( $response ); --- a/svc/members/search +++ a/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. --- a/t/DataTables/Members.t +++ a/t/DataTables/Members.t @@ -0,0 +1,14 @@ +use Modern::Perl; +use Test::More tests => 4; + +use_ok( "C4::Utils::DataTables::Members" ); + +my $patrons = C4::Utils::DataTables::Members::search({ + searchmember => "Doe", + searchfieldstype => 'standard', + searchtype => 'contains' +}); + +isnt( $patrons->{iTotalDisplayRecords}, undef, "The iTotalDisplayRecords key is defined"); +isnt( $patrons->{iTotalRecords}, undef, "The iTotalRecords key is defined"); +is( ref $patrons->{patrons}, 'ARRAY', "The patrons key is an arrayref"); --