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

(-)a/Koha/Patron.pm (+75 lines)
Lines 42-47 use Koha::Account; Link Here
42
42
43
use base qw(Koha::Object);
43
use base qw(Koha::Object);
44
44
45
our $RESULTSET_PATRON_ID_MAPPING = {
46
    Accountline          => 'borrowernumber',
47
    ArticleRequest       => 'borrowernumber',
48
    BorrowerAttribute    => 'borrowernumber',
49
    BorrowerDebarment    => 'borrowernumber',
50
    BorrowerFile         => 'borrowernumber',
51
    BorrowerModification => 'borrowernumber',
52
    ClubEnrollment       => 'borrowernumber',
53
    Issue                => 'borrowernumber',
54
    ItemsLastBorrower    => 'borrowernumber',
55
    Linktracker          => 'borrowernumber',
56
    Message              => 'borrowernumber',
57
    MessageQueue         => 'borrowernumber',
58
    OldIssue             => 'borrowernumber',
59
    OldReserve           => 'borrowernumber',
60
    Rating               => 'borrowernumber',
61
    Reserve              => 'borrowernumber',
62
    Review               => 'borrowernumber',
63
    Statistic            => 'borrowernumber',
64
    SearchHistory        => 'userid',
65
    Suggestion           => 'suggestedby',
66
    TagAll               => 'borrowernumber',
67
    Virtualshelfcontent  => 'borrowernumber',
68
    Virtualshelfshare    => 'borrowernumber',
69
    Virtualshelve        => 'owner',
70
};
71
45
=head1 NAME
72
=head1 NAME
46
73
47
Koha::Patron - Koha Patron Object class
74
Koha::Patron - Koha Patron Object class
Lines 201-206 sub siblings { Link Here
201
    );
228
    );
202
}
229
}
203
230
231
=head3 merge_with
232
233
    my $patron = Koha::Patrons->find($id);
234
    $patron->merge_with( \@patron_ids );
235
236
    This subroutine merges a list of patrons into the patron record. This is accomplished by finding
237
    all related patron ids for the patrons to be merged in other tables and changing the ids to be that
238
    of the keeper patron.
239
240
=cut
241
242
sub merge_with {
243
    my ( $self, $patron_ids ) = @_;
244
245
    my @patron_ids = @{ $patron_ids };
246
247
    # Ensure the keeper isn't in the list of patrons to merge
248
    @patron_ids = grep { $_ ne $self->id } @patron_ids;
249
250
    my $schema = Koha::Database->new()->schema();
251
252
    my $results;
253
254
    $self->_result->result_source->schema->txn_do( sub {
255
        foreach my $patron_id (@patron_ids) {
256
            my $patron = Koha::Patrons->find( $patron_id );
257
258
            next unless $patron;
259
260
            # Unbless for safety, the patron will end up being deleted
261
            $results->{merged}->{$patron_id}->{patron} = $patron->unblessed;
262
263
            while (my ($r, $field) = each(%$RESULTSET_PATRON_ID_MAPPING)) {
264
                my $rs = $schema->resultset($r)->search({ $field => $patron_id });
265
                $results->{merged}->{ $patron_id }->{updated}->{$r} = $rs->count();
266
                $rs->update({ $field => $self->id });
267
            }
268
269
            $patron->move_to_deleted();
270
            $patron->delete();
271
        }
272
    });
273
274
    return $results;
275
}
276
277
278
204
=head3 wants_check_for_previous_checkout
279
=head3 wants_check_for_previous_checkout
205
280
206
    $wants_check = $patron->wants_check_for_previous_checkout;
281
    $wants_check = $patron->wants_check_for_previous_checkout;
(-)a/Koha/Patrons.pm (-79 / +1 lines)
Lines 31-63 use Koha::Patron; Link Here
31
31
32
use base qw(Koha::Objects);
32
use base qw(Koha::Objects);
33
33
34
our $RESULTSET_PATRON_ID_MAPPING = {
35
    Accountline          => 'borrowernumber',
36
    ArticleRequest       => 'borrowernumber',
37
    BorrowerAttribute    => 'borrowernumber',
38
    BorrowerDebarment    => 'borrowernumber',
39
    BorrowerFile         => 'borrowernumber',
40
    BorrowerModification => 'borrowernumber',
41
    ClubEnrollment       => 'borrowernumber',
42
    Issue                => 'borrowernumber',
43
    ItemsLastBorrower    => 'borrowernumber',
44
    Linktracker          => 'borrowernumber',
45
    Message              => 'borrowernumber',
46
    MessageQueue         => 'borrowernumber',
47
    OldIssue             => 'borrowernumber',
48
    OldReserve           => 'borrowernumber',
49
    Rating               => 'borrowernumber',
50
    Reserve              => 'borrowernumber',
51
    Review               => 'borrowernumber',
52
    Statistic            => 'borrowernumber',
53
    SearchHistory        => 'userid',
54
    Suggestion           => 'suggestedby',
55
    TagAll               => 'borrowernumber',
56
    Virtualshelfcontent  => 'borrowernumber',
57
    Virtualshelfshare    => 'borrowernumber',
58
    Virtualshelve        => 'owner',
59
};
60
61
=head1 NAME
34
=head1 NAME
62
35
63
Koha::Patron - Koha Patron Object class
36
Koha::Patron - Koha Patron Object class
Lines 234-291 sub anonymise_issue_history { Link Here
234
    return $nb_rows;
207
    return $nb_rows;
235
}
208
}
236
209
237
=head3 merge
210
=head3 _type
238
239
    Koha::Patrons->search->merge( { keeper => $borrowernumber, patrons => \@borrowernumbers } );
240
241
    This subroutine merges a list of patrons into another patron record. This is accomplished by finding
242
    all related patron ids for the patrons to be merged in other tables and changing the ids to be that
243
    of the keeper patron.
244
245
=cut
246
247
sub merge {
248
    my ( $self, $params ) = @_;
249
250
    my $keeper          = $params->{keeper};
251
    my @borrowernumbers = @{ $params->{patrons} };
252
253
    my $patron_to_keep = Koha::Patrons->find( $keeper );
254
    return unless $patron_to_keep;
255
256
    # Ensure the keeper isn't in the list of patrons to merge
257
    @borrowernumbers = grep { $_ ne $keeper } @borrowernumbers;
258
259
    my $schema = Koha::Database->new()->schema();
260
261
    my $results;
262
263
    $self->_resultset->result_source->schema->txn_do( sub {
264
        foreach my $borrowernumber (@borrowernumbers) {
265
            my $patron = Koha::Patrons->find( $borrowernumber );
266
267
            next unless $patron;
268
269
            # Unbless for safety, the patron will end up being deleted
270
            $results->{merged}->{$borrowernumber}->{patron} = $patron->unblessed;
271
272
            while (my ($r, $field) = each(%$RESULTSET_PATRON_ID_MAPPING)) {
273
                my $rs = $schema->resultset($r)->search({ $field => $borrowernumber} );
274
                $results->{merged}->{ $borrowernumber }->{updated}->{$r} = $rs->count();
275
                $rs->update( { $field => $keeper });
276
            }
277
278
            $patron->move_to_deleted();
279
            $patron->delete();
280
        }
281
    });
282
283
    $results->{keeper} = $patron_to_keep;
284
285
    return $results;
286
}
287
288
=head3 type
289
211
290
=cut
212
=cut
291
213
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/merge-patrons.tt (-1 / +1 lines)
Lines 108-114 $(document).ready(function() { Link Here
108
                    <div class="dialog alert">Merge failed! The following error was reported: [% error %].</div>
108
                    <div class="dialog alert">Merge failed! The following error was reported: [% error %].</div>
109
                [% ELSE %]
109
                [% ELSE %]
110
                    <p>
110
                    <p>
111
                        Patron records merged into <a href="moremember.pl?borrowernumber=[% results.keeper.id %]">[% results.keeper.firstname %] [% results.keeper.surname %] ([% results.keeper.cardnumber | html %])</a>
111
                        Patron records merged into <a href="moremember.pl?borrowernumber=[% keeper.id %]">[% keeper.firstname %] [% keeper.surname %] ([% keeper.cardnumber | html %])</a>
112
                    </p>
112
                    </p>
113
113
114
                    [% FOREACH pair IN results.merged.pairs %]
114
                    [% FOREACH pair IN results.merged.pairs %]
(-)a/members/merge-patrons.pl (-11 / +16 lines)
Lines 19-24 Link Here
19
use Modern::Perl;
19
use Modern::Perl;
20
20
21
use CGI qw ( -utf8 );
21
use CGI qw ( -utf8 );
22
use Try::Tiny;
22
23
23
use C4::Auth;
24
use C4::Auth;
24
use C4::Output;
25
use C4::Output;
Lines 33-58 my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( Link Here
33
        query           => $cgi,
34
        query           => $cgi,
34
        type            => "intranet",
35
        type            => "intranet",
35
        authnotrequired => 0,
36
        authnotrequired => 0,
36
        flagsrequired   => { borrowers => 1 },
37
        flagsrequired   => { borrowers => 1 }
37
        debug           => 1,
38
    }
38
    }
39
);
39
);
40
40
41
my $action = $cgi->param('action') || 'show';
41
my $action = $cgi->param('action') || 'show';
42
my @ids = $cgi->multi_param('id');
42
my @ids    = $cgi->multi_param('id');
43
43
44
if ( $action eq 'show' ) {
44
if ( $action eq 'show' ) {
45
    my $patrons =
45
    my $patrons = Koha::Patrons->search({ borrowernumber => { -in => \@ids } });
46
      Koha::Patrons->search( { borrowernumber => { -in => \@ids } } );
47
    $template->param( patrons => $patrons );
46
    $template->param( patrons => $patrons );
48
} elsif ( $action eq 'merge' ) {
47
} elsif ( $action eq 'merge' ) {
49
    my $keeper = $cgi->param('keeper');
48
    my $keeper_id = $cgi->param('keeper');
50
    my $results;
49
    my $results;
51
    eval { $results = Koha::Patrons->merge( { keeper => $keeper, patrons => \@ids } ); };
50
52
    if ($@) {
51
    try {
53
        $template->param( results => $results );
52
        my $keeper = Koha::Patrons->find( $keeper_id );
54
    } else {
53
        $results = $keeper->merge_with( \@ids );
55
        $template->param( error => $@ );
54
        $template->param(
55
            keeper  => $keeper,
56
            results => $results
57
        );
58
    }
59
    catch {
60
        $template->param( error => $_ );
56
    }
61
    }
57
}
62
}
58
63
(-)a/t/db_dependent/Koha/Patrons.t (-2 / +46 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 29;
22
use Test::More tests => 30;
23
use Test::Warn;
23
use Test::Warn;
24
use Time::Fake;
24
use Time::Fake;
25
use DateTime;
25
use DateTime;
Lines 1334-1342 subtest 'Log cardnumber change' => sub { Link Here
1334
    is( scalar @logs, 2, 'With BorrowerLogs, Change in cardnumber should be logged, as well as general alert of patron mod.' );
1334
    is( scalar @logs, 2, 'With BorrowerLogs, Change in cardnumber should be logged, as well as general alert of patron mod.' );
1335
};
1335
};
1336
1336
1337
1338
$schema->storage->txn_rollback;
1337
$schema->storage->txn_rollback;
1339
1338
1339
subtest 'Test Koha::Patrons::merge' => sub {
1340
    plan tests => 98;
1341
1342
    my $schema = Koha::Database->new()->schema();
1343
1344
    my $resultsets = $Koha::Patron::RESULTSET_PATRON_ID_MAPPING;
1345
1346
    $schema->storage->txn_begin;
1347
1348
    my $keeper  = $builder->build_object({ class => 'Koha::Patrons' });
1349
    my $loser_1 = $builder->build({ source => 'Borrower' })->{borrowernumber};
1350
    my $loser_2 = $builder->build({ source => 'Borrower' })->{borrowernumber};
1351
1352
    while (my ($r, $field) = each(%$resultsets)) {
1353
        $builder->build({ source => $r, value => { $field => $keeper->id } });
1354
        $builder->build({ source => $r, value => { $field => $loser_1 } });
1355
        $builder->build({ source => $r, value => { $field => $loser_2 } });
1356
1357
        my $keeper_rs =
1358
          $schema->resultset($r)->search( { $field => $keeper->id } );
1359
        is( $keeper_rs->count(), 1, "Found 1 $r rows for keeper" );
1360
1361
        my $loser_1_rs =
1362
          $schema->resultset($r)->search( { $field => $loser_1 } );
1363
        is( $loser_1_rs->count(), 1, "Found 1 $r rows for loser_1" );
1364
1365
        my $loser_2_rs =
1366
          $schema->resultset($r)->search( { $field => $loser_2 } );
1367
        is( $loser_2_rs->count(), 1, "Found 1 $r rows for loser_2" );
1368
    }
1369
1370
    my $results = $keeper->merge_with([ $loser_1, $loser_2 ]);
1371
1372
    while (my ($r, $field) = each(%$resultsets)) {
1373
        my $keeper_rs =
1374
          $schema->resultset($r)->search( {$field => $keeper->id } );
1375
        is( $keeper_rs->count(), 3, "Found 2 $r rows for keeper" );
1376
    }
1377
1378
    is( Koha::Patrons->find($loser_1), undef, 'Loser 1 has been deleted' );
1379
    is( Koha::Patrons->find($loser_2), undef, 'Loser 2 has been deleted' );
1380
1381
    $schema->storage->txn_rollback;
1382
};
1383
1340
# TODO Move to t::lib::Mocks and reuse it!
1384
# TODO Move to t::lib::Mocks and reuse it!
1341
sub set_logged_in_user {
1385
sub set_logged_in_user {
1342
    my ($patron) = @_;
1386
    my ($patron) = @_;
(-)a/t/db_dependent/Patrons.t (-48 / +1 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 18;
20
use Test::More tests => 17;
21
use Test::Warn;
21
use Test::Warn;
22
22
23
use C4::Context;
23
use C4::Context;
Lines 104-154 foreach my $b ( $patrons->as_list() ) { Link Here
104
    is( $b->categorycode(), $categorycode, "Iteration returns a patron object" );
104
    is( $b->categorycode(), $categorycode, "Iteration returns a patron object" );
105
}
105
}
106
106
107
subtest 'Test Koha::Patrons::merge' => sub {
108
    plan tests => 98;
109
110
    my $schema = Koha::Database->new()->schema();
111
112
    my $resultsets = $Koha::Patrons::RESULTSET_PATRON_ID_MAPPING;
113
114
    my $keeper  = $builder->build( { source => 'Borrower' } )->{borrowernumber};
115
    my $loser_1 = $builder->build( { source => 'Borrower' } )->{borrowernumber};
116
    my $loser_2 = $builder->build( { source => 'Borrower' } )->{borrowernumber};
117
118
    while (my ($r, $field) = each(%$resultsets)) {
119
        $builder->build( { source => $r, value => { $field => $keeper } } );
120
        $builder->build( { source => $r, value => { $field => $loser_1 } } );
121
        $builder->build( { source => $r, value => { $field => $loser_2 } } );
122
123
        my $keeper_rs =
124
          $schema->resultset($r)->search( { $field => $keeper } );
125
        is( $keeper_rs->count(), 1, "Found 1 $r rows for keeper" );
126
127
        my $loser_1_rs =
128
          $schema->resultset($r)->search( { $field => $loser_1 } );
129
        is( $loser_1_rs->count(), 1, "Found 1 $r rows for loser_1" );
130
131
        my $loser_2_rs =
132
          $schema->resultset($r)->search( { $field => $loser_2 } );
133
        is( $loser_2_rs->count(), 1, "Found 1 $r rows for loser_2" );
134
    }
135
136
    my $results = Koha::Patrons->merge(
137
        {
138
            keeper  => $keeper,
139
            patrons => [ $loser_1, $loser_2 ],
140
        }
141
    );
142
143
    while (my ($r, $field) = each(%$resultsets)) {
144
        my $keeper_rs =
145
          $schema->resultset($r)->search( {$field => $keeper } );
146
        is( $keeper_rs->count(), 3, "Found 2 $r rows for keeper" );
147
    }
148
149
    is( Koha::Patrons->find($loser_1), undef, 'Loser 1 has been deleted' );
150
    is( Koha::Patrons->find($loser_2), undef, 'Loser 2 has been deleted' );
151
};
152
153
$schema->storage->txn_rollback();
107
$schema->storage->txn_rollback();
154
108
155
- 

Return to bug 9302