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 => 11;
27 use Koha::DateUtils qw(dt_from_string);
28 use Koha::ArticleRequests;
30 use Koha::Patron::Relationships;
32 use t::lib::TestBuilder;
35 my $schema = Koha::Database->new->schema;
36 my $builder = t::lib::TestBuilder->new;
38 subtest 'add_guarantor() tests' => sub {
42 $schema->storage->txn_begin;
44 t::lib::Mocks::mock_preference( 'borrowerRelationship', 'father1|father2' );
46 my $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
47 my $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
50 { $patron_1->add_guarantor({ guarantor_id => $patron_2->borrowernumber }); }
51 'Koha::Exceptions::Patron::Relationship::InvalidRelationship',
52 'Exception is thrown as no relationship passed';
54 is( $patron_1->guarantee_relationships->count, 0, 'No guarantors added' );
57 { $patron_1->add_guarantor({ guarantor_id => $patron_2->borrowernumber, relationship => 'father' }); }
58 'Koha::Exceptions::Patron::Relationship::InvalidRelationship',
59 'Exception is thrown as a wrong relationship was passed';
61 is( $patron_1->guarantee_relationships->count, 0, 'No guarantors added' );
63 $patron_1->add_guarantor({ guarantor_id => $patron_2->borrowernumber, relationship => 'father1' });
65 my $guarantors = $patron_1->guarantor_relationships;
67 is( $guarantors->count, 1, 'No guarantors added' );
71 open STDERR, '>', '/dev/null';
73 { $patron_1->add_guarantor({ guarantor_id => $patron_2->borrowernumber, relationship => 'father2' }); }
74 'Koha::Exceptions::Patron::Relationship::DuplicateRelationship',
75 'Exception is thrown for duplicated relationship';
79 $schema->storage->txn_rollback;
82 subtest 'relationships_debt() tests' => sub {
86 $schema->storage->txn_begin;
88 t::lib::Mocks::mock_preference( 'borrowerRelationship', 'parent' );
90 my $parent_1 = $builder->build_object({ class => 'Koha::Patrons', value => { firstname => "Parent 1" } });
91 my $parent_2 = $builder->build_object({ class => 'Koha::Patrons', value => { firstname => "Parent 2" } });
92 my $child_1 = $builder->build_object({ class => 'Koha::Patrons', value => { firstname => "Child 1" } });
93 my $child_2 = $builder->build_object({ class => 'Koha::Patrons', value => { firstname => "Child 2" } });
95 $child_1->add_guarantor({ guarantor_id => $parent_1->borrowernumber, relationship => 'parent' });
96 $child_1->add_guarantor({ guarantor_id => $parent_2->borrowernumber, relationship => 'parent' });
97 $child_2->add_guarantor({ guarantor_id => $parent_1->borrowernumber, relationship => 'parent' });
98 $child_2->add_guarantor({ guarantor_id => $parent_2->borrowernumber, relationship => 'parent' });
100 is( $child_1->guarantor_relationships->guarantors->count, 2, 'Child 1 has correct number of guarantors' );
101 is( $child_2->guarantor_relationships->guarantors->count, 2, 'Child 2 has correct number of guarantors' );
102 is( $parent_1->guarantee_relationships->guarantees->count, 2, 'Parent 1 has correct number of guarantees' );
103 is( $parent_2->guarantee_relationships->guarantees->count, 2, 'Parent 2 has correct number of guarantees' );
105 my $patrons = [ $parent_1, $parent_2, $child_1, $child_2 ];
107 # First test: No debt
108 my ($parent1_debt, $parent2_debt, $child1_debt, $child2_debt) = (0,0,0,0);
109 _test_combinations($patrons, $parent1_debt,$parent2_debt,$child1_debt,$child2_debt);
111 # Add debt to child_2
113 $child_2->account->add_debit({ type => 'ACCOUNT', amount => $child2_debt, interface => 'commandline' });
114 is( $child_2->account->non_issues_charges, $child2_debt, 'Debt added to Child 2' );
115 _test_combinations($patrons, $parent1_debt,$parent2_debt,$child1_debt,$child2_debt);
118 $parent_1->account->add_debit({ type => 'ACCOUNT', amount => $parent1_debt, interface => 'commandline' });
119 is( $parent_1->account->non_issues_charges, $parent1_debt, 'Debt added to Parent 1' );
120 _test_combinations($patrons, $parent1_debt,$parent2_debt,$child1_debt,$child2_debt);
123 $parent_2->account->add_debit({ type => 'ACCOUNT', amount => $parent2_debt, interface => 'commandline' });
124 is( $parent_2->account->non_issues_charges, $parent2_debt, 'Parent 2 owes correct amount' );
125 _test_combinations($patrons, $parent1_debt,$parent2_debt,$child1_debt,$child2_debt);
128 $child_1->account->add_debit({ type => 'ACCOUNT', amount => $child1_debt, interface => 'commandline' });
129 is( $child_1->account->non_issues_charges, $child1_debt, 'Child 1 owes correct amount' );
130 _test_combinations($patrons, $parent1_debt,$parent2_debt,$child1_debt,$child2_debt);
132 $schema->storage->txn_rollback;
135 sub _test_combinations {
136 my ( $patrons, $parent1_debt, $parent2_debt, $child1_debt, $child2_debt ) = @_;
139 # P1 => P1 + C1 + C2 ( - P1 ) ( + P2 )
140 # P2 => P2 + C1 + C2 ( - P2 ) ( + P1 )
141 # C1 => P1 + P2 + C1 + C2 ( - C1 )
142 # C2 => P1 + P2 + C1 + C2 ( - C2 )
144 # 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
145 for my $i ( 0 .. 7 ) {
146 my ( $only_this_guarantor, $include_guarantors, $include_this_patron )
147 = split '', sprintf( "%03b", $i );
148 for my $patron ( @$patrons ) {
149 if ( $only_this_guarantor
150 && !$patron->guarantee_relationships->count )
153 $patron->relationships_debt(
155 only_this_guarantor => $only_this_guarantor,
156 include_guarantors => $include_guarantors,
157 include_this_patron => $include_this_patron
161 'Koha::Exceptions::BadParameter',
162 'Exception is thrown as patron is not a guarantor';
168 if ( $patron->firstname eq 'Parent 1' ) {
169 $debt += $parent1_debt if ($include_this_patron && $include_guarantors);
170 $debt += $child1_debt + $child2_debt;
171 $debt += $parent2_debt unless ($only_this_guarantor || !$include_guarantors);
173 elsif ( $patron->firstname eq 'Parent 2' ) {
174 $debt += $parent2_debt if ($include_this_patron & $include_guarantors);
175 $debt += $child1_debt + $child2_debt;
176 $debt += $parent1_debt unless ($only_this_guarantor || !$include_guarantors);
178 elsif ( $patron->firstname eq 'Child 1' ) {
179 $debt += $child1_debt if ($include_this_patron);
180 $debt += $child2_debt;
181 $debt += $parent1_debt + $parent2_debt if ($include_guarantors);
184 $debt += $child2_debt if ($include_this_patron);
185 $debt += $child1_debt;
186 $debt += $parent1_debt + $parent2_debt if ($include_guarantors);
190 $patron->relationships_debt(
192 only_this_guarantor => $only_this_guarantor,
193 include_guarantors => $include_guarantors,
194 include_this_patron => $include_this_patron
199 . " debt of $debt calculated correctly for ( only_this_guarantor: $only_this_guarantor, include_guarantors: $include_guarantors, include_this_patron: $include_this_patron)"
206 subtest 'add_enrolment_fee_if_needed() tests' => sub {
210 subtest 'category has enrolment fee' => sub {
213 $schema->storage->txn_begin;
215 my $category = $builder->build_object(
217 class => 'Koha::Patron::Categories',
224 my $patron = $builder->build_object(
226 class => 'Koha::Patrons',
228 categorycode => $category->categorycode
233 my $enrollment_fee = $patron->add_enrolment_fee_if_needed();
234 is( $enrollment_fee * 1, 20, 'Enrolment fee amount is correct' );
235 my $account = $patron->account;
236 is( $patron->account->balance * 1, 20, 'Patron charged the enrolment fee' );
237 # second enrolment fee, new
238 $enrollment_fee = $patron->add_enrolment_fee_if_needed(0);
239 # third enrolment fee, renewal
240 $enrollment_fee = $patron->add_enrolment_fee_if_needed(1);
241 is( $patron->account->balance * 1, 60, 'Patron charged the enrolment fees' );
243 my @debits = $account->outstanding_debits;
244 is( scalar @debits, 3, '3 enrolment fees' );
245 is( $debits[0]->debit_type_code, 'ACCOUNT', 'Account type set correctly' );
246 is( $debits[1]->debit_type_code, 'ACCOUNT', 'Account type set correctly' );
247 is( $debits[2]->debit_type_code, 'ACCOUNT_RENEW', 'Account type set correctly' );
249 $schema->storage->txn_rollback;
252 subtest 'no enrolment fee' => sub {
256 $schema->storage->txn_begin;
258 my $category = $builder->build_object(
260 class => 'Koha::Patron::Categories',
267 my $patron = $builder->build_object(
269 class => 'Koha::Patrons',
271 categorycode => $category->categorycode
276 my $enrollment_fee = $patron->add_enrolment_fee_if_needed();
277 is( $enrollment_fee * 1, 0, 'No enrolment fee' );
278 my $account = $patron->account;
279 is( $patron->account->balance, 0, 'Patron not charged anything' );
281 my @debits = $account->outstanding_debits;
282 is( scalar @debits, 0, 'no debits' );
284 $schema->storage->txn_rollback;
288 subtest 'to_api() tests' => sub {
292 $schema->storage->txn_begin;
294 my $patron_class = Test::MockModule->new('Koha::Patron');
297 sub { return 'algo' }
300 my $patron = $builder->build_object(
302 class => 'Koha::Patrons',
309 my $restricted = $patron->to_api->{restricted};
310 ok( defined $restricted, 'restricted is defined' );
311 ok( !$restricted, 'debarred is undef, restricted evaluates to false' );
313 $patron->debarred( dt_from_string->add( days => 1 ) )->store->discard_changes;
314 $restricted = $patron->to_api->{restricted};
315 ok( defined $restricted, 'restricted is defined' );
316 ok( $restricted, 'debarred is defined, restricted evaluates to true' );
318 my $patron_json = $patron->to_api({ embed => { algo => {} } });
319 ok( exists $patron_json->{algo} );
320 is( $patron_json->{algo}, 'algo' );
322 $schema->storage->txn_rollback;
325 subtest 'login_attempts tests' => sub {
328 $schema->storage->txn_begin;
330 my $patron = $builder->build_object(
332 class => 'Koha::Patrons',
335 my $patron_info = $patron->unblessed;
337 delete $patron_info->{login_attempts};
338 my $new_patron = Koha::Patron->new($patron_info)->store;
339 is( $new_patron->discard_changes->login_attempts, 0, "login_attempts defaults to 0 as expected");
341 $schema->storage->txn_rollback;
344 subtest 'is_superlibrarian() tests' => sub {
348 $schema->storage->txn_begin;
350 my $patron = $builder->build_object(
352 class => 'Koha::Patrons',
360 is( $patron->is_superlibrarian, 0, 'Patron is not a superlibrarian and the method returns the correct value' );
362 $patron->flags(1)->store->discard_changes;
363 is( $patron->is_superlibrarian, 1, 'Patron is a superlibrarian and the method returns the correct value' );
365 $patron->flags(0)->store->discard_changes;
366 is( $patron->is_superlibrarian, 0, 'Patron is not a superlibrarian and the method returns the correct value' );
368 $schema->storage->txn_rollback;
371 subtest 'extended_attributes' => sub {
375 my $schema = Koha::Database->new->schema;
376 $schema->storage->txn_begin;
378 my $patron_1 = $builder->build_object({class=> 'Koha::Patrons'});
379 my $patron_2 = $builder->build_object({class=> 'Koha::Patrons'});
381 t::lib::Mocks::mock_userenv({ patron => $patron_1 });
383 my $attribute_type1 = Koha::Patron::Attribute::Type->new(
386 description => 'my description1',
390 my $attribute_type2 = Koha::Patron::Attribute::Type->new(
393 description => 'my description2',
395 staff_searchable => 1
399 my $new_library = $builder->build( { source => 'Branch' } );
400 my $attribute_type_limited = Koha::Patron::Attribute::Type->new(
401 { code => 'my code3', description => 'my description3' } )->store;
402 $attribute_type_limited->library_limits( [ $new_library->{branchcode} ] );
404 my $attributes_for_1 = [
406 attribute => 'my attribute1',
407 code => $attribute_type1->code(),
410 attribute => 'my attribute2',
411 code => $attribute_type2->code(),
414 attribute => 'my attribute limited',
415 code => $attribute_type_limited->code(),
419 my $attributes_for_2 = [
421 attribute => 'my attribute12',
422 code => $attribute_type1->code(),
425 attribute => 'my attribute limited 2',
426 code => $attribute_type_limited->code(),
430 my $extended_attributes = $patron_1->extended_attributes;
431 is( ref($extended_attributes), 'Koha::Patron::Attributes', 'Koha::Patron->extended_attributes must return a Koha::Patron::Attribute set' );
432 is( $extended_attributes->count, 0, 'There should not be attribute yet');
434 $patron_1->extended_attributes->filter_by_branch_limitations->delete;
435 $patron_2->extended_attributes->filter_by_branch_limitations->delete;
436 $patron_1->extended_attributes($attributes_for_1);
437 $patron_2->extended_attributes($attributes_for_2);
439 my $extended_attributes_for_1 = $patron_1->extended_attributes;
440 is( $extended_attributes_for_1->count, 3, 'There should be 3 attributes now for patron 1');
442 my $extended_attributes_for_2 = $patron_2->extended_attributes;
443 is( $extended_attributes_for_2->count, 2, 'There should be 2 attributes now for patron 2');
445 my $attribute_12 = $extended_attributes_for_2->search({ code => $attribute_type1->code })->next;
446 is( $attribute_12->attribute, 'my attribute12', 'search by code should return the correct attribute' );
448 $attribute_12 = $patron_2->get_extended_attribute( $attribute_type1->code );
449 is( $attribute_12->attribute, 'my attribute12', 'Koha::Patron->get_extended_attribute should return the correct attribute value' );
451 my $expected_attributes_for_2 = [
453 code => $attribute_type1->code(),
454 attribute => 'my attribute12',
457 code => $attribute_type_limited->code(),
458 attribute => 'my attribute limited 2',
461 # Sorting them by code
462 $expected_attributes_for_2 = [ sort { $a->{code} cmp $b->{code} } @$expected_attributes_for_2 ];
463 my @extended_attributes_for_2 = $extended_attributes_for_2->as_list;
468 code => $extended_attributes_for_2[0]->code,
469 attribute => $extended_attributes_for_2[0]->attribute
472 code => $extended_attributes_for_2[1]->code,
473 attribute => $extended_attributes_for_2[1]->attribute
476 $expected_attributes_for_2
479 # TODO - What about multiple? POD explains the problem
480 my $non_existent = $patron_2->get_extended_attribute( 'not_exist' );
481 is( $non_existent, undef, 'Koha::Patron->get_extended_attribute must return undef if the attribute does not exist' );
483 # Test branch limitations
484 t::lib::Mocks::mock_userenv({ patron => $patron_2 });
486 $extended_attributes_for_1 = $patron_1->extended_attributes;
487 is( $extended_attributes_for_1->count, 3, 'There should be 2 attributes for patron 1, the limited one should be returned');
490 $extended_attributes_for_1 = $patron_1->extended_attributes->filter_by_branch_limitations;
491 is( $extended_attributes_for_1->count, 2, 'There should be 2 attributes for patron 1, the limited one should be returned');
494 my $limited_value = $patron_1->get_extended_attribute( $attribute_type_limited->code );
495 is( $limited_value->attribute, 'my attribute limited', );
497 ## Do we need a filtered?
498 #$limited_value = $patron_1->get_extended_attribute( $attribute_type_limited->code );
499 #is( $limited_value, undef, );
501 $schema->storage->txn_rollback;
503 subtest 'non-repeatable attributes tests' => sub {
507 $schema->storage->txn_begin;
509 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
510 my $attribute_type = $builder->build_object(
512 class => 'Koha::Patron::Attribute::Types',
513 value => { repeatable => 0 }
517 is( $patron->extended_attributes->count, 0, 'Patron has no extended attributes' );
521 $patron->extended_attributes(
523 { code => $attribute_type->code, attribute => 'a' },
524 { code => $attribute_type->code, attribute => 'b' }
528 'Koha::Exceptions::Patron::Attribute::NonRepeatable',
529 'Exception thrown on non-repeatable attribute';
531 is( $patron->extended_attributes->count, 0, 'Extended attributes storing rolled back' );
533 $schema->storage->txn_rollback;
537 subtest 'unique attributes tests' => sub {
541 $schema->storage->txn_begin;
543 my $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
544 my $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
546 my $attribute_type_1 = $builder->build_object(
548 class => 'Koha::Patron::Attribute::Types',
549 value => { unique => 1 }
553 my $attribute_type_2 = $builder->build_object(
555 class => 'Koha::Patron::Attribute::Types',
556 value => { unique => 0 }
560 is( $patron_1->extended_attributes->count, 0, 'patron_1 has no extended attributes' );
561 is( $patron_2->extended_attributes->count, 0, 'patron_2 has no extended attributes' );
563 $patron_1->extended_attributes(
565 { code => $attribute_type_1->code, attribute => 'a' },
566 { code => $attribute_type_2->code, attribute => 'a' }
572 $patron_2->extended_attributes(
574 { code => $attribute_type_1->code, attribute => 'a' },
575 { code => $attribute_type_2->code, attribute => 'a' }
579 'Koha::Exceptions::Patron::Attribute::UniqueIDConstraint',
580 'Exception thrown on unique attribute';
582 is( $patron_1->extended_attributes->count, 2, 'Extended attributes stored' );
583 is( $patron_2->extended_attributes->count, 0, 'Extended attributes storing rolled back' );
585 $schema->storage->txn_rollback;
589 subtest 'invalid type attributes tests' => sub {
593 $schema->storage->txn_begin;
595 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
597 my $attribute_type_1 = $builder->build_object(
599 class => 'Koha::Patron::Attribute::Types',
600 value => { repeatable => 0 }
604 my $attribute_type_2 = $builder->build_object(
606 class => 'Koha::Patron::Attribute::Types'
610 my $type_2 = $attribute_type_2->code;
611 $attribute_type_2->delete;
613 is( $patron->extended_attributes->count, 0, 'Patron has no extended attributes' );
617 $patron->extended_attributes(
619 { code => $attribute_type_1->code, attribute => 'a' },
620 { code => $attribute_type_2->code, attribute => 'b' }
624 'Koha::Exceptions::Patron::Attribute::InvalidType',
625 'Exception thrown on invalid attribute type';
627 is( $patron->extended_attributes->count, 0, 'Extended attributes storing rolled back' );
629 $schema->storage->txn_rollback;
633 subtest 'globally mandatory attributes tests' => sub {
637 $schema->storage->txn_begin;
639 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
641 my $attribute_type_1 = $builder->build_object(
643 class => 'Koha::Patron::Attribute::Types',
644 value => { mandatory => 1, class => 'a' }
648 my $attribute_type_2 = $builder->build_object(
650 class => 'Koha::Patron::Attribute::Types',
651 value => { mandatory => 0, class => 'a' }
655 is( $patron->extended_attributes->count, 0, 'Patron has no extended attributes' );
659 $patron->extended_attributes(
661 { code => $attribute_type_2->code, attribute => 'b' }
665 'Koha::Exceptions::Patron::MissingMandatoryExtendedAttribute',
666 'Exception thrown on missing mandatory attribute type';
668 is( $@->type, $attribute_type_1->code, 'Exception parameters are correct' );
670 is( $patron->extended_attributes->count, 0, 'Extended attributes storing rolled back' );
672 $patron->extended_attributes(
674 { code => $attribute_type_1->code, attribute => 'b' }
678 is( $patron->extended_attributes->count, 1, 'Extended attributes succeeded' );
680 $schema->storage->txn_rollback;
686 subtest 'can_log_into() tests' => sub {
690 $schema->storage->txn_begin;
692 my $patron = $builder->build_object(
694 class => 'Koha::Patrons',
700 my $library = $builder->build_object({ class => 'Koha::Libraries' });
702 t::lib::Mocks::mock_preference('IndependentBranches', 1);
704 ok( $patron->can_log_into( $patron->library ), 'Patron can log into its own library' );
705 ok( !$patron->can_log_into( $library ), 'Patron cannot log into different library, IndependentBranches on' );
707 # make it a superlibrarian
708 $patron->set({ flags => 1 })->store->discard_changes;
709 ok( $patron->can_log_into( $library ), 'Superlibrarian can log into different library, IndependentBranches on' );
711 t::lib::Mocks::mock_preference('IndependentBranches', 0);
713 # No special permissions
714 $patron->set({ flags => undef })->store->discard_changes;
715 ok( $patron->can_log_into( $patron->library ), 'Patron can log into its own library' );
716 ok( $patron->can_log_into( $library ), 'Patron can log into any library' );
718 $schema->storage->txn_rollback;
721 subtest 'can_request_article() tests' => sub {
725 $schema->storage->txn_begin;
727 t::lib::Mocks::mock_preference( 'ArticleRequests', 1 );
729 my $item = $builder->build_sample_item;
731 my $library_1 = $builder->build_object( { class => 'Koha::Libraries' } );
732 my $library_2 = $builder->build_object( { class => 'Koha::Libraries' } );
733 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
735 t::lib::Mocks::mock_userenv( { branchcode => $library_2->id } );
737 Koha::CirculationRules->set_rule(
739 categorycode => undef,
740 branchcode => $library_1->id,
741 rule_name => 'open_article_requests_limit',
746 $builder->build_object(
748 class => 'Koha::ArticleRequests',
749 value => { status => 'REQUESTED', borrowernumber => $patron->id }
752 $builder->build_object(
754 class => 'Koha::ArticleRequests',
755 value => { status => 'PENDING', borrowernumber => $patron->id }
758 $builder->build_object(
760 class => 'Koha::ArticleRequests',
761 value => { status => 'PROCESSING', borrowernumber => $patron->id }
764 $builder->build_object(
766 class => 'Koha::ArticleRequests',
767 value => { status => 'CANCELED', borrowernumber => $patron->id }
772 $patron->can_request_article( $library_1->id ),
773 '3 current requests, 4 is the limit: allowed'
776 # Completed request, same day
777 my $completed = $builder->build_object(
779 class => 'Koha::ArticleRequests',
781 status => 'COMPLETED',
782 borrowernumber => $patron->id
787 ok( !$patron->can_request_article( $library_1->id ),
788 '3 current requests and a completed one the same day: denied' );
790 $completed->updated_on(
791 dt_from_string->add( days => -1 )->set(
798 ok( $patron->can_request_article( $library_1->id ),
799 '3 current requests and a completed one the day before: allowed' );
801 Koha::CirculationRules->set_rule(
803 categorycode => undef,
804 branchcode => $library_2->id,
805 rule_name => 'open_article_requests_limit',
810 ok( !$patron->can_request_article,
811 'Not passing the library_id param makes it fallback to userenv: denied'
814 $schema->storage->txn_rollback;
817 subtest 'article_requests() tests' => sub {
821 $schema->storage->txn_begin;
823 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
825 my $article_requests = $patron->article_requests;
826 is( ref($article_requests), 'Koha::ArticleRequests',
827 'In scalar context, type is correct' );
828 is( $article_requests->count, 0, 'No article requests' );
830 foreach my $i ( 0 .. 3 ) {
832 my $item = $builder->build_sample_item;
834 Koha::ArticleRequest->new(
836 borrowernumber => $patron->id,
837 biblionumber => $item->biblionumber,
838 itemnumber => $item->id,
844 $article_requests = $patron->article_requests;
845 is( $article_requests->count, 4, '4 article requests' );
847 $schema->storage->txn_rollback;
850 subtest 'safe_to_delete() tests' => sub {
854 $schema->storage->txn_begin;
856 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
858 ## Make it the anonymous
859 t::lib::Mocks::mock_preference( 'AnonymousPatron', $patron->id );
861 ok( !$patron->safe_to_delete, 'Cannot delete, it is the anonymous patron' );
862 my $message = $patron->safe_to_delete->messages->[0];
863 is( $message->type, 'error', 'Type is error' );
864 is( $message->message, 'is_anonymous_patron', 'Cannot delete, it is the anonymous patron' );
866 t::lib::Mocks::mock_preference( 'AnonymousPatron', 0 );
868 ## Make it have a checkout
869 my $checkout = $builder->build_object(
871 class => 'Koha::Checkouts',
872 value => { borrowernumber => $patron->id }
876 ok( !$patron->safe_to_delete, 'Cannot delete, has checkouts' );
877 $message = $patron->safe_to_delete->messages->[0];
878 is( $message->type, 'error', 'Type is error' );
879 is( $message->message, 'has_checkouts', 'Cannot delete, has checkouts' );
883 ## Make it have a guarantee
884 t::lib::Mocks::mock_preference( 'borrowerRelationship', 'parent' );
885 $builder->build_object({ class => 'Koha::Patrons' })
886 ->add_guarantor({ guarantor_id => $patron->id, relationship => 'parent' });
888 ok( !$patron->safe_to_delete, 'Cannot delete, has guarantees' );
889 $message = $patron->safe_to_delete->messages->[0];
890 is( $message->type, 'error', 'Type is error' );
891 is( $message->message, 'has_guarantees', 'Cannot delete, has guarantees' );
894 $patron->guarantee_relationships->delete;
897 my $debit = $patron->account->add_debit({ amount => 10, interface => 'intranet', type => 'MANUAL' });
899 ok( !$patron->safe_to_delete, 'Cannot delete, has debt' );
900 $message = $patron->safe_to_delete->messages->[0];
901 is( $message->type, 'error', 'Type is error' );
902 is( $message->message, 'has_debt', 'Cannot delete, has debt' );
904 $patron->account->pay({ amount => 10, debits => [ $debit ] });
907 ok( $patron->safe_to_delete, 'Can delete, all conditions met' );
908 my $messages = $patron->safe_to_delete->messages;
909 is_deeply( $messages, [], 'Patron can be deleted, no messages' );
911 $schema->storage->txn_rollback;