Bug 22563: Be more descriptive with accountypes
[koha.git] / t / db_dependent / Accounts.t
1 #!/usr/bin/perl
2
3 # Copyright 2015 BibLibre
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 3 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, see <http://www.gnu.org/licenses>.
18
19 use Modern::Perl;
20
21 use Test::More tests => 33;
22 use Test::MockModule;
23 use Test::Warn;
24
25 use t::lib::TestBuilder;
26 use t::lib::Mocks;
27
28 use Koha::Account;
29 use Koha::Account::Lines;
30 use Koha::Account::Offsets;
31 use Koha::Notice::Messages;
32 use Koha::Notice::Templates;
33 use Koha::DateUtils qw( dt_from_string );
34
35 BEGIN {
36     use_ok('C4::Accounts');
37     use_ok('Koha::Object');
38     use_ok('Koha::Patron');
39     use_ok('Data::Dumper');
40 }
41
42 can_ok( 'C4::Accounts',
43     qw(
44         chargelostitem
45         manualinvoice
46         purge_zero_balance_fees )
47 );
48
49 my $schema  = Koha::Database->new->schema;
50 $schema->storage->txn_begin;
51 my $dbh = C4::Context->dbh;
52
53 my $builder = t::lib::TestBuilder->new;
54 my $library = $builder->build( { source => 'Branch' } );
55
56 $dbh->do(q|DELETE FROM accountlines|);
57 $dbh->do(q|DELETE FROM issues|);
58 $dbh->do(q|DELETE FROM borrowers|);
59
60 my $branchcode = $library->{branchcode};
61 my $borrower_number;
62
63 my $context = new Test::MockModule('C4::Context');
64 $context->mock( 'userenv', sub {
65     return {
66         flags  => 1,
67         id     => 'my_userid',
68         branch => $branchcode,
69     };
70 });
71 $context->mock( 'interface', sub { return "commandline" } );
72 my $userenv_branchcode = $branchcode;
73
74 # Test manualinvoice
75 my $itemtype = $builder->build( { source => 'Itemtype' } );
76 my $item   = $builder->build( { source => 'Item', value => { itype => $itemtype->{itemtype} } } );
77 my $patron = $builder->build( { source => 'Borrower' } );
78 my $amount = '5.000000';
79 my $description = "Test fee!";
80 my $type = 'LOST';
81 my $note = 'Test note!';
82 warning_like {
83     C4::Accounts::manualinvoice( $patron->{borrowernumber},
84         $item->{itemnumber}, $description, $type, $amount, $note )
85 }
86 qr/C4::Accounts::manualinvoice is deprecated in favor of Koha::Account->add_debit/,
87   "deprecation warning received for manualinvoice";
88 my ($accountline) = Koha::Account::Lines->search(
89     {
90         borrowernumber => $patron->{borrowernumber}
91     }
92 );
93 is( $accountline->accounttype, $type, 'Accountline type set correctly for manualinvoice' );
94 is( $accountline->amount, $amount, 'Accountline amount set correctly for manualinvoice' );
95 ok( $accountline->description =~ /^$description/, 'Accountline description set correctly for manualinvoice' );
96 is( $accountline->note, $note, 'Accountline note set correctly for manualinvoice' );
97 is( $accountline->branchcode, $branchcode, 'Accountline branchcode set correctly for manualinvoice' );
98
99 $dbh->do(q|DELETE FROM accountlines|);
100
101 # Testing purge_zero_balance_fees
102
103 # The 3rd value in the insert is 'days ago' --
104 # 0 => today
105 # 1 => yesterday
106 # etc.
107
108 my $sth = $dbh->prepare(
109     "INSERT INTO accountlines (
110          borrowernumber,
111          amountoutstanding,
112          date,
113          description,
114          interface
115      )
116      VALUES ( ?, ?, (select date_sub(CURRENT_DATE, INTERVAL ? DAY) ), ?, ? )"
117 );
118
119 my $days = 5;
120
121 my @test_data = (
122     { amount => 0     , days_ago => 0         , description =>'purge_zero_balance_fees should not delete 0 balance fees with date today'                     , delete => 0 } ,
123     { amount => 0     , days_ago => $days - 1 , description =>'purge_zero_balance_fees should not delete 0 balance fees with date before threshold day'      , delete => 0 } ,
124     { amount => 0     , days_ago => $days     , description =>'purge_zero_balance_fees should not delete 0 balance fees with date on threshold day'          , delete => 0 } ,
125     { amount => 0     , days_ago => $days + 1 , description =>'purge_zero_balance_fees should delete 0 balance fees with date after threshold day'           , delete => 1 } ,
126     { amount => undef , days_ago => $days + 1 , description =>'purge_zero_balance_fees should delete NULL balance fees with date after threshold day'        , delete => 1 } ,
127     { amount => 5     , days_ago => $days - 1 , description =>'purge_zero_balance_fees should not delete fees with positive amout owed before threshold day'  , delete => 0 } ,
128     { amount => 5     , days_ago => $days     , description =>'purge_zero_balance_fees should not delete fees with positive amout owed on threshold day'      , delete => 0 } ,
129     { amount => 5     , days_ago => $days + 1 , description =>'purge_zero_balance_fees should not delete fees with positive amout owed after threshold day'   , delete => 0 } ,
130     { amount => -5    , days_ago => $days - 1 , description =>'purge_zero_balance_fees should not delete fees with negative amout owed before threshold day' , delete => 0 } ,
131     { amount => -5    , days_ago => $days     , description =>'purge_zero_balance_fees should not delete fees with negative amout owed on threshold day'     , delete => 0 } ,
132     { amount => -5    , days_ago => $days + 1 , description =>'purge_zero_balance_fees should not delete fees with negative amout owed after threshold day'  , delete => 0 }
133 );
134 my $categorycode = $builder->build({ source => 'Category' })->{categorycode};
135 my $borrower = Koha::Patron->new( { firstname => 'Test', surname => 'Patron', categorycode => $categorycode, branchcode => $branchcode } )->store();
136
137 for my $data ( @test_data ) {
138     $sth->execute($borrower->borrowernumber, $data->{amount}, $data->{days_ago}, $data->{description}, 'commandline');
139 }
140
141 purge_zero_balance_fees( $days );
142
143 $sth = $dbh->prepare(
144             "select count(*) = 0 as deleted
145              from accountlines
146              where description = ?"
147        );
148
149 #
150 sub is_delete_correct {
151     my $should_delete = shift;
152     my $description = shift;
153     $sth->execute( $description );
154     my $test = $sth->fetchrow_hashref();
155     is( $test->{deleted}, $should_delete, $description )
156 }
157
158 for my $data  (@test_data) {
159     is_delete_correct( $data->{delete}, $data->{description});
160 }
161
162 $dbh->do(q|DELETE FROM accountlines|);
163
164 subtest "Koha::Account::pay tests" => sub {
165
166     plan tests => 14;
167
168     # Create a borrower
169     my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
170     my $branchcode   = $builder->build({ source => 'Branch' })->{ branchcode };
171
172     my $borrower = Koha::Patron->new( {
173         cardnumber => '1234567890',
174         surname => 'McFly',
175         firstname => 'Marty',
176     } );
177     $borrower->categorycode( $categorycode );
178     $borrower->branchcode( $branchcode );
179     $borrower->store;
180
181     my $account = Koha::Account->new({ patron_id => $borrower->id });
182
183     my $line1 = $account->add_debit({ type => 'account', amount => 100, interface => 'commandline' });
184     my $line2 = $account->add_debit({ type => 'account', amount => 200, interface => 'commandline' });
185
186     $sth = $dbh->prepare("SELECT count(*) FROM accountlines");
187     $sth->execute;
188     my $count = $sth->fetchrow_array;
189     is($count, 2, 'There is 2 lines as expected');
190
191     # There is $100 in the account
192     $sth = $dbh->prepare("SELECT amountoutstanding FROM accountlines WHERE borrowernumber=?");
193     my $amountoutstanding = $dbh->selectcol_arrayref($sth, {}, $borrower->borrowernumber);
194     my $amountleft = 0;
195     for my $line ( @$amountoutstanding ) {
196         $amountleft += $line;
197     }
198     is($amountleft, 300, 'The account has 300$ as expected' );
199
200     # We make a $20 payment
201     my $borrowernumber = $borrower->borrowernumber;
202     my $data = '20.00';
203     my $payment_note = '$20.00 payment note';
204     my $id = $account->pay( { amount => $data, note => $payment_note, payment_type => "TEST_TYPE" } );
205
206     my $accountline = Koha::Account::Lines->find( $id );
207     is( $accountline->payment_type, "TEST_TYPE", "Payment type passed into pay is set in account line correctly" );
208
209     # There is now $280 in the account
210     $sth = $dbh->prepare("SELECT amountoutstanding FROM accountlines WHERE borrowernumber=?");
211     $amountoutstanding = $dbh->selectcol_arrayref($sth, {}, $borrower->borrowernumber);
212     $amountleft = 0;
213     for my $line ( @$amountoutstanding ) {
214         $amountleft += $line;
215     }
216     is($amountleft, 280, 'The account has $280 as expected' );
217
218     # Is the payment note well registered
219     $sth = $dbh->prepare("SELECT note FROM accountlines WHERE borrowernumber=? ORDER BY accountlines_id DESC LIMIT 1");
220     $sth->execute($borrower->borrowernumber);
221     my $note = $sth->fetchrow_array;
222     is($note,'$20.00 payment note', '$20.00 payment note is registered');
223
224     # We make a -$30 payment (a NEGATIVE payment)
225     $data = '-30.00';
226     $payment_note = '-$30.00 payment note';
227     $account->pay( { amount => $data, note => $payment_note } );
228
229     # There is now $310 in the account
230     $sth = $dbh->prepare("SELECT amountoutstanding FROM accountlines WHERE borrowernumber=?");
231     $amountoutstanding = $dbh->selectcol_arrayref($sth, {}, $borrower->borrowernumber);
232     $amountleft = 0;
233     for my $line ( @$amountoutstanding ) {
234         $amountleft += $line;
235     }
236     is($amountleft, 310, 'The account has $310 as expected' );
237     # Is the payment note well registered
238     $sth = $dbh->prepare("SELECT note FROM accountlines WHERE borrowernumber=? ORDER BY accountlines_id DESC LIMIT 1");
239     $sth->execute($borrower->borrowernumber);
240     $note = $sth->fetchrow_array;
241     is($note,'-$30.00 payment note', '-$30.00 payment note is registered');
242
243     #We make a $150 payment ( > 1stLine )
244     $data = '150.00';
245     $payment_note = '$150.00 payment note';
246     $account->pay( { amount => $data, note => $payment_note } );
247
248     # There is now $160 in the account
249     $sth = $dbh->prepare("SELECT amountoutstanding FROM accountlines WHERE borrowernumber=?");
250     $amountoutstanding = $dbh->selectcol_arrayref($sth, {}, $borrower->borrowernumber);
251     $amountleft = 0;
252     for my $line ( @$amountoutstanding ) {
253         $amountleft += $line;
254     }
255     is($amountleft, 160, 'The account has $160 as expected' );
256
257     # Is the payment note well registered
258     $sth = $dbh->prepare("SELECT note FROM accountlines WHERE borrowernumber=? ORDER BY accountlines_id DESC LIMIT 1");
259     $sth->execute($borrower->borrowernumber);
260     $note = $sth->fetchrow_array;
261     is($note,'$150.00 payment note', '$150.00 payment note is registered');
262
263     #We make a $200 payment ( > amountleft )
264     $data = '200.00';
265     $payment_note = '$200.00 payment note';
266     $account->pay( { amount => $data, note => $payment_note } );
267
268     # There is now -$40 in the account
269     $sth = $dbh->prepare("SELECT amountoutstanding FROM accountlines WHERE borrowernumber=?");
270     $amountoutstanding = $dbh->selectcol_arrayref($sth, {}, $borrower->borrowernumber);
271     $amountleft = 0;
272     for my $line ( @$amountoutstanding ) {
273         $amountleft += $line;
274     }
275     is($amountleft, -40, 'The account has -$40 as expected, (credit situation)' );
276
277     # Is the payment note well registered
278     $sth = $dbh->prepare("SELECT note FROM accountlines WHERE borrowernumber=? ORDER BY accountlines_id DESC LIMIT 1");
279     $sth->execute($borrower->borrowernumber);
280     $note = $sth->fetchrow_array;
281     is($note,'$200.00 payment note', '$200.00 payment note is registered');
282
283     my $line3 = $account->add_debit({ type => 'account', amount => 42, interface => 'commandline' });
284     my $payment_id = $account->pay( { lines => [$line3], amount => 42 } );
285     my $payment = Koha::Account::Lines->find( $payment_id );
286     is( $payment->amount(), '-42.000000', "Payment paid the specified fine" );
287     $line3 = Koha::Account::Lines->find( $line3->id );
288     is( $line3->amountoutstanding, '0.000000', "Specified fine is paid" );
289     is( $payment->branchcode, undef, 'branchcode passed, then undef' );
290 };
291
292 subtest "Koha::Account::pay particular line tests" => sub {
293
294     plan tests => 5;
295
296     # Create a borrower
297     my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
298     my $branchcode   = $builder->build({ source => 'Branch' })->{ branchcode };
299
300     my $borrower = Koha::Patron->new( {
301         cardnumber => 'kylemhall',
302         surname => 'Hall',
303         firstname => 'Kyle',
304     } );
305     $borrower->categorycode( $categorycode );
306     $borrower->branchcode( $branchcode );
307     $borrower->store;
308
309     my $account = Koha::Account->new({ patron_id => $borrower->id });
310
311     my $line1 = $account->add_debit({ type => 'account', amount => 1, interface => 'commandline' });
312     my $line2 = $account->add_debit({ type => 'account', amount => 2, interface => 'commandline' });
313     my $line3 = $account->add_debit({ type => 'account', amount => 3, interface => 'commandline' });
314     my $line4 = $account->add_debit({ type => 'account', amount => 4, interface => 'commandline' });
315
316     is( $account->balance(), 10, "Account balance is 10" );
317
318     $account->pay(
319         {
320             lines => [$line2, $line3, $line4],
321             amount => 4,
322         }
323     );
324
325     $_->_result->discard_changes foreach ( $line1, $line2, $line3, $line4 );
326
327     # Line1 is not paid at all, as it was not passed in the lines param
328     is( $line1->amountoutstanding, "1.000000", "Line 1 was not paid" );
329     # Line2 was paid in full, as it was the first in the lines list
330     is( $line2->amountoutstanding, "0.000000", "Line 2 was paid in full" );
331     # Line3 was paid partially, as the remaining balance did not cover it entirely
332     is( $line3->amountoutstanding, "1.000000", "Line 3 was paid to 1.00" );
333     # Line4 was not paid at all, as the payment was all used up by that point
334     is( $line4->amountoutstanding, "4.000000", "Line 4 was not paid" );
335 };
336
337 subtest "Koha::Account::pay writeoff tests" => sub {
338
339     plan tests => 5;
340
341     # Create a borrower
342     my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
343     my $branchcode   = $builder->build({ source => 'Branch' })->{ branchcode };
344
345     my $borrower = Koha::Patron->new( {
346         cardnumber => 'chelseahall',
347         surname => 'Hall',
348         firstname => 'Chelsea',
349     } );
350     $borrower->categorycode( $categorycode );
351     $borrower->branchcode( $branchcode );
352     $borrower->store;
353
354     my $account = Koha::Account->new({ patron_id => $borrower->id });
355
356     my $line = $account->add_debit({ type => 'account', amount => 42, interface => 'commandline' });
357
358     is( $account->balance(), 42, "Account balance is 42" );
359
360     my $id = $account->pay(
361         {
362             lines  => [$line],
363             amount => 42,
364             type   => 'writeoff',
365         }
366     );
367
368     $line->_result->discard_changes();
369
370     is( $line->amountoutstanding, "0.000000", "Line was written off" );
371
372     my $writeoff = Koha::Account::Lines->find( $id );
373
374     is( $writeoff->accounttype, 'W', 'Type is correct' );
375     is( $writeoff->description, 'Writeoff', 'Description is correct' );
376     is( $writeoff->amount, '-42.000000', 'Amount is correct' );
377 };
378
379 subtest "More Koha::Account::pay tests" => sub {
380
381     plan tests => 8;
382
383     # Create a borrower
384     my $category   = $builder->build({ source => 'Category' })->{ categorycode };
385     my $branch     = $builder->build({ source => 'Branch' })->{ branchcode };
386     $branchcode = $branch;
387     my $borrowernumber = $builder->build({
388         source => 'Borrower',
389         value  => { categorycode => $category,
390                     branchcode   => $branch }
391     })->{ borrowernumber };
392
393     my $amount = 100;
394     my $accountline = $builder->build({ source => 'Accountline',
395         value  => { borrowernumber => $borrowernumber,
396                     amount => $amount,
397                     amountoutstanding => $amount }
398     });
399
400     my $rs = $schema->resultset('Accountline')->search({
401         borrowernumber => $borrowernumber
402     });
403
404     is( $rs->count(), 1, 'Accountline created' );
405
406     my $account = Koha::Account->new( { patron_id => $borrowernumber } );
407     my $line = Koha::Account::Lines->find( $accountline->{ accountlines_id } );
408     # make the full payment
409     $account->pay({ lines => [$line], amount => $amount, library_id => $branch, note => 'A payment note' });
410
411     my $offset = Koha::Account::Offsets->search({ debit_id => $accountline->{accountlines_id} })->next();
412     is( $offset->amount(), '-100.000000', 'Offset amount is -100.00' );
413     is( $offset->type(), 'Payment', 'Offset type is Payment' );
414
415     my $stat = $schema->resultset('Statistic')->search({
416         branch  => $branch,
417         type    => 'payment'
418     }, { order_by => { -desc => 'datetime' } })->next();
419
420     ok( defined $stat, "There's a payment log that matches the branch" );
421
422     SKIP: {
423         skip "No statistic logged", 4 unless defined $stat;
424
425         is( $stat->type, 'payment', "Correct statistic type" );
426         is( $stat->branch, $branch, "Correct branch logged to statistics" );
427         is( $stat->borrowernumber, $borrowernumber, "Correct borrowernumber logged to statistics" );
428         is( $stat->value+0, $amount, "Correct amount logged to statistics" );
429     }
430 };
431
432 subtest "Even more Koha::Account::pay tests" => sub {
433
434     plan tests => 8;
435
436     # Create a borrower
437     my $category   = $builder->build({ source => 'Category' })->{ categorycode };
438     my $branch     = $builder->build({ source => 'Branch' })->{ branchcode };
439     $branchcode = $branch;
440     my $borrowernumber = $builder->build({
441         source => 'Borrower',
442         value  => { categorycode => $category,
443                     branchcode   => $branch }
444     })->{ borrowernumber };
445
446     my $amount = 100;
447     my $partialamount = 60;
448     my $accountline = $builder->build({ source => 'Accountline',
449         value  => { borrowernumber => $borrowernumber,
450                     amount => $amount,
451                     amountoutstanding => $amount }
452     });
453
454     my $rs = $schema->resultset('Accountline')->search({
455         borrowernumber => $borrowernumber
456     });
457
458     is( $rs->count(), 1, 'Accountline created' );
459
460     my $account = Koha::Account->new( { patron_id => $borrowernumber } );
461     my $line = Koha::Account::Lines->find( $accountline->{ accountlines_id } );
462     # make the full payment
463     $account->pay({ lines => [$line], amount => $partialamount, library_id => $branch, note => 'A payment note' });
464
465     my $offset = Koha::Account::Offsets->search( { debit_id => $accountline->{ accountlines_id } } )->next();
466     is( $offset->amount, '-60.000000', 'Offset amount is -60.00' );
467     is( $offset->type, 'Payment', 'Offset type is payment' );
468
469     my $stat = $schema->resultset('Statistic')->search({
470         branch  => $branch,
471         type    => 'payment'
472     }, { order_by => { -desc => 'datetime' } })->next();
473
474     ok( defined $stat, "There's a payment log that matches the branch" );
475
476     SKIP: {
477         skip "No statistic logged", 4 unless defined $stat;
478
479         is( $stat->type, 'payment', "Correct statistic type" );
480         is( $stat->branch, $branch, "Correct branch logged to statistics" );
481         is( $stat->borrowernumber, $borrowernumber, "Correct borrowernumber logged to statistics" );
482         is( $stat->value+0, $partialamount, "Correct amount logged to statistics" );
483     }
484 };
485
486 subtest 'balance' => sub {
487     plan tests => 2;
488
489     my $patron = $builder->build({source => 'Borrower'});
490     $patron = Koha::Patrons->find( $patron->{borrowernumber} );
491     my $account = $patron->account;
492     is( $account->balance, 0, 'balance should return 0 if the patron does not have fines' );
493
494     my $accountline_1 = $builder->build(
495         {
496             source => 'Accountline',
497             value  => {
498                 borrowernumber    => $patron->borrowernumber,
499                 amount            => 42,
500                 amountoutstanding => 42
501             }
502         }
503     );
504     my $accountline_2 = $builder->build(
505         {
506             source => 'Accountline',
507             value  => {
508                 borrowernumber    => $patron->borrowernumber,
509                 amount            => -13,
510                 amountoutstanding => -13
511             }
512         }
513     );
514
515     my $balance = $patron->account->balance;
516     is( int($balance), 29, 'balance should return the correct value');
517
518     $patron->delete;
519 };
520
521 subtest "C4::Accounts::chargelostitem tests" => sub {
522     plan tests => 3;
523
524     my $branch = $builder->build( { source => 'Branch' } );
525     my $branchcode = $branch->{branchcode};
526
527     my $staff = $builder->build( { source => 'Borrower' } );
528     my $staff_id = $staff->{borrowernumber};
529
530     my $module = Test::MockModule->new('C4::Context');
531     $module->mock(
532         'userenv',
533         sub {
534             return {
535                 flags  => 1,
536                 number => $staff_id,
537                 branch => $branchcode,
538             };
539         }
540     );
541
542     my $itype_no_replace_no_fee = $builder->build({ source => 'Itemtype', value => {
543             rentalcharge => 0,
544             defaultreplacecost => undef,
545             processfee => undef,
546     }});
547     my $itype_replace_no_fee = $builder->build({ source => 'Itemtype', value => {
548             rentalcharge => 0,
549             defaultreplacecost => 16.32,
550             processfee => undef,
551     }});
552     my $itype_no_replace_fee = $builder->build({ source => 'Itemtype', value => {
553             rentalcharge => 0,
554             defaultreplacecost => undef,
555             processfee => 8.16,
556     }});
557     my $itype_replace_fee = $builder->build({ source => 'Itemtype', value => {
558             rentalcharge => 0,
559             defaultreplacecost => 4.08,
560             processfee => 2.04,
561     }});
562     my $cli_borrowernumber = $builder->build({ source => 'Borrower' })->{'borrowernumber'};
563     my $cli_itemnumber1 = $builder->build({ source => 'Item', value => { itype => $itype_no_replace_no_fee->{itemtype} } })->{'itemnumber'};
564     my $cli_itemnumber2 = $builder->build({ source => 'Item', value => { itype => $itype_replace_no_fee->{itemtype} } })->{'itemnumber'};
565     my $cli_itemnumber3 = $builder->build({ source => 'Item', value => { itype => $itype_no_replace_fee->{itemtype} } })->{'itemnumber'};
566     my $cli_itemnumber4 = $builder->build({ source => 'Item', value => { itype => $itype_replace_fee->{itemtype} } })->{'itemnumber'};
567
568     my $cli_issue_id_1 = $builder->build({ source => 'Issue', value => { borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber1 } })->{issue_id};
569     my $cli_issue_id_2 = $builder->build({ source => 'Issue', value => { borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber2 } })->{issue_id};
570     my $cli_issue_id_3 = $builder->build({ source => 'Issue', value => { borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber3 } })->{issue_id};
571     my $cli_issue_id_4 = $builder->build({ source => 'Issue', value => { borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4 } })->{issue_id};
572
573     my $lostfine;
574     my $procfee;
575
576     subtest "fee application tests" => sub {
577         plan tests => 40;
578
579         t::lib::Mocks::mock_preference('item-level_itypes', '1');
580         t::lib::Mocks::mock_preference('useDefaultReplacementCost', '0');
581
582         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber1, 0, "Perdedor");
583         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber1, accounttype => 'LOST' });
584         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber1, accounttype => 'PF' });
585         ok( !$lostfine, "No lost fine if no replacementcost or default when pref off");
586         ok( !$procfee,  "No processing fee if no processing fee");
587         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber1, 6.12, "Perdedor");
588         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber1, accounttype => 'LOST' });
589         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber1, accounttype => 'PF' });
590         ok( $lostfine->amount == 6.12, "Lost fine equals replacementcost when pref off and no default set");
591         ok( !$procfee,  "No processing fee if no processing fee");
592         $lostfine->delete();
593
594         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber2, 0, "Perdedor");
595         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber2, accounttype => 'LOST' });
596         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber2, accounttype => 'PF' });
597         ok( !$lostfine, "No lost fine if no replacementcost but default set when pref off");
598         ok( !$procfee,  "No processing fee if no processing fee");
599         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber2, 6.12, "Perdedor");
600         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber2, accounttype => 'LOST' });
601         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber2, accounttype => 'PF' });
602         ok( $lostfine->amount == 6.12 , "Lost fine equals replacementcost when pref off and default set");
603         ok( !$procfee,  "No processing fee if no processing fee");
604         $lostfine->delete();
605
606         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber3, 0, "Perdedor");
607         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber3, accounttype => 'LOST' });
608         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber3, accounttype => 'PF' });
609         ok( !$lostfine, "No lost fine if no replacementcost and no default set when pref off");
610         ok( $procfee->amount == 8.16,  "Processing fee if processing fee");
611         is( $procfee->issue_id, $cli_issue_id_3, "Processing fee issue id is correct" );
612         $procfee->delete();
613         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber3, 6.12, "Perdedor");
614         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber3, accounttype => 'LOST' });
615         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber3, accounttype => 'PF' });
616         ok( $lostfine->amount == 6.12 , "Lost fine equals replacementcost when pref off and no default set");
617         ok( $procfee->amount == 8.16,  "Processing fee if processing fee");
618         is( $procfee->issue_id, $cli_issue_id_3, "Processing fee issue id is correct" );
619         $lostfine->delete();
620         $procfee->delete();
621
622         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber4, 0, "Perdedor");
623         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'LOST' });
624         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'PF' });
625         ok( !$lostfine, "No lost fine if no replacementcost but default set when pref off");
626         ok( $procfee->amount == 2.04,  "Processing fee if processing fee");
627         is( $procfee->issue_id, $cli_issue_id_4, "Processing fee issue id is correct" );
628         $procfee->delete();
629         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber4, 6.12, "Perdedor");
630         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'LOST' });
631         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'PF' });
632         ok( $lostfine->amount == 6.12 , "Lost fine equals replacementcost when pref off and default set");
633         ok( $procfee->amount == 2.04,  "Processing fee if processing fee");
634         is( $procfee->issue_id, $cli_issue_id_4, "Processing fee issue id is correct" );
635         $lostfine->delete();
636         $procfee->delete();
637
638         t::lib::Mocks::mock_preference('useDefaultReplacementCost', '1');
639
640         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber1, 0, "Perdedor");
641         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber1, accounttype => 'LOST' });
642         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber1, accounttype => 'PF' });
643         ok( !$lostfine, "No lost fine if no replacementcost or default when pref on");
644         ok( !$procfee,  "No processing fee if no processing fee");
645         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber1, 6.12, "Perdedor");
646         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber1, accounttype => 'LOST' });
647         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber1, accounttype => 'PF' });
648         is( $lostfine->amount, "6.120000", "Lost fine equals replacementcost when pref on and no default set");
649         ok( !$procfee,  "No processing fee if no processing fee");
650
651         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber2, 0, "Perdedor");
652         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber2, accounttype => 'LOST' });
653         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber2, accounttype => 'PF' });
654         is( $lostfine->amount(), "16.320000", "Lost fine is default if no replacementcost but default set when pref on");
655         ok( !$procfee,  "No processing fee if no processing fee");
656         $lostfine->delete();
657         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber2, 6.12, "Perdedor");
658         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber2, accounttype => 'LOST' });
659         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber2, accounttype => 'PF' });
660         is( $lostfine->amount, "6.120000" , "Lost fine equals replacementcost when pref on and default set");
661         ok( !$procfee,  "No processing fee if no processing fee");
662
663         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber3, 0, "Perdedor");
664         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber3, accounttype => 'LOST' });
665         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber3, accounttype => 'PF' });
666         ok( !$lostfine, "No lost fine if no replacementcost and default not set when pref on");
667         is( $procfee->amount, "8.160000",  "Processing fee if processing fee");
668         is( $procfee->issue_id, $cli_issue_id_3, "Processing fee issue id is correct" );
669         $procfee->delete();
670         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber3, 6.12, "Perdedor");
671         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber3, accounttype => 'LOST' });
672         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber3, accounttype => 'PF' });
673         is( $lostfine->amount, "6.120000", "Lost fine equals replacementcost when pref on and no default set");
674         is( $procfee->amount, "8.160000",  "Processing fee if processing fee");
675         is( $procfee->issue_id, $cli_issue_id_3, "Processing fee issue id is correct" );
676
677         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber4, 0, "Perdedor");
678         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'LOST' });
679         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'PF' });
680         is( $lostfine->amount, "4.080000", "Lost fine is default if no replacementcost but default set when pref on");
681         is( $procfee->amount, "2.040000",  "Processing fee if processing fee");
682         is( $procfee->issue_id, $cli_issue_id_4, "Processing fee issue id is correct" );
683         $lostfine->delete();
684         $procfee->delete();
685         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber4, 6.12, "Perdedor");
686         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'LOST' });
687         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'PF' });
688         is( $lostfine->amount, "6.120000", "Lost fine equals replacementcost when pref on and default set");
689         is( $procfee->amount, "2.040000",  "Processing fee if processing fee");
690         is( $procfee->issue_id, $cli_issue_id_4, "Processing fee issue id is correct" );
691         $lostfine->delete();
692         $procfee->delete();
693     };
694
695     subtest "basic fields tests" => sub {
696         plan tests => 12;
697
698         t::lib::Mocks::mock_preference('ProcessingFeeNote', 'Test Note');
699         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber4, '1.99', "Perdedor");
700
701         # Lost Item Fee
702         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'LOST' });
703         ok($lostfine, "Lost fine created");
704         is($lostfine->manager_id, $staff_id, "Lost fine manager_id set correctly");
705         is($lostfine->issue_id, $cli_issue_id_4, "Lost fine issue_id set correctly");
706         is($lostfine->description, "Perdedor", "Lost fine issue_id set correctly");
707         is($lostfine->note, '', "Lost fine does not contain a note");
708         is($lostfine->branchcode, $branchcode, "Lost fine branchcode set correctly");
709
710         # Processing Fee
711         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'PF' });
712         ok($procfee, "Processing fee created");
713         is($procfee->manager_id, $staff_id, "Processing fee manager_id set correctly");
714         is($procfee->issue_id, $cli_issue_id_4, "Processing fee issue_id set correctly");
715         is($procfee->description, "Perdedor", "Processing fee issue_id set correctly");
716         is($procfee->note, C4::Context->preference("ProcessingFeeNote"), "Processing fee contains note matching ProcessingFeeNote");
717         is($procfee->branchcode, $branchcode, "Processing fee branchcode set correctly");
718         $lostfine->delete();
719         $procfee->delete();
720     };
721
722     subtest "FinesLog tests" => sub {
723         plan tests => 2;
724
725         my $action_logs = $schema->resultset('ActionLog')->search()->count;
726
727         t::lib::Mocks::mock_preference( 'FinesLog', 0 );
728         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber4, 0, "Perdedor");
729         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'LOST' });
730         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'PF' });
731         is( $schema->resultset('ActionLog')->count(), $action_logs + 0, 'No logs were added' );
732         $lostfine->delete();
733         $procfee->delete();
734
735         t::lib::Mocks::mock_preference( 'FinesLog', 1 );
736         C4::Accounts::chargelostitem( $cli_borrowernumber, $cli_itemnumber4, 0, "Perdedor");
737         $lostfine = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'LOST' });
738         $procfee  = Koha::Account::Lines->find({ borrowernumber => $cli_borrowernumber, itemnumber => $cli_itemnumber4, accounttype => 'PF' });
739         is( $schema->resultset('ActionLog')->count(), $action_logs + 2, 'Logs were added' );
740         $lostfine->delete();
741         $procfee->delete();
742     };
743
744     # Cleanup - this must be replaced with a transaction per subtest
745     Koha::Patrons->find($cli_borrowernumber)->checkouts->delete;
746 };
747
748 subtest "Koha::Account::non_issues_charges tests" => sub {
749     plan tests => 21;
750
751     my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
752     my $account = $patron->account;
753
754     my $today  = dt_from_string;
755     my $res    = 3;
756     my $rent   = 5;
757     my $manual = 7;
758     $account->add_debit(
759         {
760             description => 'a Res fee',
761             type        => 'reserve',
762             amount      => $res,
763             interface   => 'commandline'
764         }
765     );
766     $account->add_debit(
767         {
768             description => 'a Rental fee',
769             type        => 'rent',
770             amount      => $rent,
771             interface   => 'commandline'
772         }
773     );
774     Koha::Account::Line->new(
775         {
776             borrowernumber    => $patron->borrowernumber,
777             date              => $today,
778             description       => 'a Manual invoice fee',
779             accounttype       => 'Copie',
780             amountoutstanding => $manual,
781             interface         => 'commandline'
782         }
783     )->store;
784     Koha::AuthorisedValue->new(
785         {
786             category         => 'MANUAL_INV',
787             authorised_value => 'Copie',
788             lib              => 'Fee for copie',
789         }
790     )->store;
791
792
793     t::lib::Mocks::mock_preference( 'HoldsInNoissuesCharge',   0 );
794     t::lib::Mocks::mock_preference( 'RentalsInNoissuesCharge', 0 );
795     t::lib::Mocks::mock_preference( 'ManInvInNoissuesCharge',  0 );
796     my ( $total, $non_issues_charges ) = ( $account->balance, $account->non_issues_charges );
797     my $other_charges = $total - $non_issues_charges;
798     is(
799         $account->balance,
800         $res + $rent + $manual,
801         'Total charges should be Res + Rent + Manual'
802     );
803     is( $non_issues_charges, 0,
804         'If 0|0|0 there should not have non issues charges' );
805     is( $other_charges, 15, 'If 0|0|0 there should only have other charges' );
806
807     t::lib::Mocks::mock_preference( 'HoldsInNoissuesCharge',   0 );
808     t::lib::Mocks::mock_preference( 'RentalsInNoissuesCharge', 0 );
809     t::lib::Mocks::mock_preference( 'ManInvInNoissuesCharge',  1 );
810     ( $total, $non_issues_charges ) = ( $account->balance, $account->non_issues_charges );
811     $other_charges = $total - $non_issues_charges;
812     is(
813         $total,
814         $res + $rent + $manual,
815         'Total charges should be Res + Rent + Manual'
816     );
817     is( $non_issues_charges, $manual,
818         'If 0|0|1 Only Manual should be a non issue charge' );
819     is(
820         $other_charges,
821         $res + $rent,
822         'If 0|0|1 Res + Rent should be other charges'
823     );
824
825     t::lib::Mocks::mock_preference( 'HoldsInNoissuesCharge',   0 );
826     t::lib::Mocks::mock_preference( 'RentalsInNoissuesCharge', 1 );
827     t::lib::Mocks::mock_preference( 'ManInvInNoissuesCharge',  0 );
828     ( $total, $non_issues_charges ) = ( $account->balance, $account->non_issues_charges );
829     $other_charges = $total - $non_issues_charges;
830     is(
831         $total,
832         $res + $rent + $manual,
833         'Total charges should be Res + Rent + Manual'
834     );
835     is( $non_issues_charges, $rent,
836         'If 0|1|0 Only Rental should be a non issue charge' );
837     is(
838         $other_charges,
839         $res + $manual,
840         'If 0|1|0 Rent + Manual should be other charges'
841     );
842
843     t::lib::Mocks::mock_preference( 'HoldsInNoissuesCharge',   0 );
844     t::lib::Mocks::mock_preference( 'RentalsInNoissuesCharge', 1 );
845     t::lib::Mocks::mock_preference( 'ManInvInNoissuesCharge',  1 );
846     ( $total, $non_issues_charges ) = ( $account->balance, $account->non_issues_charges );
847     $other_charges = $total - $non_issues_charges;
848     is(
849         $total,
850         $res + $rent + $manual,
851         'Total charges should be Res + Rent + Manual'
852     );
853     is(
854         $non_issues_charges,
855         $rent + $manual,
856         'If 0|1|1 Rent + Manual should be non issues charges'
857     );
858     is( $other_charges, $res, 'If 0|1|1 there should only have other charges' );
859
860     t::lib::Mocks::mock_preference( 'HoldsInNoissuesCharge',   1 );
861     t::lib::Mocks::mock_preference( 'RentalsInNoissuesCharge', 0 );
862     t::lib::Mocks::mock_preference( 'ManInvInNoissuesCharge',  0 );
863     ( $total, $non_issues_charges ) = ( $account->balance, $account->non_issues_charges );
864     $other_charges = $total - $non_issues_charges;
865     is(
866         $total,
867         $res + $rent + $manual,
868         'Total charges should be Res + Rent + Manual'
869     );
870     is( $non_issues_charges, $res,
871         'If 1|0|0 Only Res should be non issues charges' );
872     is(
873         $other_charges,
874         $rent + $manual,
875         'If 1|0|0 Rent + Manual should be other charges'
876     );
877
878     t::lib::Mocks::mock_preference( 'HoldsInNoissuesCharge',   1 );
879     t::lib::Mocks::mock_preference( 'RentalsInNoissuesCharge', 1 );
880     t::lib::Mocks::mock_preference( 'ManInvInNoissuesCharge',  0 );
881     ( $total, $non_issues_charges ) = ( $account->balance, $account->non_issues_charges );
882     $other_charges = $total - $non_issues_charges;
883     is(
884         $total,
885         $res + $rent + $manual,
886         'Total charges should be Res + Rent + Manual'
887     );
888     is(
889         $non_issues_charges,
890         $res + $rent,
891         'If 1|1|0 Res + Rent should be non issues charges'
892     );
893     is( $other_charges, $manual,
894         'If 1|1|0 Only Manual should be other charges' );
895
896     t::lib::Mocks::mock_preference( 'HoldsInNoissuesCharge',   1 );
897     t::lib::Mocks::mock_preference( 'RentalsInNoissuesCharge', 1 );
898     t::lib::Mocks::mock_preference( 'ManInvInNoissuesCharge',  1 );
899     ( $total, $non_issues_charges ) = ( $account->balance, $account->non_issues_charges );
900     $other_charges = $total - $non_issues_charges;
901     is(
902         $total,
903         $res + $rent + $manual,
904         'Total charges should be Res + Rent + Manual'
905     );
906     is(
907         $non_issues_charges,
908         $res + $rent + $manual,
909         'If 1|1|1 Res + Rent + Manual should be non issues charges'
910     );
911     is( $other_charges, 0, 'If 1|1|1 there should not have any other charges' );
912 };
913
914 subtest "Koha::Account::non_issues_charges tests" => sub {
915     plan tests => 9;
916
917     my $patron = $builder->build_object(
918         {
919             class => "Koha::Patrons",
920             value => {
921                 firstname    => 'Test',
922                 surname      => 'Patron',
923                 categorycode => $categorycode,
924                 branchcode   => $branchcode
925             }
926         }
927     );
928
929     my $debit = Koha::Account::Line->new({ borrowernumber => $patron->id, date => '1900-01-01', amountoutstanding => 0, interface => 'commandline' })->store();
930     my $credit = Koha::Account::Line->new({ borrowernumber => $patron->id, date => '1900-01-01', amountoutstanding => -5, interface => 'commandline' })->store();
931     my $offset = Koha::Account::Offset->new({ credit_id => $credit->id, debit_id => $debit->id, type => 'Payment', amount => 0 })->store();
932     purge_zero_balance_fees( 1 );
933     my $debit_2 = Koha::Account::Lines->find( $debit->id );
934     my $credit_2 = Koha::Account::Lines->find( $credit->id );
935     ok( $debit_2, 'Debit was correctly not deleted when credit has balance' );
936     ok( $credit_2, 'Credit was correctly not deleted when credit has balance' );
937     is( Koha::Account::Lines->count({ borrowernumber => $patron->id }), 2, "The 2 account lines still exists" );
938
939     $debit = Koha::Account::Line->new({ borrowernumber => $patron->id, date => '1900-01-01', amountoutstanding => 5, interface => 'commanline' })->store();
940     $credit = Koha::Account::Line->new({ borrowernumber => $patron->id, date => '1900-01-01', amountoutstanding => 0, interface => 'commandline' })->store();
941     $offset = Koha::Account::Offset->new({ credit_id => $credit->id, debit_id => $debit->id, type => 'Payment', amount => 0 })->store();
942     purge_zero_balance_fees( 1 );
943     $debit_2 = $credit_2 = undef;
944     $debit_2 = Koha::Account::Lines->find( $debit->id );
945     $credit_2 = Koha::Account::Lines->find( $credit->id );
946     ok( $debit_2, 'Debit was correctly not deleted when debit has balance' );
947     ok( $credit_2, 'Credit was correctly not deleted when debit has balance' );
948     is( Koha::Account::Lines->count({ borrowernumber => $patron->id }), 2 + 2, "The 2 + 2 account lines still exists" );
949
950     $debit = Koha::Account::Line->new({ borrowernumber => $patron->id, date => '1900-01-01', amountoutstanding => 0, interface => 'commandline' })->store();
951     $credit = Koha::Account::Line->new({ borrowernumber => $patron->id, date => '1900-01-01', amountoutstanding => 0, interface => 'commandline' })->store();
952     $offset = Koha::Account::Offset->new({ credit_id => $credit->id, debit_id => $debit->id, type => 'Payment', amount => 0 })->store();
953     purge_zero_balance_fees( 1 );
954     $debit_2 = Koha::Account::Lines->find( $debit->id );
955     $credit_2 = Koha::Account::Lines->find( $credit->id );
956     ok( !$debit_2, 'Debit was correctly deleted' );
957     ok( !$credit_2, 'Credit was correctly deleted' );
958     is( Koha::Account::Lines->count({ borrowernumber => $patron->id }), 2 + 2, "The 2 + 2 account lines still exists, the last 2 have been deleted ok" );
959 };
960
961
962 subtest "Koha::Account::Offset credit & debit tests" => sub {
963
964     plan tests => 4;
965
966     # Create a borrower
967     my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
968     my $branchcode   = $builder->build({ source => 'Branch' })->{ branchcode };
969
970     my $borrower = Koha::Patron->new( {
971         cardnumber => 'kyliehall',
972         surname => 'Hall',
973         firstname => 'Kylie',
974     } );
975     $borrower->categorycode( $categorycode );
976     $borrower->branchcode( $branchcode );
977     $borrower->store;
978
979     my $account = Koha::Account->new({ patron_id => $borrower->id });
980
981     my $line1 = Koha::Account::Line->new({ borrowernumber => $borrower->borrowernumber, amount => 10, amountoutstanding => 10, interface => 'commandline' })->store();
982     my $line2 = Koha::Account::Line->new({ borrowernumber => $borrower->borrowernumber, amount => 20, amountoutstanding => 20, interface => 'commandline' })->store();
983
984     my $id = $account->pay(
985         {
986             lines  => [$line1, $line2],
987             amount => 30,
988         }
989     );
990
991     # Test debit and credit methods for Koha::Account::Offset
992     my $account_offset = Koha::Account::Offsets->find( { credit_id => $id, debit_id => $line1->id } );
993     is( $account_offset->debit->id, $line1->id, "Koha::Account::Offset->debit gets correct accountline" );
994     is( $account_offset->credit->id, $id, "Koha::Account::Offset->credit gets correct accountline" );
995
996     $account_offset = Koha::Account::Offset->new(
997         {
998             credit_id => undef,
999             debit_id  => undef,
1000             type      => 'Payment',
1001             amount    => 0,
1002         }
1003     )->store();
1004
1005     is( $account_offset->debit, undef, "Koha::Account::Offset->debit returns undef if no associated debit" );
1006     is( $account_offset->credit, undef, "Koha::Account::Offset->credit returns undef if no associated credit" );
1007 };
1008
1009 subtest "Payment notice tests" => sub {
1010
1011     plan tests => 8;
1012
1013     Koha::Account::Lines->delete();
1014     Koha::Patrons->delete();
1015     Koha::Notice::Messages->delete();
1016     # Create a borrower
1017     my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
1018     my $branchcode   = $builder->build({ source => 'Branch' })->{ branchcode };
1019
1020     my $borrower = Koha::Patron->new(
1021         {
1022             cardnumber   => 'chelseahall',
1023             surname      => 'Hall',
1024             firstname    => 'Chelsea',
1025             email        => 'chelsea@example.com',
1026             categorycode => $categorycode,
1027             branchcode   => $branchcode,
1028         }
1029     )->store();
1030
1031     my $manager = $builder->build_object({ class => "Koha::Patrons" });
1032     my $context = new Test::MockModule('C4::Context');
1033     $context->mock( 'userenv', sub {
1034         return {
1035             number     => $manager->borrowernumber,
1036             branch     => $manager->branchcode,
1037         };
1038     });
1039     my $account = Koha::Account->new({ patron_id => $borrower->id });
1040
1041     my $line = Koha::Account::Line->new({ borrowernumber => $borrower->borrowernumber, amountoutstanding => 27, interface => 'commandline' })->store();
1042
1043     my $letter = Koha::Notice::Templates->find( { code => 'ACCOUNT_PAYMENT' } );
1044     $letter->content('[%- USE Price -%]A payment of [% credit.amount * -1 | $Price %] has been applied to your account.');
1045     $letter->store();
1046
1047     t::lib::Mocks::mock_preference('UseEmailReceipts', '0');
1048     my $id = $account->pay( { amount => 1 } );
1049     is( Koha::Notice::Messages->search()->count(), 0, 'Notice for payment not sent if UseEmailReceipts is disabled' );
1050
1051     $id = $account->pay( { amount => 1, type => 'writeoff' } );
1052     is( Koha::Notice::Messages->search()->count(), 0, 'Notice for writeoff not sent if UseEmailReceipts is disabled' );
1053
1054     t::lib::Mocks::mock_preference('UseEmailReceipts', '1');
1055
1056     $id = $account->pay( { amount => 12 } );
1057     my $notice = Koha::Notice::Messages->search()->next();
1058     is( $notice->subject, 'Account payment', 'Notice subject is correct for payment' );
1059     is( $notice->letter_code, 'ACCOUNT_PAYMENT', 'Notice letter code is correct for payment' );
1060     is( $notice->content, 'A payment of 12.00 has been applied to your account.', 'Notice content is correct for payment' );
1061     $notice->delete();
1062
1063     $letter = Koha::Notice::Templates->find( { code => 'ACCOUNT_WRITEOFF' } );
1064     $letter->content('[%- USE Price -%]A writeoff of [% credit.amount * -1 | $Price %] has been applied to your account.');
1065     $letter->store();
1066
1067     $id = $account->pay( { amount => 13, type => 'writeoff' } );
1068     $notice = Koha::Notice::Messages->search()->next();
1069     is( $notice->subject, 'Account writeoff', 'Notice subject is correct for payment' );
1070     is( $notice->letter_code, 'ACCOUNT_WRITEOFF', 'Notice letter code is correct for writeoff' );
1071     is( $notice->content, 'A writeoff of 13.00 has been applied to your account.', 'Notice content is correct for writeoff' );
1072 };
1073
1074 1;