View | Details | Raw Unified | Return to bug 30063
Collapse All | Expand All

(-)a/C4/Utils/DataTables/Members.pm (-304 lines)
Lines 1-304 Link Here
1
package C4::Utils::DataTables::Members;
2
3
use Modern::Perl;
4
use C4::Context;
5
use C4::Utils::DataTables qw( dt_build_orderby );
6
use Koha::DateUtils qw( dt_from_string output_pref );
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 $has_permission = $params->{has_permission};
17
    my $dt_params = $params->{dt_params};
18
19
    unless ( $searchmember ) {
20
        $searchmember = $dt_params->{sSearch} // '';
21
    }
22
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;
28
29
    my ($sth, $query, $iTotalQuery, $iTotalRecords, $iTotalDisplayRecords);
30
    my $dbh = C4::Context->dbh;
31
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});
37
    }
38
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};
46
    }
47
48
    if ( @restricted_branchcodes ) {
49
        push @where, "borrowers.branchcode IN (" . join( ',', ('?') x @restricted_branchcodes ) . ")";
50
        push @conditions, @restricted_branchcodes;
51
    }
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};
55
    }
56
    $iTotalQuery .= ' WHERE ' . join ' AND ', @where if @where;
57
    ($iTotalRecords) = $dbh->selectrow_array( $iTotalQuery, undef, @conditions );
58
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);
66
    }
67
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              => [],
76
            };
77
        }
78
    }
79
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};
100
    }
101
    my @where_strs;
102
    if(defined $firstletter and $firstletter ne '') {
103
        push @where_strs, "borrowers.surname LIKE ?";
104
        push @where_args, "$firstletter%";
105
    }
106
    if(defined $categorycode and $categorycode ne '') {
107
        push @where_strs, "borrowers.categorycode = ?";
108
        push @where_args, $categorycode;
109
    }
110
    if(@restricted_branchcodes ) {
111
        push @where_strs, "borrowers.branchcode IN (" . join( ',', ('?') x @restricted_branchcodes ) . ")";
112
        push @where_args, @restricted_branchcodes;
113
    }
114
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',
121
    };
122
123
    # * is replaced with % for sql
124
    $searchmember =~ s/\*/%/g;
125
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);
134
    }
135
136
    foreach my $term (@terms) {
137
        next unless $term;
138
139
        my $term_dt = eval { local $SIG{__WARN__} = {}; output_pref( { str => $term, dateonly => 1, dateformat => 'sql' } ); };
140
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 !~ /^%/;
148
        }
149
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;
155
            }
156
        } else {
157
            push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfieldstype) . " LIKE ?";
158
            push @where_args, $term;
159
        }
160
161
162
        if ( $searchfieldstype eq 'standard' and C4::Context->preference('ExtendedPatronAttributes') and $searchmember ) {
163
             push @where_strs_or, " borrowers.borrowernumber IN ( SELECT DISTINCT borrowernumber FROM borrower_attributes JOIN borrower_attribute_types USING (code) WHERE staff_searchable = 1 AND attribute LIKE ? ) ";
164
             push @where_args, $term;
165
        }
166
167
        push @where_strs, '('. join (' OR ', @where_strs_or) . ')'
168
            if @where_strs_or;
169
    }
170
171
    if ( $has_permission ) {
172
        push @where_strs, '( borrowers.flags = 1 OR borrowers.flags & (1 << ?) OR module_bit=? AND code=? )';
173
        push @where_args, ($has_permission->{module_bit}) x 2, $has_permission->{subpermission};
174
    }
175
176
    my $where = @where_strs ? " WHERE " . join (" AND ", @where_strs) : undef;
177
    my $orderby = dt_build_orderby($dt_params);
178
179
    my $limit;
180
    # If iDisplayLength == -1, we want to display all patrons
181
    if ( !$dt_params->{iDisplayLength} || $dt_params->{iDisplayLength} > -1 ) {
182
        # In order to avoid sql injection
183
        $dt_params->{iDisplayStart} =~ s/\D//g if defined($dt_params->{iDisplayStart});
184
        $dt_params->{iDisplayLength} =~ s/\D//g if defined($dt_params->{iDisplayLength});
185
        $dt_params->{iDisplayStart} //= 0;
186
        $dt_params->{iDisplayLength} //= 20;
187
        $limit = "LIMIT $dt_params->{iDisplayStart},$dt_params->{iDisplayLength}";
188
    }
189
190
    $query = join(
191
        " ",
192
        ($select ? $select : ""),
193
        ($from ? $from : ""),
194
        ($where ? $where : ""),
195
        ($orderby ? $orderby : ""),
196
        ($limit ? $limit : "")
197
    );
198
    $sth = $dbh->prepare($query);
199
    $sth->execute(@where_args);
200
    my $patrons = $sth->fetchall_arrayref({});
201
202
    # Get the iTotalDisplayRecords DataTable variable
203
    $query = "SELECT COUNT(borrowers.borrowernumber) " . $from . ($where ? $where : "");
204
    $sth = $dbh->prepare($query);
205
    $sth->execute(@where_args);
206
    ($iTotalDisplayRecords) = $sth->fetchrow_array;
207
208
    # Get some information on patrons
209
    foreach my $patron (@$patrons) {
210
        my $patron_object = Koha::Patrons->find( $patron->{borrowernumber} );
211
        $patron->{overdues} = $patron_object->get_overdues->count;
212
        $patron->{issues} = $patron_object->checkouts->count;
213
        $patron->{age} = $patron_object->get_age;
214
        my $balance = $patron_object->account->balance;
215
        # FIXME Should be formatted from the template
216
        $patron->{fines} = sprintf("%.2f", $balance);
217
218
        if( $patron->{dateexpiry} ) {
219
            # FIXME We should not format the date here, do it in template-side instead
220
            $patron->{dateexpiry} = output_pref( { dt => scalar dt_from_string( $patron->{dateexpiry}, 'iso'), dateonly => 1} );
221
        } else {
222
            $patron->{dateexpiry} = '';
223
        }
224
    }
225
226
    return {
227
        iTotalRecords => $iTotalRecords,
228
        iTotalDisplayRecords => $iTotalDisplayRecords,
229
        patrons => $patrons
230
    }
231
}
232
233
1;
234
__END__
235
236
=head1 NAME
237
238
C4::Utils::DataTables::Members - module for using DataTables with patrons
239
240
=head1 SYNOPSIS
241
242
This module provides (one for the moment) routines used by the patrons search
243
244
=head2 FUNCTIONS
245
246
=head3 search
247
248
    my $dt_infos = C4::Utils::DataTables::Members->search($params);
249
250
$params is a hashref with some keys:
251
252
=over 4
253
254
=item searchmember
255
256
  String to search in the borrowers sql table
257
258
=item firstletter
259
260
  Introduced to contain 1 letter but can contain more.
261
  The search will done on the borrowers.surname field
262
263
=item categorycode
264
265
  Search patrons with this categorycode
266
267
=item branchcode
268
269
  Search patrons with this branchcode
270
271
=item searchtype
272
273
  Can be 'start_with' or 'contain' (default value). Used for the searchmember parameter.
274
275
=item searchfieldstype
276
277
  Can be 'standard' (default value), 'email', 'borrowernumber', 'phone', 'address' or 'dateofbirth', 'sort1', 'sort2'
278
279
=item dt_params
280
281
  Is the reference of C4::Utils::DataTables::dt_get_params($input);
282
283
=cut
284
285
=back
286
287
=head1 LICENSE
288
289
This file is part of Koha.
290
291
Copyright 2013 BibLibre
292
293
Koha is free software; you can redistribute it and/or modify it
294
under the terms of the GNU General Public License as published by
295
the Free Software Foundation; either version 3 of the License, or
296
(at your option) any later version.
297
298
Koha is distributed in the hope that it will be useful, but
299
WITHOUT ANY WARRANTY; without even the implied warranty of
300
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
301
GNU General Public License for more details.
302
303
You should have received a copy of the GNU General Public License
304
along with Koha; if not, see <http://www.gnu.org/licenses>.
(-)a/circ/circulation.pl (-1 lines)
Lines 34-40 use C4::Output qw( output_and_exit_if_error output_and_exit output_html_with_htt Link Here
34
use C4::Auth qw( get_session get_template_and_user );
34
use C4::Auth qw( get_session get_template_and_user );
35
use C4::Koha;
35
use C4::Koha;
36
use C4::Circulation qw( barcodedecode CanBookBeIssued AddIssue );
36
use C4::Circulation qw( barcodedecode CanBookBeIssued AddIssue );
37
use C4::Utils::DataTables::Members;
38
use C4::Members;
37
use C4::Members;
39
use C4::Biblio qw( TransformMarcToKoha );
38
use C4::Biblio qw( TransformMarcToKoha );
40
use C4::Search qw( new_record_from_zebra );
39
use C4::Search qw( new_record_from_zebra );
(-)a/t/db_dependent/Utils/Datatables_Members.t (-599 lines)
Lines 1-598 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More tests => 53;
21
22
use C4::Context;
23
use C4::Members;
24
25
use Koha::Library;
26
use Koha::Patrons;
27
use Koha::Patron::Categories;
28
29
use t::lib::Mocks;
30
use t::lib::TestBuilder;
31
32
use Koha::Database;
33
34
use_ok( "C4::Utils::DataTables::Members" );
35
36
my $schema = Koha::Database->new->schema;
37
$schema->storage->txn_begin;
38
39
my $builder = t::lib::TestBuilder->new;
40
41
my $library = $builder->build({
42
    source => "Branch",
43
});
44
45
my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { flags => 1 } });
46
t::lib::Mocks::mock_userenv({ patron => $patron });
47
48
my $branchcode=$library->{branchcode};
49
50
my $john_doe = $builder->build({
51
        source => "Borrower",
52
        value => {
53
            cardnumber   => '123456',
54
            firstname    => 'John',
55
            surname      => 'Doe',
56
            branchcode   => $branchcode,
57
            dateofbirth  => '1983-03-01',
58
            userid       => 'john.doe',
59
            initials     => 'pacman',
60
            flags        => 0,
61
        },
62
});
63
64
my $john_smith = $builder->build({
65
        source => "Borrower",
66
        value => {
67
            cardnumber   => '234567',
68
            firstname    => 'John',
69
            surname      => 'Smith',
70
            branchcode   => $branchcode,
71
            dateofbirth  => '1982-02-01',
72
            userid       => 'john.smith',
73
            flags        => 0,
74
        },
75
});
76
77
my $jane_doe = $builder->build({
78
        source => "Borrower",
79
        value => {
80
            cardnumber   => '345678',
81
            firstname    => 'Jane',
82
            surname      => 'Doe',
83
            branchcode   => $branchcode,
84
            dateofbirth  => '1983-03-01',
85
            userid       => 'jane.doe',
86
            flags        => 0,
87
        },
88
});
89
my $jeanpaul_dupont = $builder->build({
90
        source => "Borrower",
91
        value => {
92
            cardnumber   => '456789',
93
            firstname    => 'Jean Paul',
94
            surname      => 'Dupont',
95
            branchcode   => $branchcode,
96
            dateofbirth  => '1982-02-01',
97
            userid       => 'jeanpaul.dupont',
98
            flags        => 0,
99
        },
100
});
101
my $dupont_brown = $builder->build({
102
        source => "Borrower",
103
        value => {
104
            cardnumber   => '567890',
105
            firstname    => 'Dupont',
106
            surname      => 'Brown',
107
            branchcode   => $branchcode,
108
            dateofbirth  => '1979-01-01',
109
            userid       => 'dupont.brown',
110
            flags        => 0,
111
        },
112
});
113
114
# Set common datatables params
115
my %dt_params = (
116
    iDisplayLength   => 10,
117
    iDisplayStart    => 0
118
);
119
120
t::lib::Mocks::mock_preference('DefaultPatronSearchFields', '');
121
122
# Search "John Doe"
123
my $search_results = C4::Utils::DataTables::Members::search({
124
    searchmember     => "John Doe",
125
    searchfieldstype => 'standard',
126
    searchtype       => 'contain',
127
    branchcode       => $branchcode,
128
    dt_params        => \%dt_params
129
});
130
131
is( $search_results->{ iTotalDisplayRecords }, 1,
132
    "John Doe has only one match on $branchcode (Bug 12595)");
133
134
ok( $search_results->{ patrons }[0]->{ cardnumber } eq $john_doe->{ cardnumber }
135
    && ! $search_results->{ patrons }[1],
136
    "John Doe is the only match (Bug 12595)");
137
138
# Search "Jane Doe"
139
$search_results = C4::Utils::DataTables::Members::search({
140
    searchmember     => "Jane Doe",
141
    searchfieldstype => 'standard',
142
    searchtype       => 'contain',
143
    branchcode       => $branchcode,
144
    dt_params        => \%dt_params
145
});
146
147
is( $search_results->{ iTotalDisplayRecords }, 1,
148
    "Jane Doe has only one match on $branchcode (Bug 12595)");
149
150
is( $search_results->{ patrons }[0]->{ cardnumber },
151
    $jane_doe->{ cardnumber },
152
    "Jane Doe is the only match (Bug 12595)");
153
154
# Search "John"
155
$search_results = C4::Utils::DataTables::Members::search({
156
    searchmember     => "John",
157
    searchfieldstype => 'standard',
158
    searchtype       => 'contain',
159
    branchcode       => $branchcode,
160
    dt_params        => \%dt_params
161
});
162
163
is( $search_results->{ iTotalDisplayRecords }, 2,
164
    "There are two John at $branchcode");
165
166
is( $search_results->{ patrons }[0]->{ cardnumber },
167
    $john_doe->{ cardnumber },
168
    "John Doe is the first result");
169
170
is( $search_results->{ patrons }[1]->{ cardnumber },
171
    $john_smith->{ cardnumber },
172
    "John Smith is the second result");
173
174
# Search "Doe"
175
$search_results = C4::Utils::DataTables::Members::search({
176
    searchmember     => "Doe",
177
    searchfieldstype => 'standard',
178
    searchtype       => 'contain',
179
    branchcode       => $branchcode,
180
    dt_params        => \%dt_params
181
});
182
183
is( $search_results->{ iTotalDisplayRecords }, 2,
184
    "There are two Doe at $branchcode");
185
186
is( $search_results->{ patrons }[0]->{ cardnumber },
187
    $john_doe->{ cardnumber },
188
    "John Doe is the first result");
189
190
is( $search_results->{ patrons }[1]->{ cardnumber },
191
    $jane_doe->{ cardnumber },
192
    "Jane Doe is the second result");
193
194
# Search "Smith" as surname - there is only one occurrence of Smith
195
$search_results = C4::Utils::DataTables::Members::search({
196
    searchmember     => "Smith",
197
    searchfieldstype => 'surname',
198
    searchtype       => 'contain',
199
    branchcode       => $branchcode,
200
    dt_params        => \%dt_params
201
});
202
203
is( $search_results->{ iTotalDisplayRecords }, 1,
204
    "There is one Smith at $branchcode when searching for surname");
205
206
is( $search_results->{ patrons }[0]->{ cardnumber },
207
    $john_smith->{ cardnumber },
208
    "John Smith is the first result");
209
210
# Search "Dupont" as surname - Dupont is used both as firstname and surname, we
211
# Should only fin d the user with Dupont as surname
212
$search_results = C4::Utils::DataTables::Members::search({
213
    searchmember     => "Dupont",
214
    searchfieldstype => 'surname',
215
    searchtype       => 'contain',
216
    branchcode       => $branchcode,
217
    dt_params        => \%dt_params
218
});
219
220
is( $search_results->{ iTotalDisplayRecords }, 1,
221
    "There is one Dupont at $branchcode when searching for surname");
222
223
is( $search_results->{ patrons }[0]->{ cardnumber },
224
    $jeanpaul_dupont->{ cardnumber },
225
    "Jean Paul Dupont is the first result");
226
227
# Search "Doe" as surname - Doe is used twice as surname
228
$search_results = C4::Utils::DataTables::Members::search({
229
    searchmember     => "Doe",
230
    searchfieldstype => 'surname',
231
    searchtype       => 'contain',
232
    branchcode       => $branchcode,
233
    dt_params        => \%dt_params
234
});
235
236
is( $search_results->{ iTotalDisplayRecords }, 2,
237
    "There are two Doe at $branchcode when searching for surname");
238
239
is( $search_results->{ patrons }[0]->{ cardnumber },
240
    $john_doe->{ cardnumber },
241
    "John Doe is the first result");
242
243
is( $search_results->{ patrons }[1]->{ cardnumber },
244
    $jane_doe->{ cardnumber },
245
    "Jane Doe is the second result");
246
247
# Search by userid
248
$search_results = C4::Utils::DataTables::Members::search({
249
    searchmember     => "john.doe",
250
    searchfieldstype => 'standard',
251
    searchtype       => 'contain',
252
    branchcode       => $branchcode,
253
    dt_params        => \%dt_params
254
});
255
256
is( $search_results->{ iTotalDisplayRecords }, 1,
257
    "John Doe is found by userid, standard search (Bug 14782)");
258
259
$search_results = C4::Utils::DataTables::Members::search({
260
    searchmember     => "john.doe",
261
    searchfieldstype => 'userid',
262
    searchtype       => 'contain',
263
    branchcode       => $branchcode,
264
    dt_params        => \%dt_params
265
});
266
267
is( $search_results->{ iTotalDisplayRecords }, 1,
268
    "John Doe is found by userid, userid search (Bug 14782)");
269
270
$search_results = C4::Utils::DataTables::Members::search({
271
    searchmember     => "john.doe",
272
    searchfieldstype => 'surname',
273
    searchtype       => 'contain',
274
    branchcode       => $branchcode,
275
    dt_params        => \%dt_params
276
});
277
278
is( $search_results->{ iTotalDisplayRecords }, 0,
279
    "No members are found by userid, surname search");
280
281
my $attribute_type = Koha::Patron::Attribute::Type->new(
282
    {
283
        code             => 'ATM_1',
284
        description      => 'my attribute type',
285
        staff_searchable => 1
286
    }
287
)->store;
288
289
Koha::Patrons->find( $john_doe->{borrowernumber} )->extended_attributes(
290
    [
291
        {
292
            code      => $attribute_type->code,
293
            attribute => 'the default value for a common user'
294
        }
295
    ]
296
);
297
Koha::Patrons->find( $jane_doe->{borrowernumber} )->extended_attributes(
298
    [
299
        {
300
            code      => $attribute_type->code,
301
            attribute => 'the default value for another common user'
302
        }
303
    ]
304
);
305
Koha::Patrons->find( $john_smith->{borrowernumber} )->extended_attributes(
306
    [
307
        {
308
            code      => $attribute_type->code,
309
            attribute => 'Attribute which not appears even if contains "Dupont"'
310
        }
311
    ]
312
);
313
314
t::lib::Mocks::mock_preference('ExtendedPatronAttributes', 1);
315
$search_results = C4::Utils::DataTables::Members::search({
316
    searchmember     => "common user",
317
    searchfieldstype => 'standard',
318
    searchtype       => 'contain',
319
    branchcode       => $branchcode,
320
    dt_params        => \%dt_params
321
});
322
323
is( $search_results->{ iTotalDisplayRecords}, 2, "There are 2 common users" );
324
325
t::lib::Mocks::mock_preference('ExtendedPatronAttributes', 0);
326
$search_results = C4::Utils::DataTables::Members::search({
327
    searchmember     => "common user",
328
    searchfieldstype => 'standard',
329
    searchtype       => 'contain',
330
    branchcode       => $branchcode,
331
    dt_params        => \%dt_params
332
});
333
is( $search_results->{ iTotalDisplayRecords}, 0, "There are still 2 common users, but the patron attribute is not searchable " );
334
335
$search_results = C4::Utils::DataTables::Members::search({
336
    searchmember     => "Jean Paul",
337
    searchfieldstype => 'standard',
338
    searchtype       => 'start_with',
339
    branchcode       => $branchcode,
340
    dt_params        => \%dt_params
341
});
342
343
is( $search_results->{ iTotalDisplayRecords }, 1,
344
    "Jean Paul Dupont is found using start with and two terms search 'Jean Paul' (Bug 15252)");
345
346
$search_results = C4::Utils::DataTables::Members::search({
347
    searchmember     => "Jean Pau",
348
    searchfieldstype => 'standard',
349
    searchtype       => 'start_with',
350
    branchcode       => $branchcode,
351
    dt_params        => \%dt_params
352
});
353
354
is( $search_results->{ iTotalDisplayRecords }, 1,
355
    "Jean Paul Dupont is found using start with and two terms search 'Jean Pau' (Bug 15252)");
356
357
$search_results = C4::Utils::DataTables::Members::search({
358
    searchmember     => "Jea Pau",
359
    searchfieldstype => 'standard',
360
    searchtype       => 'start_with',
361
    branchcode       => $branchcode,
362
    dt_params        => \%dt_params
363
});
364
365
is( $search_results->{ iTotalDisplayRecords }, 0,
366
    "Jean Paul Dupont is not found using start with and two terms search 'Jea Pau' (Bug 15252)");
367
368
$search_results = C4::Utils::DataTables::Members::search({
369
    searchmember     => "Jea Pau",
370
    searchfieldstype => 'standard',
371
    searchtype       => 'contain',
372
    branchcode       => $branchcode,
373
    dt_params        => \%dt_params
374
});
375
376
is( $search_results->{ iTotalDisplayRecords }, 1,
377
    "Jean Paul Dupont is found using contains and two terms search 'Jea Pau' (Bug 15252)");
378
379
my @datetimeprefs = ("dmydot","iso","metric","us");
380
my %dates_in_pref = (
381
        dmydot  => ["01.02.1982","01.03.1983","01.01.1979","01.01.1988"],
382
        iso     => ["1982-02-01","1983-03-01","1979-01-01","1988-01-01"],
383
        metric  => ["01/02/1982","01/03/1983","01/01/1979","01/01/1988"],
384
        us      => ["02/01/1982","03/01/1983","01/01/1979","01/01/1988"],
385
        );
386
foreach my $dateformloo (@datetimeprefs){
387
    t::lib::Mocks::mock_preference('dateformat', $dateformloo);
388
    t::lib::Mocks::mock_preference('DefaultPatronSearchFields', 'surname,firstname,othernames,userid,dateofbirth');
389
    $search_results = C4::Utils::DataTables::Members::search({
390
        searchmember     => $dates_in_pref{$dateformloo}[0],
391
        searchfieldstype => 'standard',
392
        searchtype       => 'contain',
393
        branchcode       => $branchcode,
394
        dt_params        => \%dt_params
395
    });
396
397
    is( $search_results->{ iTotalDisplayRecords }, 2,
398
        "dateformat: $dateformloo Two borrowers have dob $dates_in_pref{$dateformloo}[0], standard search fields plus dob works");
399
400
    $search_results = C4::Utils::DataTables::Members::search({
401
        searchmember     => $dates_in_pref{$dateformloo}[2],
402
        searchfieldstype => 'standard',
403
        searchtype       => 'contain',
404
        branchcode       => $branchcode,
405
        dt_params        => \%dt_params
406
    });
407
408
    is( $search_results->{ iTotalDisplayRecords }, 1,
409
        "dateformat: $dateformloo One borrower has dob $dates_in_pref{$dateformloo}[2], standard search fields plus dob works");
410
411
    $search_results = C4::Utils::DataTables::Members::search({
412
        searchmember     => $dates_in_pref{$dateformloo}[1],
413
        searchfieldstype => 'dateofbirth',
414
        searchtype       => 'contain',
415
        branchcode       => $branchcode,
416
        dt_params        => \%dt_params
417
    });
418
419
    is( $search_results->{ iTotalDisplayRecords }, 2,
420
        "dateformat: $dateformloo Two borrowers have dob $dates_in_pref{$dateformloo}[1], dateofbirth search field works");
421
422
    $search_results = C4::Utils::DataTables::Members::search({
423
        searchmember     => $dates_in_pref{$dateformloo}[3],
424
        searchfieldstype => 'dateofbirth',
425
        searchtype       => 'contain',
426
        branchcode       => $branchcode,
427
        dt_params        => \%dt_params
428
    });
429
430
    is( $search_results->{ iTotalDisplayRecords }, 0,
431
        "dateformat: $dateformloo No borrowers have dob $dates_in_pref{$dateformloo}[3], dateofbirth search field works");
432
433
    $search_results = C4::Utils::DataTables::Members::search({
434
        searchmember     => $dates_in_pref{$dateformloo}[3],
435
        searchfieldstype => 'standard',
436
        searchtype       => 'contain',
437
        branchcode       => $branchcode,
438
        dt_params        => \%dt_params
439
    });
440
441
    is( $search_results->{ iTotalDisplayRecords }, 0,
442
        "dateformat: $dateformloo No borrowers have dob $dates_in_pref{$dateformloo}[3], standard search fields plus dob works");
443
}
444
445
# Date of birth formatting
446
t::lib::Mocks::mock_preference('dateformat', 'metric');
447
$search_results = C4::Utils::DataTables::Members::search({
448
    searchmember     => "01/02/1982",
449
    searchfieldstype => 'dateofbirth',
450
    dt_params        => \%dt_params
451
});
452
is( $search_results->{ iTotalDisplayRecords }, 2,
453
    "Sarching by date of birth should handle date formatted given the dateformat pref");
454
$search_results = C4::Utils::DataTables::Members::search({
455
    searchmember     => "1982-02-01",
456
    searchfieldstype => 'dateofbirth',
457
    dt_params        => \%dt_params
458
});
459
is( $search_results->{ iTotalDisplayRecords }, 2,
460
    "Sarching by date of birth should handle date formatted in iso");
461
462
subtest 'ExtendedPatronAttributes' => sub {
463
    plan tests => 2;
464
    t::lib::Mocks::mock_preference('ExtendedPatronAttributes', 1);
465
    $search_results = C4::Utils::DataTables::Members::search({
466
        searchmember     => "Dupont",
467
        searchfieldstype => 'standard',
468
        searchtype       => 'contain',
469
        branchcode       => $branchcode,
470
        dt_params        => \%dt_params
471
    });
472
473
    is( $search_results->{ iTotalDisplayRecords }, 3,
474
        "'Dupont' is contained in 2 surnames and a patron attribute. Patron attribute one should be displayed if searching in all fields (Bug 18094)");
475
476
    $search_results = C4::Utils::DataTables::Members::search({
477
        searchmember     => "Dupont",
478
        searchfieldstype => 'surname',
479
        searchtype       => 'contain',
480
        branchcode       => $branchcode,
481
        dt_params        => \%dt_params
482
    });
483
484
    is( $search_results->{ iTotalDisplayRecords }, 1,
485
        "'Dupont' is contained in 2 surnames and a patron attribute. Patron attribute one should not be displayed if searching in specific fields (Bug 18094)");
486
};
487
488
subtest 'Search by any borrowers field (bug 17374)' => sub {
489
    plan tests => 2;
490
491
    my $search_results = C4::Utils::DataTables::Members::search({
492
        searchmember     => "pacman",
493
        searchfieldstype => 'initials',
494
        searchtype       => 'contain',
495
        branchcode       => $branchcode,
496
        dt_params        => \%dt_params
497
    });
498
    is( $search_results->{ iTotalDisplayRecords }, 1, "We find only 1 patron when searching for initials 'pacman'" );
499
500
    is( $search_results->{ patrons }[0]->{ cardnumber }, $john_doe->{cardnumber}, "We find the correct patron when sesrching by initials" )
501
};
502
503
subtest 'Search with permissions' => sub {
504
    plan tests => 4;
505
506
    my $superlibrarian = $builder->build_object(
507
        {
508
            class => 'Koha::Patrons',
509
            value => { branchcode => $branchcode, flags => 1 }
510
        }
511
    );
512
    my $librarian_with_full_permission = $builder->build_object(
513
        {
514
            class => 'Koha::Patrons',
515
            value => { branchcode => $branchcode, flags => 4100 }
516
        }
517
    );    # 4100 = 4096 (2^12 suggestions) + 4 (2^2 catalogue)
518
    my $librarian_with_subpermission = $builder->build_object(
519
        { class => 'Koha::Patrons', value => { branchcode => $branchcode } } );
520
    C4::Context->dbh->do(
521
        q|INSERT INTO user_permissions(borrowernumber, module_bit, code) VALUES(?,?,?)|,
522
        undef,
523
        $librarian_with_subpermission->borrowernumber,
524
        12,
525
        'suggestions_manage'
526
    );
527
528
    my $search_results = C4::Utils::DataTables::Members::search(
529
        {
530
            searchmember     => "",
531
            searchfieldstype => 'standard',
532
            searchtype       => 'contain',
533
            branchcode       => $branchcode,
534
            has_permission   => {
535
                permission    => 'suggestions',
536
                subpermission => 'suggestions_manage'
537
            },
538
            dt_params => { iDisplayLength => 3, iDisplayStart => 0 },
539
        }
540
    );
541
    is( $search_results->{iTotalDisplayRecords},
542
        3, "We find 3 patrons with suggestions_manage permission" );
543
    is_deeply(
544
        [ sort map { $_->{borrowernumber} } @{ $search_results->{patrons} } ],
545
        [
546
            $superlibrarian->borrowernumber,
547
            $librarian_with_full_permission->borrowernumber,
548
            $librarian_with_subpermission->borrowernumber
549
        ],
550
        'We got the 3 patrons we expected'
551
    );
552
553
    C4::Context->dbh->do(
554
        q|INSERT INTO user_permissions(borrowernumber, module_bit, code) VALUES(?,?,?)|,
555
        undef,
556
        $librarian_with_subpermission->borrowernumber,
557
        13,
558
        'moderate_comments'
559
    );
560
    $search_results = C4::Utils::DataTables::Members::search(
561
        {
562
            searchmember     => "",
563
            searchfieldstype => 'standard',
564
            searchtype       => 'contain',
565
            branchcode       => $branchcode,
566
            has_permission   => {
567
                permission    => 'suggestions',
568
                subpermission => 'suggestions_manage'
569
            },
570
            dt_params => { iDisplayLength => 3, iDisplayStart => 0 },
571
        }
572
    );
573
    is( $search_results->{iTotalDisplayRecords},
574
        3, "We find 3 patrons with suggestions_manage permission" );
575
    is_deeply(
576
        [ sort map { $_->{borrowernumber} } @{ $search_results->{patrons} } ],
577
        [
578
            $superlibrarian->borrowernumber,
579
            $librarian_with_full_permission->borrowernumber,
580
            $librarian_with_subpermission->borrowernumber
581
        ],
582
        'We got the 3 patrons we expected'
583
    );
584
585
};
586
587
subtest 'return values' => sub {
588
    plan tests => 1;
589
    my $search_results = C4::Utils::DataTables::Members::search({
590
        searchmember     => "John Doe",
591
        searchfieldstype => 'standard',
592
        searchtype       => 'contain',
593
    });
594
    ok(exists $search_results->{patrons}->[0]->{othernames}, 'othernames should have been retrieved' );
595
};
596
597
# End
598
$schema->storage->txn_rollback;
599
- 

Return to bug 30063