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

(-)a/Koha/Patron.pm (+75 lines)
Lines 41-46 use Koha::Account; Link Here
41
41
42
use base qw(Koha::Object);
42
use base qw(Koha::Object);
43
43
44
our $RESULTSET_PATRON_ID_MAPPING = {
45
    Accountline          => 'borrowernumber',
46
    ArticleRequest       => 'borrowernumber',
47
    BorrowerAttribute    => 'borrowernumber',
48
    BorrowerDebarment    => 'borrowernumber',
49
    BorrowerFile         => 'borrowernumber',
50
    BorrowerModification => 'borrowernumber',
51
    ClubEnrollment       => 'borrowernumber',
52
    Issue                => 'borrowernumber',
53
    ItemsLastBorrower    => 'borrowernumber',
54
    Linktracker          => 'borrowernumber',
55
    Message              => 'borrowernumber',
56
    MessageQueue         => 'borrowernumber',
57
    OldIssue             => 'borrowernumber',
58
    OldReserve           => 'borrowernumber',
59
    Rating               => 'borrowernumber',
60
    Reserve              => 'borrowernumber',
61
    Review               => 'borrowernumber',
62
    Statistic            => 'borrowernumber',
63
    SearchHistory        => 'userid',
64
    Suggestion           => 'suggestedby',
65
    TagAll               => 'borrowernumber',
66
    Virtualshelfcontent  => 'borrowernumber',
67
    Virtualshelfshare    => 'borrowernumber',
68
    Virtualshelve        => 'owner',
69
};
70
44
=head1 NAME
71
=head1 NAME
45
72
46
Koha::Patron - Koha Patron Object class
73
Koha::Patron - Koha Patron Object class
Lines 200-205 sub siblings { Link Here
200
    );
227
    );
201
}
228
}
202
229
230
=head3 merge_with
231
232
    my $patron = Koha::Patrons->find($id);
233
    $patron->merge_with( \@patron_ids );
234
235
    This subroutine merges a list of patrons into the patron record. This is accomplished by finding
236
    all related patron ids for the patrons to be merged in other tables and changing the ids to be that
237
    of the keeper patron.
238
239
=cut
240
241
sub merge_with {
242
    my ( $self, $patron_ids ) = @_;
243
244
    my @patron_ids = @{ $patron_ids };
245
246
    # Ensure the keeper isn't in the list of patrons to merge
247
    @patron_ids = grep { $_ ne $self->id } @patron_ids;
248
249
    my $schema = Koha::Database->new()->schema();
250
251
    my $results;
252
253
    $self->_result->result_source->schema->txn_do( sub {
254
        foreach my $patron_id (@patron_ids) {
255
            my $patron = Koha::Patrons->find( $patron_id );
256
257
            next unless $patron;
258
259
            # Unbless for safety, the patron will end up being deleted
260
            $results->{merged}->{$patron_id}->{patron} = $patron->unblessed;
261
262
            while (my ($r, $field) = each(%$RESULTSET_PATRON_ID_MAPPING)) {
263
                my $rs = $schema->resultset($r)->search({ $field => $patron_id });
264
                $results->{merged}->{ $patron_id }->{updated}->{$r} = $rs->count();
265
                $rs->update({ $field => $self->id });
266
            }
267
268
            $patron->move_to_deleted();
269
            $patron->delete();
270
        }
271
    });
272
273
    return $results;
274
}
275
276
277
203
=head3 wants_check_for_previous_checkout
278
=head3 wants_check_for_previous_checkout
204
279
205
    $wants_check = $patron->wants_check_for_previous_checkout;
280
    $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 => 27;
22
use Test::More tests => 28;
23
use Test::Warn;
23
use Test::Warn;
24
use Time::Fake;
24
use Time::Fake;
25
use DateTime;
25
use DateTime;
Lines 1217-1225 subtest 'Log cardnumber change' => sub { Link Here
1217
    is( scalar @logs, 2, 'With BorrowerLogs, Change in cardnumber should be logged, as well as general alert of patron mod.' );
1217
    is( scalar @logs, 2, 'With BorrowerLogs, Change in cardnumber should be logged, as well as general alert of patron mod.' );
1218
};
1218
};
1219
1219
1220
1221
$schema->storage->txn_rollback;
1220
$schema->storage->txn_rollback;
1222
1221
1222
subtest 'Test Koha::Patrons::merge' => sub {
1223
    plan tests => 98;
1224
1225
    my $schema = Koha::Database->new()->schema();
1226
1227
    my $resultsets = $Koha::Patron::RESULTSET_PATRON_ID_MAPPING;
1228
1229
    $schema->storage->txn_begin;
1230
1231
    my $keeper  = $builder->build_object({ class => 'Koha::Patrons' });
1232
    my $loser_1 = $builder->build({ source => 'Borrower' })->{borrowernumber};
1233
    my $loser_2 = $builder->build({ source => 'Borrower' })->{borrowernumber};
1234
1235
    while (my ($r, $field) = each(%$resultsets)) {
1236
        $builder->build({ source => $r, value => { $field => $keeper->id } });
1237
        $builder->build({ source => $r, value => { $field => $loser_1 } });
1238
        $builder->build({ source => $r, value => { $field => $loser_2 } });
1239
1240
        my $keeper_rs =
1241
          $schema->resultset($r)->search( { $field => $keeper->id } );
1242
        is( $keeper_rs->count(), 1, "Found 1 $r rows for keeper" );
1243
1244
        my $loser_1_rs =
1245
          $schema->resultset($r)->search( { $field => $loser_1 } );
1246
        is( $loser_1_rs->count(), 1, "Found 1 $r rows for loser_1" );
1247
1248
        my $loser_2_rs =
1249
          $schema->resultset($r)->search( { $field => $loser_2 } );
1250
        is( $loser_2_rs->count(), 1, "Found 1 $r rows for loser_2" );
1251
    }
1252
1253
    my $results = $keeper->merge_with([ $loser_1, $loser_2 ]);
1254
1255
    while (my ($r, $field) = each(%$resultsets)) {
1256
        my $keeper_rs =
1257
          $schema->resultset($r)->search( {$field => $keeper->id } );
1258
        is( $keeper_rs->count(), 3, "Found 2 $r rows for keeper" );
1259
    }
1260
1261
    is( Koha::Patrons->find($loser_1), undef, 'Loser 1 has been deleted' );
1262
    is( Koha::Patrons->find($loser_2), undef, 'Loser 2 has been deleted' );
1263
1264
    $schema->storage->txn_rollback;
1265
};
1266
1223
# TODO Move to t::lib::Mocks and reuse it!
1267
# TODO Move to t::lib::Mocks and reuse it!
1224
sub set_logged_in_user {
1268
sub set_logged_in_user {
1225
    my ($patron) = @_;
1269
    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