X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=t%2Fdb_dependent%2FKoha%2FPatrons.t;h=40d36ee49837c9706382ee481e0dd330cbd874f4;hb=0f907342c88e318ee6e774f8c085370681bc1af8;hp=12efa733f10b05b2a980898b823996306e7a5e0d;hpb=553ce38225b7334ef9354e7789b5a10e5a569bbf;p=koha-ffzg.git diff --git a/t/db_dependent/Koha/Patrons.t b/t/db_dependent/Koha/Patrons.t index 12efa733f1..40d36ee498 100644 --- a/t/db_dependent/Koha/Patrons.t +++ b/t/db_dependent/Koha/Patrons.t @@ -19,18 +19,22 @@ use Modern::Perl; -use Test::More tests => 21; +use Test::More tests => 26; use Test::Warn; +use Time::Fake; use DateTime; +use JSON; use C4::Biblio; use C4::Circulation; + use C4::Members; use C4::Circulation; use Koha::Holds; use Koha::Patron; use Koha::Patrons; +use Koha::Patron::Categories; use Koha::Database; use Koha::DateUtils; use Koha::Virtualshelves; @@ -52,6 +56,7 @@ my $new_patron_1 = Koha::Patron->new( surname => 'surname for patron1', firstname => 'firstname for patron1', userid => 'a_nonexistent_userid_1', + flags => 1, # Is superlibrarian } )->store; my $new_patron_2 = Koha::Patron->new( @@ -65,7 +70,7 @@ my $new_patron_2 = Koha::Patron->new( )->store; C4::Context->_new_userenv('xxx'); -C4::Context->set_userenv(0,0,0,'firstname','surname', $library->{branchcode}, 'Midway Public Library', '', '', ''); +set_logged_in_user( $new_patron_1 ); is( Koha::Patrons->search->count, $nb_of_patrons + 2, 'The 2 patrons should have been added' ); @@ -183,13 +188,11 @@ subtest 'update_password' => sub { }; subtest 'is_expired' => sub { - plan tests => 5; + plan tests => 4; my $patron = $builder->build({ source => 'Borrower' }); $patron = Koha::Patrons->find( $patron->{borrowernumber} ); $patron->dateexpiry( undef )->store->discard_changes; is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is not set'); - $patron->dateexpiry( '0000-00-00' )->store->discard_changes; - is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is not 0000-00-00'); $patron->dateexpiry( dt_from_string )->store->discard_changes; is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is today'); $patron->dateexpiry( dt_from_string->add( days => 1 ) )->store->discard_changes; @@ -201,13 +204,11 @@ subtest 'is_expired' => sub { }; subtest 'is_going_to_expire' => sub { - plan tests => 9; + plan tests => 8; my $patron = $builder->build({ source => 'Borrower' }); $patron = Koha::Patrons->find( $patron->{borrowernumber} ); $patron->dateexpiry( undef )->store->discard_changes; is( $patron->is_going_to_expire, 0, 'Patron should not be considered going to expire if dateexpiry is not set'); - $patron->dateexpiry( '0000-00-00' )->store->discard_changes; - is( $patron->is_going_to_expire, 0, 'Patron should not be considered going to expire if dateexpiry is not 0000-00-00'); t::lib::Mocks::mock_preference('NotifyBorrowerDeparture', 0); $patron->dateexpiry( dt_from_string )->store->discard_changes; @@ -242,80 +243,91 @@ subtest 'is_going_to_expire' => sub { subtest 'renew_account' => sub { - plan tests => 10; - my $a_month_ago = dt_from_string->add( months => -1 )->truncate( to => 'day' ); - my $a_year_later = dt_from_string->add( months => 12 )->truncate( to => 'day' ); - my $a_year_later_minus_a_month = dt_from_string->add( months => 11 )->truncate( to => 'day' ); - my $a_month_later = dt_from_string->add( months => 1 )->truncate( to => 'day' ); - my $a_year_later_plus_a_month = dt_from_string->add( months => 13 )->truncate( to => 'day' ); - my $patron_category = $builder->build( - { source => 'Category', - value => { - enrolmentperiod => 12, - enrolmentperioddate => undef, + plan tests => 36; + + for my $date ( '2016-03-31', '2016-11-30', dt_from_string() ) { + my $dt = dt_from_string( $date, 'iso' ); + Time::Fake->offset( $dt->epoch ); + my $a_month_ago = $dt->clone->subtract( months => 1, end_of_month => 'limit' )->truncate( to => 'day' ); + my $a_year_later = $dt->clone->add( months => 12, end_of_month => 'limit' )->truncate( to => 'day' ); + my $a_year_later_minus_a_month = $dt->clone->add( months => 11, end_of_month => 'limit' )->truncate( to => 'day' ); + my $a_month_later = $dt->clone->add( months => 1 , end_of_month => 'limit' )->truncate( to => 'day' ); + my $a_year_later_plus_a_month = $dt->clone->add( months => 13, end_of_month => 'limit' )->truncate( to => 'day' ); + my $patron_category = $builder->build( + { source => 'Category', + value => { + enrolmentperiod => 12, + enrolmentperioddate => undef, + } } - } - ); - my $patron = $builder->build( - { source => 'Borrower', - value => { - dateexpiry => $a_month_ago, - categorycode => $patron_category->{categorycode}, + ); + my $patron = $builder->build( + { source => 'Borrower', + value => { + dateexpiry => $a_month_ago, + categorycode => $patron_category->{categorycode}, + date_renewed => undef, # Force builder to not populate the column for new patron + } } - } - ); - my $patron_2 = $builder->build( - { source => 'Borrower', - value => { - dateexpiry => $a_month_ago, - categorycode => $patron_category->{categorycode}, + ); + my $patron_2 = $builder->build( + { source => 'Borrower', + value => { + dateexpiry => $a_month_ago, + categorycode => $patron_category->{categorycode}, + } } - } - ); - my $patron_3 = $builder->build( - { source => 'Borrower', - value => { - dateexpiry => $a_month_later, - categorycode => $patron_category->{categorycode}, - } - } - ); - my $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} ); - my $retrieved_patron_2 = Koha::Patrons->find( $patron_2->{borrowernumber} ); - my $retrieved_patron_3 = Koha::Patrons->find( $patron_3->{borrowernumber} ); - - t::lib::Mocks::mock_preference( 'BorrowerRenewalPeriodBase', 'dateexpiry' ); - t::lib::Mocks::mock_preference( 'BorrowersLog', 1 ); - my $expiry_date = $retrieved_patron->renew_account; - is( $expiry_date, $a_year_later_minus_a_month, ); - my $retrieved_expiry_date = Koha::Patrons->find( $patron->{borrowernumber} )->dateexpiry; - is( dt_from_string($retrieved_expiry_date), $a_year_later_minus_a_month ); - my $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'MEMBERS', action => 'RENEW', object => $retrieved_patron->borrowernumber } )->count; - is( $number_of_logs, 1, 'With BorrowerLogs, Koha::Patron->renew_account should have logged' ); - - t::lib::Mocks::mock_preference( 'BorrowerRenewalPeriodBase', 'now' ); - t::lib::Mocks::mock_preference( 'BorrowersLog', 0 ); - $expiry_date = $retrieved_patron->renew_account; - is( $expiry_date, $a_year_later, ); - $retrieved_expiry_date = Koha::Patrons->find( $patron->{borrowernumber} )->dateexpiry; - is( dt_from_string($retrieved_expiry_date), $a_year_later ); - $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'MEMBERS', action => 'RENEW', object => $retrieved_patron->borrowernumber } )->count; - is( $number_of_logs, 1, 'Without BorrowerLogs, Koha::Patron->renew_account should not have logged' ); - - t::lib::Mocks::mock_preference( 'BorrowerRenewalPeriodBase', 'combination' ); - $expiry_date = $retrieved_patron_2->renew_account; - is( $expiry_date, $a_year_later ); - $retrieved_expiry_date = Koha::Patrons->find( $patron_2->{borrowernumber} )->dateexpiry; - is( dt_from_string($retrieved_expiry_date), $a_year_later ); - - $expiry_date = $retrieved_patron_3->renew_account; - is( $expiry_date, $a_year_later_plus_a_month ); - $retrieved_expiry_date = Koha::Patrons->find( $patron_3->{borrowernumber} )->dateexpiry; - is( dt_from_string($retrieved_expiry_date), $a_year_later_plus_a_month ); - - $retrieved_patron->delete; - $retrieved_patron_2->delete; - $retrieved_patron_3->delete; + ); + my $patron_3 = $builder->build( + { source => 'Borrower', + value => { + dateexpiry => $a_month_later, + categorycode => $patron_category->{categorycode}, + } + } + ); + my $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} ); + my $retrieved_patron_2 = Koha::Patrons->find( $patron_2->{borrowernumber} ); + my $retrieved_patron_3 = Koha::Patrons->find( $patron_3->{borrowernumber} ); + + is( $retrieved_patron->date_renewed, undef, "Date renewed is not set for patrons that have never been renewed" ); + + t::lib::Mocks::mock_preference( 'BorrowerRenewalPeriodBase', 'dateexpiry' ); + t::lib::Mocks::mock_preference( 'BorrowersLog', 1 ); + my $expiry_date = $retrieved_patron->renew_account; + is( $expiry_date, $a_year_later_minus_a_month, "$a_month_ago + 12 months must be $a_year_later_minus_a_month" ); + my $retrieved_expiry_date = Koha::Patrons->find( $patron->{borrowernumber} )->dateexpiry; + is( dt_from_string($retrieved_expiry_date), $a_year_later_minus_a_month, "$a_month_ago + 12 months must be $a_year_later_minus_a_month" ); + my $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'MEMBERS', action => 'RENEW', object => $retrieved_patron->borrowernumber } )->count; + is( $number_of_logs, 1, 'With BorrowerLogs, Koha::Patron->renew_account should have logged' ); + + t::lib::Mocks::mock_preference( 'BorrowerRenewalPeriodBase', 'now' ); + t::lib::Mocks::mock_preference( 'BorrowersLog', 0 ); + $expiry_date = $retrieved_patron->renew_account; + is( $expiry_date, $a_year_later, "today + 12 months must be $a_year_later" ); + $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} ); + is( $retrieved_patron->date_renewed, output_pref({ dt => $dt, dateformat => 'iso', dateonly => 1 }), "Date renewed is set when calling renew_account" ); + $retrieved_expiry_date = $retrieved_patron->dateexpiry; + is( dt_from_string($retrieved_expiry_date), $a_year_later, "today + 12 months must be $a_year_later" ); + $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'MEMBERS', action => 'RENEW', object => $retrieved_patron->borrowernumber } )->count; + is( $number_of_logs, 1, 'Without BorrowerLogs, Koha::Patron->renew_account should not have logged' ); + + t::lib::Mocks::mock_preference( 'BorrowerRenewalPeriodBase', 'combination' ); + $expiry_date = $retrieved_patron_2->renew_account; + is( $expiry_date, $a_year_later, "today + 12 months must be $a_year_later" ); + $retrieved_expiry_date = Koha::Patrons->find( $patron_2->{borrowernumber} )->dateexpiry; + is( dt_from_string($retrieved_expiry_date), $a_year_later, "today + 12 months must be $a_year_later" ); + + $expiry_date = $retrieved_patron_3->renew_account; + is( $expiry_date, $a_year_later_plus_a_month, "$a_month_later + 12 months must be $a_year_later_plus_a_month" ); + $retrieved_expiry_date = Koha::Patrons->find( $patron_3->{borrowernumber} )->dateexpiry; + is( dt_from_string($retrieved_expiry_date), $a_year_later_plus_a_month, "$a_month_later + 12 months must be $a_year_later_plus_a_month" ); + + $retrieved_patron->delete; + $retrieved_patron_2->delete; + $retrieved_patron_3->delete; + } + Time::Fake->reset; }; subtest "move_to_deleted" => sub { @@ -368,14 +380,13 @@ subtest "delete" => sub { subtest 'add_enrolment_fee_if_needed' => sub { plan tests => 4; - my $enrolmentfee_K = 5; - my $enrolmentfee_J = 10; - my $enrolmentfee_YA = 20; - - my $dbh = C4::Context->dbh; - $dbh->do(q|UPDATE categories set enrolmentfee=? where categorycode=?|, undef, $enrolmentfee_K, 'K'); - $dbh->do(q|UPDATE categories set enrolmentfee=? where categorycode=?|, undef, $enrolmentfee_J, 'J'); - $dbh->do(q|UPDATE categories set enrolmentfee=? where categorycode=?|, undef, $enrolmentfee_YA, 'YA'); + my $enrolmentfees = { K => 5, J => 10, YA => 20 }; + foreach( keys %{$enrolmentfees} ) { + ( Koha::Patron::Categories->find( $_ ) // $builder->build_object({ class => 'Koha::Patron::Categories', value => { categorycode => $_ } }) )->enrolmentfee( $enrolmentfees->{$_} )->store; + } + my $enrolmentfee_K = $enrolmentfees->{K}; + my $enrolmentfee_J = $enrolmentfees->{J}; + my $enrolmentfee_YA = $enrolmentfees->{YA}; my %borrower_data = ( firstname => 'my firstname', @@ -387,14 +398,15 @@ subtest 'add_enrolment_fee_if_needed' => sub { my $borrowernumber = C4::Members::AddMember(%borrower_data); $borrower_data{borrowernumber} = $borrowernumber; - my ($total) = C4::Members::GetMemberAccountRecords($borrowernumber); - is( $total, $enrolmentfee_K, "New kid pay $enrolmentfee_K" ); + my $patron = Koha::Patrons->find( $borrowernumber ); + my $total = $patron->account->balance; + is( int($total), int($enrolmentfee_K), "New kid pay $enrolmentfee_K" ); t::lib::Mocks::mock_preference( 'FeeOnChangePatronCategory', 0 ); $borrower_data{categorycode} = 'J'; C4::Members::ModMember(%borrower_data); - ($total) = C4::Members::GetMemberAccountRecords($borrowernumber); - is( $total, $enrolmentfee_K, "Kid growing and become a juvenile, but shouldn't pay for the upgrade " ); + $total = $patron->account->balance; + is( int($total), int($enrolmentfee_K), "Kid growing and become a juvenile, but shouldn't pay for the upgrade " ); $borrower_data{categorycode} = 'K'; C4::Members::ModMember(%borrower_data); @@ -402,24 +414,23 @@ subtest 'add_enrolment_fee_if_needed' => sub { $borrower_data{categorycode} = 'J'; C4::Members::ModMember(%borrower_data); - ($total) = C4::Members::GetMemberAccountRecords($borrowernumber); - is( $total, $enrolmentfee_K + $enrolmentfee_J, "Kid growing and become a juvenile, he should pay " . ( $enrolmentfee_K + $enrolmentfee_J ) ); + $total = $patron->account->balance; + is( int($total), int($enrolmentfee_K + $enrolmentfee_J), "Kid growing and become a juvenile, they should pay " . ( $enrolmentfee_K + $enrolmentfee_J ) ); # Check with calling directly Koha::Patron->get_enrolment_fee_if_needed - my $patron = Koha::Patrons->find($borrowernumber); $patron->categorycode('YA')->store; my $fee = $patron->add_enrolment_fee_if_needed; - ($total) = C4::Members::GetMemberAccountRecords($borrowernumber); - is( $total, - $enrolmentfee_K + $enrolmentfee_J + $enrolmentfee_YA, - "Juvenile growing and become an young adult, he or she should pay " . ( $enrolmentfee_K + $enrolmentfee_J + $enrolmentfee_YA ) + $total = $patron->account->balance; + is( int($total), + int($enrolmentfee_K + $enrolmentfee_J + $enrolmentfee_YA), + "Juvenile growing and become an young adult, they should pay " . ( $enrolmentfee_K + $enrolmentfee_J + $enrolmentfee_YA ) ); $patron->delete; }; -subtest 'checkouts + get_overdues' => sub { - plan tests => 8; +subtest 'checkouts + get_overdues + old_checkouts' => sub { + plan tests => 12; my $library = $builder->build( { source => 'Branch' } ); my ($biblionumber_1) = AddBiblio( MARC::Record->new, '' ); @@ -429,7 +440,9 @@ subtest 'checkouts + get_overdues' => sub { value => { homebranch => $library->{branchcode}, holdingbranch => $library->{branchcode}, - biblionumber => $biblionumber_1 + biblionumber => $biblionumber_1, + itemlost => 0, + withdrawn => 0, } } ); @@ -439,7 +452,9 @@ subtest 'checkouts + get_overdues' => sub { value => { homebranch => $library->{branchcode}, holdingbranch => $library->{branchcode}, - biblionumber => $biblionumber_1 + biblionumber => $biblionumber_1, + itemlost => 0, + withdrawn => 0, } } ); @@ -450,7 +465,9 @@ subtest 'checkouts + get_overdues' => sub { value => { homebranch => $library->{branchcode}, holdingbranch => $library->{branchcode}, - biblionumber => $biblionumber_2 + biblionumber => $biblionumber_2, + itemlost => 0, + withdrawn => 0, } } ); @@ -465,9 +482,12 @@ subtest 'checkouts + get_overdues' => sub { my $checkouts = $patron->checkouts; is( $checkouts->count, 0, 'checkouts should not return any issues for that patron' ); is( ref($checkouts), 'Koha::Checkouts', 'checkouts should return a Koha::Checkouts object' ); + my $old_checkouts = $patron->old_checkouts; + is( $old_checkouts->count, 0, 'old_checkouts should not return any issues for that patron' ); + is( ref($old_checkouts), 'Koha::Old::Checkouts', 'old_checkouts should return a Koha::Old::Checkouts object' ); # Not sure how this is useful, but AddIssue pass this variable to different other subroutines - $patron = GetMember( borrowernumber => $patron->borrowernumber ); + $patron = Koha::Patrons->find( $patron->borrowernumber )->unblessed; my $module = new Test::MockModule('C4::Context'); $module->mock( 'userenv', sub { { branch => $library->{branchcode} } } ); @@ -487,6 +507,13 @@ subtest 'checkouts + get_overdues' => sub { is( $overdues->next->itemnumber, $item_1->{itemnumber}, 'The issue should be returned in the same order as they have been done, first is correct' ); is( $overdues->next->itemnumber, $item_2->{itemnumber}, 'The issue should be returned in the same order as they have been done, second is correct' ); + + C4::Circulation::AddReturn( $item_1->{barcode} ); + C4::Circulation::AddReturn( $item_2->{barcode} ); + $old_checkouts = $patron->old_checkouts; + is( $old_checkouts->count, 2, 'old_checkouts should return 2 old checkouts that patron' ); + is( ref($old_checkouts), 'Koha::Old::Checkouts', 'old_checkouts should return a Koha::Old::Checkouts object' ); + # Clean stuffs Koha::Checkouts->search( { borrowernumber => $patron->borrowernumber } )->delete; $patron->delete; @@ -503,17 +530,17 @@ subtest 'get_age' => sub { $patron->dateofbirth( undef ); is( $patron->get_age, undef, 'get_age should return undef if no dateofbirth is defined' ); - $patron->dateofbirth( $today->clone->add( years => -12, months => -6, days => -1 ) ); + $patron->dateofbirth( $today->clone->add( years => -12, months => -6, days => -1, end_of_month => 'limit' ) ); is( $patron->get_age, 12, 'Patron should be 12' ); - $patron->dateofbirth( $today->clone->add( years => -18, months => 0, days => 1 ) ); + $patron->dateofbirth( $today->clone->add( years => -18, months => 0, days => 1, end_of_month => 'limit' ) ); is( $patron->get_age, 17, 'Patron should be 17, happy birthday tomorrow!' ); - $patron->dateofbirth( $today->clone->add( years => -18, months => 0, days => 0 ) ); + $patron->dateofbirth( $today->clone->add( years => -18, months => 0, days => 0, end_of_month => 'limit' ) ); is( $patron->get_age, 18, 'Patron should be 18' ); - $patron->dateofbirth( $today->clone->add( years => -18, months => -12, days => -31 ) ); + $patron->dateofbirth( $today->clone->add( years => -18, months => -12, days => -31, end_of_month => 'limit' ) ); is( $patron->get_age, 19, 'Patron should be 19' ); - $patron->dateofbirth( $today->clone->add( years => -18, months => -12, days => -30 ) ); + $patron->dateofbirth( $today->clone->add( years => -18, months => -12, days => -30, end_of_month => 'limit' ) ); is( $patron->get_age, 19, 'Patron should be 19 again' ); - $patron->dateofbirth( $today->clone->add( years => 0, months => -1, days => -1 ) ); + $patron->dateofbirth( $today->clone->add( years => 0, months => -1, days => -1, end_of_month => 'limit' ) ); is( $patron->get_age, 0, 'Patron is a newborn child' ); $patron->delete; @@ -603,8 +630,8 @@ subtest 'search_upcoming_membership_expires' => sub { Koha::Patrons->search({ borrowernumber => { in => [ $patron_1->{borrowernumber}, $patron_2->{borrowernumber}, $patron_3->{borrowernumber} ] } })->delete; }; -subtest 'holds' => sub { - plan tests => 3; +subtest 'holds and old_holds' => sub { + plan tests => 6; my $library = $builder->build( { source => 'Branch' } ); my ($biblionumber_1) = AddBiblio( MARC::Record->new, '' ); @@ -661,10 +688,36 @@ subtest 'holds' => sub { $holds = $patron->holds; is( $holds->count, 2, 'There should be 2 holds placed by this patron' ); + my $old_holds = $patron->old_holds; + is( ref($old_holds), 'Koha::Old::Holds', + 'Koha::Patron->old_holds should return a Koha::Old::Holds objects' ); + is( $old_holds->count, 0, 'There should not be any old holds yet'); + + my $hold = $holds->next; + $hold->cancel; + + $old_holds = $patron->old_holds; + is( $old_holds->count, 1, 'There should be 1 old (cancelled) hold'); + + $old_holds->delete; $holds->delete; $patron->delete; }; +subtest 'notice_email_address' => sub { + plan tests => 2; + + my $patron = $builder->build_object({ class => 'Koha::Patrons' }); + + t::lib::Mocks::mock_preference( 'AutoEmailPrimaryAddress', 'OFF' ); + is ($patron->notice_email_address, $patron->email, "Koha::Patron->notice_email_address returns correct value when AutoEmailPrimaryAddress is off"); + + t::lib::Mocks::mock_preference( 'AutoEmailPrimaryAddress', 'emailpro' ); + is ($patron->notice_email_address, $patron->emailpro, "Koha::Patron->notice_email_address returns correct value when AutoEmailPrimaryAddress is emailpro"); + + $patron->delete; +}; + subtest 'search_patrons_to_anonymise & anonymise_issue_history' => sub { plan tests => 4; @@ -879,11 +932,293 @@ subtest 'search_patrons_to_anonymise & anonymise_issue_history' => sub { Koha::Patrons->find( $anonymous->{borrowernumber})->delete; Koha::Patrons->find( $userenv_patron->{borrowernumber})->delete; + + # Reset IndependentBranches for further tests + t::lib::Mocks::mock_preference('IndependentBranches', 0); +}; + +subtest 'libraries_where_can_see_patrons + can_see_patron_infos + search_limited' => sub { + plan tests => 3; + + # group1 + # + library_11 + # + library_12 + # group2 + # + library21 + my $group_1 = Koha::Library::Group->new( { title => 'TEST Group 1', ft_hide_patron_info => 1 } )->store; + my $group_2 = Koha::Library::Group->new( { title => 'TEST Group 2', ft_hide_patron_info => 1 } )->store; + my $library_11 = $builder->build( { source => 'Branch' } ); + my $library_12 = $builder->build( { source => 'Branch' } ); + my $library_21 = $builder->build( { source => 'Branch' } ); + $library_11 = Koha::Libraries->find( $library_11->{branchcode} ); + $library_12 = Koha::Libraries->find( $library_12->{branchcode} ); + $library_21 = Koha::Libraries->find( $library_21->{branchcode} ); + Koha::Library::Group->new( + { branchcode => $library_11->branchcode, parent_id => $group_1->id } )->store; + Koha::Library::Group->new( + { branchcode => $library_12->branchcode, parent_id => $group_1->id } )->store; + Koha::Library::Group->new( + { branchcode => $library_21->branchcode, parent_id => $group_2->id } )->store; + + my $sth = C4::Context->dbh->prepare(q|INSERT INTO user_permissions( borrowernumber, module_bit, code ) VALUES (?, 4, ?)|); # 4 for borrowers + # 2 patrons from library_11 (group1) + # patron_11_1 see patron's infos from outside its group + # Setting flags => undef to not be considered as superlibrarian + my $patron_11_1 = $builder->build({ source => 'Borrower', value => { branchcode => $library_11->branchcode, flags => undef, }}); + $patron_11_1 = Koha::Patrons->find( $patron_11_1->{borrowernumber} ); + $sth->execute( $patron_11_1->borrowernumber, 'edit_borrowers' ); + $sth->execute( $patron_11_1->borrowernumber, 'view_borrower_infos_from_any_libraries' ); + # patron_11_2 can only see patron's info from its group + my $patron_11_2 = $builder->build({ source => 'Borrower', value => { branchcode => $library_11->branchcode, flags => undef, }}); + $patron_11_2 = Koha::Patrons->find( $patron_11_2->{borrowernumber} ); + $sth->execute( $patron_11_2->borrowernumber, 'edit_borrowers' ); + # 1 patron from library_12 (group1) + my $patron_12 = $builder->build({ source => 'Borrower', value => { branchcode => $library_12->branchcode, flags => undef, }}); + $patron_12 = Koha::Patrons->find( $patron_12->{borrowernumber} ); + # 1 patron from library_21 (group2) can only see patron's info from its group + my $patron_21 = $builder->build({ source => 'Borrower', value => { branchcode => $library_21->branchcode, flags => undef, }}); + $patron_21 = Koha::Patrons->find( $patron_21->{borrowernumber} ); + $sth->execute( $patron_21->borrowernumber, 'edit_borrowers' ); + + # Pfiou, we can start now! + subtest 'libraries_where_can_see_patrons' => sub { + plan tests => 3; + + my @branchcodes; + + set_logged_in_user( $patron_11_1 ); + @branchcodes = $patron_11_1->libraries_where_can_see_patrons; + is_deeply( \@branchcodes, [], q|patron_11_1 has view_borrower_infos_from_any_libraries => No restriction| ); + + set_logged_in_user( $patron_11_2 ); + @branchcodes = $patron_11_2->libraries_where_can_see_patrons; + is_deeply( \@branchcodes, [ sort ( $library_11->branchcode, $library_12->branchcode ) ], q|patron_11_2 has not view_borrower_infos_from_any_libraries => Can only see patron's from its group| ); + + set_logged_in_user( $patron_21 ); + @branchcodes = $patron_21->libraries_where_can_see_patrons; + is_deeply( \@branchcodes, [$library_21->branchcode], q|patron_21 has not view_borrower_infos_from_any_libraries => Can only see patron's from its group| ); + }; + subtest 'can_see_patron_infos' => sub { + plan tests => 6; + + set_logged_in_user( $patron_11_1 ); + is( $patron_11_1->can_see_patron_infos( $patron_11_2 ), 1, q|patron_11_1 can see patron_11_2, from its library| ); + is( $patron_11_1->can_see_patron_infos( $patron_12 ), 1, q|patron_11_1 can see patron_12, from its group| ); + is( $patron_11_1->can_see_patron_infos( $patron_21 ), 1, q|patron_11_1 can see patron_11_2, from another group| ); + + set_logged_in_user( $patron_11_2 ); + is( $patron_11_2->can_see_patron_infos( $patron_11_1 ), 1, q|patron_11_2 can see patron_11_1, from its library| ); + is( $patron_11_2->can_see_patron_infos( $patron_12 ), 1, q|patron_11_2 can see patron_12, from its group| ); + is( $patron_11_2->can_see_patron_infos( $patron_21 ), 0, q|patron_11_2 can NOT see patron_21, from another group| ); + }; + subtest 'search_limited' => sub { + plan tests => 6; + + set_logged_in_user( $patron_11_1 ); + my $total_number_of_patrons = $nb_of_patrons + 6; # 2 created before + 4 for these subtests + is( Koha::Patrons->search->count, $total_number_of_patrons, 'Non-limited search should return all patrons'); + is( Koha::Patrons->search_limited->count, $total_number_of_patrons, 'patron_11_1 is allowed to see all patrons' ); + + set_logged_in_user( $patron_11_2 ); + is( Koha::Patrons->search->count, $total_number_of_patrons, 'Non-limited search should return all patrons'); + is( Koha::Patrons->search_limited->count, 3, 'patron_12_1 is not allowed to see patrons from other groups, only patron_11_1, patron_11_2 and patron_12' ); + + set_logged_in_user( $patron_21 ); + is( Koha::Patrons->search->count, $total_number_of_patrons, 'Non-limited search should return all patrons'); + is( Koha::Patrons->search_limited->count, 1, 'patron_21 is not allowed to see patrons from other groups, only himself' ); + }; + $patron_11_1->delete; + $patron_11_2->delete; + $patron_12->delete; + $patron_21->delete; +}; + +subtest 'account_locked' => sub { + plan tests => 8; + my $patron = $builder->build({ source => 'Borrower', value => { login_attempts => 0 } }); + $patron = Koha::Patrons->find( $patron->{borrowernumber} ); + for my $value ( undef, '', 0 ) { + t::lib::Mocks::mock_preference('FailedloginAttempts', $value); + is( $patron->account_locked, 0, 'Feature is disabled, patron account should not be considered locked' ); + $patron->login_attempts(1)->store; + is( $patron->account_locked, 0, 'Feature is disabled, patron account should not be considered locked' ); + } + + t::lib::Mocks::mock_preference('FailedloginAttempts', 3); + $patron->login_attempts(2)->store; + is( $patron->account_locked, 0, 'Patron has 2 failed attempts, account should not be considered locked yet' ); + $patron->login_attempts(3)->store; + is( $patron->account_locked, 1, 'Patron has 3 failed attempts, account should be considered locked yet' ); + + $patron->delete; +}; + +subtest 'is_child | is_adult' => sub { + plan tests => 8; + my $category = $builder->build_object( + { + class => 'Koha::Patron::Categories', + value => { category_type => 'A' } + } + ); + my $patron_adult = $builder->build_object( + { + class => 'Koha::Patrons', + value => { categorycode => $category->categorycode } + } + ); + $category = $builder->build_object( + { + class => 'Koha::Patron::Categories', + value => { category_type => 'I' } + } + ); + my $patron_adult_i = $builder->build_object( + { + class => 'Koha::Patrons', + value => { categorycode => $category->categorycode } + } + ); + $category = $builder->build_object( + { + class => 'Koha::Patron::Categories', + value => { category_type => 'C' } + } + ); + my $patron_child = $builder->build_object( + { + class => 'Koha::Patrons', + value => { categorycode => $category->categorycode } + } + ); + $category = $builder->build_object( + { + class => 'Koha::Patron::Categories', + value => { category_type => 'O' } + } + ); + my $patron_other = $builder->build_object( + { + class => 'Koha::Patrons', + value => { categorycode => $category->categorycode } + } + ); + is( $patron_adult->is_adult, 1, 'Patron from category A should be considered adult' ); + is( $patron_adult_i->is_adult, 1, 'Patron from category I should be considered adult' ); + is( $patron_child->is_adult, 0, 'Patron from category C should not be considered adult' ); + is( $patron_other->is_adult, 0, 'Patron from category O should not be considered adult' ); + + is( $patron_adult->is_child, 0, 'Patron from category A should be considered child' ); + is( $patron_adult_i->is_child, 0, 'Patron from category I should be considered child' ); + is( $patron_child->is_child, 1, 'Patron from category C should not be considered child' ); + is( $patron_other->is_child, 0, 'Patron from category O should not be considered child' ); + + # Clean up + $patron_adult->delete; + $patron_adult_i->delete; + $patron_child->delete; + $patron_other->delete; +}; + +subtest 'get_overdues' => sub { + plan tests => 7; + + my $library = $builder->build( { source => 'Branch' } ); + my ($biblionumber_1) = AddBiblio( MARC::Record->new, '' ); + my $item_1 = $builder->build( + { + source => 'Item', + value => { + homebranch => $library->{branchcode}, + holdingbranch => $library->{branchcode}, + biblionumber => $biblionumber_1 + } + } + ); + my $item_2 = $builder->build( + { + source => 'Item', + value => { + homebranch => $library->{branchcode}, + holdingbranch => $library->{branchcode}, + biblionumber => $biblionumber_1 + } + } + ); + my ($biblionumber_2) = AddBiblio( MARC::Record->new, '' ); + my $item_3 = $builder->build( + { + source => 'Item', + value => { + homebranch => $library->{branchcode}, + holdingbranch => $library->{branchcode}, + biblionumber => $biblionumber_2 + } + } + ); + my $patron = $builder->build( + { + source => 'Borrower', + value => { branchcode => $library->{branchcode} } + } + ); + + my $module = new Test::MockModule('C4::Context'); + $module->mock( 'userenv', sub { { branch => $library->{branchcode} } } ); + + AddIssue( $patron, $item_1->{barcode}, DateTime->now->subtract( days => 1 ) ); + AddIssue( $patron, $item_2->{barcode}, DateTime->now->subtract( days => 5 ) ); + AddIssue( $patron, $item_3->{barcode} ); + + $patron = Koha::Patrons->find( $patron->{borrowernumber} ); + my $overdues = $patron->get_overdues; + is( $overdues->count, 2, 'Patron should have 2 overdues'); + is( $overdues->next->itemnumber, $item_1->{itemnumber}, 'The issue should be returned in the same order as they have been done, first is correct' ); + is( $overdues->next->itemnumber, $item_2->{itemnumber}, 'The issue should be returned in the same order as they have been done, second is correct' ); + + my $o = $overdues->reset->next; + my $unblessed_overdue = $o->unblessed_all_relateds; + is( exists( $unblessed_overdue->{issuedate} ), 1, 'Fields from the issues table should be filled' ); + is( exists( $unblessed_overdue->{itemcallnumber} ), 1, 'Fields from the items table should be filled' ); + is( exists( $unblessed_overdue->{title} ), 1, 'Fields from the biblio table should be filled' ); + is( exists( $unblessed_overdue->{itemtype} ), 1, 'Fields from the biblioitems table should be filled' ); + + # Clean stuffs + $patron->checkouts->delete; + $patron->delete; }; $retrieved_patron_1->delete; is( Koha::Patrons->search->count, $nb_of_patrons + 1, 'Delete should have deleted the patron' ); +subtest 'Log cardnumber change' => sub { + plan tests => 3; + + t::lib::Mocks::mock_preference( 'BorrowersLog', 1 ); + my $patron = $builder->build( { source => 'Borrower' } ); + + my $cardnumber = $patron->{cardnumber}; + $patron->{cardnumber} = 'TESTCARDNUMBER'; + ModMember(%$patron); + + my @logs = $schema->resultset('ActionLog')->search( { module => 'MEMBERS', action => 'MODIFY', object => $patron->{borrowernumber} } ); + my $log_info = from_json( $logs[0]->info ); + is( $log_info->{cardnumber_replaced}->{new_cardnumber}, 'TESTCARDNUMBER', 'Got correct new cardnumber' ); + is( $log_info->{cardnumber_replaced}->{previous_cardnumber}, $cardnumber, 'Got correct old cardnumber' ); + is( scalar @logs, 2, 'With BorrowerLogs, Change in cardnumber should be logged, as well as general alert of patron mod.' ); +}; + + $schema->storage->txn_rollback; -1; +# TODO Move to t::lib::Mocks and reuse it! +sub set_logged_in_user { + my ($patron) = @_; + C4::Context->set_userenv( + $patron->borrowernumber, $patron->userid, + $patron->cardnumber, 'firstname', + 'surname', $patron->library->branchcode, + 'Midway Public Library', $patron->flags, + '', '' + ); +}