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

(-)a/t/db_dependent/Koha/Account/Line.t (-1 / +51 lines)
Lines 20-26 Link Here
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::NoWarnings;
22
use Test::NoWarnings;
23
use Test::More tests => 16;
23
use Test::More tests => 17;
24
use Test::Exception;
24
use Test::Exception;
25
use Test::MockModule;
25
use Test::MockModule;
26
26
Lines 1470-1473 subtest "cancel() tests" => sub { Link Here
1470
    $schema->storage->txn_rollback;
1470
    $schema->storage->txn_rollback;
1471
};
1471
};
1472
1472
1473
subtest 'linking methods tests' => sub {
1474
    plan tests => 6;
1475
1476
    $schema->storage->txn_begin;
1477
1478
    # Create test data
1479
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
1480
    my $biblio = $builder->build_sample_biblio();
1481
    my $item   = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
1482
1483
    # Create a hold
1484
    my $hold = Koha::Hold->new(
1485
        {
1486
            borrowernumber => $patron->borrowernumber,
1487
            biblionumber   => $biblio->biblionumber,
1488
            itemnumber     => $item->itemnumber,
1489
            branchcode     => $patron->branchcode,
1490
            reservedate    => '2023-01-01',
1491
            priority       => 1,
1492
        }
1493
    )->store;
1494
1495
    # Create an account line
1496
    my $account_line = $patron->account->add_debit(
1497
        {
1498
            amount      => 5.00,
1499
            description => 'Mixed fee',
1500
            type        => 'MANUAL',
1501
            interface   => 'intranet'
1502
        }
1503
    );
1504
1505
    # Test add_link method
1506
    my $hold_link = $account_line->add_link( 'hold', $hold->id );
1507
    isa_ok( $hold_link, 'Koha::Account::Link', 'add_link returns Link object' );
1508
1509
    # Test links method
1510
    my $links = $account_line->links;
1511
    isa_ok( $links, 'Koha::Account::Links', 'links returns Links collection' );
1512
    is( $links->count, 1, 'Account line has one link' );
1513
1514
    # Test holds method
1515
    my @holds = $account_line->holds;
1516
    is( scalar @holds, 1, 'holds() returns correct number of holds' );
1517
    isa_ok( $holds[0], 'Koha::Hold', 'holds() returns Hold object' );
1518
    is( $holds[0]->id, $hold->id, 'holds() returns correct hold' );
1519
1520
    $schema->storage->txn_rollback;
1521
};
1522
1473
1;
1523
1;
(-)a/t/db_dependent/Koha/Account/Link.t (+295 lines)
Line 0 Link Here
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 <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More tests => 6;
21
use Test::Exception;
22
use Test::Warn;
23
24
use Koha::Database;
25
use Koha::Account::Link;
26
use Koha::Account::Links;
27
28
use t::lib::TestBuilder;
29
use t::lib::Mocks;
30
31
my $schema = Koha::Database->new->schema;
32
$schema->storage->txn_begin;
33
34
my $builder = t::lib::TestBuilder->new;
35
36
subtest 'Basic object creation and validation' => sub {
37
    plan tests => 8;
38
39
    # Create test data
40
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
41
    my $biblio = $builder->build_sample_biblio();
42
    my $item   = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
43
44
    # Create a hold
45
    my $hold = Koha::Hold->new(
46
        {
47
            borrowernumber => $patron->borrowernumber,
48
            biblionumber   => $biblio->biblionumber,
49
            itemnumber     => $item->itemnumber,
50
            branchcode     => $patron->branchcode,
51
            reservedate    => '2023-01-01',
52
            priority       => 1,
53
        }
54
    )->store;
55
56
    # Create an account line
57
    my $account_line = $patron->account->add_debit(
58
        {
59
            amount      => 5.00,
60
            description => 'Hold fee',
61
            type        => 'RESERVE',
62
            interface   => 'intranet'
63
        }
64
    );
65
66
    # Test link creation
67
    my $link = Koha::Account::Link->new(
68
        {
69
            accountlines_id => $account_line->id,
70
            link_type       => 'hold',
71
            linked_id       => $hold->id,
72
        }
73
    );
74
75
    is( $link->accountlines_id, $account_line->id, 'Account line ID set correctly' );
76
    is( $link->link_type,       'hold',            'Link type set correctly' );
77
    is( $link->linked_id,       $hold->id,         'Linked ID set correctly' );
78
79
    # Test validation passes
80
    ok( $link->_validate_link_integrity(), 'Link validation passes for valid data' );
81
82
    # Test store
83
    lives_ok { $link->store() } 'Link stores without error';
84
    ok( $link->id, 'Link has ID after storing' );
85
86
    # Test linked_object method
87
    my $linked_obj = $link->linked_object;
88
    isa_ok( $linked_obj, 'Koha::Schema::Result::Reserve', 'linked_object returns correct type' );
89
    is( $linked_obj->reserve_id, $hold->id, 'linked_object returns correct hold' );
90
};
91
92
subtest 'Link validation' => sub {
93
    plan tests => 4;
94
95
    my $patron       = $builder->build_object( { class => 'Koha::Patrons' } );
96
    my $account_line = $patron->account->add_debit(
97
        {
98
            amount      => 3.00,
99
            description => 'Test fee',
100
            type        => 'MANUAL',
101
            interface   => 'intranet'
102
        }
103
    );
104
105
    # Test invalid link type
106
    my $invalid_link = Koha::Account::Link->new(
107
        {
108
            accountlines_id => $account_line->id,
109
            link_type       => 'invalid_type',
110
            linked_id       => 999,
111
        }
112
    );
113
114
    ok( !$invalid_link->_validate_link_integrity(), 'Validation fails for invalid link type' );
115
116
    # Test nonexistent linked entity
117
    my $nonexistent_link = Koha::Account::Link->new(
118
        {
119
            accountlines_id => $account_line->id,
120
            link_type       => 'hold',
121
            linked_id       => 99999,               # Doesn't exist
122
        }
123
    );
124
125
    ok( !$nonexistent_link->_validate_link_integrity(), 'Validation fails for nonexistent linked entity' );
126
127
    # Test store with invalid data
128
    throws_ok {
129
        $invalid_link->store()
130
    }
131
    'Koha::Exceptions::Account::InvalidLinkType', 'Store throws InvalidLinkType exception for invalid link';
132
133
    throws_ok {
134
        $nonexistent_link->store()
135
    }
136
    'Koha::Exceptions::Account::InvalidLinkTarget', 'Store throws InvalidLinkTarget exception for nonexistent entity';
137
};
138
139
subtest 'Linked Koha object access' => sub {
140
    plan tests => 3;
141
142
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
143
    my $biblio = $builder->build_sample_biblio();
144
    my $hold   = Koha::Hold->new(
145
        {
146
            borrowernumber => $patron->borrowernumber,
147
            biblionumber   => $biblio->biblionumber,
148
            branchcode     => $patron->branchcode,
149
            reservedate    => '2023-01-01',
150
            priority       => 1,
151
        }
152
    )->store;
153
154
    my $account_line = $patron->account->add_debit(
155
        {
156
            amount      => 2.00,
157
            description => 'Hold fee',
158
            type        => 'RESERVE',
159
            interface   => 'intranet'
160
        }
161
    );
162
163
    my $link = Koha::Account::Link->new(
164
        {
165
            accountlines_id => $account_line->id,
166
            link_type       => 'hold',
167
            linked_id       => $hold->id,
168
        }
169
    )->store;
170
171
    # Test linked_koha_object method
172
    my $koha_hold = $link->linked_koha_object;
173
    isa_ok( $koha_hold, 'Koha::Hold', 'linked_koha_object returns Koha::Hold object' );
174
    is( $koha_hold->id,             $hold->id,               'Returned object has correct ID' );
175
    is( $koha_hold->borrowernumber, $patron->borrowernumber, 'Returned object has correct patron' );
176
};
177
178
subtest 'Account line integration' => sub {
179
    plan tests => 4;
180
181
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
182
    my $biblio = $builder->build_sample_biblio();
183
    my $hold   = Koha::Hold->new(
184
        {
185
            borrowernumber => $patron->borrowernumber,
186
            biblionumber   => $biblio->biblionumber,
187
            branchcode     => $patron->branchcode,
188
            reservedate    => '2023-01-01',
189
            priority       => 1,
190
        }
191
    )->store;
192
193
    my $account_line = $patron->account->add_debit(
194
        {
195
            amount      => 1.50,
196
            description => 'Hold fee',
197
            type        => 'RESERVE',
198
            interface   => 'intranet'
199
        }
200
    );
201
202
    # Test add_link method
203
    my $link = $account_line->add_link( 'hold', $hold->id );
204
    isa_ok( $link, 'Koha::Account::Link', 'add_link returns Link object' );
205
    is( $link->accountlines_id, $account_line->id, 'Link has correct account line ID' );
206
207
    # Test links method
208
    my $links = $account_line->links;
209
    isa_ok( $links, 'Koha::Account::Links', 'links returns Links collection' );
210
    is( $links->count, 1, 'Account line has one link' );
211
};
212
213
subtest 'Hold integration' => sub {
214
    plan tests => 3;
215
216
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
217
    my $biblio = $builder->build_sample_biblio();
218
    my $hold   = Koha::Hold->new(
219
        {
220
            borrowernumber => $patron->borrowernumber,
221
            biblionumber   => $biblio->biblionumber,
222
            branchcode     => $patron->branchcode,
223
            reservedate    => '2023-01-01',
224
            priority       => 1,
225
        }
226
    )->store;
227
228
    # Create multiple account lines for this hold
229
    my $fee1 = $patron->account->add_debit(
230
        {
231
            amount      => 2.00,
232
            description => 'Hold placement fee',
233
            type        => 'RESERVE',
234
            interface   => 'intranet'
235
        }
236
    );
237
238
    my $fee2 = $patron->account->add_debit(
239
        {
240
            amount      => 1.00,
241
            description => 'Hold collection fee',
242
            type        => 'RESERVE_EXPIRED',
243
            interface   => 'intranet'
244
        }
245
    );
246
247
    # Link both fees to the hold
248
    $fee1->add_link( 'hold', $hold->id );
249
    $fee2->add_link( 'hold', $hold->id );
250
251
    # Test hold can find its account lines
252
    my $debits = $hold->debits;
253
    isa_ok( $debits, 'Koha::Account::Debits', 'debits returns Debits collection' );
254
    is( $debits->search( {} )->count, 2, 'Hold has two linked debit lines' );
255
256
    my $total_fees = $debits->total_outstanding;
257
    is( $total_fees, 3.00, 'Total fees calculated correctly' );
258
};
259
260
subtest 'Unique constraint and duplicate prevention' => sub {
261
    plan tests => 2;
262
263
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
264
    my $biblio = $builder->build_sample_biblio();
265
    my $hold   = Koha::Hold->new(
266
        {
267
            borrowernumber => $patron->borrowernumber,
268
            biblionumber   => $biblio->biblionumber,
269
            branchcode     => $patron->branchcode,
270
            reservedate    => '2023-01-01',
271
            priority       => 1,
272
        }
273
    )->store;
274
275
    my $account_line = $patron->account->add_debit(
276
        {
277
            amount      => 5.00,
278
            description => 'Hold fee',
279
            type        => 'RESERVE',
280
            interface   => 'intranet'
281
        }
282
    );
283
284
    # Create first link
285
    my $link1 = $account_line->add_link( 'hold', $hold->id );
286
    ok( $link1->id, 'First link created successfully' );
287
288
    # Try to create duplicate link
289
    throws_ok {
290
        $account_line->add_link( 'hold', $hold->id )
291
    }
292
    qr/duplicate/i, 'Duplicate link creation fails with unique constraint error';
293
};
294
295
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Koha/Account/Links.t (-1 / +279 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 <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More tests => 4;
21
22
use Koha::Database;
23
use Koha::Account::Links;
24
25
use t::lib::TestBuilder;
26
27
my $schema = Koha::Database->new->schema;
28
$schema->storage->txn_begin;
29
30
my $builder = t::lib::TestBuilder->new;
31
32
subtest 'Basic collection functionality' => sub {
33
    plan tests => 3;
34
35
    $schema->storage->txn_begin;
36
37
    # Create test data
38
    my $patron1 = $builder->build_object( { class => 'Koha::Patrons' } );
39
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
40
    my $biblio  = $builder->build_sample_biblio();
41
42
    my $hold1 = Koha::Hold->new(
43
        {
44
            borrowernumber => $patron1->borrowernumber,
45
            biblionumber   => $biblio->biblionumber,
46
            branchcode     => $patron1->branchcode,
47
            reservedate    => '2023-01-01',
48
            priority       => 1,
49
        }
50
    )->store;
51
52
    my $hold2 = Koha::Hold->new(
53
        {
54
            borrowernumber => $patron2->borrowernumber,
55
            biblionumber   => $biblio->biblionumber,
56
            branchcode     => $patron2->branchcode,
57
            reservedate    => '2023-01-02',
58
            priority       => 2,
59
        }
60
    )->store;
61
62
    # Create account lines and links
63
    my $fee1 = $patron1->account->add_debit(
64
        {
65
            amount      => 2.00,
66
            description => 'Hold fee 1',
67
            type        => 'RESERVE',
68
            interface   => 'intranet'
69
        }
70
    );
71
72
    my $fee2 = $patron2->account->add_debit(
73
        {
74
            amount      => 3.00,
75
            description => 'Hold fee 2',
76
            type        => 'RESERVE',
77
            interface   => 'intranet'
78
        }
79
    );
80
81
    $fee1->add_link( 'hold', $hold1->id );
82
    $fee2->add_link( 'hold', $hold2->id );
83
84
    # Test collection methods
85
    my $all_links = Koha::Account::Links->search( {} );
86
    is( $all_links->count, 2, 'Found both links in collection' );
87
88
    my $hold_links = $all_links->by_link_type('hold');
89
    is( $hold_links->count, 2, 'by_link_type filters correctly' );
90
91
    my $specific_links = $all_links->by_linked_id( $hold1->id );
92
    is( $specific_links->count, 1, 'by_linked_id filters correctly' );
93
94
    $schema->storage->txn_rollback;
95
};
96
97
subtest 'Filtering methods' => sub {
98
    plan tests => 3;
99
100
    $schema->storage->txn_begin;
101
102
    # Create diverse test data
103
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
104
    my $biblio = $builder->build_sample_biblio();
105
    my $item   = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
106
107
    # Create hold
108
    my $hold = Koha::Hold->new(
109
        {
110
            borrowernumber => $patron->borrowernumber,
111
            biblionumber   => $biblio->biblionumber,
112
            itemnumber     => $item->itemnumber,
113
            branchcode     => $patron->branchcode,
114
            reservedate    => '2023-01-01',
115
            priority       => 1,
116
        }
117
    )->store;
118
119
    # Create different types of fees
120
    my $hold_fee = $patron->account->add_debit(
121
        {
122
            amount      => 2.00,
123
            description => 'Hold fee',
124
            type        => 'RESERVE',
125
            interface   => 'intranet'
126
        }
127
    );
128
129
    my $manual_fee = $patron->account->add_debit(
130
        {
131
            amount      => 1.00,
132
            description => 'Manual fee',
133
            type        => 'MANUAL',
134
            interface   => 'intranet'
135
        }
136
    );
137
138
    # Create links
139
    $hold_fee->add_link( 'hold', $hold->id );
140
141
    # Manual fee has no link
142
143
    my $all_links = Koha::Account::Links->search( {} );
144
    is( $all_links->count, 1, 'Total links created correctly' );
145
146
    # Test filtering by type
147
    my $hold_links = $all_links->by_link_type('hold');
148
    is( $hold_links->count, 1, 'Hold links filtered correctly' );
149
150
    # Test filtering by ID
151
    my $hold_id_links = $all_links->by_linked_id( $hold->id );
152
    is( $hold_id_links->count, 1, 'Links filtered by ID correctly' );
153
154
    $schema->storage->txn_rollback;
155
};
156
157
subtest 'Collection methods for related objects' => sub {
158
    plan tests => 3;
159
160
    $schema->storage->txn_begin;
161
162
    my $patron  = $builder->build_object( { class => 'Koha::Patrons' } );
163
    my $biblio1 = $builder->build_sample_biblio();
164
    my $biblio2 = $builder->build_sample_biblio();
165
166
    # Create multiple holds
167
    my $hold1 = Koha::Hold->new(
168
        {
169
            borrowernumber => $patron->borrowernumber,
170
            biblionumber   => $biblio1->biblionumber,
171
            branchcode     => $patron->branchcode,
172
            reservedate    => '2023-01-01',
173
            priority       => 1,
174
        }
175
    )->store;
176
177
    my $hold2 = Koha::Hold->new(
178
        {
179
            borrowernumber => $patron->borrowernumber,
180
            biblionumber   => $biblio2->biblionumber,
181
            branchcode     => $patron->branchcode,
182
            reservedate    => '2023-01-02',
183
            priority       => 1,
184
        }
185
    )->store;
186
187
    # Create fees for both holds
188
    my $fee1 = $patron->account->add_debit(
189
        {
190
            amount      => 2.00,
191
            description => 'Hold fee 1',
192
            type        => 'RESERVE',
193
            interface   => 'intranet'
194
        }
195
    );
196
197
    my $fee2 = $patron->account->add_debit(
198
        {
199
            amount      => 3.00,
200
            description => 'Hold fee 2',
201
            type        => 'RESERVE',
202
            interface   => 'intranet'
203
        }
204
    );
205
206
    # Link fees to holds
207
    $fee1->add_link( 'hold', $hold1->id );
208
    $fee2->add_link( 'hold', $hold2->id );
209
210
    # Test holds collection method
211
    my $links = Koha::Account::Links->search( {} );
212
    my @holds = $links->holds();
213
214
    is( scalar @holds, 2, 'holds() method returns correct number of holds' );
215
216
    my @hold_ids     = sort map { $_->id } @holds;
217
    my @expected_ids = sort ( $hold1->id, $hold2->id );
218
219
    is_deeply( \@hold_ids, \@expected_ids, 'holds() method returns correct holds' );
220
221
    # Test filtering and then getting related objects
222
    my $hold1_links    = $links->by_linked_id( $hold1->id );
223
    my @filtered_holds = $hold1_links->holds();
224
    is( scalar @filtered_holds, 1, 'Filtered links return correct number of holds' );
225
226
    $schema->storage->txn_rollback;
227
};
228
229
subtest 'Integration with account line methods' => sub {
230
    plan tests => 4;
231
232
    $schema->storage->txn_begin;
233
234
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
235
    my $biblio = $builder->build_sample_biblio();
236
    my $item   = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
237
238
    # Create hold
239
    my $hold = Koha::Hold->new(
240
        {
241
            borrowernumber => $patron->borrowernumber,
242
            biblionumber   => $biblio->biblionumber,
243
            itemnumber     => $item->itemnumber,
244
            branchcode     => $patron->branchcode,
245
            reservedate    => '2023-01-01',
246
            priority       => 1,
247
        }
248
    )->store;
249
250
    # Create account line
251
    my $account_line = $patron->account->add_debit(
252
        {
253
            amount      => 4.00,
254
            description => 'Mixed fee',
255
            type        => 'MANUAL',
256
            interface   => 'intranet'
257
        }
258
    );
259
260
    # Link to both hold and checkout (edge case)
261
    $account_line->add_link( 'hold', $hold->id );
262
263
    # Test account line can access its links
264
    my $links = $account_line->links;
265
    is( $links->count, 1, 'Account line has links' );
266
267
    # Test account line can get specific types
268
    my @holds = $account_line->holds;
269
    is( scalar @holds, 1,         'Account line holds() method works' );
270
    is( $holds[0]->id, $hold->id, 'Correct hold returned' );
271
272
    # Test hold can find its account lines
273
    my $hold_fees = $hold->debits;
274
    is( $hold_fees->count, 1, 'Hold can find its account lines' );
275
276
    $schema->storage->txn_rollback;
277
};
278
279
$schema->storage->txn_rollback;

Return to bug 40808