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

(-)a/Koha/Item/LastPatrons.pm (+41 lines)
Lines 22-27 use Carp; Link Here
22
use Koha::Item::LastPatron;
22
use Koha::Item::LastPatron;
23
23
24
use Koha::Database;
24
use Koha::Database;
25
use Koha::DateUtils;
25
26
26
use base qw(Koha::Objects);
27
use base qw(Koha::Objects);
27
28
Lines 35-40 Koha::Item::LastPatrons - Koha Item LastPatron Object set class Link Here
35
36
36
=cut
37
=cut
37
38
39
=head3 anonymise_items_last_borrower
40
41
    Koha::Patrons->search->anonymise_items_last_borrower( { [ before => $older_than_date ] } );
42
43
Anonymise last borrower history (items_last_borrower) for all patrons older than the given date (optional).
44
To make sure all the conditions are met, the caller has the responsibility to
45
call search_patrons_to_anonymise to filter the Koha::Patrons set
46
47
=cut
48
49
sub anonymise_items_last_borrower {
50
    my ( $self, $params ) = @_;
51
52
    my $older_than_date = $params->{before};
53
54
    $older_than_date = dt_from_string $older_than_date if $older_than_date;
55
56
    # The default of 0 does not work due to foreign key constraints
57
    # The anonymisation should not fail quietly if AnonymousPatron is not a valid entry
58
    # Set it to undef (NULL)
59
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
60
    my $nb_rows = 0;
61
    my $last_borrowers = $self->search(
62
        {
63
            (
64
                $older_than_date
65
                ? ( created_on =>
66
                      { '<' => $dtf->format_datetime($older_than_date) } )
67
                : ()
68
            )
69
        }
70
    );
71
    my $anonymous_patron = C4::Context->preference('AnonymousPatron') || undef;
72
    while(my $last_borrower = $last_borrowers->next) {
73
        $last_borrower->borrowernumber( $anonymous_patron )->store;
74
        $nb_rows++;
75
    }
76
    return $nb_rows;
77
}
78
38
=head3 type
79
=head3 type
39
80
40
=cut
81
=cut
(-)a/Koha/Patrons.pm (-74 / +13 lines)
Lines 130-136 sub search_upcoming_membership_expires { Link Here
130
130
131
=head3 search_patrons_to_anonymise
131
=head3 search_patrons_to_anonymise
132
132
133
    my $patrons = Koha::Patrons->search_patrons_to_anonymise( { before => $older_than_date, [ library => $library, for => $table_to_anonymize ] } );
133
    my $patrons = Koha::Patrons->search_patrons_to_anonymise( { before => $older_than_date, [ library => $library ] } );
134
134
135
This method returns all patrons who has an issue history older than a given date.
135
This method returns all patrons who has an issue history older than a given date.
136
136
Lines 140-146 sub search_patrons_to_anonymise { Link Here
140
    my ( $class, $params ) = @_;
140
    my ( $class, $params ) = @_;
141
    my $older_than_date = $params->{before};
141
    my $older_than_date = $params->{before};
142
    my $library         = $params->{library};
142
    my $library         = $params->{library};
143
    my $for           = $params->{for};
143
144
    $older_than_date = $older_than_date ? dt_from_string($older_than_date) : dt_from_string;
144
    $older_than_date = $older_than_date ? dt_from_string($older_than_date) : dt_from_string;
145
    $library ||=
145
    $library ||=
146
      ( C4::Context->preference('IndependentBranches') && C4::Context->userenv && !C4::Context->IsSuperLibrarian() && C4::Context->userenv->{branch} )
146
      ( C4::Context->preference('IndependentBranches') && C4::Context->userenv && !C4::Context->IsSuperLibrarian() && C4::Context->userenv->{branch} )
Lines 149-183 sub search_patrons_to_anonymise { Link Here
149
    my $anonymous_patron = C4::Context->preference('AnonymousPatron') || undef;
149
    my $anonymous_patron = C4::Context->preference('AnonymousPatron') || undef;
150
150
151
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
151
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
152
    my $rs;
152
    my $rs = $class->_resultset->search(
153
    if($for && $for eq 'items_last_borrower') {
153
        {   returndate                  => { '<'   =>  $dtf->format_datetime($older_than_date), },
154
        $rs = $class->_resultset->search(
154
            'old_issues.borrowernumber' => { 'not' => undef },
155
            {   'items_last_borrowers.created_on' => { '<'   =>  $dtf->format_datetime($older_than_date), },
155
            privacy                     => { '<>'  => 0 },                  # Keep forever
156
                'items_last_borrowers.borrowernumber' => { 'not' => undef },
156
            ( $library ? ( 'old_issues.branchcode' => $library ) : () ),
157
                'itemnumber.damaged' => 0,
157
            ( $anonymous_patron ? ( 'old_issues.borrowernumber' => { '!=' => $anonymous_patron } ) : () ),
158
                'itemnumber.itemlost' => 0,
158
        },
159
                'itemnumber.withdrawn' => 0,
159
        {   join     => ["old_issues"],
160
                ( $library ? ( 'itemnumber.homebranch' => $library ) : () ),
160
            distinct => 1,
161
                ( $anonymous_patron ? ( 'items_last_borrowers.borrowernumber' => { '!=' => $anonymous_patron } ) : () ),
161
        }
162
            },
162
    );
163
            {   join     => { "items_last_borrowers" => "itemnumber" },
164
                distinct => 1,
165
            }
166
        );
167
    } else {
168
        #for old_issues
169
        $rs = $class->_resultset->search(
170
            {   returndate                  => { '<'   =>  $dtf->format_datetime($older_than_date), },
171
                'old_issues.borrowernumber' => { 'not' => undef },
172
                privacy                     => { '<>'  => 0 },                  # Keep forever
173
                ( $library ? ( 'old_issues.branchcode' => $library ) : () ),
174
                ( $anonymous_patron ? ( 'old_issues.borrowernumber' => { '!=' => $anonymous_patron } ) : () ),
175
            },
176
            {   join     => ["old_issues"],
177
                distinct => 1,
178
            }
179
        );
180
    }
181
    return Koha::Patrons->_new_from_dbic($rs);
163
    return Koha::Patrons->_new_from_dbic($rs);
182
}
164
}
183
165
Lines 220-268 sub anonymise_issue_history { Link Here
220
    return $nb_rows;
202
    return $nb_rows;
221
}
203
}
222
204
223
=head3 anonymise_items_last_borrower
224
225
    Koha::Patrons->search->anonymise_items_last_borrower( { [ before => $older_than_date ] } );
226
227
Anonymise last borrower history (items_last_borrower) for all patrons older than the given date (optional).
228
To make sure all the conditions are met, the caller has the responsibility to
229
call search_patrons_to_anonymise to filter the Koha::Patrons set
230
231
=cut
232
233
sub anonymise_items_last_borrower {
234
    my ( $self, $params ) = @_;
235
236
    my $older_than_date = $params->{before};
237
238
    $older_than_date = dt_from_string $older_than_date if $older_than_date;
239
240
    # The default of 0 does not work due to foreign key constraints
241
    # The anonymisation should not fail quietly if AnonymousPatron is not a valid entry
242
    # Set it to undef (NULL)
243
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
244
    my $nb_rows = 0;
245
    while ( my $patron = $self->next ) {
246
        my $last_borrowers = Koha::Item::LastPatrons->search(
247
        {
248
            borrowernumber => $patron->borrowernumber,
249
            (
250
                $older_than_date
251
                ? ( created_on =>
252
                      { '<' => $dtf->format_datetime($older_than_date) } )
253
                : ()
254
            )
255
        }
256
        );
257
        my $anonymous_patron = C4::Context->preference('AnonymousPatron') || undef;
258
        while(my $last_borrower = $last_borrowers->next) {
259
            $last_borrower->borrowernumber( $anonymous_patron )->store;
260
            $nb_rows++;
261
        }
262
    }
263
    return $nb_rows;
264
}
265
266
=head3 delete
205
=head3 delete
267
206
268
    Koha::Patrons->search({ some filters here })->delete({ move => 1, verbose => 1 });
207
    Koha::Patrons->search({ some filters here })->delete({ move => 1, verbose => 1 });
(-)a/misc/cronjobs/batch_anonymise.pl (-1 / +2 lines)
Lines 32-37 BEGIN { Link Here
32
use Koha::Script -cron;
32
use Koha::Script -cron;
33
use C4::Context;
33
use C4::Context;
34
use Koha::Patrons;
34
use Koha::Patrons;
35
use Koha::Item::LastPatrons;
35
use Date::Calc qw(
36
use Date::Calc qw(
36
  Today
37
  Today
37
  Add_Delta_Days
38
  Add_Delta_Days
Lines 78-84 $verbose and print "Checkouts and items last borrowers before $formatdate will b Link Here
78
my $rows = Koha::Patrons->search_patrons_to_anonymise( { before => $formatdate } )->anonymise_issue_history( { before => $formatdate } );
79
my $rows = Koha::Patrons->search_patrons_to_anonymise( { before => $formatdate } )->anonymise_issue_history( { before => $formatdate } );
79
$verbose and print int($rows) . " checkouts anonymised.\n";
80
$verbose and print int($rows) . " checkouts anonymised.\n";
80
81
81
$rows = Koha::Patrons->search_patrons_to_anonymise( { before => $formatdate , for => 'items_last_borrower'} )->anonymise_items_last_borrower( { before => $formatdate } );
82
$rows = Koha::Item::LastPatrons->anonymise_items_last_borrower( { before => $formatdate } );
82
$verbose and print int($rows) . " items last borrower anonymised.\n";
83
$verbose and print int($rows) . " items last borrower anonymised.\n";
83
84
84
exit(0);
85
exit(0);
(-)a/t/db_dependent/Koha/Patrons.t (-37 / +4 lines)
Lines 36-41 use Koha::ActionLogs; Link Here
36
use Koha::Holds;
36
use Koha::Holds;
37
use Koha::Old::Holds;
37
use Koha::Old::Holds;
38
use Koha::Patrons;
38
use Koha::Patrons;
39
use Koha::Item::LastPatrons;
39
use Koha::Patron::Categories;
40
use Koha::Patron::Categories;
40
use Koha::Patron::Relationship;
41
use Koha::Patron::Relationship;
41
use Koha::Database;
42
use Koha::Database;
Lines 1181-1187 subtest 'search_patrons_to_anonymise & anonymise_issue_history' => sub { Link Here
1181
};
1182
};
1182
1183
1183
subtest 'search_patrons_to_anonymise & anonymise_items_last_borrower' => sub {
1184
subtest 'search_patrons_to_anonymise & anonymise_items_last_borrower' => sub {
1184
    plan tests => 3;
1185
    plan tests => 2;
1185
1186
1186
    my $branch = $builder->build({ source => 'Branch' });
1187
    my $branch = $builder->build({ source => 'Branch' });
1187
    my $userenv_patron = $builder->build_object({
1188
    my $userenv_patron = $builder->build_object({
Lines 1224-1230 subtest 'search_patrons_to_anonymise & anonymise_items_last_borrower' => sub { Link Here
1224
        my ( $returned, undef, undef ) = C4::Circulation::AddReturn( $item->{barcode}, undef, undef, $now );
1225
        my ( $returned, undef, undef ) = C4::Circulation::AddReturn( $item->{barcode}, undef, undef, $now );
1225
        is( $returned, 1, 'The item should have been returned' );
1226
        is( $returned, 1, 'The item should have been returned' );
1226
        my $before = $now + DateTime::Duration->new( days => 1 );
1227
        my $before = $now + DateTime::Duration->new( days => 1 );
1227
        my $rows_affected = Koha::Patrons->search_patrons_to_anonymise( { before => $before->ymd, for => 'items_last_borrower' } )->anonymise_items_last_borrower( { before => $before->ymd } );
1228
        my $rows_affected = Koha::Item::LastPatrons->anonymise_items_last_borrower( { before => $before->ymd } );
1228
        ok( $rows_affected > 0, 'AnonymiseIssueHistory should affect at least 1 row' );
1229
        ok( $rows_affected > 0, 'AnonymiseIssueHistory should affect at least 1 row' );
1229
        my $dbh = C4::Context->dbh;
1230
        my $dbh = C4::Context->dbh;
1230
        my ($borrowernumber_used_to_anonymised) = $dbh->selectrow_array(q|
1231
        my ($borrowernumber_used_to_anonymised) = $dbh->selectrow_array(q|
Lines 1267-1273 subtest 'search_patrons_to_anonymise & anonymise_items_last_borrower' => sub { Link Here
1267
        my ( $returned, undef, undef ) = C4::Circulation::AddReturn( $item->{barcode}, undef, undef, $now );
1268
        my ( $returned, undef, undef ) = C4::Circulation::AddReturn( $item->{barcode}, undef, undef, $now );
1268
        is( $returned, 1, 'The item should have been returned' );
1269
        is( $returned, 1, 'The item should have been returned' );
1269
        my $before = $now + DateTime::Duration->new( days => 1 );
1270
        my $before = $now + DateTime::Duration->new( days => 1 );
1270
        my $rows_affected = Koha::Patrons->search_patrons_to_anonymise( { before => $before->ymd, for => 'items_last_borrower' } )->anonymise_items_last_borrower( { before => $before->ymd } );
1271
        my $rows_affected = Koha::Item::LastPatrons->anonymise_items_last_borrower( { before => $before->ymd } );
1271
        ok( $rows_affected > 0, 'AnonymiseIssueHistory should affect at least 1 row' );
1272
        ok( $rows_affected > 0, 'AnonymiseIssueHistory should affect at least 1 row' );
1272
        my $dbh = C4::Context->dbh;
1273
        my $dbh = C4::Context->dbh;
1273
        my ($borrowernumber_used_to_anonymised) = $dbh->selectrow_array(q|
1274
        my ($borrowernumber_used_to_anonymised) = $dbh->selectrow_array(q|
Lines 1277-1315 subtest 'search_patrons_to_anonymise & anonymise_items_last_borrower' => sub { Link Here
1277
        Koha::Patrons->find( $patron->{borrowernumber})->delete;
1278
        Koha::Patrons->find( $patron->{borrowernumber})->delete;
1278
    };
1279
    };
1279
1280
1280
    subtest 'Logged in librarian is not superlibrarian & IndependentBranches' => sub {
1281
        plan tests => 1;
1282
        t::lib::Mocks::mock_preference( 'IndependentBranches', 1 );
1283
        my $patron = $builder->build(
1284
            {   source => 'Borrower',
1285
                value  => { privacy => 1 }    # Another branchcode than the logged in librarian
1286
            }
1287
        );
1288
        my $item = $builder->build(
1289
            {   source => 'Item',
1290
                value  => {
1291
                    itemlost  => 0,
1292
                    withdrawn => 0,
1293
                    damaged => 0
1294
                },
1295
            }
1296
        );
1297
        my $issue = $builder->build(
1298
            {   source => 'Issue',
1299
                value  => {
1300
                    borrowernumber => $patron->{borrowernumber},
1301
                    itemnumber     => $item->{itemnumber},
1302
                },
1303
            }
1304
        );
1305
1306
        my $now = DateTime->now;
1307
        my ( $returned, undef, undef ) = C4::Circulation::AddReturn( $item->{barcode}, undef, undef, $now );
1308
        my $before = $now + DateTime::Duration->new( days => 1 );
1309
        is( Koha::Patrons->search_patrons_to_anonymise( { before => $before->ymd, for => 'items_last_borrower' } )->count, 0 );
1310
        Koha::Patrons->find( $patron->{borrowernumber})->delete;
1311
    };
1312
1313
    $userenv_patron->delete;
1281
    $userenv_patron->delete;
1314
    t::lib::Mocks::mock_preference('StoreLastBorrower', 0);
1282
    t::lib::Mocks::mock_preference('StoreLastBorrower', 0);
1315
    t::lib::Mocks::mock_preference('IndependentBranches', 0);
1283
    t::lib::Mocks::mock_preference('IndependentBranches', 0);
1316
- 

Return to bug 23260