3 # Copyright 2019 Koha Development team
5 # This file is part of Koha
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
22 use Test::More tests => 25;
26 use Koha::CirculationRules;
28 use Koha::DateUtils qw(dt_from_string);
29 use Koha::ArticleRequests;
31 use Koha::Patron::Relationships;
32 use C4::Circulation qw( AddIssue AddReturn );
34 use t::lib::TestBuilder;
37 my $schema = Koha::Database->new->schema;
38 my $builder = t::lib::TestBuilder->new;
40 subtest 'add_guarantor() tests' => sub {
44 $schema->storage->txn_begin;
46 t::lib::Mocks::mock_preference( 'borrowerRelationship', 'father1|father2' );
48 my $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
49 my $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
52 { $patron_1->add_guarantor({ guarantor_id => $patron_2->borrowernumber }); }
53 'Koha::Exceptions::Patron::Relationship::InvalidRelationship',
54 'Exception is thrown as no relationship passed';
56 is( $patron_1->guarantee_relationships->count, 0, 'No guarantors added' );
59 { $patron_1->add_guarantor({ guarantor_id => $patron_2->borrowernumber, relationship => 'father' }); }
60 'Koha::Exceptions::Patron::Relationship::InvalidRelationship',
61 'Exception is thrown as a wrong relationship was passed';
63 is( $patron_1->guarantee_relationships->count, 0, 'No guarantors added' );
65 $patron_1->add_guarantor({ guarantor_id => $patron_2->borrowernumber, relationship => 'father1' });
67 my $guarantors = $patron_1->guarantor_relationships;
69 is( $guarantors->count, 1, 'No guarantors added' );
73 open STDERR, '>', '/dev/null';
75 { $patron_1->add_guarantor({ guarantor_id => $patron_2->borrowernumber, relationship => 'father2' }); }
76 'Koha::Exceptions::Patron::Relationship::DuplicateRelationship',
77 'Exception is thrown for duplicated relationship';
81 $schema->storage->txn_rollback;
84 subtest 'relationships_debt() tests' => sub {
88 $schema->storage->txn_begin;
90 t::lib::Mocks::mock_preference( 'borrowerRelationship', 'parent' );
92 my $parent_1 = $builder->build_object({ class => 'Koha::Patrons', value => { firstname => "Parent 1" } });
93 my $parent_2 = $builder->build_object({ class => 'Koha::Patrons', value => { firstname => "Parent 2" } });
94 my $child_1 = $builder->build_object({ class => 'Koha::Patrons', value => { firstname => " Child 1" } });
95 my $child_2 = $builder->build_object({ class => 'Koha::Patrons', value => { firstname => " Child 2" } });
97 $child_1->add_guarantor({ guarantor_id => $parent_1->borrowernumber, relationship => 'parent' });
98 $child_1->add_guarantor({ guarantor_id => $parent_2->borrowernumber, relationship => 'parent' });
99 $child_2->add_guarantor({ guarantor_id => $parent_1->borrowernumber, relationship => 'parent' });
100 $child_2->add_guarantor({ guarantor_id => $parent_2->borrowernumber, relationship => 'parent' });
102 is( $child_1->guarantor_relationships->guarantors->count, 2, 'Child 1 has correct number of guarantors' );
103 is( $child_2->guarantor_relationships->guarantors->count, 2, 'Child 2 has correct number of guarantors' );
104 is( $parent_1->guarantee_relationships->guarantees->count, 2, 'Parent 1 has correct number of guarantees' );
105 is( $parent_2->guarantee_relationships->guarantees->count, 2, 'Parent 2 has correct number of guarantees' );
107 my $patrons = [ $parent_1, $parent_2, $child_1, $child_2 ];
109 # First test: No debt
110 my ($parent1_debt, $parent2_debt, $child1_debt, $child2_debt) = (0,0,0,0);
111 _test_combinations($patrons, $parent1_debt,$parent2_debt,$child1_debt,$child2_debt);
113 # Add debt to child_2
115 $child_2->account->add_debit({ type => 'ACCOUNT', amount => $child2_debt, interface => 'commandline' });
116 is( $child_2->account->non_issues_charges, $child2_debt, 'Debt added to Child 2' );
117 _test_combinations($patrons, $parent1_debt,$parent2_debt,$child1_debt,$child2_debt);
120 $parent_1->account->add_debit({ type => 'ACCOUNT', amount => $parent1_debt, interface => 'commandline' });
121 is( $parent_1->account->non_issues_charges, $parent1_debt, 'Debt added to Parent 1' );
122 _test_combinations($patrons, $parent1_debt,$parent2_debt,$child1_debt,$child2_debt);
125 $parent_2->account->add_debit({ type => 'ACCOUNT', amount => $parent2_debt, interface => 'commandline' });
126 is( $parent_2->account->non_issues_charges, $parent2_debt, 'Parent 2 owes correct amount' );
127 _test_combinations($patrons, $parent1_debt,$parent2_debt,$child1_debt,$child2_debt);
130 $child_1->account->add_debit({ type => 'ACCOUNT', amount => $child1_debt, interface => 'commandline' });
131 is( $child_1->account->non_issues_charges, $child1_debt, 'Child 1 owes correct amount' );
132 _test_combinations($patrons, $parent1_debt,$parent2_debt,$child1_debt,$child2_debt);
134 $schema->storage->txn_rollback;
137 sub _test_combinations {
138 my ( $patrons, $parent1_debt, $parent2_debt, $child1_debt, $child2_debt ) = @_;
139 note("Testing with parent 1 debt $parent1_debt | Parent 2 debt $parent2_debt | Child 1 debt $child1_debt | Child 2 debt $child2_debt");
141 # P1 => P1 + C1 + C2 ( - P1 ) ( + P2 )
142 # P2 => P2 + C1 + C2 ( - P2 ) ( + P1 )
143 # C1 => P1 + P2 + C1 + C2 ( - C1 )
144 # C2 => P1 + P2 + C1 + C2 ( - C2 )
146 # 3 params, count from 0 to 7 in binary ( 3 places ) to get the set of switches, then do that 4 times, one for each parent and child
147 for my $i ( 0 .. 7 ) {
148 my ( $only_this_guarantor, $include_guarantors, $include_this_patron )
149 = split '', sprintf( "%03b", $i );
150 note("---------------------");
151 for my $patron ( @$patrons ) {
152 if ( $only_this_guarantor
153 && !$patron->guarantee_relationships->count )
156 $patron->relationships_debt(
158 only_this_guarantor => $only_this_guarantor,
159 include_guarantors => $include_guarantors,
160 include_this_patron => $include_this_patron
164 'Koha::Exceptions::BadParameter',
165 'Exception is thrown as patron is not a guarantor';
171 if ( $patron->firstname eq 'Parent 1' ) {
172 $debt += $parent1_debt if ($include_this_patron && $include_guarantors);
173 $debt += $child1_debt + $child2_debt;
174 $debt += $parent2_debt unless ($only_this_guarantor || !$include_guarantors);
176 elsif ( $patron->firstname eq 'Parent 2' ) {
177 $debt += $parent2_debt if ($include_this_patron & $include_guarantors);
178 $debt += $child1_debt + $child2_debt;
179 $debt += $parent1_debt unless ($only_this_guarantor || !$include_guarantors);
181 elsif ( $patron->firstname eq ' Child 1' ) {
182 $debt += $child1_debt if ($include_this_patron);
183 $debt += $child2_debt;
184 $debt += $parent1_debt + $parent2_debt if ($include_guarantors);
187 $debt += $child2_debt if ($include_this_patron);
188 $debt += $child1_debt;
189 $debt += $parent1_debt + $parent2_debt if ($include_guarantors);
193 $patron->relationships_debt(
195 only_this_guarantor => $only_this_guarantor,
196 include_guarantors => $include_guarantors,
197 include_this_patron => $include_this_patron
202 . " debt of " . sprintf('%02d',$debt) . " calculated correctly for ( only_this_guarantor: $only_this_guarantor, include_guarantors: $include_guarantors, include_this_patron: $include_this_patron)"
209 subtest 'add_enrolment_fee_if_needed() tests' => sub {
213 subtest 'category has enrolment fee' => sub {
216 $schema->storage->txn_begin;
218 my $category = $builder->build_object(
220 class => 'Koha::Patron::Categories',
227 my $patron = $builder->build_object(
229 class => 'Koha::Patrons',
231 categorycode => $category->categorycode
236 my $enrollment_fee = $patron->add_enrolment_fee_if_needed();
237 is( $enrollment_fee * 1, 20, 'Enrolment fee amount is correct' );
238 my $account = $patron->account;
239 is( $patron->account->balance * 1, 20, 'Patron charged the enrolment fee' );
240 # second enrolment fee, new
241 $enrollment_fee = $patron->add_enrolment_fee_if_needed(0);
242 # third enrolment fee, renewal
243 $enrollment_fee = $patron->add_enrolment_fee_if_needed(1);
244 is( $patron->account->balance * 1, 60, 'Patron charged the enrolment fees' );
246 my @debits = $account->outstanding_debits->as_list;
247 is( scalar @debits, 3, '3 enrolment fees' );
248 is( $debits[0]->debit_type_code, 'ACCOUNT', 'Account type set correctly' );
249 is( $debits[1]->debit_type_code, 'ACCOUNT', 'Account type set correctly' );
250 is( $debits[2]->debit_type_code, 'ACCOUNT_RENEW', 'Account type set correctly' );
252 $schema->storage->txn_rollback;
255 subtest 'no enrolment fee' => sub {
259 $schema->storage->txn_begin;
261 my $category = $builder->build_object(
263 class => 'Koha::Patron::Categories',
270 my $patron = $builder->build_object(
272 class => 'Koha::Patrons',
274 categorycode => $category->categorycode
279 my $enrollment_fee = $patron->add_enrolment_fee_if_needed();
280 is( $enrollment_fee * 1, 0, 'No enrolment fee' );
281 my $account = $patron->account;
282 is( $patron->account->balance, 0, 'Patron not charged anything' );
284 my @debits = $account->outstanding_debits->as_list;
285 is( scalar @debits, 0, 'no debits' );
287 $schema->storage->txn_rollback;
291 subtest 'messaging_preferences() tests' => sub {
294 $schema->storage->txn_begin;
296 my $mtt = $builder->build_object({
297 class => 'Koha::Patron::MessagePreference::Transport::Types'
299 my $attribute = $builder->build_object({
300 class => 'Koha::Patron::MessagePreference::Attributes'
302 my $branchcode = $builder->build({
303 source => 'Branch' })->{branchcode};
304 my $letter = $builder->build_object({
305 class => 'Koha::Notice::Templates',
309 message_transport_type => $mtt->message_transport_type
313 Koha::Patron::MessagePreference::Transport->new({
314 message_attribute_id => $attribute->message_attribute_id,
315 message_transport_type => $mtt->message_transport_type,
317 letter_module => $letter->module,
318 letter_code => $letter->code,
321 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
323 my $preference = Koha::Patron::MessagePreference->new({
324 borrowernumber => $patron->borrowernumber,
325 message_attribute_id => $attribute->message_attribute_id,
327 days_in_advance => undef,
330 my $messaging_preferences = $patron->messaging_preferences();
331 is($messaging_preferences->count, 1, 'Found one preference');
333 my $messaging_preference = $messaging_preferences->next;
334 is($messaging_preference->borrowernumber, $patron->borrowernumber);
335 is($messaging_preference->message_attribute_id, $attribute->message_attribute_id);
336 is($messaging_preference->wants_digest, 0);
337 is($messaging_preference->days_in_advance, undef);
339 $schema->storage->txn_rollback;
342 subtest 'to_api() tests' => sub {
346 $schema->storage->txn_begin;
348 my $patron_class = Test::MockModule->new('Koha::Patron');
351 sub { return 'algo' }
354 my $patron = $builder->build_object(
356 class => 'Koha::Patrons',
363 my $restricted = $patron->to_api->{restricted};
364 ok( defined $restricted, 'restricted is defined' );
365 ok( !$restricted, 'debarred is undef, restricted evaluates to false' );
367 $patron->debarred( dt_from_string->add( days => 1 ) )->store->discard_changes;
368 $restricted = $patron->to_api->{restricted};
369 ok( defined $restricted, 'restricted is defined' );
370 ok( $restricted, 'debarred is defined, restricted evaluates to true' );
372 my $patron_json = $patron->to_api({ embed => { algo => {} } });
373 ok( exists $patron_json->{algo} );
374 is( $patron_json->{algo}, 'algo' );
376 $schema->storage->txn_rollback;
379 subtest 'login_attempts tests' => sub {
382 $schema->storage->txn_begin;
384 my $patron = $builder->build_object(
386 class => 'Koha::Patrons',
389 my $patron_info = $patron->unblessed;
391 delete $patron_info->{login_attempts};
392 my $new_patron = Koha::Patron->new($patron_info)->store;
393 is( $new_patron->discard_changes->login_attempts, 0, "login_attempts defaults to 0 as expected");
395 $schema->storage->txn_rollback;
398 subtest 'is_superlibrarian() tests' => sub {
402 $schema->storage->txn_begin;
404 my $patron = $builder->build_object(
406 class => 'Koha::Patrons',
414 is( $patron->is_superlibrarian, 0, 'Patron is not a superlibrarian and the method returns the correct value' );
416 $patron->flags(1)->store->discard_changes;
417 is( $patron->is_superlibrarian, 1, 'Patron is a superlibrarian and the method returns the correct value' );
419 $patron->flags(0)->store->discard_changes;
420 is( $patron->is_superlibrarian, 0, 'Patron is not a superlibrarian and the method returns the correct value' );
422 $schema->storage->txn_rollback;
425 subtest 'extended_attributes' => sub {
429 my $schema = Koha::Database->new->schema;
430 $schema->storage->txn_begin;
432 Koha::Patron::Attribute::Types->search->delete;
434 my $patron_1 = $builder->build_object({class=> 'Koha::Patrons'});
435 my $patron_2 = $builder->build_object({class=> 'Koha::Patrons'});
437 t::lib::Mocks::mock_userenv({ patron => $patron_1 });
439 my $attribute_type1 = Koha::Patron::Attribute::Type->new(
442 description => 'my description1',
446 my $attribute_type2 = Koha::Patron::Attribute::Type->new(
449 description => 'my description2',
451 staff_searchable => 1
455 my $new_library = $builder->build( { source => 'Branch' } );
456 my $attribute_type_limited = Koha::Patron::Attribute::Type->new(
457 { code => 'my code3', description => 'my description3' } )->store;
458 $attribute_type_limited->library_limits( [ $new_library->{branchcode} ] );
460 my $attributes_for_1 = [
462 attribute => 'my attribute1',
463 code => $attribute_type1->code(),
466 attribute => 'my attribute2',
467 code => $attribute_type2->code(),
470 attribute => 'my attribute limited',
471 code => $attribute_type_limited->code(),
475 my $attributes_for_2 = [
477 attribute => 'my attribute12',
478 code => $attribute_type1->code(),
481 attribute => 'my attribute limited 2',
482 code => $attribute_type_limited->code(),
486 my $extended_attributes = $patron_1->extended_attributes;
487 is( ref($extended_attributes), 'Koha::Patron::Attributes', 'Koha::Patron->extended_attributes must return a Koha::Patron::Attribute set' );
488 is( $extended_attributes->count, 0, 'There should not be attribute yet');
490 $patron_1->extended_attributes->filter_by_branch_limitations->delete;
491 $patron_2->extended_attributes->filter_by_branch_limitations->delete;
492 $patron_1->extended_attributes($attributes_for_1);
493 $patron_2->extended_attributes($attributes_for_2);
495 my $extended_attributes_for_1 = $patron_1->extended_attributes;
496 is( $extended_attributes_for_1->count, 3, 'There should be 3 attributes now for patron 1');
498 my $extended_attributes_for_2 = $patron_2->extended_attributes;
499 is( $extended_attributes_for_2->count, 2, 'There should be 2 attributes now for patron 2');
501 my $attribute_12 = $extended_attributes_for_2->search({ code => $attribute_type1->code })->next;
502 is( $attribute_12->attribute, 'my attribute12', 'search by code should return the correct attribute' );
504 $attribute_12 = $patron_2->get_extended_attribute( $attribute_type1->code );
505 is( $attribute_12->attribute, 'my attribute12', 'Koha::Patron->get_extended_attribute should return the correct attribute value' );
507 my $expected_attributes_for_2 = [
509 code => $attribute_type1->code(),
510 attribute => 'my attribute12',
513 code => $attribute_type_limited->code(),
514 attribute => 'my attribute limited 2',
517 # Sorting them by code
518 $expected_attributes_for_2 = [ sort { $a->{code} cmp $b->{code} } @$expected_attributes_for_2 ];
519 my @extended_attributes_for_2 = $extended_attributes_for_2->as_list;
524 code => $extended_attributes_for_2[0]->code,
525 attribute => $extended_attributes_for_2[0]->attribute
528 code => $extended_attributes_for_2[1]->code,
529 attribute => $extended_attributes_for_2[1]->attribute
532 $expected_attributes_for_2
535 # TODO - What about multiple? POD explains the problem
536 my $non_existent = $patron_2->get_extended_attribute( 'not_exist' );
537 is( $non_existent, undef, 'Koha::Patron->get_extended_attribute must return undef if the attribute does not exist' );
539 # Test branch limitations
540 t::lib::Mocks::mock_userenv({ patron => $patron_2 });
542 $extended_attributes_for_1 = $patron_1->extended_attributes;
543 is( $extended_attributes_for_1->count, 3, 'There should be 2 attributes for patron 1, the limited one should be returned');
546 $extended_attributes_for_1 = $patron_1->extended_attributes->filter_by_branch_limitations;
547 is( $extended_attributes_for_1->count, 2, 'There should be 2 attributes for patron 1, the limited one should be returned');
550 my $limited_value = $patron_1->get_extended_attribute( $attribute_type_limited->code );
551 is( $limited_value->attribute, 'my attribute limited', );
553 ## Do we need a filtered?
554 #$limited_value = $patron_1->get_extended_attribute( $attribute_type_limited->code );
555 #is( $limited_value, undef, );
557 $schema->storage->txn_rollback;
559 subtest 'non-repeatable attributes tests' => sub {
563 $schema->storage->txn_begin;
564 Koha::Patron::Attribute::Types->search->delete;
566 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
567 my $attribute_type = $builder->build_object(
569 class => 'Koha::Patron::Attribute::Types',
570 value => { repeatable => 0 }
574 is( $patron->extended_attributes->count, 0, 'Patron has no extended attributes' );
578 $patron->extended_attributes(
580 { code => $attribute_type->code, attribute => 'a' },
581 { code => $attribute_type->code, attribute => 'b' }
585 'Koha::Exceptions::Patron::Attribute::NonRepeatable',
586 'Exception thrown on non-repeatable attribute';
588 is( $patron->extended_attributes->count, 0, 'Extended attributes storing rolled back' );
590 $schema->storage->txn_rollback;
594 subtest 'unique attributes tests' => sub {
598 $schema->storage->txn_begin;
599 Koha::Patron::Attribute::Types->search->delete;
601 my $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
602 my $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
604 my $attribute_type_1 = $builder->build_object(
606 class => 'Koha::Patron::Attribute::Types',
607 value => { unique_id => 1 }
611 my $attribute_type_2 = $builder->build_object(
613 class => 'Koha::Patron::Attribute::Types',
614 value => { unique_id => 0 }
618 is( $patron_1->extended_attributes->count, 0, 'patron_1 has no extended attributes' );
619 is( $patron_2->extended_attributes->count, 0, 'patron_2 has no extended attributes' );
621 $patron_1->extended_attributes(
623 { code => $attribute_type_1->code, attribute => 'a' },
624 { code => $attribute_type_2->code, attribute => 'a' }
630 $patron_2->extended_attributes(
632 { code => $attribute_type_1->code, attribute => 'a' },
633 { code => $attribute_type_2->code, attribute => 'a' }
637 'Koha::Exceptions::Patron::Attribute::UniqueIDConstraint',
638 'Exception thrown on unique attribute';
640 is( $patron_1->extended_attributes->count, 2, 'Extended attributes stored' );
641 is( $patron_2->extended_attributes->count, 0, 'Extended attributes storing rolled back' );
643 $schema->storage->txn_rollback;
647 subtest 'invalid type attributes tests' => sub {
651 $schema->storage->txn_begin;
652 Koha::Patron::Attribute::Types->search->delete;
654 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
656 my $attribute_type_1 = $builder->build_object(
658 class => 'Koha::Patron::Attribute::Types',
659 value => { repeatable => 0 }
663 my $attribute_type_2 = $builder->build_object(
665 class => 'Koha::Patron::Attribute::Types'
669 my $type_2 = $attribute_type_2->code;
670 $attribute_type_2->delete;
672 is( $patron->extended_attributes->count, 0, 'Patron has no extended attributes' );
676 $patron->extended_attributes(
678 { code => $attribute_type_1->code, attribute => 'a' },
679 { code => $attribute_type_2->code, attribute => 'b' }
683 'Koha::Exceptions::Patron::Attribute::InvalidType',
684 'Exception thrown on invalid attribute type';
686 is( $patron->extended_attributes->count, 0, 'Extended attributes storing rolled back' );
688 $schema->storage->txn_rollback;
692 subtest 'globally mandatory attributes tests' => sub {
696 $schema->storage->txn_begin;
697 Koha::Patron::Attribute::Types->search->delete;
699 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
701 my $attribute_type_1 = $builder->build_object(
703 class => 'Koha::Patron::Attribute::Types',
704 value => { mandatory => 1, class => 'a', category_code => undef }
708 my $attribute_type_2 = $builder->build_object(
710 class => 'Koha::Patron::Attribute::Types',
711 value => { mandatory => 0, class => 'a', category_code => undef }
715 is( $patron->extended_attributes->count, 0, 'Patron has no extended attributes' );
719 $patron->extended_attributes(
721 { code => $attribute_type_2->code, attribute => 'b' }
725 'Koha::Exceptions::Patron::MissingMandatoryExtendedAttribute',
726 'Exception thrown on missing mandatory attribute type';
728 is( $@->type, $attribute_type_1->code, 'Exception parameters are correct' );
730 is( $patron->extended_attributes->count, 0, 'Extended attributes storing rolled back' );
732 $patron->extended_attributes(
734 { code => $attribute_type_1->code, attribute => 'b' }
738 is( $patron->extended_attributes->count, 1, 'Extended attributes succeeded' );
740 $schema->storage->txn_rollback;
744 subtest 'limited category mandatory attributes tests' => sub {
748 $schema->storage->txn_begin;
749 Koha::Patron::Attribute::Types->search->delete;
751 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
753 my $attribute_type_1 = $builder->build_object(
755 class => 'Koha::Patron::Attribute::Types',
756 value => { mandatory => 1, class => 'a', category_code => $patron->categorycode }
760 $patron->extended_attributes(
762 { code => $attribute_type_1->code, attribute => 'a' }
766 is( $patron->extended_attributes->count, 1, 'Extended attributes succeeded' );
768 $patron = $builder->build_object({ class => 'Koha::Patrons' });
769 # new patron, new category - they shouldn't be required to have any attributes
772 ok( $patron->extended_attributes([]), "We can set no attributes, mandatory attribute for other category not required");
781 subtest 'can_log_into() tests' => sub {
785 $schema->storage->txn_begin;
787 my $patron = $builder->build_object(
789 class => 'Koha::Patrons',
795 my $library = $builder->build_object({ class => 'Koha::Libraries' });
797 t::lib::Mocks::mock_preference('IndependentBranches', 1);
799 ok( $patron->can_log_into( $patron->library ), 'Patron can log into its own library' );
800 ok( !$patron->can_log_into( $library ), 'Patron cannot log into different library, IndependentBranches on' );
802 # make it a superlibrarian
803 $patron->set({ flags => 1 })->store->discard_changes;
804 ok( $patron->can_log_into( $library ), 'Superlibrarian can log into different library, IndependentBranches on' );
806 t::lib::Mocks::mock_preference('IndependentBranches', 0);
808 # No special permissions
809 $patron->set({ flags => undef })->store->discard_changes;
810 ok( $patron->can_log_into( $patron->library ), 'Patron can log into its own library' );
811 ok( $patron->can_log_into( $library ), 'Patron can log into any library' );
813 $schema->storage->txn_rollback;
816 subtest 'can_request_article() tests' => sub {
820 $schema->storage->txn_begin;
822 t::lib::Mocks::mock_preference( 'ArticleRequests', 1 );
824 my $item = $builder->build_sample_item;
826 my $library_1 = $builder->build_object( { class => 'Koha::Libraries' } );
827 my $library_2 = $builder->build_object( { class => 'Koha::Libraries' } );
828 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
830 t::lib::Mocks::mock_userenv( { branchcode => $library_2->id } );
832 Koha::CirculationRules->set_rule(
834 categorycode => undef,
835 branchcode => $library_1->id,
836 rule_name => 'open_article_requests_limit',
841 $builder->build_object(
843 class => 'Koha::ArticleRequests',
844 value => { status => 'REQUESTED', borrowernumber => $patron->id }
847 $builder->build_object(
849 class => 'Koha::ArticleRequests',
850 value => { status => 'PENDING', borrowernumber => $patron->id }
853 $builder->build_object(
855 class => 'Koha::ArticleRequests',
856 value => { status => 'PROCESSING', borrowernumber => $patron->id }
859 $builder->build_object(
861 class => 'Koha::ArticleRequests',
862 value => { status => 'CANCELED', borrowernumber => $patron->id }
867 $patron->can_request_article( $library_1->id ),
868 '3 current requests, 4 is the limit: allowed'
871 # Completed request, same day
872 my $completed = $builder->build_object(
874 class => 'Koha::ArticleRequests',
876 status => 'COMPLETED',
877 borrowernumber => $patron->id
882 ok( !$patron->can_request_article( $library_1->id ),
883 '3 current requests and a completed one the same day: denied' );
885 $completed->updated_on(
886 dt_from_string->add( days => -1 )->set(
893 ok( $patron->can_request_article( $library_1->id ),
894 '3 current requests and a completed one the day before: allowed' );
896 Koha::CirculationRules->set_rule(
898 categorycode => undef,
899 branchcode => $library_2->id,
900 rule_name => 'open_article_requests_limit',
905 ok( !$patron->can_request_article,
906 'Not passing the library_id param makes it fallback to userenv: denied'
909 $schema->storage->txn_rollback;
912 subtest 'article_requests() tests' => sub {
916 $schema->storage->txn_begin;
918 my $library = $builder->build_object({ class => 'Koha::Libraries' });
919 t::lib::Mocks::mock_userenv( { branchcode => $library->id } );
921 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
923 my $article_requests = $patron->article_requests;
924 is( ref($article_requests), 'Koha::ArticleRequests',
925 'In scalar context, type is correct' );
926 is( $article_requests->count, 0, 'No article requests' );
928 foreach my $i ( 0 .. 3 ) {
930 my $item = $builder->build_sample_item;
932 Koha::ArticleRequest->new(
934 borrowernumber => $patron->id,
935 biblionumber => $item->biblionumber,
936 itemnumber => $item->id,
942 $article_requests = $patron->article_requests;
943 is( $article_requests->count, 4, '4 article requests' );
945 $schema->storage->txn_rollback;
949 subtest 'can_patron_change_staff_only_lists() tests' => sub {
953 $schema->storage->txn_begin;
955 # make a user with no special permissions
956 my $patron = $builder->build_object(
958 class => 'Koha::Patrons',
964 is( $patron->can_patron_change_staff_only_lists(), 0, 'Patron without permissions cannot change staff only lists');
966 # make it a 'Catalogue' permission
967 $patron->set({ flags => 4 })->store->discard_changes;
968 is( $patron->can_patron_change_staff_only_lists(), 1, 'Catalogue patron can change staff only lists');
971 # make it a superlibrarian
972 $patron->set({ flags => 1 })->store->discard_changes;
973 is( $patron->can_patron_change_staff_only_lists(), 1, 'Superlibrarian patron can change staff only lists');
975 $schema->storage->txn_rollback;
978 subtest 'can_patron_change_permitted_staff_lists() tests' => sub {
982 $schema->storage->txn_begin;
984 # make a user with no special permissions
985 my $patron = $builder->build_object(
987 class => 'Koha::Patrons',
993 is( $patron->can_patron_change_permitted_staff_lists(), 0, 'Patron without permissions cannot change permitted staff lists');
995 # make it a 'Catalogue' permission
996 $patron->set({ flags => 4 })->store->discard_changes;
997 is( $patron->can_patron_change_permitted_staff_lists(), 0, 'Catalogue patron cannot change permitted staff lists');
999 # make it a 'Catalogue' permission and 'edit_public_list_contents' sub-permission
1000 $patron->set({ flags => 4 })->store->discard_changes;
1003 source => 'UserPermission',
1005 borrowernumber => $patron->borrowernumber,
1006 module_bit => 20, # lists
1007 code => 'edit_public_list_contents',
1011 is( $patron->can_patron_change_permitted_staff_lists(), 1, 'Catalogue and "edit_public_list_contents" patron can change permitted staff lists');
1013 # make it a superlibrarian
1014 $patron->set({ flags => 1 })->store->discard_changes;
1015 is( $patron->can_patron_change_permitted_staff_lists(), 1, 'Superlibrarian patron can change permitted staff lists');
1017 $schema->storage->txn_rollback;
1020 subtest 'password expiration tests' => sub {
1024 $schema->storage->txn_begin;
1025 my $date = dt_from_string();
1026 my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => {
1027 password_expiry_days => 10,
1028 require_strong_password => 0,
1031 my $patron = $builder->build_object({ class=> 'Koha::Patrons', value => {
1032 categorycode => $category->categorycode,
1037 $patron->delete()->store()->discard_changes(); # Make sure we are storing a 'new' patron
1039 is( $patron->password_expiration_date(), $date->add( days => 10 )->ymd() , "Password expiration date set correctly on patron creation");
1041 $patron = $builder->build_object({ class => 'Koha::Patrons', value => {
1042 categorycode => $category->categorycode,
1046 $patron->delete()->store()->discard_changes();
1048 is( $patron->password_expiration_date(), undef, "Password expiration date is not set if patron does not have a password");
1050 $category->password_expiry_days(undef)->store();
1051 $patron = $builder->build_object({ class => 'Koha::Patrons', value => {
1052 categorycode => $category->categorycode
1055 $patron->delete()->store()->discard_changes();
1056 is( $patron->password_expiration_date(), undef, "Password expiration date is not set if category does not have expiry days set");
1058 $schema->storage->txn_rollback;
1060 subtest 'password_expired' => sub {
1064 $schema->storage->txn_begin;
1065 my $date = dt_from_string();
1066 $patron = $builder->build_object({ class => 'Koha::Patrons', value => {
1067 password_expiration_date => undef
1070 is( $patron->password_expired, 0, "Patron with no password expiration date, password not expired");
1071 $patron->password_expiration_date( $date )->store;
1072 $patron->discard_changes();
1073 is( $patron->password_expired, 1, "Patron with password expiration date of today, password expired");
1074 $date->subtract( days => 1 );
1075 $patron->password_expiration_date( $date )->store;
1076 $patron->discard_changes();
1077 is( $patron->password_expired, 1, "Patron with password expiration date in past, password expired");
1079 $schema->storage->txn_rollback;
1082 subtest 'set_password' => sub {
1086 $schema->storage->txn_begin;
1088 my $date = dt_from_string();
1089 my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => {
1090 password_expiry_days => 10
1093 my $patron = $builder->build_object({ class => 'Koha::Patrons', value => {
1094 categorycode => $category->categorycode,
1095 password_expiration_date => $date->subtract( days => 1 )
1098 is( $patron->password_expired, 1, "Patron password is expired");
1100 $date = dt_from_string();
1101 $patron->set_password({ password => "kitten", skip_validation => 1 })->discard_changes();
1102 is( $patron->password_expired, 0, "Patron password no longer expired when new password set");
1103 is( $patron->password_expiration_date(), $date->add( days => 10 )->ymd(), "Password expiration date set correctly on patron creation");
1106 $category->password_expiry_days( undef )->store();
1107 $patron->set_password({ password => "puppies", skip_validation => 1 })->discard_changes();
1108 is( $patron->password_expiration_date(), undef, "Password expiration date is unset if category does not have expiry days");
1110 $schema->storage->txn_rollback;
1115 subtest 'safe_to_delete() tests' => sub {
1119 $schema->storage->txn_begin;
1121 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
1123 ## Make it the anonymous
1124 t::lib::Mocks::mock_preference( 'AnonymousPatron', $patron->id );
1126 ok( !$patron->safe_to_delete, 'Cannot delete, it is the anonymous patron' );
1127 my $message = $patron->safe_to_delete->messages->[0];
1128 is( $message->type, 'error', 'Type is error' );
1129 is( $message->message, 'is_anonymous_patron', 'Cannot delete, it is the anonymous patron' );
1131 t::lib::Mocks::mock_preference( 'AnonymousPatron', 0 );
1133 ## Make it have a checkout
1134 my $checkout = $builder->build_object(
1136 class => 'Koha::Checkouts',
1137 value => { borrowernumber => $patron->id }
1141 ok( !$patron->safe_to_delete, 'Cannot delete, has checkouts' );
1142 $message = $patron->safe_to_delete->messages->[0];
1143 is( $message->type, 'error', 'Type is error' );
1144 is( $message->message, 'has_checkouts', 'Cannot delete, has checkouts' );
1148 ## Make it have a guarantee
1149 t::lib::Mocks::mock_preference( 'borrowerRelationship', 'parent' );
1150 $builder->build_object({ class => 'Koha::Patrons' })
1151 ->add_guarantor({ guarantor_id => $patron->id, relationship => 'parent' });
1153 ok( !$patron->safe_to_delete, 'Cannot delete, has guarantees' );
1154 $message = $patron->safe_to_delete->messages->[0];
1155 is( $message->type, 'error', 'Type is error' );
1156 is( $message->message, 'has_guarantees', 'Cannot delete, has guarantees' );
1159 $patron->guarantee_relationships->delete;
1161 ## Make it have debt
1162 my $debit = $patron->account->add_debit({ amount => 10, interface => 'intranet', type => 'MANUAL' });
1164 ok( !$patron->safe_to_delete, 'Cannot delete, has debt' );
1165 $message = $patron->safe_to_delete->messages->[0];
1166 is( $message->type, 'error', 'Type is error' );
1167 is( $message->message, 'has_debt', 'Cannot delete, has debt' );
1169 $patron->account->pay({ amount => 10, debits => [ $debit ] });
1172 ok( $patron->safe_to_delete, 'Can delete, all conditions met' );
1173 my $messages = $patron->safe_to_delete->messages;
1174 is_deeply( $messages, [], 'Patron can be deleted, no messages' );
1177 subtest 'article_request_fee() tests' => sub {
1181 $schema->storage->txn_begin;
1183 # Cleanup, to avoid interference
1184 Koha::CirculationRules->search( { rule_name => 'article_request_fee' } )->delete;
1186 t::lib::Mocks::mock_preference( 'ArticleRequests', 1 );
1188 my $item = $builder->build_sample_item;
1190 my $library_1 = $builder->build_object( { class => 'Koha::Libraries' } );
1191 my $library_2 = $builder->build_object( { class => 'Koha::Libraries' } );
1192 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
1194 # Rule that should never be picked, because the patron's category is always picked
1195 Koha::CirculationRules->set_rule(
1196 { categorycode => undef,
1197 branchcode => undef,
1198 rule_name => 'article_request_fee',
1203 is( $patron->article_request_fee( { library_id => $library_2->id } ), 1, 'library_id used correctly' );
1205 Koha::CirculationRules->set_rule(
1206 { categorycode => $patron->categorycode,
1207 branchcode => undef,
1208 rule_name => 'article_request_fee',
1213 Koha::CirculationRules->set_rule(
1214 { categorycode => $patron->categorycode,
1215 branchcode => $library_1->id,
1216 rule_name => 'article_request_fee',
1221 is( $patron->article_request_fee( { library_id => $library_2->id } ), 2, 'library_id used correctly' );
1223 t::lib::Mocks::mock_userenv( { branchcode => $library_1->id } );
1225 is( $patron->article_request_fee(), 3, 'env used correctly' );
1227 $schema->storage->txn_rollback;
1230 subtest 'add_article_request_fee_if_needed() tests' => sub {
1234 $schema->storage->txn_begin;
1238 my $patron_mock = Test::MockModule->new('Koha::Patron');
1239 $patron_mock->mock( 'article_request_fee', sub { return $amount; } );
1241 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
1243 is( $patron->article_request_fee, $amount, 'article_request_fee mocked' );
1245 my $library_1 = $builder->build_object( { class => 'Koha::Libraries' } );
1246 my $library_2 = $builder->build_object( { class => 'Koha::Libraries' } );
1247 my $staff = $builder->build_object( { class => 'Koha::Patrons' } );
1248 my $item = $builder->build_sample_item;
1250 t::lib::Mocks::mock_userenv(
1251 { branchcode => $library_1->id, patron => $staff } );
1253 my $debit = $patron->add_article_request_fee_if_needed();
1254 is( $debit, undef, 'No fee, no debit line' );
1259 $debit = $patron->add_article_request_fee_if_needed({ item_id => $item->id });
1260 is( ref($debit), 'Koha::Account::Line', 'Debit object type correct' );
1261 is( $debit->amount, $amount,
1262 'amount set to $patron->article_request_fee value' );
1263 is( $debit->manager_id, $staff->id,
1264 'manager_id set to userenv session user' );
1265 is( $debit->branchcode, $library_1->id,
1266 'branchcode set to userenv session library' );
1267 is( $debit->debit_type_code, 'ARTICLE_REQUEST',
1268 'debit_type_code set correctly' );
1269 is( $debit->itemnumber, $item->id,
1270 'itemnumber set correctly' );
1274 $debit = $patron->add_article_request_fee_if_needed({ library_id => $library_2->id });
1275 is( ref($debit), 'Koha::Account::Line', 'Debit object type correct' );
1276 is( $debit->amount, $amount,
1277 'amount set to $patron->article_request_fee value' );
1278 is( $debit->branchcode, $library_2->id,
1279 'branchcode set to userenv session library' );
1280 is( $debit->itemnumber, undef,
1281 'itemnumber set correctly to undef' );
1283 $schema->storage->txn_rollback;
1286 subtest 'messages' => sub {
1289 $schema->storage->txn_begin;
1291 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
1292 my $messages = $patron->messages;
1293 is( $messages->count, 0, "No message yet" );
1294 my $message_1 = $builder->build_object(
1296 class => 'Koha::Patron::Messages',
1297 value => { borrowernumber => $patron->borrowernumber }
1300 my $message_2 = $builder->build_object(
1302 class => 'Koha::Patron::Messages',
1303 value => { borrowernumber => $patron->borrowernumber }
1307 $messages = $patron->messages;
1308 is( $messages->count, 2, "There are two messages for this patron" );
1309 is( $messages->next->message, $message_1->message );
1310 is( $messages->next->message, $message_2->message );
1311 $schema->storage->txn_rollback;
1314 subtest 'recalls() tests' => sub {
1318 $schema->storage->txn_begin;
1320 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
1321 my $biblio1 = $builder->build_object({ class => 'Koha::Biblios' });
1322 my $item1 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $biblio1->biblionumber } });
1323 my $biblio2 = $builder->build_object({ class => 'Koha::Biblios' });
1324 my $item2 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $biblio2->biblionumber } });
1327 { biblio_id => $biblio1->biblionumber,
1328 patron_id => $patron->borrowernumber,
1329 item_id => $item1->itemnumber,
1330 pickup_library_id => $patron->branchcode,
1331 created_date => \'NOW()',
1336 { biblio_id => $biblio2->biblionumber,
1337 patron_id => $patron->borrowernumber,
1338 item_id => $item2->itemnumber,
1339 pickup_library_id => $patron->branchcode,
1340 created_date => \'NOW()',
1345 { biblio_id => $biblio1->biblionumber,
1346 patron_id => $patron->borrowernumber,
1348 pickup_library_id => $patron->branchcode,
1349 created_date => \'NOW()',
1353 my $recall = Koha::Recall->new(
1354 { biblio_id => $biblio1->biblionumber,
1355 patron_id => $patron->borrowernumber,
1357 pickup_library_id => $patron->branchcode,
1358 created_date => \'NOW()',
1362 $recall->set_cancelled;
1364 is( $patron->recalls->count, 4, "Correctly gets this patron's recalls" );
1365 is( $patron->recalls->filter_by_current->count, 3, "Correctly gets this patron's active recalls" );
1366 is( $patron->recalls->filter_by_current->search( { biblio_id => $biblio1->biblionumber } )->count, 2, "Correctly gets this patron's active recalls on a specific biblio" );
1368 $schema->storage->txn_rollback;
1371 subtest 'encode_secret and decoded_secret' => sub {
1373 $schema->storage->txn_begin;
1375 t::lib::Mocks::mock_config('encryption_key', 't0P_secret');
1377 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
1378 is( $patron->decoded_secret, undef, 'TestBuilder does not initialize it' );
1379 $patron->secret(q{});
1380 is( $patron->decoded_secret, q{}, 'Empty string case' );
1382 $patron->encode_secret('encrypt_me'); # Note: lazy testing; should be base32 string normally.
1383 is( length($patron->secret) > 0, 1, 'Secret length' );
1384 isnt( $patron->secret, 'encrypt_me', 'Encrypted column' );
1385 is( $patron->decoded_secret, 'encrypt_me', 'Decrypted column' );
1387 $schema->storage->txn_rollback;
1390 subtest 'notify_library_of_registration()' => sub {
1394 $schema->storage->txn_begin;
1395 my $dbh = C4::Context->dbh;
1397 my $library = $builder->build_object(
1399 class => 'Koha::Libraries',
1401 branchemail => 'from@mybranch.com',
1402 branchreplyto => 'to@mybranch.com'
1406 my $patron = $builder->build_object(
1408 class => 'Koha::Patrons',
1410 branchcode => $library->branchcode
1415 t::lib::Mocks::mock_preference( 'KohaAdminEmailAddress', 'root@localhost' );
1416 t::lib::Mocks::mock_preference( 'EmailAddressForPatronRegistrations', 'library@localhost' );
1418 # Test when EmailPatronRegistrations equals BranchEmailAddress
1419 t::lib::Mocks::mock_preference( 'EmailPatronRegistrations', 'BranchEmailAddress' );
1420 is( $patron->notify_library_of_registration(C4::Context->preference('EmailPatronRegistrations')), 1, 'OPAC_REG email is queued if EmailPatronRegistration syspref equals BranchEmailAddress');
1421 my $sth = $dbh->prepare("SELECT to_address FROM message_queue where borrowernumber = ?");
1422 $sth->execute( $patron->borrowernumber );
1423 my $to_address = $sth->fetchrow_array;
1424 is( $to_address, 'to@mybranch.com', 'OPAC_REG email queued to go to branchreplyto address when EmailPatronRegistration equals BranchEmailAddress' );
1425 $dbh->do(q|DELETE FROM message_queue|);
1427 # Test when EmailPatronRegistrations equals EmailAddressForPatronRegistrations
1428 t::lib::Mocks::mock_preference( 'EmailPatronRegistrations', 'EmailAddressForPatronRegistrations' );
1429 is( $patron->notify_library_of_registration(C4::Context->preference('EmailPatronRegistrations')), 1, 'OPAC_REG email is queued if EmailPatronRegistration syspref equals EmailAddressForPatronRegistrations');
1430 $sth->execute( $patron->borrowernumber );
1431 $to_address = $sth->fetchrow_array;
1432 is( $to_address, 'library@localhost', 'OPAC_REG email queued to go to EmailAddressForPatronRegistrations syspref when EmailPatronRegistration equals EmailAddressForPatronRegistrations' );
1433 $dbh->do(q|DELETE FROM message_queue|);
1435 # Test when EmailPatronRegistrations equals KohaAdminEmailAddress
1436 t::lib::Mocks::mock_preference( 'EmailPatronRegistrations', 'KohaAdminEmailAddress' );
1437 t::lib::Mocks::mock_preference( 'ReplyToDefault', 'root@localhost' ); # FIXME Remove localhost
1438 is( $patron->notify_library_of_registration(C4::Context->preference('EmailPatronRegistrations')), 1, 'OPAC_REG email is queued if EmailPatronRegistration syspref equals KohaAdminEmailAddress');
1439 $sth->execute( $patron->borrowernumber );
1440 $to_address = $sth->fetchrow_array;
1441 is( $to_address, 'root@localhost', 'OPAC_REG email queued to go to KohaAdminEmailAddress syspref when EmailPatronRegistration equals KohaAdminEmailAddress' );
1442 $dbh->do(q|DELETE FROM message_queue|);
1444 $schema->storage->txn_rollback;
1447 subtest 'notice_email_address' => sub {
1450 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
1452 t::lib::Mocks::mock_preference( 'EmailFieldPrecedence', 'email|emailpro' );
1453 t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'OFF' );
1454 is ($patron->notice_email_address, $patron->email, "Koha::Patron->notice_email_address returns correct value when EmailFieldPrimary is off");
1456 t::lib::Mocks::mock_preference( 'EmailFieldPrimary', 'emailpro' );
1457 is ($patron->notice_email_address, $patron->emailpro, "Koha::Patron->notice_email_address returns correct value when EmailFieldPrimary is emailpro");
1462 subtest 'first_valid_email_address' => sub {
1465 my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { emailpro => ''}});
1467 t::lib::Mocks::mock_preference( 'EmailFieldPrecedence', 'emailpro|email' );
1468 is ($patron->first_valid_email_address, $patron->email, "Koha::Patron->first_valid_email_address returns correct value when EmailFieldPrecedence is 'emailpro|email' and emailpro is empty");
1473 subtest 'get_savings tests' => sub {
1477 $schema->storage->txn_begin;
1479 my $library = $builder->build_object({ class => 'Koha::Libraries' });
1480 my $patron = $builder->build_object({ class => 'Koha::Patrons' }, { value => { branchcode => $library->branchcode } });
1482 t::lib::Mocks::mock_userenv({ patron => $patron, branchcode => $library->branchcode });
1484 my $biblio = $builder->build_sample_biblio;
1485 my $item1 = $builder->build_sample_item(
1487 biblionumber => $biblio->biblionumber,
1488 library => $library->branchcode,
1489 replacementprice => rand(20),
1492 my $item2 = $builder->build_sample_item(
1494 biblionumber => $biblio->biblionumber,
1495 library => $library->branchcode,
1496 replacementprice => rand(20),
1500 is( $patron->get_savings, 0, 'No checkouts, no savings' );
1502 # Add an old checkout with deleted itemnumber
1503 $builder->build_object({ class => 'Koha::Old::Checkouts', value => { itemnumber => undef, borrowernumber => $patron->id } });
1505 is( $patron->get_savings, 0, 'No checkouts with itemnumber, no savings' );
1507 AddIssue( $patron->unblessed, $item1->barcode );
1508 AddIssue( $patron->unblessed, $item2->barcode );
1510 my $savings = $patron->get_savings;
1511 is( $savings + 0, $item1->replacementprice + $item2->replacementprice, "Savings correctly calculated from current issues" );
1513 AddReturn( $item2->barcode, $item2->homebranch );
1515 $savings = $patron->get_savings;
1516 is( $savings + 0, $item1->replacementprice + $item2->replacementprice, "Savings correctly calculated from current and old issues" );
1518 $schema->storage->txn_rollback;
1521 subtest 'update privacy tests' => sub {
1525 my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { privacy => 1 } });
1527 my $old_checkout = $builder->build_object({ class => 'Koha::Old::Checkouts', value => { borrowernumber => $patron->id } });
1529 t::lib::Mocks::mock_preference( 'AnonymousPatron', '0' );
1531 $patron->privacy(2); #set to never
1533 throws_ok{ $patron->store } 'Koha::Exceptions::Patron::FailedAnonymizing', 'We throw an exception when anonymizing fails';
1535 $old_checkout->discard_changes; #refresh from db
1536 $patron->discard_changes;
1538 is( $old_checkout->borrowernumber, $patron->id, "When anonymizing fails, we don't clear the checkouts");
1539 is( $patron->privacy(), 1, "When anonymizing fails, we don't chaneg the privacy");
1541 my $anon_patron = $builder->build_object({ class => 'Koha::Patrons'});
1542 t::lib::Mocks::mock_preference( 'AnonymousPatron', $anon_patron->id );
1544 $patron->privacy(2)->store(); #set to never
1546 $old_checkout->discard_changes; #refresh from db
1547 $patron->discard_changes;
1549 is( $old_checkout->borrowernumber, $anon_patron->id, "Checkout is successfully anonymized");
1550 is( $patron->privacy(), 2, "Patron privacy is successfully updated");