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

(-)a/t/db_dependent/Koha/Account.t (-1 / +107 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::MockModule;
24
use Test::MockModule;
25
use Test::Exception;
25
use Test::Exception;
26
use Test::Warn;
26
use Test::Warn;
Lines 32-37 use Koha::Account::CreditTypes; Link Here
32
use Koha::Account::Lines;
32
use Koha::Account::Lines;
33
use Koha::Account::Offsets;
33
use Koha::Account::Offsets;
34
use Koha::DateUtils qw( dt_from_string );
34
use Koha::DateUtils qw( dt_from_string );
35
use Koha::Holds;
36
use Koha::Old::Holds;
35
37
36
use t::lib::Mocks;
38
use t::lib::Mocks;
37
use t::lib::TestBuilder;
39
use t::lib::TestBuilder;
Lines 1549-1551 subtest 'Koha::Account::payin_amount() tests' => sub { Link Here
1549
1551
1550
    $schema->storage->txn_rollback;
1552
    $schema->storage->txn_rollback;
1551
};
1553
};
1554
1555
subtest 'add_debit() with hold_id tests' => sub {
1556
1557
    plan tests => 8;
1558
1559
    $schema->storage->txn_begin;
1560
1561
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
1562
    my $biblio = $builder->build_sample_biblio;
1563
    my $item   = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
1564
1565
    # Create a hold
1566
    my $hold = $builder->build_object(
1567
        {
1568
            class => 'Koha::Holds',
1569
            value => {
1570
                borrowernumber => $patron->borrowernumber,
1571
                biblionumber   => $biblio->biblionumber,
1572
                itemnumber     => $item->itemnumber,
1573
                branchcode     => $patron->branchcode,
1574
            }
1575
        }
1576
    );
1577
1578
    # Create an old hold
1579
    my $old_hold = $builder->build_object(
1580
        {
1581
            class => 'Koha::Old::Holds',
1582
            value => {
1583
                borrowernumber => $patron->borrowernumber,
1584
                biblionumber   => $biblio->biblionumber,
1585
                itemnumber     => $item->itemnumber,
1586
                branchcode     => $patron->branchcode,
1587
            }
1588
        }
1589
    );
1590
1591
    my $account = $patron->account;
1592
1593
    # Test 1: add_debit with current hold_id sets reserve_id
1594
    my $debit1 = $account->add_debit(
1595
        {
1596
            amount      => 5.00,
1597
            description => 'Hold fee',
1598
            type        => 'RESERVE',
1599
            user_id     => 1,
1600
            library_id  => $patron->branchcode,
1601
            interface   => 'intranet',
1602
            hold_id     => $hold->id,
1603
        }
1604
    );
1605
1606
    is( $debit1->reserve_id,     $hold->id, 'add_debit() sets reserve_id correctly for current hold' );
1607
    is( $debit1->old_reserve_id, undef,     'add_debit() leaves old_reserve_id undef for current hold' );
1608
1609
    # Test 2: add_debit with old hold_id sets old_reserve_id
1610
    my $debit2 = $account->add_debit(
1611
        {
1612
            amount      => 3.00,
1613
            description => 'Old hold fee',
1614
            type        => 'RESERVE',
1615
            user_id     => 1,
1616
            library_id  => $patron->branchcode,
1617
            interface   => 'intranet',
1618
            hold_id     => $old_hold->id,
1619
        }
1620
    );
1621
1622
    is( $debit2->reserve_id,     undef,         'add_debit() leaves reserve_id undef for old hold' );
1623
    is( $debit2->old_reserve_id, $old_hold->id, 'add_debit() sets old_reserve_id correctly for old hold' );
1624
1625
    # Test 3: add_debit without hold_id leaves both fields undef
1626
    my $debit3 = $account->add_debit(
1627
        {
1628
            amount      => 2.00,
1629
            description => 'Regular fee',
1630
            type        => 'OVERDUE',
1631
            user_id     => 1,
1632
            library_id  => $patron->branchcode,
1633
            interface   => 'intranet',
1634
        }
1635
    );
1636
1637
    is( $debit3->reserve_id,     undef, 'add_debit() without hold_id leaves reserve_id undef' );
1638
    is( $debit3->old_reserve_id, undef, 'add_debit() without hold_id leaves old_reserve_id undef' );
1639
1640
    # Test 4: add_debit with non-existent hold_id handles gracefully
1641
    my $debit4 = $account->add_debit(
1642
        {
1643
            amount      => 1.50,
1644
            description => 'Fee for missing hold',
1645
            type        => 'RESERVE',
1646
            user_id     => 1,
1647
            library_id  => $patron->branchcode,
1648
            interface   => 'intranet',
1649
            hold_id     => 99999,                    # Non-existent hold ID
1650
        }
1651
    );
1652
1653
    is( $debit4->reserve_id,     undef, 'add_debit() handles non-existent hold_id gracefully (reserve_id)' );
1654
    is( $debit4->old_reserve_id, undef, 'add_debit() handles non-existent hold_id gracefully (old_reserve_id)' );
1655
1656
    $schema->storage->txn_rollback;
1657
};
(-)a/t/db_dependent/Koha/Account/Line.t (-1 / +98 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 30-36 use C4::Circulation qw( AddRenewal CanBookBeRenewed LostItem AddIssue AddReturn Link Here
30
use Koha::Account;
30
use Koha::Account;
31
use Koha::Account::Lines;
31
use Koha::Account::Lines;
32
use Koha::Account::Offsets;
32
use Koha::Account::Offsets;
33
use Koha::Holds;
33
use Koha::Items;
34
use Koha::Items;
35
use Koha::Old::Holds;
34
use Koha::DateUtils qw( dt_from_string );
36
use Koha::DateUtils qw( dt_from_string );
35
37
36
use t::lib::Mocks;
38
use t::lib::Mocks;
Lines 1470-1473 subtest "cancel() tests" => sub { Link Here
1470
    $schema->storage->txn_rollback;
1472
    $schema->storage->txn_rollback;
1471
};
1473
};
1472
1474
1475
subtest 'hold() tests' => sub {
1476
1477
    plan tests => 7;
1478
1479
    $schema->storage->txn_begin;
1480
1481
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
1482
    my $patron  = $builder->build_object( { class => 'Koha::Patrons' } );
1483
    my $biblio  = $builder->build_sample_biblio;
1484
1485
    # Create a hold
1486
    my $hold = $builder->build_object(
1487
        {
1488
            class => 'Koha::Holds',
1489
            value => {
1490
                borrowernumber => $patron->borrowernumber,
1491
                biblionumber   => $biblio->biblionumber,
1492
                branchcode     => $library->branchcode,
1493
            }
1494
        }
1495
    );
1496
1497
    # Create an old hold
1498
    my $old_hold = $builder->build_object(
1499
        {
1500
            class => 'Koha::Old::Holds',
1501
            value => {
1502
                borrowernumber => $patron->borrowernumber,
1503
                biblionumber   => $biblio->biblionumber,
1504
                branchcode     => $library->branchcode,
1505
            }
1506
        }
1507
    );
1508
1509
    # Test 1: Account line with reserve_id returns current hold
1510
    my $line_with_hold = Koha::Account::Line->new(
1511
        {
1512
            borrowernumber  => $patron->borrowernumber,
1513
            debit_type_code => "RESERVE",
1514
            status          => "UNRETURNED",
1515
            amount          => 5.00,
1516
            reserve_id      => $hold->reserve_id,
1517
            interface       => 'commandline',
1518
        }
1519
    )->store;
1520
1521
    my $returned_hold = $line_with_hold->hold;
1522
    is( ref($returned_hold),        'Koha::Hold',      'hold() returns a Koha::Hold object when reserve_id is set' );
1523
    is( $returned_hold->reserve_id, $hold->reserve_id, 'hold() returns the correct hold' );
1524
1525
    # Test 2: Account line with old_reserve_id returns old hold
1526
    my $line_with_old_hold = Koha::Account::Line->new(
1527
        {
1528
            borrowernumber  => $patron->borrowernumber,
1529
            debit_type_code => "RESERVE",
1530
            status          => "UNRETURNED",
1531
            amount          => 5.00,
1532
            old_reserve_id  => $old_hold->reserve_id,
1533
            interface       => 'commandline',
1534
        }
1535
    )->store;
1536
1537
    my $returned_old_hold = $line_with_old_hold->hold;
1538
    is(
1539
        ref($returned_old_hold), 'Koha::Old::Hold',
1540
        'hold() returns a Koha::Old::Hold object when old_reserve_id is set'
1541
    );
1542
    is( $returned_old_hold->reserve_id, $old_hold->reserve_id, 'hold() returns the correct old hold' );
1543
1544
    # Test 3: Account line with neither reserve_id nor old_reserve_id returns undef
1545
    my $line_without_hold = Koha::Account::Line->new(
1546
        {
1547
            borrowernumber  => $patron->borrowernumber,
1548
            debit_type_code => "OVERDUE",
1549
            status          => "RETURNED",
1550
            amount          => 3.00,
1551
            interface       => 'commandline',
1552
        }
1553
    )->store;
1554
1555
    is( $line_without_hold->hold, undef, 'hold() returns undef when neither reserve_id nor old_reserve_id is set' );
1556
1557
    # Test 4: Set reserve_id to NULL and verify it returns undef
1558
    $line_with_hold->reserve_id(undef)->store;
1559
1560
    is( $line_with_hold->hold, undef, 'hold() returns undef when reserve_id is set to NULL' );
1561
1562
    # Test 5: Set old_reserve_id to NULL and verify it returns undef
1563
    $line_with_old_hold->old_reserve_id(undef)->store;
1564
1565
    is( $line_with_old_hold->hold, undef, 'hold() returns undef when old_reserve_id is set to NULL' );
1566
1567
    $schema->storage->txn_rollback;
1568
};
1569
1473
1;
1570
1;
(-)a/t/db_dependent/Koha/Hold.t (-1 / +156 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 => 21;
23
use Test::More tests => 23;
24
24
25
use Test::Exception;
25
use Test::Exception;
26
use Test::MockModule;
26
use Test::MockModule;
Lines 2202-2204 subtest 'charge_hold_fee() tests' => sub { Link Here
2202
2202
2203
    $schema->storage->txn_rollback;
2203
    $schema->storage->txn_rollback;
2204
};
2204
};
2205
2206
subtest 'debits() tests' => sub {
2207
2208
    plan tests => 5;
2209
2210
    $schema->storage->txn_begin;
2211
2212
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
2213
    my $biblio = $builder->build_sample_biblio;
2214
    my $item   = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
2215
2216
    # Create a hold
2217
    my $hold = $builder->build_object(
2218
        {
2219
            class => 'Koha::Holds',
2220
            value => {
2221
                borrowernumber => $patron->borrowernumber,
2222
                biblionumber   => $biblio->biblionumber,
2223
                itemnumber     => $item->itemnumber,
2224
                branchcode     => $patron->branchcode,
2225
            }
2226
        }
2227
    );
2228
2229
    # Test 1: Hold with no debits returns empty collection
2230
    my $debits = $hold->debits;
2231
    isa_ok( $debits, 'Koha::Account::Debits', 'debits() returns a Koha::Account::Debits object' );
2232
    is( $debits->count, 0, 'debits() returns empty collection when no debits exist' );
2233
2234
    # Test 2: Create some account lines (debits and credits) linked to the hold
2235
    my $account = $patron->account;
2236
2237
    # Add a debit (hold fee)
2238
    my $debit1 = $account->add_debit(
2239
        {
2240
            amount      => 5.00,
2241
            description => 'Hold fee',
2242
            type        => 'RESERVE',
2243
            user_id     => 1,
2244
            library_id  => $patron->branchcode,
2245
            interface   => 'intranet',
2246
            hold_id     => $hold->id,
2247
        }
2248
    );
2249
2250
    # Add another debit (expiration fee)
2251
    my $debit2 = $account->add_debit(
2252
        {
2253
            amount      => 2.00,
2254
            description => 'Hold expiration fee',
2255
            type        => 'RESERVE_EXPIRED',
2256
            user_id     => 1,
2257
            library_id  => $patron->branchcode,
2258
            interface   => 'intranet',
2259
            hold_id     => $hold->id,
2260
        }
2261
    );
2262
2263
    # Add a credit (should not appear in debits)
2264
    my $credit = $account->add_credit(
2265
        {
2266
            amount      => 3.00,
2267
            description => 'Credit for hold',
2268
            type        => 'CREDIT',
2269
            user_id     => 1,
2270
            library_id  => $patron->branchcode,
2271
            interface   => 'intranet',
2272
        }
2273
    );
2274
2275
    # Link credit to hold manually since add_credit doesn't have hold_id parameter
2276
    $credit->reserve_id( $hold->id )->store;
2277
2278
    # Test 3: Hold debits returns only debit lines, ordered by timestamp descending
2279
    $debits = $hold->debits;
2280
    is( $debits->count, 2, 'debits() returns correct count of debit lines only' );
2281
2282
    my @debit_amounts = sort { $b <=> $a } map { $_->amount + 0 } $debits->as_list;
2283
    is_deeply( \@debit_amounts, [ 5.0, 2.0 ], 'debits() returns correct amounts in descending order' );
2284
2285
    # Test 4: Verify both debit types are present
2286
    my @debit_types = sort map { $_->debit_type_code } $debits->as_list;
2287
    is_deeply( \@debit_types, [ 'RESERVE', 'RESERVE_EXPIRED' ], 'debits() returns both expected debit types' );
2288
2289
    $schema->storage->txn_rollback;
2290
};
2291
2292
subtest '_move_to_old() account migration tests' => sub {
2293
2294
    plan tests => 6;
2295
2296
    $schema->storage->txn_begin;
2297
2298
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
2299
    my $biblio = $builder->build_sample_biblio;
2300
    my $item   = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
2301
2302
    # Create a hold
2303
    my $hold = $builder->build_object(
2304
        {
2305
            class => 'Koha::Holds',
2306
            value => {
2307
                borrowernumber => $patron->borrowernumber,
2308
                biblionumber   => $biblio->biblionumber,
2309
                itemnumber     => $item->itemnumber,
2310
                branchcode     => $patron->branchcode,
2311
            }
2312
        }
2313
    );
2314
2315
    my $account = $patron->account;
2316
2317
    # Create account lines linked to the hold
2318
    my $debit1 = $account->add_debit(
2319
        {
2320
            amount      => 5.00,
2321
            description => 'Hold fee',
2322
            type        => 'RESERVE',
2323
            user_id     => 1,
2324
            library_id  => $patron->branchcode,
2325
            interface   => 'intranet',
2326
            hold_id     => $hold->id,
2327
        }
2328
    );
2329
2330
    my $debit2 = $account->add_debit(
2331
        {
2332
            amount      => 2.00,
2333
            description => 'Hold expiration fee',
2334
            type        => 'RESERVE_EXPIRED',
2335
            user_id     => 1,
2336
            library_id  => $patron->branchcode,
2337
            interface   => 'intranet',
2338
            hold_id     => $hold->id,
2339
        }
2340
    );
2341
2342
    # Test initial state
2343
    is( $debit1->reserve_id,     $hold->id, 'Account line initially has reserve_id set' );
2344
    is( $debit1->old_reserve_id, undef,     'Account line initially has old_reserve_id unset' );
2345
    is( $debit2->reserve_id,     $hold->id, 'Second account line initially has reserve_id set' );
2346
2347
    # Call _move_to_old
2348
    my $old_hold = $hold->_move_to_old;
2349
2350
    # Verify account lines were updated
2351
    $debit1->discard_changes;
2352
    $debit2->discard_changes;
2353
2354
    is( $debit1->reserve_id,     undef,     'Account line reserve_id cleared after _move_to_old' );
2355
    is( $debit1->old_reserve_id, $hold->id, 'Account line old_reserve_id set after _move_to_old' );
2356
    is( $debit2->old_reserve_id, $hold->id, 'Second account line old_reserve_id set after _move_to_old' );
2357
2358
    $schema->storage->txn_rollback;
2359
};
(-)a/t/db_dependent/Koha/Old/Hold.t (-2 / +88 lines)
Lines 17-27 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 4;
20
use Test::More tests => 5;
21
use Test::NoWarnings;
21
use Test::NoWarnings;
22
use Test::Exception;
22
use Test::Exception;
23
23
24
use Koha::Database;
24
use Koha::Database;
25
use Koha::Account;
25
26
26
use t::lib::Mocks;
27
use t::lib::Mocks;
27
use t::lib::TestBuilder;
28
use t::lib::TestBuilder;
Lines 148-150 subtest 'item/pickup_library() tests' => sub { Link Here
148
149
149
    $schema->storage->txn_rollback;
150
    $schema->storage->txn_rollback;
150
};
151
};
151
- 
152
153
subtest 'debits() tests' => sub {
154
155
    plan tests => 5;
156
157
    $schema->storage->txn_begin;
158
159
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
160
    my $biblio = $builder->build_sample_biblio;
161
    my $item   = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
162
163
    # Create an old hold
164
    my $old_hold = $builder->build_object(
165
        {
166
            class => 'Koha::Old::Holds',
167
            value => {
168
                borrowernumber => $patron->borrowernumber,
169
                biblionumber   => $biblio->biblionumber,
170
                itemnumber     => $item->itemnumber,
171
                branchcode     => $patron->branchcode,
172
            }
173
        }
174
    );
175
176
    # Test 1: Old hold with no debits returns empty collection
177
    my $debits = $old_hold->debits;
178
    isa_ok( $debits, 'Koha::Account::Debits', 'debits() returns a Koha::Account::Debits object' );
179
    is( $debits->count, 0, 'debits() returns empty collection when no debits exist' );
180
181
    # Test 2: Create account lines (debits and credits) linked to the old hold
182
    my $account = $patron->account;
183
184
    # Add a debit linked to old hold
185
    my $debit1 = $account->add_debit(
186
        {
187
            amount      => 3.50,
188
            description => 'Old hold fee',
189
            type        => 'RESERVE',
190
            user_id     => 1,
191
            library_id  => $patron->branchcode,
192
            interface   => 'intranet',
193
        }
194
    );
195
196
    # Manually set old_reserve_id since add_debit doesn't handle old holds directly
197
    $debit1->old_reserve_id( $old_hold->reserve_id )->store;
198
199
    # Add another debit
200
    my $debit2 = $account->add_debit(
201
        {
202
            amount      => 1.50,
203
            description => 'Old hold expiration fee',
204
            type        => 'RESERVE_EXPIRED',
205
            user_id     => 1,
206
            library_id  => $patron->branchcode,
207
            interface   => 'intranet',
208
        }
209
    );
210
    $debit2->old_reserve_id( $old_hold->reserve_id )->store;
211
212
    # Add a credit (should not appear in debits)
213
    my $credit = $account->add_credit(
214
        {
215
            amount      => 2.00,
216
            description => 'Credit for old hold',
217
            type        => 'CREDIT',
218
            user_id     => 1,
219
            library_id  => $patron->branchcode,
220
            interface   => 'intranet',
221
        }
222
    );
223
    $credit->old_reserve_id( $old_hold->reserve_id )->store;
224
225
    # Test 3: Old hold debits returns only debit lines, ordered by timestamp descending
226
    $debits = $old_hold->debits;
227
    is( $debits->count, 2, 'debits() returns correct count of debit lines only' );
228
229
    my @debit_amounts = sort { $b <=> $a } map { $_->amount + 0 } $debits->as_list;
230
    is_deeply( \@debit_amounts, [ 3.5, 1.5 ], 'debits() returns correct amounts in descending order' );
231
232
    # Test 4: Verify both debit types are present
233
    my @debit_types = sort map { $_->debit_type_code } $debits->as_list;
234
    is_deeply( \@debit_types, [ 'RESERVE', 'RESERVE_EXPIRED' ], 'debits() returns both expected debit types' );
235
236
    $schema->storage->txn_rollback;
237
};

Return to bug 40817