View | Details | Raw Unified | Return to bug 37845
Collapse All | Expand All

(-)a/C4/Members.pm (-36 lines)
Lines 45-52 BEGIN { Link Here
45
      GetBorrowersToExpunge
45
      GetBorrowersToExpunge
46
46
47
      IssueSlip
47
      IssueSlip
48
49
      DeleteExpiredOpacRegistrations
50
    );
48
    );
51
}
49
}
52
50
Lines 489-528 sub IssueSlip { Link Here
489
    );
487
    );
490
}
488
}
491
489
492
=head2 DeleteExpiredOpacRegistrations
493
494
    Delete accounts that haven't been upgraded from the 'temporary' category
495
    Returns the number of removed patrons
496
497
=cut
498
499
sub DeleteExpiredOpacRegistrations {
500
501
    my $delay = C4::Context->preference('PatronSelfRegistrationExpireTemporaryAccountsDelay');
502
    my $category_code = C4::Context->preference('PatronSelfRegistrationDefaultCategory');
503
504
    return 0 unless $category_code && $delay;
505
        # DO NOT REMOVE test on delay here!
506
        # Some libraries may not use a temporary category, but want to keep patrons.
507
        # We should not delete patrons when the value is NULL, empty string or 0.
508
509
    my $date_enrolled = dt_from_string();
510
    $date_enrolled->subtract( days => $delay );
511
512
    my $registrations_to_del = Koha::Patrons->search({
513
        dateenrolled => {'<=' => $date_enrolled->ymd},
514
        categorycode => $category_code,
515
    });
516
517
    my $cnt=0;
518
    while ( my $registration = $registrations_to_del->next() ) {
519
        next if $registration->checkouts->count || $registration->account->balance;
520
        $registration->delete;
521
        $cnt++;
522
    }
523
    return $cnt;
524
}
525
526
END { }    # module clean-up code here (global destructor)
490
END { }    # module clean-up code here (global destructor)
527
491
528
1;
492
1;
(-)a/Koha/Patrons.pm (+49 lines)
Lines 27-32 use Koha::DateUtils qw( dt_from_string ); Link Here
27
use Koha::ArticleRequests;
27
use Koha::ArticleRequests;
28
use Koha::Patron;
28
use Koha::Patron;
29
use Koha::Exceptions::Patron;
29
use Koha::Exceptions::Patron;
30
use Koha::Exceptions::SysPref;
30
use Koha::Patron::Categories;
31
use Koha::Patron::Categories;
31
32
32
use base qw(Koha::Objects::Mixin::ExtendedAttributes Koha::Objects);
33
use base qw(Koha::Objects::Mixin::ExtendedAttributes Koha::Objects);
Lines 566-571 sub filter_by_have_permission { Link Here
566
    );
567
    );
567
}
568
}
568
569
570
=head3 filter_by_expired_opac_registrations
571
572
    my $expired_registrations = $patrons->filter_by_expired_opac_registrations;
573
574
Return patrons that have not upgraded from the 'temporary' category
575
576
=cut
577
578
sub filter_by_expired_opac_registrations {
579
    my ($self) = @_;
580
581
    my $category_code = C4::Context->preference('PatronSelfRegistrationDefaultCategory');
582
    Koha::Exceptions::SysPref::NotSet->throw( syspref => 'PatronSelfRegistrationDefaultCategory' )
583
        unless $category_code;
584
585
    my $delay = C4::Context->preference('PatronSelfRegistrationExpireTemporaryAccountsDelay');
586
    Koha::Exceptions::SysPref::NotSet->throw( syspref => 'PatronSelfRegistrationExpireTemporaryAccountsDelay' )
587
        unless $delay;
588
589
    # DO NOT REMOVE test on delay here!
590
    # Some libraries may not use a temporary category, but want to keep patrons.
591
    # We should not delete patrons when the value is NULL, empty string or 0.
592
593
    return $self->search(
594
        {
595
            categorycode => $category_code,
596
        }
597
    )->filter_by_last_update( { timestamp_column_name => 'dateenrolled', days => $delay } );
598
}
599
600
=head3 filter_by_safe_to_delete
601
602
    my $safe_to_delete_patrons = $patrons->filter_by_safe_to_delete;
603
604
Return the patrons that are safe to delete
605
606
=cut
607
608
sub filter_by_safe_to_delete {
609
    my ($self) = @_;
610
    my @ids;
611
    while ( my $patron = $self->next ) {
612
        push @ids, $patron->borrowernumber
613
            if $patron->safe_to_delete;
614
    }
615
    return Koha::Patrons->search( { borrowernumber => \@ids } );
616
}
617
569
=head3 extended_attributes_config
618
=head3 extended_attributes_config
570
619
571
=cut
620
=cut
(-)a/misc/cronjobs/cleanup_database.pl (-12 / +19 lines)
Lines 32-37 use constant DEFAULT_JOBS_PURGETYPES => qw{ update_elastic_index }; Link Here
32
use constant DEFAULT_EDIFACT_MSG_PURGEDAYS        => 365;
32
use constant DEFAULT_EDIFACT_MSG_PURGEDAYS        => 365;
33
33
34
use Getopt::Long qw( GetOptions );
34
use Getopt::Long qw( GetOptions );
35
use Try::Tiny;
35
36
36
use Koha::Script -cron;
37
use Koha::Script -cron;
37
38
Lines 513-526 if ($verbose) { Link Here
513
    say $confirm ? sprintf( "Deleted %d patrons", $count ) : sprintf( "%d patrons would have been deleted", $count );
514
    say $confirm ? sprintf( "Deleted %d patrons", $count ) : sprintf( "%d patrons would have been deleted", $count );
514
}
515
}
515
516
516
# FIXME The output for dry-run mode needs to be improved
517
# But non trivial changes to C4::Members need to be done before.
518
if ($pExpSelfReg) {
517
if ($pExpSelfReg) {
519
    if ($confirm) {
518
    try {
520
        DeleteExpiredSelfRegs();
519
        my $opac_registrations = Koha::Patrons->search->filter_by_expired_opac_registrations->filter_by_safe_to_delete;
521
    } elsif ($verbose) {
520
        my $count              = $opac_registrations->count;
522
        say "self-registered borrowers may be deleted";
521
        $opac_registrations->delete if $confirm;
523
    }
522
        if ($verbose) {
523
            say $confirm
524
                ? sprintf( "Done with removing %d expired self-registrations",      $count )
525
                : sprintf( "%d expired self-registrations would have been removed", $count );
526
        }
527
    } catch {
528
        if ( ref($_) eq 'Koha::Exceptions::SysPref::NotSet' ) {
529
            say sprintf "Self-registrations cannot be removed, system preference %s is not set", $_->syspref;
530
        } else {
531
            $_->rethrow;
532
        }
533
    };
524
}
534
}
525
535
526
if ($pUnvSelfReg) {
536
if ($pUnvSelfReg) {
Lines 536-541 if ($pUnvSelfReg) { Link Here
536
    }
546
    }
537
}
547
}
538
548
549
# FIXME The output for dry-run mode needs to be improved
550
# But non trivial changes to C4::Members need to be done before.
539
if ($special_holidays_days) {
551
if ($special_holidays_days) {
540
    if ($confirm) {
552
    if ($confirm) {
541
        DeleteSpecialHolidays( abs($special_holidays_days) );
553
        DeleteSpecialHolidays( abs($special_holidays_days) );
Lines 908-918 sub PurgeCreatorBatches { Link Here
908
    return $count;
920
    return $count;
909
}
921
}
910
922
911
sub DeleteExpiredSelfRegs {
912
    my $cnt = C4::Members::DeleteExpiredOpacRegistrations();
913
    print "Removed $cnt expired self-registered borrowers\n" if $verbose;
914
}
915
916
sub DeleteSpecialHolidays {
923
sub DeleteSpecialHolidays {
917
    my ($days) = @_;
924
    my ($days) = @_;
918
925
(-)a/t/db_dependent/Koha/Patrons.t (-1 / +83 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 43;
22
use Test::More tests => 44;
23
use Test::Warn;
23
use Test::Warn;
24
use Test::Exception;
24
use Test::Exception;
25
use Test::MockModule;
25
use Test::MockModule;
Lines 2678-2681 subtest 'filter_by_have_permission' => sub { Link Here
2678
    $schema->storage->txn_rollback;
2678
    $schema->storage->txn_rollback;
2679
};
2679
};
2680
2680
2681
subtest 'filter_by_expired_opac_registrations' => sub {
2682
    plan tests => 8;
2683
2684
    $schema->storage->txn_begin;
2685
2686
    my $category = $builder->build_object( { class => 'Koha::Patron::Categories' } );
2687
    t::lib::Mocks::mock_preference( 'PatronSelfRegistrationDefaultCategory', $category->categorycode );
2688
    my $self_reg = $builder->build_object(
2689
        {
2690
            class => 'Koha::Patrons',
2691
            value => {
2692
                dateenrolled => '2014-01-01 01:02:03',
2693
                categorycode => $category->categorycode
2694
            }
2695
        }
2696
    );
2697
2698
    # First test if empty PatronSelfRegistrationExpireTemporaryAccountsDelay returns an exception
2699
    t::lib::Mocks::mock_preference( 'PatronSelfRegistrationExpireTemporaryAccountsDelay', q{} );
2700
    throws_ok { Koha::Patrons->filter_by_expired_opac_registrations }
2701
    'Koha::Exceptions::SysPref::NotSet',
2702
        'Attempt to filter with empty PatronSelfRegistrationExpireTemporaryAccountsDelay throws exception.';
2703
2704
    # Test zero too
2705
    t::lib::Mocks::mock_preference( 'PatronSelfRegistrationExpireTemporaryAccountsDelay', 0 );
2706
    throws_ok { Koha::Patrons->filter_by_expired_opac_registrations }
2707
    'Koha::Exceptions::SysPref::NotSet',
2708
        'Attempt to filter with PatronSelfRegistrationExpireTemporaryAccountsDelay set to 0 throws exception.';
2709
2710
    # Also check empty category
2711
    t::lib::Mocks::mock_preference( 'PatronSelfRegistrationDefaultCategory', q{} );
2712
    throws_ok { Koha::Patrons->filter_by_expired_opac_registrations }
2713
    'Koha::Exceptions::SysPref::NotSet',
2714
        'Attempt to filter with empty PatronSelfRegistrationDefaultCategory throws exception.';
2715
2716
    t::lib::Mocks::mock_preference( 'PatronSelfRegistrationExpireTemporaryAccountsDelay', 360 );
2717
    throws_ok { Koha::Patrons->filter_by_expired_opac_registrations }
2718
    'Koha::Exceptions::SysPref::NotSet',
2719
        'Attempt to filter with empty PatronSelfRegistrationDefaultCategory throws exception, even if PatronSelfRegistrationExpireTemporaryAccountsDelay is set.';
2720
2721
    t::lib::Mocks::mock_preference( 'PatronSelfRegistrationDefaultCategory', $category->categorycode );
2722
2723
    my $checkout = $builder->build_object(
2724
        {
2725
            class => 'Koha::Checkouts',
2726
            value => { borrowernumber => $self_reg->borrowernumber }
2727
        }
2728
    );
2729
    is(
2730
        Koha::Patrons->filter_by_expired_opac_registrations->filter_by_safe_to_delete->count, 0,
2731
        "filter_by_safe_to_delete doesn't delete borrower with checkout"
2732
    );
2733
2734
    my $account_line = $builder->build_object(
2735
        {
2736
            class => 'Koha::Account::Lines',
2737
            value => {
2738
                borrowernumber    => $self_reg->borrowernumber,
2739
                amountoutstanding => 5,
2740
            }
2741
        }
2742
    );
2743
    is(
2744
        Koha::Patrons->filter_by_expired_opac_registrations->filter_by_safe_to_delete->count, 0,
2745
        "filter_by_safe_to_delete doesn't delete borrower with checkout and fine"
2746
    );
2747
2748
    $checkout->delete;
2749
    is(
2750
        Koha::Patrons->filter_by_expired_opac_registrations->filter_by_safe_to_delete->count, 0,
2751
        "filter_by_safe_to_delete doesn't delete borrower with fine and no checkout"
2752
    );
2753
2754
    $account_line->delete;
2755
    is(
2756
        Koha::Patrons->filter_by_expired_opac_registrations->filter_by_safe_to_delete->count, 1,
2757
        "filter_by_safe_to_delete does delete borrower with no fines and no checkouts"
2758
    );
2759
2760
    $schema->storage->txn_rollback;
2761
};
2762
2681
$schema->storage->txn_rollback;
2763
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Members.t (-58 / +2 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 51;
20
use Test::More tests => 50;
21
use Test::MockModule;
21
use Test::MockModule;
22
use Test::Exception;
22
use Test::Exception;
23
23
Lines 33-39 use t::lib::Mocks; Link Here
33
use t::lib::TestBuilder;
33
use t::lib::TestBuilder;
34
34
35
BEGIN {
35
BEGIN {
36
        use_ok('C4::Members', qw( GetBorrowersToExpunge DeleteExpiredOpacRegistrations ));
36
        use_ok('C4::Members', qw( GetBorrowersToExpunge ));
37
}
37
}
38
38
39
my $schema = Koha::Database->schema;
39
my $schema = Koha::Database->schema;
Lines 388-448 ok( $borrowernumber > 0, 'Koha::Patron->store should have inserted the patron ev Link Here
388
$borrower = Koha::Patrons->find( $borrowernumber )->unblessed;
388
$borrower = Koha::Patrons->find( $borrowernumber )->unblessed;
389
ok( $borrower->{userid},  'A userid should have been generated correctly' );
389
ok( $borrower->{userid},  'A userid should have been generated correctly' );
390
390
391
subtest 'purgeSelfRegistration' => sub {
392
    plan tests => 7;
393
394
    #purge members in temporary category
395
    my $c= 'XYZ';
396
    $dbh->do("INSERT IGNORE INTO categories (categorycode) VALUES ('$c')");
397
    t::lib::Mocks::mock_preference('PatronSelfRegistrationDefaultCategory', $c );
398
    C4::Members::DeleteExpiredOpacRegistrations();
399
    my $self_reg = $builder->build_object({
400
        class => 'Koha::Patrons',
401
        value => {
402
            dateenrolled => '2014-01-01 01:02:03',
403
            categorycode => $c
404
        }
405
    });
406
407
    # First test if empty PatronSelfRegistrationExpireTemporaryAccountsDelay returns zero
408
    t::lib::Mocks::mock_preference('PatronSelfRegistrationExpireTemporaryAccountsDelay', q{} );
409
    is( C4::Members::DeleteExpiredOpacRegistrations(), 0, "DeleteExpiredOpacRegistrations with empty delay" );
410
    # Test zero too
411
    t::lib::Mocks::mock_preference('PatronSelfRegistrationExpireTemporaryAccountsDelay', 0 );
412
    is( C4::Members::DeleteExpiredOpacRegistrations(), 0, "DeleteExpiredOpacRegistrations with delay 0" );
413
    # Also check empty category
414
    t::lib::Mocks::mock_preference('PatronSelfRegistrationDefaultCategory', q{} );
415
    t::lib::Mocks::mock_preference('PatronSelfRegistrationExpireTemporaryAccountsDelay', 360 );
416
    is( C4::Members::DeleteExpiredOpacRegistrations(), 0, "DeleteExpiredOpacRegistrations with empty category" );
417
    t::lib::Mocks::mock_preference('PatronSelfRegistrationDefaultCategory', $c );
418
419
    my $checkout     = $builder->build_object({
420
        class=>'Koha::Checkouts',
421
        value=>{
422
            borrowernumber=>$self_reg->borrowernumber
423
        }
424
    });
425
    is( C4::Members::DeleteExpiredOpacRegistrations(), 0, "DeleteExpiredOpacRegistrations doesn't delete borrower with checkout");
426
427
    my $account_line = $builder->build_object(
428
        {
429
            class => 'Koha::Account::Lines',
430
            value => {
431
                borrowernumber    => $self_reg->borrowernumber,
432
                amountoutstanding => 5,
433
            }
434
        }
435
    );
436
    is( C4::Members::DeleteExpiredOpacRegistrations(), 0, "DeleteExpiredOpacRegistrations doesn't delete borrower with checkout and fine");
437
438
    $checkout->delete;
439
    is( C4::Members::DeleteExpiredOpacRegistrations(), 0, "DeleteExpiredOpacRegistrations doesn't delete borrower with fine and no checkout");
440
441
    $account_line->delete;
442
    is( C4::Members::DeleteExpiredOpacRegistrations(), 1, "DeleteExpiredOpacRegistrations does delete borrower with no fines and no checkouts");
443
444
};
445
446
sub _find_member {
391
sub _find_member {
447
    my ($resultset) = @_;
392
    my ($resultset) = @_;
448
    my $found = $resultset && grep( { $_->{cardnumber} && $_->{cardnumber} eq $CARDNUMBER } @$resultset );
393
    my $found = $resultset && grep( { $_->{cardnumber} && $_->{cardnumber} eq $CARDNUMBER } @$resultset );
449
- 

Return to bug 37845