Bug 25416: Unit tests
[koha.git] / t / db_dependent / Utils / Datatables_Members.t
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 => 52;
21
22 use C4::Context;
23 use C4::Members;
24
25 use C4::Members::Attributes;
26 use C4::Members::AttributeTypes;
27
28 use Koha::Library;
29 use Koha::Patron::Categories;
30
31 use t::lib::Mocks;
32 use t::lib::TestBuilder;
33
34 use Koha::Database;
35
36 use_ok( "C4::Utils::DataTables::Members" );
37
38 my $schema = Koha::Database->new->schema;
39 $schema->storage->txn_begin;
40
41 my $builder = t::lib::TestBuilder->new;
42
43 my $library = $builder->build({
44     source => "Branch",
45 });
46
47 my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { flags => 1 } });
48 t::lib::Mocks::mock_userenv({ patron => $patron });
49
50 my $branchcode=$library->{branchcode};
51
52 my $john_doe = $builder->build({
53         source => "Borrower",
54         value => {
55             cardnumber   => '123456',
56             firstname    => 'John',
57             surname      => 'Doe',
58             branchcode   => $branchcode,
59             dateofbirth  => '1983-03-01',
60             userid       => 'john.doe',
61             flags        => 0,
62         },
63 });
64
65 my $john_smith = $builder->build({
66         source => "Borrower",
67         value => {
68             cardnumber   => '234567',
69             firstname    => 'John',
70             surname      => 'Smith',
71             branchcode   => $branchcode,
72             dateofbirth  => '1982-02-01',
73             userid       => 'john.smith',
74             flags        => 0,
75         },
76 });
77
78 my $jane_doe = $builder->build({
79         source => "Borrower",
80         value => {
81             cardnumber   => '345678',
82             firstname    => 'Jane',
83             surname      => 'Doe',
84             branchcode   => $branchcode,
85             dateofbirth  => '1983-03-01',
86             userid       => 'jane.doe',
87             flags        => 0,
88         },
89 });
90 my $jeanpaul_dupont = $builder->build({
91         source => "Borrower",
92         value => {
93             cardnumber   => '456789',
94             firstname    => 'Jean Paul',
95             surname      => 'Dupont',
96             branchcode   => $branchcode,
97             dateofbirth  => '1982-02-01',
98             userid       => 'jeanpaul.dupont',
99             flags        => 0,
100         },
101 });
102 my $dupont_brown = $builder->build({
103         source => "Borrower",
104         value => {
105             cardnumber   => '567890',
106             firstname    => 'Dupont',
107             surname      => 'Brown',
108             branchcode   => $branchcode,
109             dateofbirth  => '1979-01-01',
110             userid       => 'dupont.brown',
111             flags        => 0,
112         },
113 });
114
115 # Set common datatables params
116 my %dt_params = (
117     iDisplayLength   => 10,
118     iDisplayStart    => 0
119 );
120
121 # Search "John Doe"
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
128 });
129
130 is( $search_results->{ iTotalDisplayRecords }, 1,
131     "John Doe has only one match on $branchcode (Bug 12595)");
132
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)");
136
137 # Search "Jane Doe"
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
144 });
145
146 is( $search_results->{ iTotalDisplayRecords }, 1,
147     "Jane Doe has only one match on $branchcode (Bug 12595)");
148
149 is( $search_results->{ patrons }[0]->{ cardnumber },
150     $jane_doe->{ cardnumber },
151     "Jane Doe is the only match (Bug 12595)");
152
153 # Search "John"
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
160 });
161
162 is( $search_results->{ iTotalDisplayRecords }, 2,
163     "There are two John at $branchcode");
164
165 is( $search_results->{ patrons }[0]->{ cardnumber },
166     $john_doe->{ cardnumber },
167     "John Doe is the first result");
168
169 is( $search_results->{ patrons }[1]->{ cardnumber },
170     $john_smith->{ cardnumber },
171     "John Smith is the second result");
172
173 # Search "Doe"
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
180 });
181
182 is( $search_results->{ iTotalDisplayRecords }, 2,
183     "There are two Doe at $branchcode");
184
185 is( $search_results->{ patrons }[0]->{ cardnumber },
186     $john_doe->{ cardnumber },
187     "John Doe is the first result");
188
189 is( $search_results->{ patrons }[1]->{ cardnumber },
190     $jane_doe->{ cardnumber },
191     "Jane Doe is the second result");
192
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
200 });
201
202 is( $search_results->{ iTotalDisplayRecords }, 1,
203     "There is one Smith at $branchcode when searching for surname");
204
205 is( $search_results->{ patrons }[0]->{ cardnumber },
206     $john_smith->{ cardnumber },
207     "John Smith is the first result");
208
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
217 });
218
219 is( $search_results->{ iTotalDisplayRecords }, 1,
220     "There is one Dupont at $branchcode when searching for surname");
221
222 is( $search_results->{ patrons }[0]->{ cardnumber },
223     $jeanpaul_dupont->{ cardnumber },
224     "Jean Paul Dupont is the first result");
225
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
233 });
234
235 is( $search_results->{ iTotalDisplayRecords }, 2,
236     "There are two Doe at $branchcode when searching for surname");
237
238 is( $search_results->{ patrons }[0]->{ cardnumber },
239     $john_doe->{ cardnumber },
240     "John Doe is the first result");
241
242 is( $search_results->{ patrons }[1]->{ cardnumber },
243     $jane_doe->{ cardnumber },
244     "Jane Doe is the second result");
245
246 # Search by userid
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
253 });
254
255 is( $search_results->{ iTotalDisplayRecords }, 1,
256     "John Doe is found by userid, standard search (Bug 14782)");
257
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
264 });
265
266 is( $search_results->{ iTotalDisplayRecords }, 1,
267     "John Doe is found by userid, userid search (Bug 14782)");
268
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
275 });
276
277 is( $search_results->{ iTotalDisplayRecords }, 0,
278     "No members are found by userid, surname search");
279
280 my $attribute_type = C4::Members::AttributeTypes->new( 'ATM_1', 'my attribute type' );
281 $attribute_type->{staff_searchable} = 1;
282 $attribute_type->store;
283
284
285 C4::Members::Attributes::SetBorrowerAttributes(
286     $john_doe->{borrowernumber}, [ { code => $attribute_type->{code}, value => 'the default value for a common user' } ]
287 );
288 C4::Members::Attributes::SetBorrowerAttributes(
289     $jane_doe->{borrowernumber}, [ { code => $attribute_type->{code}, value => 'the default value for another common user' } ]
290 );
291 C4::Members::Attributes::SetBorrowerAttributes(
292     $john_smith->{borrowernumber}, [ { code => $attribute_type->{code}, value => 'Attribute which not appears even if contains "Dupont"' } ]
293 );
294
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
302 });
303
304 is( $search_results->{ iTotalDisplayRecords}, 2, "There are 2 common users" );
305
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
313 });
314 is( $search_results->{ iTotalDisplayRecords}, 0, "There are still 2 common users, but the patron attribute is not searchable " );
315
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
322 });
323
324 is( $search_results->{ iTotalDisplayRecords }, 1,
325     "Jean Paul Dupont is found using start with and two terms search 'Jean Paul' (Bug 15252)");
326
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
333 });
334
335 is( $search_results->{ iTotalDisplayRecords }, 1,
336     "Jean Paul Dupont is found using start with and two terms search 'Jean Pau' (Bug 15252)");
337
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
344 });
345
346 is( $search_results->{ iTotalDisplayRecords }, 0,
347     "Jean Paul Dupont is not found using start with and two terms search 'Jea Pau' (Bug 15252)");
348
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
355 });
356
357 is( $search_results->{ iTotalDisplayRecords }, 1,
358     "Jean Paul Dupont is found using contains and two terms search 'Jea Pau' (Bug 15252)");
359
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"],
366         );
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
376     });
377
378     is( $search_results->{ iTotalDisplayRecords }, 2,
379         "dateformat: $dateformloo Two borrowers have dob $dates_in_pref{$dateformloo}[0], standard search fields plus dob works");
380
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
387     });
388
389     is( $search_results->{ iTotalDisplayRecords }, 1,
390         "dateformat: $dateformloo One borrower has dob $dates_in_pref{$dateformloo}[2], standard search fields plus dob works");
391
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
398     });
399
400     is( $search_results->{ iTotalDisplayRecords }, 2,
401         "dateformat: $dateformloo Two borrowers have dob $dates_in_pref{$dateformloo}[1], dateofbirth search field works");
402
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
409     });
410
411     is( $search_results->{ iTotalDisplayRecords }, 0,
412         "dateformat: $dateformloo No borrowers have dob $dates_in_pref{$dateformloo}[3], dateofbirth search field works");
413
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
420     });
421
422     is( $search_results->{ iTotalDisplayRecords }, 0,
423         "dateformat: $dateformloo No borrowers have dob $dates_in_pref{$dateformloo}[3], standard search fields plus dob works");
424 }
425
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
432 });
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
439 });
440 is( $search_results->{ iTotalDisplayRecords }, 2,
441     "Sarching by date of birth should handle date formatted in iso");
442
443 subtest 'ExtendedPatronAttributes' => sub {
444     plan tests => 2;
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
452     });
453
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)");
456
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
463     });
464
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)");
467 };
468
469 subtest 'Search with permissions' => sub {
470     plan tests => 2;
471
472     my $superlibrarian = $builder->build_object(
473         {
474             class => 'Koha::Patrons',
475             value => { branchcode => $branchcode, flags => 1 }
476         }
477     );
478     my $librarian_with_full_permission = $builder->build_object(
479         {
480             class => 'Koha::Patrons',
481             value => { branchcode => $branchcode, flags => 4100 }
482         }
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(?,?,?)|,
488         undef,
489         $librarian_with_subpermission->borrowernumber,
490         12,
491         'suggestions_manage'
492     );
493
494     my $search_results = C4::Utils::DataTables::Members::search(
495         {
496             searchmember     => "",
497             searchfieldstype => 'standard',
498             searchtype       => 'contain',
499             branchcode       => $branchcode,
500             has_permission   => {
501                 permission    => 'suggestions',
502                 subpermission => 'suggestions_manage'
503             },
504             dt_params => { iDisplayLength => 3, iDisplayStart => 0 },
505         }
506     );
507     is( $search_results->{iTotalDisplayRecords},
508         3, "We find 3 patrons with suggestions_manage permission" );
509     is_deeply(
510         [ sort map { $_->{borrowernumber} } @{ $search_results->{patrons} } ],
511         [
512             $superlibrarian->borrowernumber,
513             $librarian_with_full_permission->borrowernumber,
514             $librarian_with_subpermission->borrowernumber
515         ],
516         'We got the 3 patrons we expected'
517     );
518 };
519
520 subtest 'return values' => sub {
521     plan tests => 1;
522     my $search_results = C4::Utils::DataTables::Members::search({
523         searchmember     => "John Doe",
524         searchfieldstype => 'standard',
525         searchtype       => 'contain',
526     });
527     ok(exists $search_results->{patrons}->[0]->{othernames}, 'othernames should have been retrieved' );
528 };
529
530 # End
531 $schema->storage->txn_rollback;