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

(-)a/t/db_dependent/Koha/Account/PrintNoticeCharges.t (+274 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2024 Koha Development team
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>
19
20
use Modern::Perl;
21
22
use Test::More tests => 8;
23
use Test::MockModule;
24
use Test::Exception;
25
use Test::Warn;
26
27
use C4::Context;
28
use Koha::Account;
29
use Koha::Account::Lines;
30
use Koha::Patrons;
31
32
use t::lib::Mocks;
33
use t::lib::TestBuilder;
34
35
my $schema = Koha::Database->new->schema;
36
$schema->storage->dbh->{PrintError} = 0;
37
my $builder = t::lib::TestBuilder->new;
38
C4::Context->interface('commandline');
39
40
subtest 'add_print_notice_charge_if_needed with charging disabled' => sub {
41
    plan tests => 3;
42
43
    $schema->storage->txn_begin;
44
45
    # Create category with print notice charging disabled (0.00)
46
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.00 } });
47
    my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category->categorycode } });
48
    my $account = Koha::Account->new({ patron_id => $patron->borrowernumber });
49
50
    my $initial_balance = $account->balance;
51
52
    my $result = $patron->add_print_notice_charge_if_needed({
53
        notice_code => 'ODUE',
54
        library_id => $patron->branchcode
55
    });
56
57
    is($result, undef, 'No charge applied when charging disabled');
58
    is($account->balance, $initial_balance, 'Account balance unchanged');
59
    is($account->lines->count, 0, 'No account lines created');
60
61
    $schema->storage->txn_rollback;
62
};
63
64
subtest 'add_print_notice_charge_if_needed with charging enabled' => sub {
65
    plan tests => 7;
66
67
    $schema->storage->txn_begin;
68
69
    # Create category with print notice charging enabled (0.75)
70
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.75 } });
71
    my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category->categorycode } });
72
    my $account = Koha::Account->new({ patron_id => $patron->borrowernumber });
73
74
    my $initial_balance = $account->balance;
75
76
    my $result = $patron->add_print_notice_charge_if_needed({
77
        notice_code => 'ODUE',
78
        library_id => $patron->branchcode
79
    });
80
81
    isa_ok($result, 'Koha::Account::Line', 'Returns account line object');
82
    is($account->balance, $initial_balance + 0.75, 'Account balance increased by charge amount');
83
    is($result->debit_type_code, 'PRINT_NOTICE', 'Correct debit type applied');
84
    cmp_ok($result->amount, '==', 0.75, 'Correct amount charged');
85
    cmp_ok($result->amountoutstanding, '==', 0.75, 'Full amount outstanding');
86
    is($result->borrowernumber, $patron->borrowernumber, 'Correct patron charged');
87
    is($result->interface, 'commandline', 'Correct interface recorded');
88
89
    $schema->storage->txn_rollback;
90
};
91
92
subtest 'add_print_notice_charge_if_needed with custom amount' => sub {
93
    plan tests => 3;
94
95
    $schema->storage->txn_begin;
96
97
    # Create category with print notice charging enabled (0.50)
98
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.50 } });
99
    my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category->categorycode } });
100
    my $account = Koha::Account->new({ patron_id => $patron->borrowernumber });
101
102
    my $custom_amount = 1.25;
103
    my $result = $patron->add_print_notice_charge_if_needed({
104
        notice_code => 'PREDUE',
105
        library_id => $patron->branchcode,
106
        amount => $custom_amount
107
    });
108
109
    isa_ok($result, 'Koha::Account::Line', 'Returns account line object');
110
    is($result->amount, $custom_amount, 'Custom amount used instead of system preference');
111
    is($account->balance, $custom_amount, 'Account balance reflects custom amount');
112
113
    $schema->storage->txn_rollback;
114
};
115
116
subtest 'add_print_notice_charge_if_needed with zero amount' => sub {
117
    plan tests => 3;
118
119
    $schema->storage->txn_begin;
120
121
    # Create category with charging disabled (0.00)
122
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.00 } });
123
    my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category->categorycode } });
124
    my $account = Koha::Account->new({ patron_id => $patron->borrowernumber });
125
126
    my $result = $patron->add_print_notice_charge_if_needed({
127
        notice_code => 'HOLD',
128
        library_id => $patron->branchcode
129
    });
130
131
    is($result, undef, 'No charge applied when amount is zero');
132
    is($account->balance, 0, 'Account balance unchanged');
133
    is($account->lines->count, 0, 'No account lines created');
134
135
    $schema->storage->txn_rollback;
136
};
137
138
subtest 'add_print_notice_charge_if_needed validation tests' => sub {
139
    plan tests => 3;
140
141
    $schema->storage->txn_begin;
142
143
    # Create category with print notice charging enabled
144
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.50 } });
145
    my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category->categorycode } });
146
147
    # Test with invalid negative amount
148
    my $result1 = $patron->add_print_notice_charge_if_needed({
149
        notice_code => 'ODUE',
150
        library_id => $patron->branchcode,
151
        amount => -0.50
152
    });
153
    is($result1, undef, 'No charge applied for negative amount');
154
155
    # Test with invalid non-numeric amount
156
    my $result2 = $patron->add_print_notice_charge_if_needed({
157
        notice_code => 'ODUE',
158
        library_id => $patron->branchcode,
159
        amount => 'invalid'
160
    });
161
    is($result2, undef, 'No charge applied for non-numeric amount');
162
163
    # Test with valid amount works
164
    my $result3 = $patron->add_print_notice_charge_if_needed({
165
        notice_code => 'ODUE',
166
        library_id => $patron->branchcode,
167
        amount => 1.00
168
    });
169
    isa_ok($result3, 'Koha::Account::Line', 'Valid amount works correctly');
170
171
    $schema->storage->txn_rollback;
172
};
173
174
subtest 'add_print_notice_charge_if_needed without notice code' => sub {
175
    plan tests => 2;
176
177
    $schema->storage->txn_begin;
178
179
    # Create category with print notice charging enabled (0.50)
180
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.50 } });
181
    my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category->categorycode } });
182
    my $account = Koha::Account->new({ patron_id => $patron->borrowernumber });
183
184
    my $result = $patron->add_print_notice_charge_if_needed({
185
        library_id => $patron->branchcode
186
    });
187
188
    isa_ok($result, 'Koha::Account::Line', 'Returns account line object even without notice code');
189
    cmp_ok($result->amount, '==', 0.50, 'Category amount used');
190
191
    $schema->storage->txn_rollback;
192
};
193
194
subtest 'add_print_notice_charge_if_needed library_id handling' => sub {
195
    plan tests => 4;
196
197
    $schema->storage->txn_begin;
198
199
    # Create category with print notice charging enabled (0.50)
200
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.50 } });
201
    my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category->categorycode } });
202
    my $account = Koha::Account->new({ patron_id => $patron->borrowernumber });
203
204
    # Get the patron's library for testing
205
    my $patron_library = $patron->branchcode;
206
207
    # Mock userenv for default library
208
    my $mock_context = Test::MockModule->new('C4::Context');
209
    $mock_context->mock('userenv', sub {
210
        return { branch => $patron_library };
211
    });
212
213
    # Test with explicit library_id
214
    my $result1 = $patron->add_print_notice_charge_if_needed({
215
        notice_code => 'ODUE',
216
        library_id => $patron_library
217
    });
218
    is($result1->branchcode, $patron_library, 'Explicit library_id used when provided');
219
220
    # Test without library_id (should use userenv)
221
    my $result2 = $patron->add_print_notice_charge_if_needed({
222
        notice_code => 'PREDUE'
223
    });
224
    is($result2->branchcode, $patron_library, 'Default library from userenv used when not provided');
225
226
    # Test with undefined userenv
227
    $mock_context->mock('userenv', sub { return; });
228
    my $result3 = $patron->add_print_notice_charge_if_needed({
229
        notice_code => 'HOLD'
230
    });
231
    isa_ok($result3, 'Koha::Account::Line', 'Still works with undefined userenv');
232
    is($result3->branchcode, undef, 'Library_id is undef when no userenv');
233
234
    $schema->storage->txn_rollback;
235
};
236
237
subtest 'add_print_notice_charge_if_needed category isolation test' => sub {
238
    plan tests => 6;
239
240
    $schema->storage->txn_begin;
241
242
    # Create two categories - one with charging enabled, one disabled
243
    my $category_enabled = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 1.25 } });
244
    my $category_disabled = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.00 } });
245
246
    # Create patrons in each category
247
    my $patron_enabled = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category_enabled->categorycode } });
248
    my $patron_disabled = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category_disabled->categorycode } });
249
250
    my $account_enabled = Koha::Account->new({ patron_id => $patron_enabled->borrowernumber });
251
    my $account_disabled = Koha::Account->new({ patron_id => $patron_disabled->borrowernumber });
252
253
    # Test patron with enabled category gets charged
254
    my $result_enabled = $patron_enabled->add_print_notice_charge_if_needed({
255
        notice_code => 'ODUE',
256
        library_id => $patron_enabled->branchcode
257
    });
258
259
    isa_ok($result_enabled, 'Koha::Account::Line', 'Patron with enabled category gets charged');
260
    cmp_ok($result_enabled->amount, '==', 1.25, 'Correct amount from enabled category');
261
    cmp_ok($account_enabled->balance, '==', 1.25, 'Enabled patron account balance updated');
262
263
    # Test patron with disabled category does not get charged
264
    my $result_disabled = $patron_disabled->add_print_notice_charge_if_needed({
265
        notice_code => 'ODUE',
266
        library_id => $patron_disabled->branchcode
267
    });
268
269
    is($result_disabled, undef, 'Patron with disabled category not charged');
270
    cmp_ok($account_disabled->balance, '==', 0, 'Disabled patron account balance unchanged');
271
    is($account_disabled->lines->count, 0, 'No account lines for disabled category patron');
272
273
    $schema->storage->txn_rollback;
274
};
(-)a/t/db_dependent/Koha/Patron/Category.t (-1 / +49 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 => 9;
23
use Test::More tests => 10;
24
24
25
use t::lib::TestBuilder;
25
use t::lib::TestBuilder;
26
use t::lib::Mocks;
26
use t::lib::Mocks;
Lines 362-364 subtest 'can_make_suggestions' => sub { Link Here
362
362
363
    $schema->storage->txn_rollback;
363
    $schema->storage->txn_rollback;
364
};
364
};
365
366
subtest 'print_notice_charge attribute tests' => sub {
367
368
    plan tests => 6;
369
370
    $schema->storage->txn_begin;
371
372
    # Test creation with default value (0 = disabled)
373
    my $category_default = $builder->build_object(
374
        {
375
            class => 'Koha::Patron::Categories',
376
            value => { print_notice_charge => 0 }
377
        }
378
    );
379
380
    cmp_ok( $category_default->print_notice_charge, '==', 0, 'Default print_notice_charge is 0 (disabled)' );
381
382
    # Test creation with custom value
383
    my $category_custom = $builder->build_object(
384
        {
385
            class => 'Koha::Patron::Categories',
386
            value => { print_notice_charge => 1.50 }
387
        }
388
    );
389
390
    cmp_ok( $category_custom->print_notice_charge, '==', 1.50, 'Custom print_notice_charge value set correctly' );
391
392
    # Test updating the value
393
    $category_custom->print_notice_charge(2.25)->store;
394
    cmp_ok( $category_custom->print_notice_charge, '==', 2.25, 'print_notice_charge updated correctly' );
395
396
    # Test zero value (disabled)
397
    $category_custom->print_notice_charge(0.00)->store;
398
    cmp_ok( $category_custom->print_notice_charge, '==', 0.00, 'print_notice_charge can be set to zero (disabled)' );
399
400
    # Test decimal precision handling
401
    $category_custom->print_notice_charge(0.123456)->store;
402
    cmp_ok(
403
        $category_custom->print_notice_charge, '==', 0.123456,
404
        'print_notice_charge handles decimal precision correctly'
405
    );
406
407
    # Test null/undef handling
408
    $category_custom->print_notice_charge(undef)->store;
409
    is( $category_custom->print_notice_charge, undef, 'print_notice_charge can be set to undef' );
410
411
    $schema->storage->txn_rollback;
412
};
(-)a/t/db_dependent/PrintNoticeCharging_EndToEnd.t (-1 / +386 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# Copyright 2024 Koha Development team
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>
19
20
use Modern::Perl;
21
22
use Test::More tests => 6;
23
use Test::Warn;
24
25
use C4::Context;
26
use C4::Letters;
27
use Koha::Account;
28
use Koha::Account::Lines;
29
use Koha::Patrons;
30
use Koha::Notice::Messages;
31
use Koha::Libraries;
32
33
use t::lib::TestBuilder;
34
35
my $schema = Koha::Database->new->schema;
36
$schema->storage->dbh->{PrintError} = 0;
37
my $builder = t::lib::TestBuilder->new;
38
C4::Context->interface('commandline');
39
40
subtest 'print notice charging workflow with charging enabled' => sub {
41
    plan tests => 7;
42
43
    $schema->storage->txn_begin;
44
45
    # Create category with print notice charging enabled (1.00)
46
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 1.00 } });
47
    
48
    # Create test patron and library
49
    my $library = $builder->build_object({ class => 'Koha::Libraries' });
50
    my $patron = $builder->build_object({
51
        class => 'Koha::Patrons',
52
        value => { 
53
            branchcode => $library->branchcode,
54
            categorycode => $category->categorycode
55
        }
56
    });
57
58
    # Create a print notice in message queue
59
    my $message = Koha::Notice::Message->new({
60
        borrowernumber => $patron->borrowernumber,
61
        subject => 'Test Notice',
62
        content => 'This is a test print notice',
63
        message_transport_type => 'print',
64
        status => 'pending',
65
        letter_code => 'ODUE',
66
        to_address => $patron->address,
67
    })->store();
68
69
    my $account = $patron->account;
70
    my $initial_balance = $account->balance;
71
    my $initial_lines = $account->lines->count;
72
73
    # Simulate what gather_print_notices.pl does
74
    is($message->status, 'pending', 'Message starts as pending');
75
76
    # Apply print notice charge (this is what our enhanced gather_print_notices.pl does)
77
    my $charge_result = $patron->add_print_notice_charge_if_needed({
78
        notice_code => $message->letter_code,
79
        library_id => $library->branchcode,
80
    });
81
82
    # Update message status to sent (as gather_print_notices.pl would do)
83
    $message->status('sent')->store();
84
85
    # Verify the charge was applied
86
    isa_ok($charge_result, 'Koha::Account::Line', 'Charge was created');
87
    is($account->balance, $initial_balance + 1.00, 'Account balance increased by charge amount');
88
    is($account->lines->count, $initial_lines + 1, 'New account line created');
89
    is($charge_result->debit_type_code, 'PRINT_NOTICE', 'Correct debit type');
90
    is($charge_result->borrowernumber, $patron->borrowernumber, 'Correct patron charged');
91
    is($message->status, 'sent', 'Message marked as sent');
92
93
    $schema->storage->txn_rollback;
94
};
95
96
subtest 'print notice charging workflow with charging disabled' => sub {
97
    plan tests => 4;
98
99
    $schema->storage->txn_begin;
100
101
    # Create category with print notice charging disabled (0.00)
102
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.00 } });
103
    
104
    # Create test patron and library
105
    my $library = $builder->build_object({ class => 'Koha::Libraries' });
106
    my $patron = $builder->build_object({
107
        class => 'Koha::Patrons',
108
        value => { 
109
            branchcode => $library->branchcode,
110
            categorycode => $category->categorycode
111
        }
112
    });
113
114
    # Create a print notice in message queue
115
    my $message = Koha::Notice::Message->new({
116
        borrowernumber => $patron->borrowernumber,
117
        subject => 'Test Notice',
118
        content => 'This is a test print notice',
119
        message_transport_type => 'print',
120
        status => 'pending',
121
        letter_code => 'ODUE',
122
        to_address => $patron->address,
123
    })->store();
124
125
    my $account = $patron->account;
126
    my $initial_balance = $account->balance;
127
    my $initial_lines = $account->lines->count;
128
129
    # Simulate what gather_print_notices.pl does when charging disabled
130
    my $charge_result = $patron->add_print_notice_charge_if_needed({
131
        notice_code => $message->letter_code,
132
        library_id => $library->branchcode,
133
    });
134
    $message->status('sent')->store();
135
136
    # Verify no charge was applied
137
    is($charge_result, undef, 'No charge created when charging disabled');
138
    is($account->balance, $initial_balance, 'Account balance unchanged');
139
    is($account->lines->count, $initial_lines, 'No new account lines created');
140
    is($message->status, 'sent', 'Message still marked as sent');
141
142
    $schema->storage->txn_rollback;
143
};
144
145
subtest 'multiple print notices for same patron' => sub {
146
    plan tests => 4;
147
148
    $schema->storage->txn_begin;
149
150
    # Create category with print notice charging enabled (0.50)
151
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.50 } });
152
    
153
    # Create test patron
154
    my $patron = $builder->build_object({ 
155
        class => 'Koha::Patrons',
156
        value => { categorycode => $category->categorycode }
157
    });
158
    my $account = $patron->account;
159
160
    # Create multiple print notices
161
    my @notice_codes = ('ODUE', 'PREDUE', 'HOLD');
162
    my @charges;
163
164
    foreach my $code (@notice_codes) {
165
        my $message = Koha::Notice::Message->new({
166
            borrowernumber => $patron->borrowernumber,
167
            subject => "Test $code Notice",
168
            content => "This is a test $code print notice",
169
            message_transport_type => 'print',
170
            status => 'pending',
171
            letter_code => $code,
172
            to_address => $patron->address,
173
        })->store();
174
175
        # Apply charge for each notice
176
        my $charge = $patron->add_print_notice_charge_if_needed({
177
            notice_code => $code,
178
            library_id => $patron->branchcode,
179
        });
180
        push @charges, $charge;
181
        $message->status('sent')->store();
182
    }
183
184
    # Verify all charges were applied
185
    is(scalar @charges, 3, 'Three charges created');
186
    is($account->balance, 1.50, 'Total balance is 3 × $0.50 = $1.50');
187
    is($account->lines->count, 3, 'Three account lines created');
188
189
    # Verify each charge has correct debit type
190
    my @lines = $account->lines->as_list;
191
    my @debit_types = map { $_->debit_type_code } @lines;
192
    is(scalar(grep { $_ eq 'PRINT_NOTICE' } @debit_types), 3, 'All charges have PRINT_NOTICE debit type');
193
194
    $schema->storage->txn_rollback;
195
};
196
197
subtest 'print notice charging with missing patron data' => sub {
198
    plan tests => 4;
199
200
    $schema->storage->txn_begin;
201
202
    # Create category with print notice charging enabled (1.00)
203
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 1.00 } });
204
    
205
    # Create a patron then delete it to simulate missing data
206
    my $patron = $builder->build_object({ 
207
        class => 'Koha::Patrons',
208
        value => { categorycode => $category->categorycode }
209
    });
210
    my $borrowernumber = $patron->borrowernumber;
211
    $patron->delete();
212
213
    # Create a message with reference to deleted patron
214
    my $message = {
215
        borrowernumber => $borrowernumber,
216
        letter_code => 'ODUE',
217
    };
218
219
    # Test our apply_print_notice_charge function behavior
220
    # This simulates what would happen in gather_print_notices.pl
221
    my $found_patron = Koha::Patrons->find($borrowernumber);
222
    is($found_patron, undef, 'Patron not found as expected');
223
224
    # The function should handle missing patrons gracefully
225
    my $result;
226
    warnings_are {
227
        if ($found_patron) {
228
            my $account = Koha::Account->new({ patron_id => $borrowernumber });
229
            $result = $patron->add_print_notice_charge_if_needed({
230
                notice_code => $message->{letter_code},
231
                library_id => 'CPL',  # Use a default library for this test
232
            });
233
        } else {
234
            $result = undef;
235
        }
236
    } [], 'No warnings when patron not found';
237
238
    is($result, undef, 'No charge attempted for missing patron');
239
240
    # Verify no orphaned account lines
241
    my $orphaned_lines = Koha::Account::Lines->search({
242
        borrowernumber => $borrowernumber
243
    });
244
    is($orphaned_lines->count, 0, 'No orphaned account lines created');
245
246
    $schema->storage->txn_rollback;
247
};
248
249
subtest 'print notice charging with different amounts' => sub {
250
    plan tests => 6;
251
252
    $schema->storage->txn_begin;
253
254
    # Create category with print notice charging enabled (0.75)
255
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.75 } });
256
    
257
    my $patron = $builder->build_object({ 
258
        class => 'Koha::Patrons',
259
        value => { categorycode => $category->categorycode }
260
    });
261
    my $account = $patron->account;
262
263
    # Test 1: Use system preference amount
264
    my $charge1 = $patron->add_print_notice_charge_if_needed({
265
        notice_code => 'ODUE',
266
        library_id => $patron->branchcode,
267
    });
268
    cmp_ok($charge1->amount, '==', 0.75, 'Category amount used when no custom amount');
269
270
    # Test 2: Use custom amount
271
    my $charge2 = $patron->add_print_notice_charge_if_needed({
272
        notice_code => 'PREDUE',
273
        library_id => $patron->branchcode,
274
        amount => 1.50,
275
    });
276
    is($charge2->amount, 1.50, 'Custom amount used when provided');
277
278
    # Test 3: Zero custom amount should not create charge
279
    my $charge3 = $patron->add_print_notice_charge_if_needed({
280
        notice_code => 'HOLD',
281
        library_id => $patron->branchcode,
282
        amount => 0.00,
283
    });
284
    is($charge3, undef, 'No charge created for zero amount');
285
286
    # Test 4: Very small amount
287
    my $charge4 = $patron->add_print_notice_charge_if_needed({
288
        notice_code => 'RENEWAL',
289
        library_id => $patron->branchcode,
290
        amount => 0.01,
291
    });
292
    is($charge4->amount, 0.01, 'Very small amounts work correctly');
293
294
    # Verify total balance
295
    is($account->balance, 2.26, 'Total balance is 0.75 + 1.50 + 0.01 = 2.26');
296
    is($account->lines->count, 3, 'Three charges created (zero amount not counted)');
297
298
    $schema->storage->txn_rollback;
299
};
300
301
subtest 'gather_print_notices.pl helper function tests' => sub {
302
    plan tests => 8;
303
304
    $schema->storage->txn_begin;
305
306
    # Create category with print notice charging enabled (0.60)
307
    my $category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { print_notice_charge => 0.60 } });
308
    
309
    # Create test patron
310
    my $patron = $builder->build_object({ 
311
        class => 'Koha::Patrons',
312
        value => { categorycode => $category->categorycode }
313
    });
314
    my $account = $patron->account;
315
316
    # Test valid message hash
317
    my $valid_message = {
318
        borrowernumber => $patron->borrowernumber,
319
        letter_code => 'ODUE',
320
    };
321
322
    # Simulate the apply_print_notice_charge function from gather_print_notices.pl
323
    my $apply_charge = sub {
324
        my ($message) = @_;
325
326
        return unless $message->{borrowernumber};
327
328
        my $patron = Koha::Patrons->find($message->{borrowernumber});
329
        return unless $patron;
330
331
        eval {
332
            my $account = Koha::Account->new({ patron_id => $patron->borrowernumber });
333
            $patron->add_print_notice_charge_if_needed({
334
                notice_code => $message->{letter_code},
335
                library_id  => $patron->branchcode,
336
            });
337
        };
338
339
        if ($@) {
340
            warn "Error applying print notice charge for patron " . $patron->borrowernumber . ": $@";
341
            return;
342
        }
343
        return 1;
344
    };
345
346
    # Test 1: Valid message
347
    my $result1 = $apply_charge->($valid_message);
348
    is($result1, 1, 'Valid message processed successfully');
349
    is($account->balance, 0.60, 'Charge applied correctly');
350
351
    # Test 2: Message with missing borrowernumber
352
    my $invalid_message1 = {
353
        letter_code => 'ODUE',
354
        branchcode => $patron->branchcode,
355
    };
356
    my $result2 = $apply_charge->($invalid_message1);
357
    is($result2, undef, 'Message without borrowernumber handled gracefully');
358
359
    # Test 3: Message with invalid borrowernumber
360
    my $invalid_message2 = {
361
        borrowernumber => 999999,
362
        letter_code => 'ODUE',
363
        branchcode => $patron->branchcode,
364
    };
365
    my $result3 = $apply_charge->($invalid_message2);
366
    is($result3, undef, 'Message with invalid borrowernumber handled gracefully');
367
368
    # Test 4: Another valid message to same patron
369
    my $valid_message2 = {
370
        borrowernumber => $patron->borrowernumber,
371
        letter_code => 'PREDUE',
372
        branchcode => $patron->branchcode,
373
    };
374
    my $result4 = $apply_charge->($valid_message2);
375
    is($result4, 1, 'Second valid message processed successfully');
376
    is($account->balance, 1.20, 'Second charge applied correctly');
377
378
    # Test 5: Verify account lines
379
    my @lines = $account->lines->as_list;
380
    is(scalar @lines, 2, 'Two account lines created');
381
382
    my @debit_types = map { $_->debit_type_code } @lines;
383
    is(scalar(grep { $_ eq 'PRINT_NOTICE' } @debit_types), 2, 'Both charges have PRINT_NOTICE debit type');
384
385
    $schema->storage->txn_rollback;
386
};

Return to bug 4858