Josef Moravec
2cc3d05d26
Test plan: 0) Apply the patch 1) Go to all of these pages Patron detail Other patron pages - look on the left side (circ-menu) Patron search Guarantor search ( go to child patron -> edit -> in guarantor section click "Set to patron" Search through "Check out" (in the header) 2) Confirm that does show date of birth and date consistantly, try it on patrons with and without date of birth set to find possible reggressions Signed-off-by: Aleisha Amohia <aleishaamohia@hotmail.com> Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com> Signed-off-by: Séverine QUEUNE <severine.queune@bulac.fr> Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de> Signed-off-by: Michal Denar <black23@gmail.com> Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de> Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
308 lines
11 KiB
Perl
308 lines
11 KiB
Perl
package C4::Utils::DataTables::Members;
|
|
|
|
use Modern::Perl;
|
|
use C4::Context;
|
|
use C4::Utils::DataTables;
|
|
use Koha::DateUtils;
|
|
|
|
sub search {
|
|
my ( $params ) = @_;
|
|
my $searchmember = $params->{searchmember};
|
|
my $firstletter = $params->{firstletter};
|
|
my $categorycode = $params->{categorycode};
|
|
my $branchcode = $params->{branchcode};
|
|
my $searchtype = $params->{searchtype} || 'contain';
|
|
my $searchfieldstype = $params->{searchfieldstype} || 'standard';
|
|
my $has_permission = $params->{has_permission};
|
|
my $dt_params = $params->{dt_params};
|
|
|
|
unless ( $searchmember ) {
|
|
$searchmember = $dt_params->{sSearch} // '';
|
|
}
|
|
|
|
# If branches are independent and user is not superlibrarian
|
|
# The search has to be only on the user branch
|
|
my $userenv = C4::Context->userenv;
|
|
my $logged_in_user = Koha::Patrons->find( $userenv->{number} );
|
|
my @restricted_branchcodes = $logged_in_user->libraries_where_can_see_patrons;
|
|
|
|
my ($sth, $query, $iTotalQuery, $iTotalRecords, $iTotalDisplayRecords);
|
|
my $dbh = C4::Context->dbh;
|
|
|
|
# Get the module_bit from a given permission code
|
|
if ( $has_permission ) {
|
|
($has_permission->{module_bit}) = $dbh->selectrow_array(q|
|
|
SELECT bit FROM userflags WHERE flag=?
|
|
|, undef, $has_permission->{permission});
|
|
}
|
|
|
|
my (@where, @conditions);
|
|
# Get the iTotalRecords DataTable variable
|
|
$iTotalQuery = "SELECT COUNT(borrowers.borrowernumber) FROM borrowers";
|
|
if ( $has_permission ) {
|
|
$iTotalQuery .= ' LEFT JOIN user_permissions ON borrowers.borrowernumber=user_permissions.borrowernumber';
|
|
$iTotalQuery .= ' AND module_bit=? AND code=?';
|
|
push @conditions, $has_permission->{module_bit}, $has_permission->{subpermission};
|
|
}
|
|
|
|
if ( @restricted_branchcodes ) {
|
|
push @where, "borrowers.branchcode IN (" . join( ',', ('?') x @restricted_branchcodes ) . ")";
|
|
push @conditions, @restricted_branchcodes;
|
|
}
|
|
if ( $has_permission ) {
|
|
push @where, '( borrowers.flags = 1 OR borrowers.flags & (1 << ?) OR module_bit=? AND code=? )';
|
|
push @conditions, ($has_permission->{module_bit}) x 2, $has_permission->{subpermission};
|
|
}
|
|
$iTotalQuery .= ' WHERE ' . join ' AND ', @where if @where;
|
|
($iTotalRecords) = $dbh->selectrow_array( $iTotalQuery, undef, @conditions );
|
|
|
|
# Do that after iTotalQuery!
|
|
if ( defined $branchcode and $branchcode ) {
|
|
@restricted_branchcodes = @restricted_branchcodes
|
|
? grep ({ $_ eq $branchcode } @restricted_branchcodes)
|
|
? ($branchcode)
|
|
: (undef) # Do not return any results
|
|
: ($branchcode);
|
|
}
|
|
|
|
if ( $searchfieldstype eq 'dateofbirth' ) {
|
|
# Return an empty list if the date of birth is not correctly formatted
|
|
$searchmember = eval { output_pref( { str => $searchmember, dateformat => 'iso', dateonly => 1 } ); };
|
|
if ( $@ or not $searchmember ) {
|
|
return {
|
|
iTotalRecords => $iTotalRecords,
|
|
iTotalDisplayRecords => 0,
|
|
patrons => [],
|
|
};
|
|
}
|
|
}
|
|
|
|
my $select = "SELECT
|
|
borrowers.borrowernumber, borrowers.surname, borrowers.firstname,
|
|
borrowers.othernames,
|
|
borrowers.flags,
|
|
borrowers.streetnumber, borrowers.streettype, borrowers.address,
|
|
borrowers.address2, borrowers.city, borrowers.state, borrowers.zipcode,
|
|
borrowers.country, cardnumber, borrowers.dateexpiry,
|
|
borrowers.borrowernotes, borrowers.branchcode, borrowers.email,
|
|
borrowers.userid, borrowers.dateofbirth, borrowers.categorycode,
|
|
categories.description AS category_description, categories.category_type,
|
|
branches.branchname, borrowers.phone";
|
|
my $from = "FROM borrowers
|
|
LEFT JOIN branches ON borrowers.branchcode = branches.branchcode
|
|
LEFT JOIN categories ON borrowers.categorycode = categories.categorycode";
|
|
my @where_args;
|
|
if ( $has_permission ) {
|
|
$from .= '
|
|
LEFT JOIN user_permissions ON borrowers.borrowernumber=user_permissions.borrowernumber
|
|
AND module_bit=? AND code=?';
|
|
push @where_args, $has_permission->{module_bit}, $has_permission->{subpermission};
|
|
}
|
|
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(@restricted_branchcodes ) {
|
|
push @where_strs, "borrowers.branchcode IN (" . join( ',', ('?') x @restricted_branchcodes ) . ")";
|
|
push @where_args, @restricted_branchcodes;
|
|
}
|
|
|
|
my $searchfields = {
|
|
standard => C4::Context->preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid',
|
|
email => 'email,emailpro,B_email',
|
|
borrowernumber => 'borrowernumber',
|
|
phone => 'phone,phonepro,B_phone,altcontactphone,mobile',
|
|
address => 'streetnumber,streettype,address,address2,city,state,zipcode,country',
|
|
};
|
|
|
|
# * is replaced with % for sql
|
|
$searchmember =~ s/\*/%/g;
|
|
|
|
# split into search terms
|
|
my @terms;
|
|
# consider coma as space
|
|
$searchmember =~ s/,/ /g;
|
|
if ( $searchtype eq 'contain' ) {
|
|
@terms = split / /, $searchmember;
|
|
} else {
|
|
@terms = ($searchmember);
|
|
}
|
|
|
|
foreach my $term (@terms) {
|
|
next unless $term;
|
|
|
|
my $term_dt = eval { local $SIG{__WARN__} = {}; output_pref( { str => $term, dateonly => 1, dateformat => 'sql' } ); };
|
|
|
|
if ($term_dt) {
|
|
$term = $term_dt;
|
|
} else {
|
|
$term .= '%' # end with anything
|
|
if $term !~ /%$/;
|
|
$term = "%$term" # begin with anythin unless start_with
|
|
if $searchtype eq 'contain' && $term !~ /^%/;
|
|
}
|
|
|
|
my @where_strs_or;
|
|
if ( defined $searchfields->{$searchfieldstype} ) {
|
|
for my $searchfield ( split /,/, $searchfields->{$searchfieldstype} ) {
|
|
push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfield) . " LIKE ?";
|
|
push @where_args, $term;
|
|
}
|
|
} else {
|
|
push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfieldstype) . " LIKE ?";
|
|
push @where_args, $term;
|
|
}
|
|
|
|
|
|
if ( $searchfieldstype eq 'standard' and C4::Context->preference('ExtendedPatronAttributes') and $searchmember ) {
|
|
my @matching_borrowernumbers = Koha::Patrons->filter_by_attribute_value($searchmember)->get_column('borrowernumber');
|
|
|
|
for my $borrowernumber ( @matching_borrowernumbers ) {
|
|
push @where_strs_or, "borrowers.borrowernumber = ?";
|
|
push @where_args, $borrowernumber;
|
|
}
|
|
}
|
|
|
|
push @where_strs, '('. join (' OR ', @where_strs_or) . ')'
|
|
if @where_strs_or;
|
|
}
|
|
|
|
if ( $has_permission ) {
|
|
push @where_strs, '( borrowers.flags = 1 OR borrowers.flags & (1 << ?) OR module_bit=? AND code=? )';
|
|
push @where_args, ($has_permission->{module_bit}) x 2, $has_permission->{subpermission};
|
|
}
|
|
|
|
my $where = @where_strs ? " WHERE " . join (" AND ", @where_strs) : undef;
|
|
my $orderby = dt_build_orderby($dt_params);
|
|
|
|
my $limit;
|
|
# If iDisplayLength == -1, we want to display all patrons
|
|
if ( !$dt_params->{iDisplayLength} || $dt_params->{iDisplayLength} > -1 ) {
|
|
# In order to avoid sql injection
|
|
$dt_params->{iDisplayStart} =~ s/\D//g if defined($dt_params->{iDisplayStart});
|
|
$dt_params->{iDisplayLength} =~ s/\D//g if defined($dt_params->{iDisplayLength});
|
|
$dt_params->{iDisplayStart} //= 0;
|
|
$dt_params->{iDisplayLength} //= 20;
|
|
$limit = "LIMIT $dt_params->{iDisplayStart},$dt_params->{iDisplayLength}";
|
|
}
|
|
|
|
$query = join(
|
|
" ",
|
|
($select ? $select : ""),
|
|
($from ? $from : ""),
|
|
($where ? $where : ""),
|
|
($orderby ? $orderby : ""),
|
|
($limit ? $limit : "")
|
|
);
|
|
$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 some information on patrons
|
|
foreach my $patron (@$patrons) {
|
|
my $patron_object = Koha::Patrons->find( $patron->{borrowernumber} );
|
|
$patron->{overdues} = $patron_object->get_overdues->count;
|
|
$patron->{issues} = $patron_object->checkouts->count;
|
|
$patron->{age} = $patron_object->get_age;
|
|
my $balance = $patron_object->account->balance;
|
|
# FIXME Should be formatted from the template
|
|
$patron->{fines} = sprintf("%.2f", $balance);
|
|
|
|
if( $patron->{dateexpiry} ) {
|
|
# FIXME We should not format the date here, do it in template-side instead
|
|
$patron->{dateexpiry} = output_pref( { dt => scalar dt_from_string( $patron->{dateexpiry}, 'iso'), dateonly => 1} );
|
|
} else {
|
|
$patron->{dateexpiry} = '';
|
|
}
|
|
}
|
|
|
|
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 'start_with' or 'contain' (default value). Used for the searchmember parameter.
|
|
|
|
=item searchfieldstype
|
|
|
|
Can be 'standard' (default value), '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
|
|
|
|
This file is part of Koha.
|
|
|
|
Copyright 2013 BibLibre
|
|
|
|
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 3 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, see <http://www.gnu.org/licenses>.
|