Bug 17588: ->get_issues has been replaced with ->checkouts
[koha.git] / C4 / Utils / DataTables / Members.pm
1 package C4::Utils::DataTables::Members;
2
3 use Modern::Perl;
4 use C4::Context;
5 use C4::Utils::DataTables;
6 use Koha::DateUtils;
7
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 $dt_params = $params->{dt_params};
17
18     unless ( $searchmember ) {
19         $searchmember = $dt_params->{sSearch} // '';
20     }
21
22     my ($sth, $query, $iTotalRecords, $iTotalDisplayRecords);
23     my $dbh = C4::Context->dbh;
24     # Get the iTotalRecords DataTable variable
25     $query = "SELECT COUNT(borrowers.borrowernumber) FROM borrowers";
26     $sth = $dbh->prepare($query);
27     $sth->execute;
28     ($iTotalRecords) = $sth->fetchrow_array;
29
30     if ( $searchfieldstype eq 'dateofbirth' ) {
31         # Return an empty list if the date of birth is not correctly formatted
32         $searchmember = eval { output_pref( { str => $searchmember, dateformat => 'iso', dateonly => 1 } ); };
33         if ( $@ or not $searchmember ) {
34             return {
35                 iTotalRecords        => 0,
36                 iTotalDisplayRecords => 0,
37                 patrons              => [],
38             };
39         }
40     }
41
42     # If branches are independent and user is not superlibrarian
43     # The search has to be only on the user branch
44     if ( C4::Context::only_my_library ) {
45         my $userenv = C4::Context->userenv;
46         $branchcode = $userenv->{'branch'};
47
48     }
49
50     my $select = "SELECT
51         borrowers.borrowernumber, borrowers.surname, borrowers.firstname,
52         borrowers.streetnumber, borrowers.streettype, borrowers.address,
53         borrowers.address2, borrowers.city, borrowers.state, borrowers.zipcode,
54         borrowers.country, cardnumber, borrowers.dateexpiry,
55         borrowers.borrowernotes, borrowers.branchcode, borrowers.email,
56         borrowers.userid, borrowers.dateofbirth, borrowers.categorycode,
57         categories.description AS category_description, categories.category_type,
58         branches.branchname";
59     my $from = "FROM borrowers
60         LEFT JOIN branches ON borrowers.branchcode = branches.branchcode
61         LEFT JOIN categories ON borrowers.categorycode = categories.categorycode";
62     my @where_args;
63     my @where_strs;
64     if(defined $firstletter and $firstletter ne '') {
65         push @where_strs, "borrowers.surname LIKE ?";
66         push @where_args, "$firstletter%";
67     }
68     if(defined $categorycode and $categorycode ne '') {
69         push @where_strs, "borrowers.categorycode = ?";
70         push @where_args, $categorycode;
71     }
72     if(defined $branchcode and $branchcode ne '') {
73         push @where_strs, "borrowers.branchcode = ?";
74         push @where_args, $branchcode;
75     }
76
77     my $searchfields = {
78         standard => C4::Context->preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid',
79         surname => 'surname',
80         email => 'email,emailpro,B_email',
81         borrowernumber => 'borrowernumber',
82         userid => 'userid',
83         phone => 'phone,phonepro,B_phone,altcontactphone,mobile',
84         address => 'streettype,address,address2,city,state,zipcode,country',
85         dateofbirth => 'dateofbirth',
86         sort1 => 'sort1',
87         sort2 => 'sort2',
88     };
89
90     # * is replaced with % for sql
91     $searchmember =~ s/\*/%/g;
92
93     # split into search terms
94     my @terms;
95     # consider coma as space
96     $searchmember =~ s/,/ /g;
97     if ( $searchtype eq 'contain' ) {
98        @terms = split / /, $searchmember;
99     } else {
100        @terms = ($searchmember);
101     }
102
103     foreach my $term (@terms) {
104         next unless $term;
105
106         my $term_dt = eval { local $SIG{__WARN__} = {}; output_pref( { str => $term, dateonly => 1, dateformat => 'sql' } ); };
107
108         if ($term_dt) {
109             $term = $term_dt;
110         } else {
111             $term .= '%'    # end with anything
112               if $term !~ /%$/;
113             $term = "%$term"    # begin with anythin unless start_with
114               if $searchtype eq 'contain' && $term !~ /^%/;
115         }
116
117         my @where_strs_or;
118         for my $searchfield ( split /,/, $searchfields->{$searchfieldstype} ) {
119             push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfield) . " LIKE ?";
120             push @where_args, $term;
121         }
122
123         if ( C4::Context->preference('ExtendedPatronAttributes') and $searchmember ) {
124             my $matching_borrowernumbers = C4::Members::Attributes::SearchIdMatchingAttribute($searchmember);
125
126             for my $borrowernumber ( @$matching_borrowernumbers ) {
127                 push @where_strs_or, "borrowers.borrowernumber = ?";
128                 push @where_args, $borrowernumber;
129             }
130         }
131
132         push @where_strs, '('. join (' OR ', @where_strs_or) . ')'
133             if @where_strs_or;
134     }
135
136     my $where;
137     $where = " WHERE " . join (" AND ", @where_strs) if @where_strs;
138     my $orderby = dt_build_orderby($dt_params);
139
140     my $limit;
141     # If iDisplayLength == -1, we want to display all patrons
142     if ( !$dt_params->{iDisplayLength} || $dt_params->{iDisplayLength} > -1 ) {
143         # In order to avoid sql injection
144         $dt_params->{iDisplayStart} =~ s/\D//g if defined($dt_params->{iDisplayStart});
145         $dt_params->{iDisplayLength} =~ s/\D//g if defined($dt_params->{iDisplayLength});
146         $dt_params->{iDisplayStart} //= 0;
147         $dt_params->{iDisplayLength} //= 20;
148         $limit = "LIMIT $dt_params->{iDisplayStart},$dt_params->{iDisplayLength}";
149     }
150
151     $query = join(
152         " ",
153         ($select ? $select : ""),
154         ($from ? $from : ""),
155         ($where ? $where : ""),
156         ($orderby ? $orderby : ""),
157         ($limit ? $limit : "")
158     );
159     $sth = $dbh->prepare($query);
160     $sth->execute(@where_args);
161     my $patrons = $sth->fetchall_arrayref({});
162
163     # Get the iTotalDisplayRecords DataTable variable
164     $query = "SELECT COUNT(borrowers.borrowernumber) " . $from . ($where ? $where : "");
165     $sth = $dbh->prepare($query);
166     $sth->execute(@where_args);
167     ($iTotalDisplayRecords) = $sth->fetchrow_array;
168
169     # Get some information on patrons
170     foreach my $patron (@$patrons) {
171         my $patron_object = Koha::Patrons->find( $patron->{borrowernumber} );
172         $patron->{overdues} = $patron_object->get_overdues->count;
173         $patron->{issues} = $patron_object->checkouts->count;
174         my $balance = $patron_object->account->balance;
175         # FIXME Should be formatted from the template
176         $patron->{fines} = sprintf("%.2f", $balance);
177
178         if($patron->{dateexpiry} and $patron->{dateexpiry} ne '0000-00-00') {
179             $patron->{dateexpiry} = output_pref( { dt => dt_from_string( $patron->{dateexpiry}, 'iso'), dateonly => 1} );
180         } else {
181             $patron->{dateexpiry} = '';
182         }
183     }
184
185     return {
186         iTotalRecords => $iTotalRecords,
187         iTotalDisplayRecords => $iTotalDisplayRecords,
188         patrons => $patrons
189     }
190 }
191
192 1;
193 __END__
194
195 =head1 NAME
196
197 C4::Utils::DataTables::Members - module for using DataTables with patrons
198
199 =head1 SYNOPSIS
200
201 This module provides (one for the moment) routines used by the patrons search
202
203 =head2 FUNCTIONS
204
205 =head3 search
206
207     my $dt_infos = C4::Utils::DataTables::Members->search($params);
208
209 $params is a hashref with some keys:
210
211 =over 4
212
213 =item searchmember
214
215   String to search in the borrowers sql table
216
217 =item firstletter
218
219   Introduced to contain 1 letter but can contain more.
220   The search will done on the borrowers.surname field
221
222 =item categorycode
223
224   Search patrons with this categorycode
225
226 =item branchcode
227
228   Search patrons with this branchcode
229
230 =item searchtype
231
232   Can be 'start_with' or 'contain' (default value). Used for the searchmember parameter.
233
234 =item searchfieldstype
235
236   Can be 'standard' (default value), 'email', 'borrowernumber', 'phone', 'address' or 'dateofbirth', 'sort1', 'sort2'
237
238 =item dt_params
239
240   Is the reference of C4::Utils::DataTables::dt_get_params($input);
241
242 =cut
243
244 =back
245
246 =head1 LICENSE
247
248 This file is part of Koha.
249
250 Copyright 2013 BibLibre
251
252 Koha is free software; you can redistribute it and/or modify it
253 under the terms of the GNU General Public License as published by
254 the Free Software Foundation; either version 3 of the License, or
255 (at your option) any later version.
256
257 Koha is distributed in the hope that it will be useful, but
258 WITHOUT ANY WARRANTY; without even the implied warranty of
259 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
260 GNU General Public License for more details.
261
262 You should have received a copy of the GNU General Public License
263 along with Koha; if not, see <http://www.gnu.org/licenses>.