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

(-)a/t/db_dependent/Koha/Patron/AccountLink.t (-1 / +385 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <https://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::NoWarnings;
21
use Test::More tests => 10;
22
use Test::Exception;
23
24
use Koha::Patron::AccountLink;
25
use Koha::Patron::AccountLinks;
26
use Koha::Database;
27
28
use t::lib::TestBuilder;
29
use t::lib::Mocks;
30
31
my $schema  = Koha::Database->new->schema;
32
my $builder = t::lib::TestBuilder->new;
33
34
subtest 'Basic CRUD operations' => sub {
35
    plan tests => 6;
36
37
    $schema->storage->txn_begin;
38
39
    my $patron1 = $builder->build_object( { class => 'Koha::Patrons' } );
40
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
41
    my $patron3 = $builder->build_object( { class => 'Koha::Patrons' } );
42
43
    my $link_group_id = Koha::Patron::AccountLinks->get_next_group_id();
44
45
    my $link1 = Koha::Patron::AccountLink->new(
46
        {
47
            link_group_id  => $link_group_id,
48
            borrowernumber => $patron1->borrowernumber,
49
        }
50
    )->store;
51
52
    ok( $link1->id, 'AccountLink created with id' );
53
    is( $link1->link_group_id, $link_group_id, 'link_group_id set correctly' );
54
55
    my $link2 = Koha::Patron::AccountLink->new(
56
        {
57
            link_group_id  => $link_group_id,
58
            borrowernumber => $patron2->borrowernumber,
59
        }
60
    )->store;
61
62
    my $link3 = Koha::Patron::AccountLink->new(
63
        {
64
            link_group_id  => $link_group_id,
65
            borrowernumber => $patron3->borrowernumber,
66
        }
67
    )->store;
68
69
    is(
70
        Koha::Patron::AccountLinks->search( { link_group_id => $link_group_id } )->count,
71
        3, 'Three links in same group'
72
    );
73
74
    # Delete one link - leaves 2, no orphan cleanup triggered
75
    $link1->delete;
76
    is(
77
        Koha::Patron::AccountLinks->search( { link_group_id => $link_group_id } )->count,
78
        2, 'Two links after deletion (no orphan cleanup with 2 remaining)'
79
    );
80
81
    my $retrieved = Koha::Patron::AccountLinks->find( $link2->id );
82
    is( $retrieved->borrowernumber, $patron2->borrowernumber, 'Can retrieve link by id' );
83
84
    # Delete another - triggers orphan cleanup since only 1 would remain
85
    $link2->delete;
86
    is(
87
        Koha::Patron::AccountLinks->search( { link_group_id => $link_group_id } )->count,
88
        0, 'No links after orphan cleanup (deleting from 2-patron group removes both)'
89
    );
90
91
    $schema->storage->txn_rollback;
92
};
93
94
subtest 'patron() method' => sub {
95
    plan tests => 2;
96
97
    $schema->storage->txn_begin;
98
99
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
100
    my $link   = Koha::Patron::AccountLink->new(
101
        {
102
            link_group_id  => Koha::Patron::AccountLinks->get_next_group_id(),
103
            borrowernumber => $patron->borrowernumber,
104
        }
105
    )->store;
106
107
    my $linked_patron = $link->patron;
108
    isa_ok( $linked_patron, 'Koha::Patron' );
109
    is( $linked_patron->borrowernumber, $patron->borrowernumber, 'patron() returns correct patron' );
110
111
    $schema->storage->txn_rollback;
112
};
113
114
subtest 'linked_patrons() method' => sub {
115
    plan tests => 4;
116
117
    $schema->storage->txn_begin;
118
119
    my $patron1 = $builder->build_object( { class => 'Koha::Patrons' } );
120
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
121
    my $patron3 = $builder->build_object( { class => 'Koha::Patrons' } );
122
123
    my $link_group_id = Koha::Patron::AccountLinks->get_next_group_id();
124
125
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron1->borrowernumber } )
126
        ->store;
127
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron2->borrowernumber } )
128
        ->store;
129
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron3->borrowernumber } )
130
        ->store;
131
132
    my $link1 = Koha::Patron::AccountLinks->find( { borrowernumber => $patron1->borrowernumber } );
133
134
    my $linked = $link1->linked_patrons;
135
    isa_ok( $linked, 'Koha::Patrons' );
136
    is( $linked->count, 2, 'linked_patrons returns 2 patrons (excludes self)' );
137
138
    my @linked_ids = $linked->get_column('borrowernumber');
139
    ok( ( grep { $_ == $patron2->borrowernumber } @linked_ids ), 'patron2 is in linked_patrons' );
140
    ok( ( grep { $_ == $patron3->borrowernumber } @linked_ids ), 'patron3 is in linked_patrons' );
141
142
    $schema->storage->txn_rollback;
143
};
144
145
subtest 'all_linked_borrowernumbers() method' => sub {
146
    plan tests => 2;
147
148
    $schema->storage->txn_begin;
149
150
    my $patron1 = $builder->build_object( { class => 'Koha::Patrons' } );
151
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
152
153
    my $link_group_id = Koha::Patron::AccountLinks->get_next_group_id();
154
155
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron1->borrowernumber } )
156
        ->store;
157
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron2->borrowernumber } )
158
        ->store;
159
160
    my $link1 = Koha::Patron::AccountLinks->find( { borrowernumber => $patron1->borrowernumber } );
161
    my $all   = $link1->all_linked_borrowernumbers;
162
163
    is( ref($all),     'ARRAY', 'Returns arrayref' );
164
    is( scalar(@$all), 2,       'Contains both borrowernumbers' );
165
166
    $schema->storage->txn_rollback;
167
};
168
169
subtest 'get_next_group_id() class method' => sub {
170
    plan tests => 3;
171
172
    $schema->storage->txn_begin;
173
174
    my $first_id = Koha::Patron::AccountLinks->get_next_group_id();
175
    ok( $first_id >= 1, 'get_next_group_id returns positive integer' );
176
177
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
178
    Koha::Patron::AccountLink->new( { link_group_id => $first_id, borrowernumber => $patron->borrowernumber } )->store;
179
180
    my $second_id = Koha::Patron::AccountLinks->get_next_group_id();
181
    is( $second_id, $first_id + 1, 'get_next_group_id increments after use' );
182
183
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
184
    Koha::Patron::AccountLink->new( { link_group_id => $first_id, borrowernumber => $patron2->borrowernumber } )->store;
185
186
    my $third_id = Koha::Patron::AccountLinks->get_next_group_id();
187
    is( $third_id, $first_id + 1, 'get_next_group_id still returns same next id when adding to existing group' );
188
189
    $schema->storage->txn_rollback;
190
};
191
192
subtest 'Koha::Patron linked account methods' => sub {
193
    plan tests => 9;
194
195
    $schema->storage->txn_begin;
196
197
    my $patron1 = $builder->build_object( { class => 'Koha::Patrons' } );
198
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
199
    my $patron3 = $builder->build_object( { class => 'Koha::Patrons' } );
200
201
    is( $patron1->account_link,           undef, 'account_link returns undef when not linked' );
202
    is( $patron1->linked_accounts->count, 0,     'linked_accounts returns empty set when not linked' );
203
204
    my $all_unlinked = $patron1->all_linked_borrowernumbers;
205
    is( scalar(@$all_unlinked), 1, 'all_linked_borrowernumbers returns just self when not linked' );
206
    is( $all_unlinked->[0],     $patron1->borrowernumber, '...and that is the patron itself' );
207
208
    my $link_group_id = Koha::Patron::AccountLinks->get_next_group_id();
209
210
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron1->borrowernumber } )
211
        ->store;
212
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron2->borrowernumber } )
213
        ->store;
214
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron3->borrowernumber } )
215
        ->store;
216
217
    my $link = $patron1->account_link;
218
    isa_ok( $link, 'Koha::Patron::AccountLink', 'account_link returns AccountLink object' );
219
220
    my $linked = $patron1->linked_accounts;
221
    is( $linked->count, 2, 'linked_accounts returns 2 patrons' );
222
223
    my $all_linked = $patron1->all_linked_borrowernumbers;
224
    is( scalar(@$all_linked), 3, 'all_linked_borrowernumbers returns all 3' );
225
226
    my $debt = $patron1->linked_accounts_debt;
227
    is( $debt, 0, 'linked_accounts_debt returns 0 when no fines' );
228
229
    $patron2->account->add_debit( { amount => 10.50, type => 'OVERDUE', interface => 'test' } );
230
    $patron3->account->add_debit( { amount => 5.25,  type => 'OVERDUE', interface => 'test' } );
231
232
    my $total_debt = $patron1->linked_accounts_debt;
233
    is( $total_debt, 15.75, 'linked_accounts_debt returns combined fines' );
234
235
    $schema->storage->txn_rollback;
236
};
237
238
subtest 'linked_account_links() method' => sub {
239
    plan tests => 4;
240
241
    $schema->storage->txn_begin;
242
243
    my $patron1 = $builder->build_object( { class => 'Koha::Patrons' } );
244
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
245
246
    is( $patron1->linked_account_links, undef, 'linked_account_links returns undef when not linked' );
247
248
    my $link_group_id = Koha::Patron::AccountLinks->get_next_group_id();
249
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron1->borrowernumber } )
250
        ->store;
251
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron2->borrowernumber } )
252
        ->store;
253
254
    my $links = $patron1->linked_account_links;
255
    isa_ok( $links, 'Koha::Patron::AccountLinks' );
256
    is( $links->count, 2, 'linked_account_links returns all links in group' );
257
258
    my @borrowernumbers = $links->get_column('borrowernumber');
259
    ok(
260
               ( grep { $_ == $patron1->borrowernumber } @borrowernumbers )
261
            && ( grep { $_ == $patron2->borrowernumber } @borrowernumbers ),
262
        'Both patrons included in links'
263
    );
264
265
    $schema->storage->txn_rollback;
266
};
267
268
subtest 'link_to_patron() method' => sub {
269
    plan tests => 10;
270
271
    $schema->storage->txn_begin;
272
273
    my $patron1 = $builder->build_object( { class => 'Koha::Patrons' } );
274
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
275
    my $patron3 = $builder->build_object( { class => 'Koha::Patrons' } );
276
    my $patron4 = $builder->build_object( { class => 'Koha::Patrons' } );
277
278
    # Test linking two unlinked patrons
279
    my $link = $patron1->link_to_patron($patron2);
280
    isa_ok( $link, 'Koha::Patron::AccountLink' );
281
    ok( $patron1->account_link, 'patron1 now has account_link' );
282
    ok( $patron2->account_link, 'patron2 now has account_link' );
283
    is(
284
        $patron1->account_link->link_group_id,
285
        $patron2->account_link->link_group_id,
286
        'Both patrons in same link group'
287
    );
288
289
    # Test adding to existing group
290
    my $link3 = $patron1->link_to_patron($patron3);
291
    is(
292
        $patron3->account_link->link_group_id,
293
        $patron1->account_link->link_group_id,
294
        'patron3 added to existing group'
295
    );
296
    is( $patron1->linked_account_links->count, 3, 'Group now has 3 members' );
297
298
    # Test AlreadyLinked exception
299
    throws_ok { $patron1->link_to_patron($patron2) }
300
    'Koha::Exceptions::PatronAccountLink::AlreadyLinked',
301
        'AlreadyLinked exception when patrons already in same group';
302
303
    # Test DifferentGroups exception
304
    my $other_group_id = Koha::Patron::AccountLinks->get_next_group_id();
305
    Koha::Patron::AccountLink->new( { link_group_id => $other_group_id, borrowernumber => $patron4->borrowernumber } )
306
        ->store;
307
308
    throws_ok { $patron1->link_to_patron($patron4) }
309
    'Koha::Exceptions::PatronAccountLink::DifferentGroups',
310
        'DifferentGroups exception when patrons in different groups';
311
312
    # Test linking when other patron has group but self doesn't
313
    my $patron5 = $builder->build_object( { class => 'Koha::Patrons' } );
314
    my $link5   = $patron5->link_to_patron($patron1);
315
    is(
316
        $patron5->account_link->link_group_id,
317
        $patron1->account_link->link_group_id,
318
        'Unlinked patron joins existing group of other patron'
319
    );
320
    is( $patron1->linked_account_links->count, 4, 'Group now has 4 members' );
321
322
    $schema->storage->txn_rollback;
323
};
324
325
subtest 'delete() orphan cleanup' => sub {
326
    plan tests => 8;
327
328
    $schema->storage->txn_begin;
329
330
    my $patron1 = $builder->build_object( { class => 'Koha::Patrons' } );
331
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
332
    my $patron3 = $builder->build_object( { class => 'Koha::Patrons' } );
333
334
    # Create a 3-patron group
335
    my $link_group_id = Koha::Patron::AccountLinks->get_next_group_id();
336
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron1->borrowernumber } )
337
        ->store;
338
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron2->borrowernumber } )
339
        ->store;
340
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id, borrowernumber => $patron3->borrowernumber } )
341
        ->store;
342
343
    is(
344
        Koha::Patron::AccountLinks->search( { link_group_id => $link_group_id } )->count,
345
        3, 'Group has 3 members initially'
346
    );
347
348
    # Delete one patron's link - should leave 2, no orphan cleanup
349
    $patron1->account_link->delete;
350
351
    is(
352
        Koha::Patron::AccountLinks->search( { link_group_id => $link_group_id } )->count,
353
        2, 'Group has 2 members after first delete'
354
    );
355
    ok( $patron2->account_link, 'patron2 still has link' );
356
    ok( $patron3->account_link, 'patron3 still has link' );
357
358
    # Delete another patron's link - should trigger orphan cleanup
359
    $patron2->account_link->delete;
360
361
    is(
362
        Koha::Patron::AccountLinks->search( { link_group_id => $link_group_id } )->count,
363
        0, 'Group has 0 members after orphan cleanup'
364
    );
365
    is( $patron3->account_link, undef, 'patron3 orphan link was cleaned up' );
366
367
    # Test 2-patron group deletion directly
368
    my $patron4        = $builder->build_object( { class => 'Koha::Patrons' } );
369
    my $patron5        = $builder->build_object( { class => 'Koha::Patrons' } );
370
    my $link_group_id2 = Koha::Patron::AccountLinks->get_next_group_id();
371
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id2, borrowernumber => $patron4->borrowernumber } )
372
        ->store;
373
    Koha::Patron::AccountLink->new( { link_group_id => $link_group_id2, borrowernumber => $patron5->borrowernumber } )
374
        ->store;
375
376
    $patron4->account_link->delete;
377
378
    is(
379
        Koha::Patron::AccountLinks->search( { link_group_id => $link_group_id2 } )->count,
380
        0, '2-patron group fully cleaned up on delete'
381
    );
382
    is( $patron5->account_link, undef, 'Other patron in 2-person group also cleaned up' );
383
384
    $schema->storage->txn_rollback;
385
};

Return to bug 39658