Bug 25273: (follow-up) Don't die on unknown authtype
[koha.git] / C4 / Utils / DataTables / Members.pm
bloba718a9633e5a0c1663389e3151b9851f408bf343
1 package C4::Utils::DataTables::Members;
3 use Modern::Perl;
4 use C4::Context;
5 use C4::Utils::DataTables;
6 use Koha::DateUtils;
8 sub search {
9 my ( $params ) = @_;
10 my $searchmember = $params->{searchmember};
11 my $firstletter = $params->{firstletter};
12 my $categorycode = $params->{categorycode};
13 my $branchcode = $params->{branchcode};
14 my $searchtype = $params->{searchtype} || 'contain';
15 my $searchfieldstype = $params->{searchfieldstype} || 'standard';
16 my $has_permission = $params->{has_permission};
17 my $dt_params = $params->{dt_params};
19 unless ( $searchmember ) {
20 $searchmember = $dt_params->{sSearch} // '';
23 # If branches are independent and user is not superlibrarian
24 # The search has to be only on the user branch
25 my $userenv = C4::Context->userenv;
26 my $logged_in_user = Koha::Patrons->find( $userenv->{number} );
27 my @restricted_branchcodes = $logged_in_user->libraries_where_can_see_patrons;
29 my ($sth, $query, $iTotalQuery, $iTotalRecords, $iTotalDisplayRecords);
30 my $dbh = C4::Context->dbh;
32 # Get the module_bit from a given permission code
33 if ( $has_permission ) {
34 ($has_permission->{module_bit}) = $dbh->selectrow_array(q|
35 SELECT bit FROM userflags WHERE flag=?
36 |, undef, $has_permission->{permission});
39 my (@where, @conditions);
40 # Get the iTotalRecords DataTable variable
41 $iTotalQuery = "SELECT COUNT(borrowers.borrowernumber) FROM borrowers";
42 if ( $has_permission ) {
43 $iTotalQuery .= ' LEFT JOIN user_permissions ON borrowers.borrowernumber=user_permissions.borrowernumber';
44 $iTotalQuery .= ' AND module_bit=? AND code=?';
45 push @conditions, $has_permission->{module_bit}, $has_permission->{subpermission};
48 if ( @restricted_branchcodes ) {
49 push @where, "borrowers.branchcode IN (" . join( ',', ('?') x @restricted_branchcodes ) . ")";
50 push @conditions, @restricted_branchcodes;
52 if ( $has_permission ) {
53 push @where, '( borrowers.flags = 1 OR borrowers.flags & (1 << ?) OR module_bit=? AND code=? )';
54 push @conditions, ($has_permission->{module_bit}) x 2, $has_permission->{subpermission};
56 $iTotalQuery .= ' WHERE ' . join ' AND ', @where if @where;
57 ($iTotalRecords) = $dbh->selectrow_array( $iTotalQuery, undef, @conditions );
59 # Do that after iTotalQuery!
60 if ( defined $branchcode and $branchcode ) {
61 @restricted_branchcodes = @restricted_branchcodes
62 ? grep ({ $_ eq $branchcode } @restricted_branchcodes)
63 ? ($branchcode)
64 : (undef) # Do not return any results
65 : ($branchcode);
68 if ( $searchfieldstype eq 'dateofbirth' ) {
69 # Return an empty list if the date of birth is not correctly formatted
70 $searchmember = eval { output_pref( { str => $searchmember, dateformat => 'iso', dateonly => 1 } ); };
71 if ( $@ or not $searchmember ) {
72 return {
73 iTotalRecords => $iTotalRecords,
74 iTotalDisplayRecords => 0,
75 patrons => [],
80 my $select = "SELECT
81 borrowers.borrowernumber, borrowers.surname, borrowers.firstname,
82 borrowers.othernames,
83 borrowers.flags,
84 borrowers.streetnumber, borrowers.streettype, borrowers.address,
85 borrowers.address2, borrowers.city, borrowers.state, borrowers.zipcode,
86 borrowers.country, cardnumber, borrowers.dateexpiry,
87 borrowers.borrowernotes, borrowers.branchcode, borrowers.email,
88 borrowers.userid, borrowers.dateofbirth, borrowers.categorycode,
89 categories.description AS category_description, categories.category_type,
90 branches.branchname, borrowers.phone";
91 my $from = "FROM borrowers
92 LEFT JOIN branches ON borrowers.branchcode = branches.branchcode
93 LEFT JOIN categories ON borrowers.categorycode = categories.categorycode";
94 my @where_args;
95 if ( $has_permission ) {
96 $from .= '
97 LEFT JOIN user_permissions ON borrowers.borrowernumber=user_permissions.borrowernumber
98 AND module_bit=? AND code=?';
99 push @where_args, $has_permission->{module_bit}, $has_permission->{subpermission};
101 my @where_strs;
102 if(defined $firstletter and $firstletter ne '') {
103 push @where_strs, "borrowers.surname LIKE ?";
104 push @where_args, "$firstletter%";
106 if(defined $categorycode and $categorycode ne '') {
107 push @where_strs, "borrowers.categorycode = ?";
108 push @where_args, $categorycode;
110 if(@restricted_branchcodes ) {
111 push @where_strs, "borrowers.branchcode IN (" . join( ',', ('?') x @restricted_branchcodes ) . ")";
112 push @where_args, @restricted_branchcodes;
115 my $searchfields = {
116 standard => C4::Context->preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid',
117 email => 'email,emailpro,B_email',
118 borrowernumber => 'borrowernumber',
119 phone => 'phone,phonepro,B_phone,altcontactphone,mobile',
120 address => 'streetnumber,streettype,address,address2,city,state,zipcode,country',
123 # * is replaced with % for sql
124 $searchmember =~ s/\*/%/g;
126 # split into search terms
127 my @terms;
128 # consider coma as space
129 $searchmember =~ s/,/ /g;
130 if ( $searchtype eq 'contain' ) {
131 @terms = split / /, $searchmember;
132 } else {
133 @terms = ($searchmember);
136 foreach my $term (@terms) {
137 next unless $term;
139 my $term_dt = eval { local $SIG{__WARN__} = {}; output_pref( { str => $term, dateonly => 1, dateformat => 'sql' } ); };
141 if ($term_dt) {
142 $term = $term_dt;
143 } else {
144 $term .= '%' # end with anything
145 if $term !~ /%$/;
146 $term = "%$term" # begin with anythin unless start_with
147 if $searchtype eq 'contain' && $term !~ /^%/;
150 my @where_strs_or;
151 if ( defined $searchfields->{$searchfieldstype} ) {
152 for my $searchfield ( split /,/, $searchfields->{$searchfieldstype} ) {
153 push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfield) . " LIKE ?";
154 push @where_args, $term;
156 } else {
157 push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfieldstype) . " LIKE ?";
158 push @where_args, $term;
162 if ( $searchfieldstype eq 'standard' and C4::Context->preference('ExtendedPatronAttributes') and $searchmember ) {
163 my @matching_borrowernumbers = Koha::Patrons->filter_by_attribute_value($searchmember)->get_column('borrowernumber');
165 for my $borrowernumber ( @matching_borrowernumbers ) {
166 push @where_strs_or, "borrowers.borrowernumber = ?";
167 push @where_args, $borrowernumber;
171 push @where_strs, '('. join (' OR ', @where_strs_or) . ')'
172 if @where_strs_or;
175 if ( $has_permission ) {
176 push @where_strs, '( borrowers.flags = 1 OR borrowers.flags & (1 << ?) OR module_bit=? AND code=? )';
177 push @where_args, ($has_permission->{module_bit}) x 2, $has_permission->{subpermission};
180 my $where = @where_strs ? " WHERE " . join (" AND ", @where_strs) : undef;
181 my $orderby = dt_build_orderby($dt_params);
183 my $limit;
184 # If iDisplayLength == -1, we want to display all patrons
185 if ( !$dt_params->{iDisplayLength} || $dt_params->{iDisplayLength} > -1 ) {
186 # In order to avoid sql injection
187 $dt_params->{iDisplayStart} =~ s/\D//g if defined($dt_params->{iDisplayStart});
188 $dt_params->{iDisplayLength} =~ s/\D//g if defined($dt_params->{iDisplayLength});
189 $dt_params->{iDisplayStart} //= 0;
190 $dt_params->{iDisplayLength} //= 20;
191 $limit = "LIMIT $dt_params->{iDisplayStart},$dt_params->{iDisplayLength}";
194 $query = join(
195 " ",
196 ($select ? $select : ""),
197 ($from ? $from : ""),
198 ($where ? $where : ""),
199 ($orderby ? $orderby : ""),
200 ($limit ? $limit : "")
202 $sth = $dbh->prepare($query);
203 $sth->execute(@where_args);
204 my $patrons = $sth->fetchall_arrayref({});
206 # Get the iTotalDisplayRecords DataTable variable
207 $query = "SELECT COUNT(borrowers.borrowernumber) " . $from . ($where ? $where : "");
208 $sth = $dbh->prepare($query);
209 $sth->execute(@where_args);
210 ($iTotalDisplayRecords) = $sth->fetchrow_array;
212 # Get some information on patrons
213 foreach my $patron (@$patrons) {
214 my $patron_object = Koha::Patrons->find( $patron->{borrowernumber} );
215 $patron->{overdues} = $patron_object->get_overdues->count;
216 $patron->{issues} = $patron_object->checkouts->count;
217 $patron->{age} = $patron_object->get_age;
218 my $balance = $patron_object->account->balance;
219 # FIXME Should be formatted from the template
220 $patron->{fines} = sprintf("%.2f", $balance);
222 if( $patron->{dateexpiry} ) {
223 # FIXME We should not format the date here, do it in template-side instead
224 $patron->{dateexpiry} = output_pref( { dt => scalar dt_from_string( $patron->{dateexpiry}, 'iso'), dateonly => 1} );
225 } else {
226 $patron->{dateexpiry} = '';
230 return {
231 iTotalRecords => $iTotalRecords,
232 iTotalDisplayRecords => $iTotalDisplayRecords,
233 patrons => $patrons
238 __END__
240 =head1 NAME
242 C4::Utils::DataTables::Members - module for using DataTables with patrons
244 =head1 SYNOPSIS
246 This module provides (one for the moment) routines used by the patrons search
248 =head2 FUNCTIONS
250 =head3 search
252 my $dt_infos = C4::Utils::DataTables::Members->search($params);
254 $params is a hashref with some keys:
256 =over 4
258 =item searchmember
260 String to search in the borrowers sql table
262 =item firstletter
264 Introduced to contain 1 letter but can contain more.
265 The search will done on the borrowers.surname field
267 =item categorycode
269 Search patrons with this categorycode
271 =item branchcode
273 Search patrons with this branchcode
275 =item searchtype
277 Can be 'start_with' or 'contain' (default value). Used for the searchmember parameter.
279 =item searchfieldstype
281 Can be 'standard' (default value), 'email', 'borrowernumber', 'phone', 'address' or 'dateofbirth', 'sort1', 'sort2'
283 =item dt_params
285 Is the reference of C4::Utils::DataTables::dt_get_params($input);
287 =cut
289 =back
291 =head1 LICENSE
293 This file is part of Koha.
295 Copyright 2013 BibLibre
297 Koha is free software; you can redistribute it and/or modify it
298 under the terms of the GNU General Public License as published by
299 the Free Software Foundation; either version 3 of the License, or
300 (at your option) any later version.
302 Koha is distributed in the hope that it will be useful, but
303 WITHOUT ANY WARRANTY; without even the implied warranty of
304 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
305 GNU General Public License for more details.
307 You should have received a copy of the GNU General Public License
308 along with Koha; if not, see <http://www.gnu.org/licenses>.