Bug 25079: Show club enrollment question answers in staff client
[koha.git] / t / db_dependent / SIP / Transaction.t
1 #!/usr/bin/perl
2
3 # Tests for SIP::ILS::Transaction
4 # Current state is very rudimentary. Please help to extend it!
5
6 use Modern::Perl;
7 use Test::More tests => 17;
8
9 use Koha::Database;
10 use t::lib::TestBuilder;
11 use t::lib::Mocks;
12 use C4::SIP::ILS;
13 use C4::SIP::ILS::Patron;
14 use C4::SIP::ILS::Transaction::RenewAll;
15 use C4::SIP::ILS::Transaction::Checkout;
16 use C4::SIP::ILS::Transaction::FeePayment;
17 use C4::SIP::ILS::Transaction::Hold;
18 use C4::SIP::ILS::Transaction::Checkout;
19 use C4::SIP::ILS::Transaction::Checkin;
20
21 use C4::Reserves qw( AddReserve ModReserve ModReserveAffect RevertWaitingStatus );
22 use Koha::CirculationRules;
23 use Koha::Item::Transfer;
24 use Koha::DateUtils qw( dt_from_string output_pref );
25
26 my $schema = Koha::Database->new->schema;
27 $schema->storage->txn_begin;
28
29 my $builder = t::lib::TestBuilder->new();
30 my $borr1 = $builder->build({ source => 'Borrower' });
31 my $card = $borr1->{cardnumber};
32 my $sip_patron = C4::SIP::ILS::Patron->new( $card );
33
34 # Create transaction RenewAll, assign patron, and run (no items)
35 my $transaction = C4::SIP::ILS::Transaction::RenewAll->new();
36 is( ref $transaction, "C4::SIP::ILS::Transaction::RenewAll", "New transaction created" );
37 is( $transaction->patron( $sip_patron ), $sip_patron, "Patron assigned to transaction" );
38 isnt( $transaction->do_renew_all, undef, "RenewAll on zero items" );
39
40 subtest fill_holds_at_checkout => sub {
41     plan tests => 6;
42
43
44     my $category = $builder->build({ source => 'Category', value => { category_type => 'A' }});
45     my $branch   = $builder->build({ source => 'Branch' });
46     my $borrower = $builder->build({ source => 'Borrower', value =>{
47         branchcode => $branch->{branchcode},
48         categorycode=>$category->{categorycode}
49         }
50     });
51     t::lib::Mocks::mock_userenv({ branchcode => $branch->{branchcode}, flags => 1 });
52
53     my $itype = $builder->build({ source => 'Itemtype', value =>{notforloan=>0} });
54     my $item1 = $builder->build_sample_item({
55         barcode       => 'barcode4test',
56         homebranch    => $branch->{branchcode},
57         holdingbranch => $branch->{branchcode},
58         itype         => $itype->{itemtype},
59         notforloan       => 0,
60     })->unblessed;
61     my $item2 = $builder->build_sample_item({
62         homebranch    => $branch->{branchcode},
63         holdingbranch => $branch->{branchcode},
64         biblionumber  => $item1->{biblionumber},
65         itype         => $itype->{itemtype},
66         notforloan       => 0,
67     })->unblessed;
68
69     Koha::CirculationRules->set_rules(
70         {
71             categorycode => $borrower->{categorycode},
72             branchcode   => $branch->{branchcode},
73             itemtype     => $itype->{itemtype},
74             rules        => {
75                 onshelfholds     => 1,
76                 reservesallowed  => 3,
77                 holds_per_record => 3,
78                 issuelength      => 5,
79                 lengthunit       => 'days',
80             }
81         }
82     );
83
84     my $reserve1 = AddReserve(
85         {
86             branchcode     => $branch->{branchcode},
87             borrowernumber => $borrower->{borrowernumber},
88             biblionumber   => $item1->{biblionumber}
89         }
90     );
91     my $reserve2 = AddReserve(
92         {
93             branchcode     => $branch->{branchcode},
94             borrowernumber => $borrower->{borrowernumber},
95             biblionumber   => $item1->{biblionumber}
96         }
97     );
98
99     my $bib = Koha::Biblios->find( $item1->{biblionumber} );
100     is( $bib->holds->count(), 2, "Bib has 2 holds");
101
102     my $sip_patron = C4::SIP::ILS::Patron->new( $borrower->{cardnumber} );
103     my $sip_item   = C4::SIP::ILS::Item->new( $item1->{barcode} );
104     my $transaction = C4::SIP::ILS::Transaction::Checkout->new();
105     is( ref $transaction, "C4::SIP::ILS::Transaction::Checkout", "New transaction created" );
106     is( $transaction->patron( $sip_patron ), $sip_patron, "Patron assigned to transaction" );
107     is( $transaction->item( $sip_item ), $sip_item, "Item assigned to transaction" );
108     my $checkout = $transaction->do_checkout();
109     use Data::Dumper; # Temporary debug statement
110     is( $bib->holds->count(), 1, "Bib has 1 holds remaining") or diag Dumper $checkout;
111
112     t::lib::Mocks::mock_preference('itemBarcodeInputFilter', 'whitespace');
113     $sip_item   = C4::SIP::ILS::Item->new( ' barcode 4 test ');
114     $transaction = C4::SIP::ILS::Transaction::Checkout->new();
115     is( $sip_item->{barcode}, $item1->{barcode}, "Item assigned to transaction" );
116 };
117
118 subtest "FeePayment->pay tests" => sub {
119
120     plan tests => 5;
121
122     # Create a borrower and add some outstanding debts to their account
123     my $patron = $builder->build( { source => 'Borrower' } );
124     my $account =
125       Koha::Account->new( { patron_id => $patron->{borrowernumber} } );
126     my $debt1 = $account->add_debit(
127         { type => 'ACCOUNT', amount => 100, interface => 'commandline' } );
128     my $debt2 = $account->add_debit(
129         { type => 'ACCOUNT', amount => 200, interface => 'commandline' } );
130
131     # Instantiate a new FeePayment transaction object
132     my $trans = C4::SIP::ILS::Transaction::FeePayment->new();
133     is(
134         ref $trans,
135         "C4::SIP::ILS::Transaction::FeePayment",
136         "New fee transaction created"
137     );
138
139     # Test the 'pay' method
140     # FIXME: pay should not require a borrowernumber
141     # (we should reach out to the transaction which should contain a patron object)
142     my $pay_type = '00';    # 00 - Cash, 01 - VISA, 02 - Creditcard
143     my $ok =
144       $trans->pay( $patron->{borrowernumber}, 100, $pay_type, $debt1->id, 0,
145         0 );
146     ok( $ok, "FeePayment transaction succeeded" );
147     $debt1->discard_changes;
148     is( $debt1->amountoutstanding + 0, 0,
149         "Debt1 was reduced to 0 as expected" );
150     my $offsets = Koha::Account::Offsets->search(
151         { debit_id => $debt1->id, credit_id => { '!=' => undef } } );
152     is( $offsets->count, 1, "FeePayment produced an offset line correctly" );
153     my $credit = $offsets->next->credit;
154     is( $credit->payment_type, 'SIP00', "Payment type was set correctly" );
155 };
156
157 subtest cancel_hold => sub {
158     plan tests => 7;
159
160     my $library = $builder->build_object ({ class => 'Koha::Libraries' });
161     my $patron = $builder->build_object(
162         {
163             class => 'Koha::Patrons',
164             value => {
165                 branchcode => $library->branchcode,
166             }
167         }
168     );
169     t::lib::Mocks::mock_userenv({ branchcode => $library->branchcode, flags => 1 });
170
171     my $item = $builder->build_sample_item({
172         library       => $library->branchcode,
173     });
174
175     Koha::CirculationRules->set_rules(
176         {
177             categorycode => $patron->categorycode,
178             branchcode   => $library->branchcode,
179             itemtype     => $item->effective_itemtype,
180             rules        => {
181                 onshelfholds     => 1,
182                 reservesallowed  => 3,
183                 holds_per_record => 3,
184                 issuelength      => 5,
185                 lengthunit       => 'days',
186             }
187         }
188     );
189
190     my $reserve1 = AddReserve(
191         {
192             branchcode     => $library->branchcode,
193             borrowernumber => $patron->borrowernumber,
194             biblionumber   => $item->biblio->biblionumber,
195             itemnumber     => $item->itemnumber,
196         }
197     );
198     is( $item->biblio->holds->count(), 1, "Hold was placed on bib");
199     is( $item->holds->count(),1,"Hold was placed on specific item");
200
201     my $sip_patron = C4::SIP::ILS::Patron->new( $patron->cardnumber );
202     my $sip_item   = C4::SIP::ILS::Item->new( $item->barcode );
203     my $transaction = C4::SIP::ILS::Transaction::Hold->new();
204     is( ref $transaction, "C4::SIP::ILS::Transaction::Hold", "New transaction created" );
205     is( $transaction->patron( $sip_patron ), $sip_patron, "Patron assigned to transaction" );
206     is( $transaction->item( $sip_item ), $sip_item, "Item assigned to transaction" );
207     my $hold = $transaction->drop_hold();
208     is( $item->biblio->holds->count(), 0, "Bib has 0 holds remaining");
209     is( $item->holds->count(), 0,  "Item has 0 holds remaining");
210 };
211
212 subtest do_hold => sub {
213     plan tests => 8;
214
215     my $library = $builder->build_object(
216         {
217             class => 'Koha::Libraries',
218             value => {
219                 pickup_location => 1
220             }
221         }
222     );
223     my $patron_1 = $builder->build_object(
224         {
225             class => 'Koha::Patrons',
226             value => {
227                 branchcode => $library->branchcode,
228             }
229         }
230     );
231     my $patron_2 = $builder->build_object(
232         {
233             class => 'Koha::Patrons',
234             value => {
235                 branchcode   => $library->branchcode,
236                 categorycode => $patron_1->categorycode,
237             }
238         }
239     );
240
241     t::lib::Mocks::mock_userenv(
242         { branchcode => $library->branchcode, flags => 1 } );
243
244     my $item = $builder->build_sample_item(
245         {
246             library => $library->branchcode,
247         }
248     );
249
250     my $reserve1 = AddReserve(
251         {
252             branchcode     => $library->branchcode,
253             borrowernumber => $patron_1->borrowernumber,
254             biblionumber   => $item->biblio->biblionumber,
255             itemnumber     => $item->itemnumber,
256         }
257     );
258     is( $item->biblio->holds->count(), 1, "Hold was placed on bib" );
259     is( $item->holds->count(),         1, "Hold was placed on specific item" );
260
261     my $sip_patron  = C4::SIP::ILS::Patron->new( $patron_2->cardnumber );
262     my $sip_item    = C4::SIP::ILS::Item->new( $item->barcode );
263     my $transaction = C4::SIP::ILS::Transaction::Hold->new();
264     is(
265         ref $transaction,
266         "C4::SIP::ILS::Transaction::Hold",
267         "New transaction created"
268     );
269     is( $transaction->patron($sip_patron),
270         $sip_patron, "Patron assigned to transaction" );
271     is( $transaction->item($sip_item),
272         $sip_item, "Item assigned to transaction" );
273     my $hold = $transaction->do_hold();
274     is( $item->biblio->holds->count(), 2, "Bib has 2 holds" );
275
276     my $THE_hold = $patron_2->holds->next;
277     is( $THE_hold->priority, 2, 'Hold placed from SIP should have a correct priority of 2');
278     is( $THE_hold->branchcode, $patron_2->branchcode, 'Hold placed from SIP should have the branchcode set' );
279 };
280
281 subtest "Placing holds via SIP check CanItemBeReserved" => sub {
282     plan tests => 4;
283
284     my $library = $builder->build_object(
285         {
286             class => 'Koha::Libraries',
287             value => {
288                 pickup_location => 0
289             }
290         }
291     );
292     my $patron_1 = $builder->build_object(
293         {
294             class => 'Koha::Patrons',
295             value => {
296                 branchcode => $library->branchcode,
297             }
298         }
299     );
300     my $patron_2 = $builder->build_object(
301         {
302             class => 'Koha::Patrons',
303             value => {
304                 branchcode   => $library->branchcode,
305                 categorycode => $patron_1->categorycode,
306             }
307         }
308     );
309
310     t::lib::Mocks::mock_userenv(
311         { branchcode => $library->branchcode, flags => 1 } );
312
313     my $item = $builder->build_sample_item(
314         {
315             library => $library->branchcode,
316         }
317     );
318
319     my $sip_patron  = C4::SIP::ILS::Patron->new( $patron_2->cardnumber );
320     my $sip_item    = C4::SIP::ILS::Item->new( $item->barcode );
321     my $transaction = C4::SIP::ILS::Transaction::Hold->new();
322     is(
323         ref $transaction,
324         "C4::SIP::ILS::Transaction::Hold",
325         "New transaction created"
326     );
327     is( $transaction->patron($sip_patron),
328         $sip_patron, "Patron assigned to transaction" );
329     is( $transaction->item($sip_item),
330         $sip_item, "Item assigned to transaction" );
331     my $hold = $transaction->do_hold();
332
333     is( $transaction->ok, 0, "Hold was not allowed" );
334 };
335
336 subtest do_checkin => sub {
337     plan tests => 13;
338
339     my $mockILS = Test::MockObject->new;
340     my $server = { ils => $mockILS };
341     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
342     my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
343     my $patron = $builder->build_object(
344         {
345             class => 'Koha::Patrons',
346             value => {
347                 branchcode => $library->branchcode,
348             }
349         }
350     );
351
352     t::lib::Mocks::mock_userenv(
353         { branchcode => $library->branchcode, flags => 1 } );
354
355     my $item = $builder->build_sample_item(
356         {
357             library => $library->branchcode,
358         }
359     );
360
361
362     # Checkout
363     my $sip_patron  = C4::SIP::ILS::Patron->new( $patron->cardnumber );
364     my $sip_item    = C4::SIP::ILS::Item->new( $item->barcode );
365     my $co_transaction = C4::SIP::ILS::Transaction::Checkout->new();
366     is( $co_transaction->patron($sip_patron),
367         $sip_patron, "Patron assigned to transaction" );
368     is( $co_transaction->item($sip_item),
369         $sip_item, "Item assigned to transaction" );
370     my $checkout = $co_transaction->do_checkout();
371     is( $patron->checkouts->count, 1, 'Checkout should have been done successfully');
372
373     # Checkin
374     my $ci_transaction = C4::SIP::ILS::Transaction::Checkin->new();
375     is( $ci_transaction->patron($sip_patron),
376         $sip_patron, "Patron assigned to transaction" );
377     is( $ci_transaction->item($sip_item),
378         $sip_item, "Item assigned to transaction" );
379
380     my $checkin = $ci_transaction->do_checkin($library->branchcode, C4::SIP::Sip::timestamp);
381     is( $patron->checkouts->count, 0, 'Checkin should have been done successfully');
382
383     # Test checkin without return date
384     $co_transaction->do_checkout;
385     is( $patron->checkouts->count, 1, 'Checkout should have been done successfully');
386     $ci_transaction->do_checkin($library->branchcode, undef);
387     is( $patron->checkouts->count, 0, 'Checkin should have been done successfully');
388
389     my $result  = $ci_transaction->do_checkin($library2->branchcode, undef);
390     is($ci_transaction->alert_type,'04',"Checkin of item no issued at another branch succeeds");
391     is_deeply(
392         $result,
393         {
394             messages => {
395                 'NotIssued'       => $item->barcode,
396                 'WasTransfered'   => $library->branchcode,
397                 'TransferTrigger' => 'ReturnToHome'
398             }
399         },
400         "Messages show not issued and transferred"
401     );
402     is( $ci_transaction->item->destination_loc,$library->branchcode,"Item destination correctly set");
403
404     subtest 'Checkin an in transit item' => sub {
405
406         plan tests => 5;
407
408         my $library_1 = $builder->build_object({ class => 'Koha::Libraries' });
409         my $library_2 = $builder->build_object({ class => 'Koha::Libraries' });
410
411         my $patron = $builder->build_object({ class => 'Koha::Patrons', value => {branchcode => $library_1->branchcode, }});
412         my $sip_patron = C4::SIP::ILS::Patron->new( $patron->cardnumber );
413         my $item = $builder->build_sample_item({ library => $library_1->branchcode });
414         my $sip_item   = C4::SIP::ILS::Item->new( $item->barcode );
415
416         t::lib::Mocks::mock_userenv(
417             { branchcode => $library_1->branchcode, flags => 1 } );
418
419         my $reserve = AddReserve(
420             {
421                 branchcode     => $library_1->branchcode,
422                 borrowernumber => $patron->borrowernumber,
423                 biblionumber   => $item->biblionumber,
424             }
425         );
426
427         ModReserveAffect( $item->itemnumber, $patron->borrowernumber ); # Mark waiting
428
429         my $ci_transaction = C4::SIP::ILS::Transaction::Checkin->new();
430         is( $ci_transaction->patron($sip_patron),
431             $sip_patron, "Patron assigned to transaction" );
432         is( $ci_transaction->item($sip_item),
433             $sip_item, "Item assigned to transaction" );
434
435         my $checkin = $ci_transaction->do_checkin($library_2->branchcode, C4::SIP::Sip::timestamp);
436
437         my $hold = Koha::Holds->find($reserve);
438         is( $hold->found, 'T', );
439         is( $hold->itemnumber, $item->itemnumber, );
440         is( Koha::Checkouts->search({itemnumber => $item->itemnumber})->count, 0, );
441     };
442
443     subtest 'Checkin with fines' => sub {
444         plan tests => 2;
445
446         my $mockILS = Test::MockObject->new;
447         my $server = { ils => $mockILS };
448         my $library = $builder->build_object( { class => 'Koha::Libraries' } );
449         my $institution = {
450             id             => $library->id,
451             implementation => "ILS",
452             policy         => {
453                 checkin  => "true",
454                 renewal  => "true",
455                 checkout => "true",
456                 timeout  => 100,
457                 retries  => 5,
458             }
459         };
460         my $ils = C4::SIP::ILS->new($institution);
461         my $item = $builder->build_sample_item(
462             {
463                 library => $library->branchcode,
464             }
465         );
466
467         # show_outstanding_amount disabled
468         my $patron = $builder->build_object(
469             {
470                 class => 'Koha::Patrons',
471                 value => {
472                     branchcode => $library->branchcode,
473                 }
474             }
475         );
476         my $circ = $ils->checkout($patron->cardnumber, $item->barcode, undef, undef, $server->{account});
477         my $fee1 = $builder->build(
478             {
479                 source => 'Accountline',
480                 value  => {
481                     borrowernumber => $patron->borrowernumber,
482                     amountoutstanding => 12,
483                     debit_type_code   => 'OVERDUE',
484                     itemnumber        => $item->itemnumber
485                 }
486             }
487         );
488         $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode, undef, undef, $server->{account} );
489         is( $circ->{screen_msg}, '', "The fine is not displayed on checkin when show_outstanding_amount is disabled" );
490
491         # show_outstanding_amount enabled
492         $patron = $builder->build_object(
493             {
494                 class => 'Koha::Patrons',
495                 value => {
496                     branchcode => $library->branchcode,
497                 }
498             }
499         );
500         $circ = $ils->checkout($patron->cardnumber, $item->barcode, undef, undef, $server->{account});
501
502         $fee1 = $builder->build(
503             {
504                 source => 'Accountline',
505                 value  => {
506                     borrowernumber => $patron->borrowernumber,
507                     amountoutstanding => 12,
508                     debit_type_code   => 'OVERDUE',
509                     itemnumber        => $item->itemnumber
510                 }
511             }
512         );
513
514         $server->{account}->{show_outstanding_amount} = 1;
515         $circ = $ils->checkout($patron->cardnumber, $item->barcode, undef, undef, $server->{account});
516
517         $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode, undef, undef, $server->{account} );
518         is( $circ->{screen_msg}, 'You owe $12.00 for this item.', "The fine is displayed on checkin when show_outstanding_amount is enabled" );
519
520     };
521 };
522
523 subtest do_checkout_with_sysprefs_override => sub {
524     plan tests => 8;
525
526     my $mockILS = Test::MockObject->new;
527     my $server = { ils => $mockILS };
528     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
529     my $institution = {
530         id             => $library->id,
531         implementation => "ILS",
532         policy         => {
533             checkin  => "true",
534             renewal  => "true",
535             checkout => "true",
536             timeout  => 100,
537             retries  => 5,
538         }
539     };
540     my $ils = C4::SIP::ILS->new($institution);
541     my $item = $builder->build_sample_item(
542         {
543             library => $library->branchcode,
544         }
545     );
546
547     my $patron_under_noissuescharge = $builder->build_object(
548         {
549             class => 'Koha::Patrons',
550             value => {
551                 branchcode => $library->branchcode,
552             }
553         }
554     );
555
556     my $fee_under_noissuescharge = $builder->build(
557         {
558             source => 'Accountline',
559             value  => {
560                 borrowernumber => $patron_under_noissuescharge->borrowernumber,
561                 amountoutstanding => 4,
562                 debit_type_code   => 'OVERDUE',
563             }
564         }
565     );
566
567     my $patron_over_noissuescharge = $builder->build_object(
568
569         {
570             class => 'Koha::Patrons',
571             value => {
572                 branchcode => $library->branchcode,
573             }
574         }
575     );
576
577     my $fee_over_noissuescharge = $builder->build(
578         {
579             source => 'Accountline',
580             value  => {
581                 borrowernumber => $patron_over_noissuescharge->borrowernumber,
582                 amountoutstanding => 6,
583                 debit_type_code   => 'OVERDUE',
584             }
585         }
586     );
587
588
589     $server->{account}->{override_fine_on_checkout} = 0;
590
591     t::lib::Mocks::mock_preference( 'AllFinesNeedOverride', '0' );
592     t::lib::Mocks::mock_preference( 'AllowFineOverride', '0' );
593     my $circ = $ils->checkout($patron_under_noissuescharge->cardnumber, $item->barcode, undef, undef, $server->{account});
594     is( $patron_under_noissuescharge->checkouts->count, 1, 'Checkout is allowed when the amount is under noissuecharge, AllFinesNeedOverride and AllowFineOverride disabled');
595
596     $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode );
597
598     $circ = $ils->checkout($patron_over_noissuescharge->cardnumber, $item->barcode, undef, undef, $server->{account});
599     is( $patron_over_noissuescharge->checkouts->count, 0, 'Checkout is blocked when the amount is over noissuecharge, AllFinesNeedOverride and AllowFineOverride disabled');
600
601     t::lib::Mocks::mock_preference( 'AllFinesNeedOverride', '0' );
602     t::lib::Mocks::mock_preference( 'AllowFineOverride', '1' );
603
604     $circ = $ils->checkout($patron_under_noissuescharge->cardnumber, $item->barcode, undef, undef, $server->{account});
605     is( $patron_under_noissuescharge->checkouts->count, 1, 'Checkout is allowed when the amount is under noissuecharge, AllFinesNeedOverride disabled and AllowFineOverride enabled');
606
607     $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode );
608
609     $circ = $ils->checkout($patron_over_noissuescharge->cardnumber, $item->barcode, undef, undef, $server->{account});
610     is( $patron_over_noissuescharge->checkouts->count, 0, 'Checkout is blocked when the amount is over noissuecharge, AllFinesNeedOverride disabled and AllowFineOverride enabled');
611
612     t::lib::Mocks::mock_preference( 'AllFinesNeedOverride', '1' );
613     t::lib::Mocks::mock_preference( 'AllowFineOverride', '0' );
614
615     $circ = $ils->checkout($patron_under_noissuescharge->cardnumber, $item->barcode, undef, undef, $server->{account});
616     is( $patron_under_noissuescharge->checkouts->count, 0, 'Checkout is blocked when the amount is under noissuecharge, AllFinesNeedOverride enabled and AllowFineOverride disabled');
617
618     $circ = $ils->checkout($patron_over_noissuescharge->cardnumber, $item->barcode, undef, undef, $server->{account});
619     is( $patron_over_noissuescharge->checkouts->count, 0, 'Checkout is blocked when the amount is over noissuecharge, AllFinesNeedOverride enabled and AllowFineOverride disabled');
620
621     t::lib::Mocks::mock_preference( 'AllFinesNeedOverride', '1' );
622     t::lib::Mocks::mock_preference( 'AllowFineOverride', '1' );
623
624     $circ = $ils->checkout($patron_under_noissuescharge->cardnumber, $item->barcode, undef, undef, $server->{account});
625     is( $patron_under_noissuescharge->checkouts->count, 0, 'Checkout is blocked when the amount is under noissuecharge, AllFinesNeedOverride and AllowFineOverride enabled');
626
627     $circ = $ils->checkout($patron_over_noissuescharge->cardnumber, $item->barcode, undef, undef, $server->{account});
628     is( $patron_over_noissuescharge->checkouts->count, 0, 'Checkout is blocked when the amount is over noissuecharge, AllFinesNeedOverride and AllowFineOverride enabled');
629 };
630
631
632 subtest do_checkout_with_patron_blocked => sub {
633     plan tests => 5;
634
635     my $mockILS = Test::MockObject->new;
636     my $server = { ils => $mockILS };
637     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
638     my $institution = {
639         id             => $library->id,
640         implementation => "ILS",
641         policy         => {
642             checkin  => "true",
643             renewal  => "true",
644             checkout => "true",
645             timeout  => 100,
646             retries  => 5,
647         }
648     };
649     my $ils = C4::SIP::ILS->new($institution);
650     my $item = $builder->build_sample_item(
651         {
652             library => $library->branchcode,
653         }
654     );
655
656     my $expired_patron = $builder->build_object(
657         {
658             class => 'Koha::Patrons',
659             value => {
660                 branchcode => $library->branchcode,
661                 dateexpiry => '2020/01/03',
662             }
663         }
664     );
665     my $circ = $ils->checkout($expired_patron->cardnumber, $item->barcode);
666     is( $circ->{screen_msg}, 'Patron expired on 01/03/2020', "Got correct expired screen message" );
667
668     my $fines_patron = $builder->build_object(
669         {
670             class => 'Koha::Patrons',
671             value => {
672                 branchcode => $library->branchcode,
673             }
674         }
675     );
676     my $fee1 = $builder->build(
677         {
678             source => 'Accountline',
679             value  => {
680                 borrowernumber => $fines_patron->borrowernumber,
681                 amountoutstanding => 10,
682                 debit_type_code   => 'OVERDUE',
683             }
684         }
685     );
686
687     my $fines_sip_patron  = C4::SIP::ILS::Patron->new( $fines_patron->cardnumber );
688
689     $circ = $ils->checkout($fines_patron->cardnumber, $item->barcode, undef, undef, $server->{account});
690     is( $circ->{screen_msg}, 'Patron has fines', "Got correct fines screen message" );
691
692     $server->{account}->{show_outstanding_amount} = 1;
693     $circ = $ils->checkout($fines_patron->cardnumber, $item->barcode, undef, undef, $server->{account});
694     is( $circ->{screen_msg}, 'Patron has fines - You owe $10.00.', "Got correct fines with amount screen message" );
695     my $debarred_patron = $builder->build_object(
696         {
697             class => 'Koha::Patrons',
698             value => {
699                 branchcode => $library->branchcode,
700                 debarred => '9999/01/01',
701             }
702         }
703     );
704     my $debarred_sip_patron  = C4::SIP::ILS::Patron->new( $debarred_patron->cardnumber );
705     $circ = $ils->checkout($debarred_patron->cardnumber, $item->barcode);
706     is( $circ->{screen_msg}, 'Patron debarred', "Got correct debarred screen message" );
707
708     my $overdue_patron = $builder->build_object(
709         {
710             class => 'Koha::Patrons',
711             value => {
712                 branchcode => $library->branchcode,
713             }
714         }
715     );
716
717     my $odue = $builder->build({ source => 'Issue', value => {
718             borrowernumber => $overdue_patron->borrowernumber,
719             date_due => '2017-01-01',
720         }
721     });
722     t::lib::Mocks::mock_preference( 'OverduesBlockCirc', 'block' );
723     my $overdue_sip_patron  = C4::SIP::ILS::Patron->new( $overdue_patron->cardnumber );
724     $circ = $ils->checkout($overdue_patron->cardnumber, $item->barcode);
725     is( $circ->{screen_msg}, 'Patron blocked', "Got correct blocked screen message" );
726
727 };
728
729 subtest do_checkout_with_noblock => sub {
730     plan tests => 3;
731
732     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
733     my $patron = $builder->build_object(
734         {
735             class => 'Koha::Patrons',
736             value => {
737                 branchcode => $library->branchcode,
738                 debarred => '9999/01/01',
739             },
740         }
741     );
742
743     t::lib::Mocks::mock_userenv(
744         { branchcode => $library->branchcode, flags => 1 } );
745
746     my $item = $builder->build_sample_item(
747         {
748             library => $library->branchcode,
749         }
750     );
751
752
753     my $sip_patron  = C4::SIP::ILS::Patron->new( $patron->cardnumber );
754     my $sip_item    = C4::SIP::ILS::Item->new( $item->barcode );
755     my $co_transaction = C4::SIP::ILS::Transaction::Checkout->new();
756     is( $co_transaction->patron($sip_patron),
757         $sip_patron, "Patron assigned to transaction" );
758     is( $co_transaction->item($sip_item),
759         $sip_item, "Item assigned to transaction" );
760
761     $co_transaction->do_checkout(undef, '19990102    030405');
762
763     is( $patron->checkouts->count, 1, 'No Block checkout was performed for debarred patron');
764 };
765
766 subtest do_checkout_with_holds => sub {
767     plan tests => 7;
768
769     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
770     my $patron = $builder->build_object(
771         {
772             class => 'Koha::Patrons',
773             value => {
774                 branchcode => $library->branchcode,
775             }
776         }
777     );
778     my $patron2 = $builder->build_object(
779         {
780             class => 'Koha::Patrons',
781             value => {
782                 branchcode => $library->branchcode,
783             }
784         }
785     );
786
787     t::lib::Mocks::mock_userenv(
788         { branchcode => $library->branchcode, flags => 1 } );
789
790     my $item = $builder->build_sample_item(
791         {
792             library => $library->branchcode,
793         }
794     );
795
796     my $reserve = AddReserve(
797         {
798                 branchcode     => $library->branchcode,
799                 borrowernumber => $patron2->borrowernumber,
800                 biblionumber   => $item->biblionumber,
801         }
802     );
803
804     my $sip_patron  = C4::SIP::ILS::Patron->new( $patron->cardnumber );
805     my $sip_item    = C4::SIP::ILS::Item->new( $item->barcode );
806     my $co_transaction = C4::SIP::ILS::Transaction::Checkout->new();
807     is( $co_transaction->patron($sip_patron),
808         $sip_patron, "Patron assigned to transaction" );
809     is( $co_transaction->item($sip_item),
810         $sip_item, "Item assigned to transaction" );
811
812     # Test attached holds
813     ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 0, $reserve ); # Mark waiting (W)
814     my $hold = Koha::Holds->find($reserve);
815     $co_transaction->do_checkout();
816     is( $patron->checkouts->count, 0, 'Checkout was not done due to attached hold (W)');
817
818     $hold->set_transfer;
819     $co_transaction->do_checkout();
820     is( $patron->checkouts->count, 0, 'Checkout was not done due to attached hold (T)');
821
822     $hold->set_processing;
823     $co_transaction->do_checkout();
824     is( $patron->checkouts->count, 0, 'Checkout was not done due to attached hold (P)');
825
826     # Test non-attached holds
827     C4::Reserves::RevertWaitingStatus({ itemnumber => $hold->itemnumber });
828     t::lib::Mocks::mock_preference('AllowItemsOnHoldCheckoutSIP', '0');
829     $co_transaction->do_checkout();
830     is( $patron->checkouts->count, 0, 'Checkout refused due to hold and AllowItemsOnHoldCheckoutSIP');
831
832     t::lib::Mocks::mock_preference('AllowItemsOnHoldCheckoutSIP', '1');
833     $co_transaction->do_checkout();
834     is( $patron->checkouts->count, 1, 'Checkout allowed due to hold and AllowItemsOnHoldCheckoutSIP');
835 };
836
837 subtest checkin_lost => sub {
838     plan tests => 2;
839
840     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
841
842     t::lib::Mocks::mock_userenv(
843         { branchcode => $library->branchcode, flags => 1 } );
844
845     my $item = $builder->build_sample_item(
846         {
847             library     => $library->branchcode,
848         }
849     );
850
851     $item->itemlost(1)->itemlost_on(dt_from_string)->store();
852
853     my $instituation = {
854         id             => $library->id,
855         implementation => "ILS",
856         policy         => {
857             checkin  => "true",
858             renewal  => "true",
859             checkout => "true",
860             timeout  => 100,
861             retries  => 5,
862         }
863     };
864     my $ils = C4::SIP::ILS->new( $instituation );
865
866     t::lib::Mocks::mock_preference('BlockReturnOfLostItems', '1');
867     my $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode );
868     is( $circ->{screen_msg}, 'Item lost, return not allowed', "Got correct screen message" );
869
870     t::lib::Mocks::mock_preference('BlockReturnOfLostItems', '0');
871     $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode );
872     is( $circ->{screen_msg}, 'Item not checked out', "Got 'Item not checked out' screen message" );
873 };
874
875 subtest checkin_withdrawn => sub {
876     plan tests => 2;
877
878     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
879
880     t::lib::Mocks::mock_userenv(
881         { branchcode => $library->branchcode, flags => 1 } );
882
883     my $item = $builder->build_sample_item(
884         {
885             library     => $library->branchcode,
886         }
887     );
888
889     $item->withdrawn(1)->withdrawn_on(dt_from_string)->store();
890
891     my $instituation = {
892         id             => $library->id,
893         implementation => "ILS",
894         policy         => {
895             checkin  => "true",
896             renewal  => "true",
897             checkout => "true",
898             timeout  => 100,
899             retries  => 5,
900         }
901     };
902     my $ils = C4::SIP::ILS->new( $instituation );
903
904     t::lib::Mocks::mock_preference('BlockReturnOfWithdrawnItems', '1');
905     my $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode );
906     is( $circ->{screen_msg}, 'Item withdrawn, return not allowed', "Got correct screen message" );
907
908     t::lib::Mocks::mock_preference('BlockReturnOfWithdrawnItems', '0');
909     $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode );
910     is( $circ->{screen_msg}, 'Item not checked out', "Got 'Item not checked out' screen message" );
911 };
912
913 subtest _get_sort_bin => sub {
914     plan tests => 4;
915
916     my $library  = $builder->build_object( { class => 'Koha::Libraries' } );
917     my $branch   = $library->branchcode;
918     my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
919     my $branch2  = $library2->branchcode;
920
921     my $rules = <<"RULES";
922 $branch:homebranch:ne:\$holdingbranch:X\r
923 $branch:effective_itemtype:eq:CD:0\r
924 $branch:itemcallnumber:<:340:1\r
925 $branch:itemcallnumber:<:370:2\r
926 $branch:itemcallnumber:<:600:3\r
927 $branch2:homebranch:ne:\$holdingbranch:X\r
928 $branch2:effective_itemtype:eq:CD:4\r
929 $branch2:itemcallnumber:>:600:5\r
930 RULES
931     t::lib::Mocks::mock_preference('SIP2SortBinMapping', $rules);
932
933     my $item_cd = $builder->build_sample_item(
934         {
935             library     => $library->branchcode,
936             itype       => 'CD'
937         }
938     );
939
940     my $item_book = $builder->build_sample_item(
941         {
942             library        => $library->branchcode,
943             itype          => 'BOOK',
944             itemcallnumber => '200.01'
945         }
946     );
947
948     my $bin;
949
950     # Set holdingbranch as though item returned to library other than homebranch (As AddReturn would)
951     $item_cd->holdingbranch($library2->branchcode)->store();
952     $bin = C4::SIP::ILS::Transaction::Checkin::_get_sort_bin( $item_cd, $library2->branchcode );
953     is($bin, 'X', "Item parameter on RHS of comparison works (ne comparator)");
954
955     # Reset holdingbranch as though item returned to home library
956     $item_cd->holdingbranch($library->branchcode)->store();
957     $bin = C4::SIP::ILS::Transaction::Checkin::_get_sort_bin( $item_cd, $library->branchcode );
958     is($bin, '0', "Fixed value on RHS of comparison works (eq comparator)");
959     $bin = C4::SIP::ILS::Transaction::Checkin::_get_sort_bin( $item_book, $library->branchcode );
960     is($bin, '1', "Rules applied in order (< comparator)");
961     $item_book->itemcallnumber('350.20')->store();
962     $bin = C4::SIP::ILS::Transaction::Checkin::_get_sort_bin( $item_book, $library->branchcode );
963     is($bin, '2', "Rules applied in order (< comparator)");
964 };
965
966 subtest item_circulation_status => sub {
967     plan tests => 7;
968
969     my $library  = $builder->build_object( { class => 'Koha::Libraries' } );
970     my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
971
972     my $patron = $builder->build_object(
973         {
974             class => 'Koha::Patrons',
975             value => {
976                 branchcode => $library->branchcode,
977             }
978         }
979     );
980
981     t::lib::Mocks::mock_userenv(
982         { branchcode => $library->branchcode, flags => 1 } );
983
984     my $item = $builder->build_sample_item(
985         {
986             library => $library->branchcode,
987         }
988     );
989
990     my $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
991     my $status = $sip_item->sip_circulation_status;
992     is( $status, '03', "Item circulation status is available");
993
994     my $transfer = Koha::Item::Transfer->new({
995         itemnumber => $item->id,
996         datesent   => '2020-01-01',
997         frombranch => $library->branchcode,
998         tobranch   => $library2->branchcode,
999     })->store();
1000
1001     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
1002     $status = $sip_item->sip_circulation_status;
1003     is( $status, '10', "Item circulation status is in transit" );
1004
1005     $transfer->delete;
1006
1007     my $claim = Koha::Checkouts::ReturnClaim->new({
1008         itemnumber     => $item->id,
1009         borrowernumber => $patron->id,
1010         created_by     => $patron->id,
1011     })->store();
1012
1013     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
1014     $status = $sip_item->sip_circulation_status;
1015     is( $status, '11', "Item circulation status is claimed returned" );
1016
1017     $claim->delete;
1018
1019     $item->itemlost(1)->store();
1020     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
1021     $status = $sip_item->sip_circulation_status;
1022     is( $status, '12', "Item circulation status is lost" );
1023     $item->itemlost(0)->store();
1024
1025     my $location = $item->location;
1026     $item->location("CART")->store();
1027     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
1028     $status = $sip_item->sip_circulation_status;
1029     is( $status, '09', "Item circulation status is waiting to be re-shelved" );
1030     $item->location($location)->store();
1031
1032     my $nfl = $item->notforloan;
1033     $item->notforloan(-1)->store();
1034     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
1035     $status = $sip_item->sip_circulation_status;
1036     is( $status, '02', "Item circulation status is on order" );
1037     $item->notforloan($nfl)->store();
1038
1039     my $damaged = $item->damaged;
1040     $item->damaged(1)->store();
1041     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
1042     $status = $sip_item->sip_circulation_status;
1043     is( $status, '01', "Item circulation status is damaged" );
1044     $item->damaged(0)->store();
1045 };
1046 $schema->storage->txn_rollback;