3 # This file is part of Koha.
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.
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.
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>.
20 use Test::More tests => 52;
25 use C4::Members::Attributes;
26 use C4::Members::AttributeTypes;
29 use Koha::Patron::Categories;
32 use t::lib::TestBuilder;
36 use_ok( "C4::Utils::DataTables::Members" );
38 my $schema = Koha::Database->new->schema;
39 $schema->storage->txn_begin;
41 my $builder = t::lib::TestBuilder->new;
43 my $library = $builder->build({
47 my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { flags => 1 } });
48 t::lib::Mocks::mock_userenv({ patron => $patron });
50 my $branchcode=$library->{branchcode};
52 my $john_doe = $builder->build({
55 cardnumber => '123456',
58 branchcode => $branchcode,
59 dateofbirth => '1983-03-01',
65 my $john_smith = $builder->build({
68 cardnumber => '234567',
71 branchcode => $branchcode,
72 dateofbirth => '1982-02-01',
73 userid => 'john.smith',
78 my $jane_doe = $builder->build({
81 cardnumber => '345678',
84 branchcode => $branchcode,
85 dateofbirth => '1983-03-01',
90 my $jeanpaul_dupont = $builder->build({
93 cardnumber => '456789',
94 firstname => 'Jean Paul',
96 branchcode => $branchcode,
97 dateofbirth => '1982-02-01',
98 userid => 'jeanpaul.dupont',
102 my $dupont_brown = $builder->build({
103 source => "Borrower",
105 cardnumber => '567890',
106 firstname => 'Dupont',
108 branchcode => $branchcode,
109 dateofbirth => '1979-01-01',
110 userid => 'dupont.brown',
115 # Set common datatables params
117 iDisplayLength => 10,
122 my $search_results = C4::Utils::DataTables::Members::search({
123 searchmember => "John Doe",
124 searchfieldstype => 'standard',
125 searchtype => 'contain',
126 branchcode => $branchcode,
127 dt_params => \%dt_params
130 is( $search_results->{ iTotalDisplayRecords }, 1,
131 "John Doe has only one match on $branchcode (Bug 12595)");
133 ok( $search_results->{ patrons }[0]->{ cardnumber } eq $john_doe->{ cardnumber }
134 && ! $search_results->{ patrons }[1],
135 "John Doe is the only match (Bug 12595)");
138 $search_results = C4::Utils::DataTables::Members::search({
139 searchmember => "Jane Doe",
140 searchfieldstype => 'standard',
141 searchtype => 'contain',
142 branchcode => $branchcode,
143 dt_params => \%dt_params
146 is( $search_results->{ iTotalDisplayRecords }, 1,
147 "Jane Doe has only one match on $branchcode (Bug 12595)");
149 is( $search_results->{ patrons }[0]->{ cardnumber },
150 $jane_doe->{ cardnumber },
151 "Jane Doe is the only match (Bug 12595)");
154 $search_results = C4::Utils::DataTables::Members::search({
155 searchmember => "John",
156 searchfieldstype => 'standard',
157 searchtype => 'contain',
158 branchcode => $branchcode,
159 dt_params => \%dt_params
162 is( $search_results->{ iTotalDisplayRecords }, 2,
163 "There are two John at $branchcode");
165 is( $search_results->{ patrons }[0]->{ cardnumber },
166 $john_doe->{ cardnumber },
167 "John Doe is the first result");
169 is( $search_results->{ patrons }[1]->{ cardnumber },
170 $john_smith->{ cardnumber },
171 "John Smith is the second result");
174 $search_results = C4::Utils::DataTables::Members::search({
175 searchmember => "Doe",
176 searchfieldstype => 'standard',
177 searchtype => 'contain',
178 branchcode => $branchcode,
179 dt_params => \%dt_params
182 is( $search_results->{ iTotalDisplayRecords }, 2,
183 "There are two Doe at $branchcode");
185 is( $search_results->{ patrons }[0]->{ cardnumber },
186 $john_doe->{ cardnumber },
187 "John Doe is the first result");
189 is( $search_results->{ patrons }[1]->{ cardnumber },
190 $jane_doe->{ cardnumber },
191 "Jane Doe is the second result");
193 # Search "Smith" as surname - there is only one occurrence of Smith
194 $search_results = C4::Utils::DataTables::Members::search({
195 searchmember => "Smith",
196 searchfieldstype => 'surname',
197 searchtype => 'contain',
198 branchcode => $branchcode,
199 dt_params => \%dt_params
202 is( $search_results->{ iTotalDisplayRecords }, 1,
203 "There is one Smith at $branchcode when searching for surname");
205 is( $search_results->{ patrons }[0]->{ cardnumber },
206 $john_smith->{ cardnumber },
207 "John Smith is the first result");
209 # Search "Dupont" as surname - Dupont is used both as firstname and surname, we
210 # Should only fin d the user with Dupont as surname
211 $search_results = C4::Utils::DataTables::Members::search({
212 searchmember => "Dupont",
213 searchfieldstype => 'surname',
214 searchtype => 'contain',
215 branchcode => $branchcode,
216 dt_params => \%dt_params
219 is( $search_results->{ iTotalDisplayRecords }, 1,
220 "There is one Dupont at $branchcode when searching for surname");
222 is( $search_results->{ patrons }[0]->{ cardnumber },
223 $jeanpaul_dupont->{ cardnumber },
224 "Jean Paul Dupont is the first result");
226 # Search "Doe" as surname - Doe is used twice as surname
227 $search_results = C4::Utils::DataTables::Members::search({
228 searchmember => "Doe",
229 searchfieldstype => 'surname',
230 searchtype => 'contain',
231 branchcode => $branchcode,
232 dt_params => \%dt_params
235 is( $search_results->{ iTotalDisplayRecords }, 2,
236 "There are two Doe at $branchcode when searching for surname");
238 is( $search_results->{ patrons }[0]->{ cardnumber },
239 $john_doe->{ cardnumber },
240 "John Doe is the first result");
242 is( $search_results->{ patrons }[1]->{ cardnumber },
243 $jane_doe->{ cardnumber },
244 "Jane Doe is the second result");
247 $search_results = C4::Utils::DataTables::Members::search({
248 searchmember => "john.doe",
249 searchfieldstype => 'standard',
250 searchtype => 'contain',
251 branchcode => $branchcode,
252 dt_params => \%dt_params
255 is( $search_results->{ iTotalDisplayRecords }, 1,
256 "John Doe is found by userid, standard search (Bug 14782)");
258 $search_results = C4::Utils::DataTables::Members::search({
259 searchmember => "john.doe",
260 searchfieldstype => 'userid',
261 searchtype => 'contain',
262 branchcode => $branchcode,
263 dt_params => \%dt_params
266 is( $search_results->{ iTotalDisplayRecords }, 1,
267 "John Doe is found by userid, userid search (Bug 14782)");
269 $search_results = C4::Utils::DataTables::Members::search({
270 searchmember => "john.doe",
271 searchfieldstype => 'surname',
272 searchtype => 'contain',
273 branchcode => $branchcode,
274 dt_params => \%dt_params
277 is( $search_results->{ iTotalDisplayRecords }, 0,
278 "No members are found by userid, surname search");
280 my $attribute_type = C4::Members::AttributeTypes->new( 'ATM_1', 'my attribute type' );
281 $attribute_type->{staff_searchable} = 1;
282 $attribute_type->store;
285 C4::Members::Attributes::SetBorrowerAttributes(
286 $john_doe->{borrowernumber}, [ { code => $attribute_type->{code}, value => 'the default value for a common user' } ]
288 C4::Members::Attributes::SetBorrowerAttributes(
289 $jane_doe->{borrowernumber}, [ { code => $attribute_type->{code}, value => 'the default value for another common user' } ]
291 C4::Members::Attributes::SetBorrowerAttributes(
292 $john_smith->{borrowernumber}, [ { code => $attribute_type->{code}, value => 'Attribute which not appears even if contains "Dupont"' } ]
295 t::lib::Mocks::mock_preference('ExtendedPatronAttributes', 1);
296 $search_results = C4::Utils::DataTables::Members::search({
297 searchmember => "common user",
298 searchfieldstype => 'standard',
299 searchtype => 'contain',
300 branchcode => $branchcode,
301 dt_params => \%dt_params
304 is( $search_results->{ iTotalDisplayRecords}, 2, "There are 2 common users" );
306 t::lib::Mocks::mock_preference('ExtendedPatronAttributes', 0);
307 $search_results = C4::Utils::DataTables::Members::search({
308 searchmember => "common user",
309 searchfieldstype => 'standard',
310 searchtype => 'contain',
311 branchcode => $branchcode,
312 dt_params => \%dt_params
314 is( $search_results->{ iTotalDisplayRecords}, 0, "There are still 2 common users, but the patron attribute is not searchable " );
316 $search_results = C4::Utils::DataTables::Members::search({
317 searchmember => "Jean Paul",
318 searchfieldstype => 'standard',
319 searchtype => 'start_with',
320 branchcode => $branchcode,
321 dt_params => \%dt_params
324 is( $search_results->{ iTotalDisplayRecords }, 1,
325 "Jean Paul Dupont is found using start with and two terms search 'Jean Paul' (Bug 15252)");
327 $search_results = C4::Utils::DataTables::Members::search({
328 searchmember => "Jean Pau",
329 searchfieldstype => 'standard',
330 searchtype => 'start_with',
331 branchcode => $branchcode,
332 dt_params => \%dt_params
335 is( $search_results->{ iTotalDisplayRecords }, 1,
336 "Jean Paul Dupont is found using start with and two terms search 'Jean Pau' (Bug 15252)");
338 $search_results = C4::Utils::DataTables::Members::search({
339 searchmember => "Jea Pau",
340 searchfieldstype => 'standard',
341 searchtype => 'start_with',
342 branchcode => $branchcode,
343 dt_params => \%dt_params
346 is( $search_results->{ iTotalDisplayRecords }, 0,
347 "Jean Paul Dupont is not found using start with and two terms search 'Jea Pau' (Bug 15252)");
349 $search_results = C4::Utils::DataTables::Members::search({
350 searchmember => "Jea Pau",
351 searchfieldstype => 'standard',
352 searchtype => 'contain',
353 branchcode => $branchcode,
354 dt_params => \%dt_params
357 is( $search_results->{ iTotalDisplayRecords }, 1,
358 "Jean Paul Dupont is found using contains and two terms search 'Jea Pau' (Bug 15252)");
360 my @datetimeprefs = ("dmydot","iso","metric","us");
361 my %dates_in_pref = (
362 dmydot => ["01.02.1982","01.03.1983","01.01.1979","01.01.1988"],
363 iso => ["1982-02-01","1983-03-01","1979-01-01","1988-01-01"],
364 metric => ["01/02/1982","01/03/1983","01/01/1979","01/01/1988"],
365 us => ["02/01/1982","03/01/1983","01/01/1979","01/01/1988"],
367 foreach my $dateformloo (@datetimeprefs){
368 t::lib::Mocks::mock_preference('dateformat', $dateformloo);
369 t::lib::Mocks::mock_preference('DefaultPatronSearchFields', 'surname,firstname,othernames,userid,dateofbirth');
370 $search_results = C4::Utils::DataTables::Members::search({
371 searchmember => $dates_in_pref{$dateformloo}[0],
372 searchfieldstype => 'standard',
373 searchtype => 'contain',
374 branchcode => $branchcode,
375 dt_params => \%dt_params
378 is( $search_results->{ iTotalDisplayRecords }, 2,
379 "dateformat: $dateformloo Two borrowers have dob $dates_in_pref{$dateformloo}[0], standard search fields plus dob works");
381 $search_results = C4::Utils::DataTables::Members::search({
382 searchmember => $dates_in_pref{$dateformloo}[2],
383 searchfieldstype => 'standard',
384 searchtype => 'contain',
385 branchcode => $branchcode,
386 dt_params => \%dt_params
389 is( $search_results->{ iTotalDisplayRecords }, 1,
390 "dateformat: $dateformloo One borrower has dob $dates_in_pref{$dateformloo}[2], standard search fields plus dob works");
392 $search_results = C4::Utils::DataTables::Members::search({
393 searchmember => $dates_in_pref{$dateformloo}[1],
394 searchfieldstype => 'dateofbirth',
395 searchtype => 'contain',
396 branchcode => $branchcode,
397 dt_params => \%dt_params
400 is( $search_results->{ iTotalDisplayRecords }, 2,
401 "dateformat: $dateformloo Two borrowers have dob $dates_in_pref{$dateformloo}[1], dateofbirth search field works");
403 $search_results = C4::Utils::DataTables::Members::search({
404 searchmember => $dates_in_pref{$dateformloo}[3],
405 searchfieldstype => 'dateofbirth',
406 searchtype => 'contain',
407 branchcode => $branchcode,
408 dt_params => \%dt_params
411 is( $search_results->{ iTotalDisplayRecords }, 0,
412 "dateformat: $dateformloo No borrowers have dob $dates_in_pref{$dateformloo}[3], dateofbirth search field works");
414 $search_results = C4::Utils::DataTables::Members::search({
415 searchmember => $dates_in_pref{$dateformloo}[3],
416 searchfieldstype => 'standard',
417 searchtype => 'contain',
418 branchcode => $branchcode,
419 dt_params => \%dt_params
422 is( $search_results->{ iTotalDisplayRecords }, 0,
423 "dateformat: $dateformloo No borrowers have dob $dates_in_pref{$dateformloo}[3], standard search fields plus dob works");
426 # Date of birth formatting
427 t::lib::Mocks::mock_preference('dateformat', 'metric');
428 $search_results = C4::Utils::DataTables::Members::search({
429 searchmember => "01/02/1982",
430 searchfieldstype => 'dateofbirth',
431 dt_params => \%dt_params
433 is( $search_results->{ iTotalDisplayRecords }, 2,
434 "Sarching by date of birth should handle date formatted given the dateformat pref");
435 $search_results = C4::Utils::DataTables::Members::search({
436 searchmember => "1982-02-01",
437 searchfieldstype => 'dateofbirth',
438 dt_params => \%dt_params
440 is( $search_results->{ iTotalDisplayRecords }, 2,
441 "Sarching by date of birth should handle date formatted in iso");
443 subtest 'ExtendedPatronAttributes' => sub {
445 t::lib::Mocks::mock_preference('ExtendedPatronAttributes', 1);
446 $search_results = C4::Utils::DataTables::Members::search({
447 searchmember => "Dupont",
448 searchfieldstype => 'standard',
449 searchtype => 'contain',
450 branchcode => $branchcode,
451 dt_params => \%dt_params
454 is( $search_results->{ iTotalDisplayRecords }, 3,
455 "'Dupont' is contained in 2 surnames and a patron attribute. Patron attribute one should be displayed if searching in all fields (Bug 18094)");
457 $search_results = C4::Utils::DataTables::Members::search({
458 searchmember => "Dupont",
459 searchfieldstype => 'surname',
460 searchtype => 'contain',
461 branchcode => $branchcode,
462 dt_params => \%dt_params
465 is( $search_results->{ iTotalDisplayRecords }, 1,
466 "'Dupont' is contained in 2 surnames and a patron attribute. Patron attribute one should not be displayed if searching in specific fields (Bug 18094)");
469 subtest 'Search with permissions' => sub {
472 my $superlibrarian = $builder->build_object(
474 class => 'Koha::Patrons',
475 value => { branchcode => $branchcode, flags => 1 }
478 my $librarian_with_full_permission = $builder->build_object(
480 class => 'Koha::Patrons',
481 value => { branchcode => $branchcode, flags => 4100 }
483 ); # 4100 = 4096 (2^12 suggestions) + 4 (2^2 catalogue)
484 my $librarian_with_subpermission = $builder->build_object(
485 { class => 'Koha::Patrons', value => { branchcode => $branchcode } } );
486 C4::Context->dbh->do(
487 q|INSERT INTO user_permissions(borrowernumber, module_bit, code) VALUES(?,?,?)|,
489 $librarian_with_subpermission->borrowernumber,
494 my $search_results = C4::Utils::DataTables::Members::search(
497 searchfieldstype => 'standard',
498 searchtype => 'contain',
499 branchcode => $branchcode,
501 permission => 'suggestions',
502 subpermission => 'suggestions_manage'
504 dt_params => { iDisplayLength => 3, iDisplayStart => 0 },
507 is( $search_results->{iTotalDisplayRecords},
508 3, "We find 3 patrons with suggestions_manage permission" );
510 [ sort map { $_->{borrowernumber} } @{ $search_results->{patrons} } ],
512 $superlibrarian->borrowernumber,
513 $librarian_with_full_permission->borrowernumber,
514 $librarian_with_subpermission->borrowernumber
516 'We got the 3 patrons we expected'
520 subtest 'return values' => sub {
522 my $search_results = C4::Utils::DataTables::Members::search({
523 searchmember => "John Doe",
524 searchfieldstype => 'standard',
525 searchtype => 'contain',
527 ok(exists $search_results->{patrons}->[0]->{othernames}, 'othernames should have been retrieved' );
531 $schema->storage->txn_rollback;