Bug 29094: Adding hold via SIP should check if patron can hold item first
[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 => 15;
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 => 12;
338
339     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
340     my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
341     my $patron = $builder->build_object(
342         {
343             class => 'Koha::Patrons',
344             value => {
345                 branchcode => $library->branchcode,
346             }
347         }
348     );
349
350     t::lib::Mocks::mock_userenv(
351         { branchcode => $library->branchcode, flags => 1 } );
352
353     my $item = $builder->build_sample_item(
354         {
355             library => $library->branchcode,
356         }
357     );
358
359
360     # Checkout
361     my $sip_patron  = C4::SIP::ILS::Patron->new( $patron->cardnumber );
362     my $sip_item    = C4::SIP::ILS::Item->new( $item->barcode );
363     my $co_transaction = C4::SIP::ILS::Transaction::Checkout->new();
364     is( $co_transaction->patron($sip_patron),
365         $sip_patron, "Patron assigned to transaction" );
366     is( $co_transaction->item($sip_item),
367         $sip_item, "Item assigned to transaction" );
368     my $checkout = $co_transaction->do_checkout();
369     is( $patron->checkouts->count, 1, 'Checkout should have been done successfully');
370
371     # Checkin
372     my $ci_transaction = C4::SIP::ILS::Transaction::Checkin->new();
373     is( $ci_transaction->patron($sip_patron),
374         $sip_patron, "Patron assigned to transaction" );
375     is( $ci_transaction->item($sip_item),
376         $sip_item, "Item assigned to transaction" );
377
378     my $checkin = $ci_transaction->do_checkin($library->branchcode, C4::SIP::Sip::timestamp);
379     is( $patron->checkouts->count, 0, 'Checkin should have been done successfully');
380
381     # Test checkin without return date
382     $co_transaction->do_checkout;
383     is( $patron->checkouts->count, 1, 'Checkout should have been done successfully');
384     $ci_transaction->do_checkin($library->branchcode, undef);
385     is( $patron->checkouts->count, 0, 'Checkin should have been done successfully');
386
387     my $result  = $ci_transaction->do_checkin($library2->branchcode, undef);
388     is($ci_transaction->alert_type,'04',"Checkin of item no issued at another branch succeeds");
389     is_deeply(
390         $result,
391         {
392             messages => {
393                 'NotIssued'       => $item->barcode,
394                 'WasTransfered'   => $library->branchcode,
395                 'TransferTrigger' => 'ReturnToHome'
396             }
397         },
398         "Messages show not issued and transferred"
399     );
400     is( $ci_transaction->item->destination_loc,$library->branchcode,"Item destination correctly set");
401
402     subtest 'Checkin an in transit item' => sub {
403
404         plan tests => 5;
405
406         my $library_1 = $builder->build_object({ class => 'Koha::Libraries' });
407         my $library_2 = $builder->build_object({ class => 'Koha::Libraries' });
408
409         my $patron = $builder->build_object({ class => 'Koha::Patrons', value => {branchcode => $library_1->branchcode, }});
410         my $sip_patron = C4::SIP::ILS::Patron->new( $patron->cardnumber );
411         my $item = $builder->build_sample_item({ library => $library_1->branchcode });
412         my $sip_item   = C4::SIP::ILS::Item->new( $item->barcode );
413
414         t::lib::Mocks::mock_userenv(
415             { branchcode => $library_1->branchcode, flags => 1 } );
416
417         my $reserve = AddReserve(
418             {
419                 branchcode     => $library_1->branchcode,
420                 borrowernumber => $patron->borrowernumber,
421                 biblionumber   => $item->biblionumber,
422             }
423         );
424
425         ModReserveAffect( $item->itemnumber, $patron->borrowernumber ); # Mark waiting
426
427         my $ci_transaction = C4::SIP::ILS::Transaction::Checkin->new();
428         is( $ci_transaction->patron($sip_patron),
429             $sip_patron, "Patron assigned to transaction" );
430         is( $ci_transaction->item($sip_item),
431             $sip_item, "Item assigned to transaction" );
432
433         my $checkin = $ci_transaction->do_checkin($library_2->branchcode, C4::SIP::Sip::timestamp);
434
435         my $hold = Koha::Holds->find($reserve);
436         is( $hold->found, 'T', );
437         is( $hold->itemnumber, $item->itemnumber, );
438         is( Koha::Checkouts->search({itemnumber => $item->itemnumber})->count, 0, );
439     };
440 };
441
442 subtest do_checkout_with_patron_blocked => sub {
443     plan tests => 4;
444
445     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
446     my $institution = {
447         id             => $library->id,
448         implementation => "ILS",
449         policy         => {
450             checkin  => "true",
451             renewal  => "true",
452             checkout => "true",
453             timeout  => 100,
454             retries  => 5,
455         }
456     };
457     my $ils = C4::SIP::ILS->new($institution);
458     my $item = $builder->build_sample_item(
459         {
460             library => $library->branchcode,
461         }
462     );
463
464     my $expired_patron = $builder->build_object(
465         {
466             class => 'Koha::Patrons',
467             value => {
468                 branchcode => $library->branchcode,
469                 dateexpiry => '2020/01/01',
470             }
471         }
472     );
473     my $circ = $ils->checkout($expired_patron->cardnumber, $item->barcode);
474     is( $circ->{screen_msg}, 'Patron expired', "Got correct expired screen message" );
475
476     my $fines_patron = $builder->build_object(
477         {
478             class => 'Koha::Patrons',
479             value => {
480                 branchcode => $library->branchcode,
481             }
482         }
483     );
484     my $fee1 = $builder->build(
485         {
486             source => 'Accountline',
487             value  => {
488                 borrowernumber => $fines_patron->borrowernumber,
489                 amountoutstanding => 10,
490             }
491         }
492     );
493
494     my $fines_sip_patron  = C4::SIP::ILS::Patron->new( $fines_patron->cardnumber );
495     $circ = $ils->checkout($fines_patron->cardnumber, $item->barcode);
496     is( $circ->{screen_msg}, 'Patron has fines', "Got correct fines screen message" );
497
498     my $debarred_patron = $builder->build_object(
499         {
500             class => 'Koha::Patrons',
501             value => {
502                 branchcode => $library->branchcode,
503                 debarred => '9999/01/01',
504             }
505         }
506     );
507     my $debarred_sip_patron  = C4::SIP::ILS::Patron->new( $debarred_patron->cardnumber );
508     $circ = $ils->checkout($debarred_patron->cardnumber, $item->barcode);
509     is( $circ->{screen_msg}, 'Patron debarred', "Got correct debarred screen message" );
510
511     my $overdue_patron = $builder->build_object(
512         {
513             class => 'Koha::Patrons',
514             value => {
515                 branchcode => $library->branchcode,
516             }
517         }
518     );
519
520     my $odue = $builder->build({ source => 'Issue', value => {
521             borrowernumber => $overdue_patron->borrowernumber,
522             date_due => '2017-01-01',
523         }
524     });
525     t::lib::Mocks::mock_preference( 'OverduesBlockCirc', 'block' );
526     my $overdue_sip_patron  = C4::SIP::ILS::Patron->new( $overdue_patron->cardnumber );
527     $circ = $ils->checkout($overdue_patron->cardnumber, $item->barcode);
528     is( $circ->{screen_msg}, 'Patron blocked', "Got correct blocked screen message" );
529
530 };
531
532 subtest do_checkout_with_holds => sub {
533     plan tests => 7;
534
535     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
536     my $patron = $builder->build_object(
537         {
538             class => 'Koha::Patrons',
539             value => {
540                 branchcode => $library->branchcode,
541             }
542         }
543     );
544     my $patron2 = $builder->build_object(
545         {
546             class => 'Koha::Patrons',
547             value => {
548                 branchcode => $library->branchcode,
549             }
550         }
551     );
552
553     t::lib::Mocks::mock_userenv(
554         { branchcode => $library->branchcode, flags => 1 } );
555
556     my $item = $builder->build_sample_item(
557         {
558             library => $library->branchcode,
559         }
560     );
561
562     my $reserve = AddReserve(
563         {
564                 branchcode     => $library->branchcode,
565                 borrowernumber => $patron2->borrowernumber,
566                 biblionumber   => $item->biblionumber,
567         }
568     );
569
570     my $sip_patron  = C4::SIP::ILS::Patron->new( $patron->cardnumber );
571     my $sip_item    = C4::SIP::ILS::Item->new( $item->barcode );
572     my $co_transaction = C4::SIP::ILS::Transaction::Checkout->new();
573     is( $co_transaction->patron($sip_patron),
574         $sip_patron, "Patron assigned to transaction" );
575     is( $co_transaction->item($sip_item),
576         $sip_item, "Item assigned to transaction" );
577
578     # Test attached holds
579     ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 0, $reserve ); # Mark waiting (W)
580     my $hold = Koha::Holds->find($reserve);
581     $co_transaction->do_checkout();
582     is( $patron->checkouts->count, 0, 'Checkout was not done due to attached hold (W)');
583
584     $hold->set_transfer;
585     $co_transaction->do_checkout();
586     is( $patron->checkouts->count, 0, 'Checkout was not done due to attached hold (T)');
587
588     $hold->set_processing;
589     $co_transaction->do_checkout();
590     is( $patron->checkouts->count, 0, 'Checkout was not done due to attached hold (P)');
591
592     # Test non-attached holds
593     C4::Reserves::RevertWaitingStatus({ itemnumber => $hold->itemnumber });
594     t::lib::Mocks::mock_preference('AllowItemsOnHoldCheckoutSIP', '0');
595     $co_transaction->do_checkout();
596     is( $patron->checkouts->count, 0, 'Checkout refused due to hold and AllowItemsOnHoldCheckoutSIP');
597
598     t::lib::Mocks::mock_preference('AllowItemsOnHoldCheckoutSIP', '1');
599     $co_transaction->do_checkout();
600     is( $patron->checkouts->count, 1, 'Checkout allowed due to hold and AllowItemsOnHoldCheckoutSIP');
601 };
602
603 subtest checkin_lost => sub {
604     plan tests => 2;
605
606     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
607
608     t::lib::Mocks::mock_userenv(
609         { branchcode => $library->branchcode, flags => 1 } );
610
611     my $item = $builder->build_sample_item(
612         {
613             library     => $library->branchcode,
614         }
615     );
616
617     $item->itemlost(1)->itemlost_on(dt_from_string)->store();
618
619     my $instituation = {
620         id             => $library->id,
621         implementation => "ILS",
622         policy         => {
623             checkin  => "true",
624             renewal  => "true",
625             checkout => "true",
626             timeout  => 100,
627             retries  => 5,
628         }
629     };
630     my $ils = C4::SIP::ILS->new( $instituation );
631
632     t::lib::Mocks::mock_preference('BlockReturnOfLostItems', '1');
633     my $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode );
634     is( $circ->{screen_msg}, 'Item lost, return not allowed', "Got correct screen message" );
635
636     t::lib::Mocks::mock_preference('BlockReturnOfLostItems', '0');
637     $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode );
638     is( $circ->{screen_msg}, 'Item not checked out', "Got 'Item not checked out' screen message" );
639 };
640
641 subtest checkin_withdrawn => sub {
642     plan tests => 2;
643
644     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
645
646     t::lib::Mocks::mock_userenv(
647         { branchcode => $library->branchcode, flags => 1 } );
648
649     my $item = $builder->build_sample_item(
650         {
651             library     => $library->branchcode,
652         }
653     );
654
655     $item->withdrawn(1)->withdrawn_on(dt_from_string)->store();
656
657     my $instituation = {
658         id             => $library->id,
659         implementation => "ILS",
660         policy         => {
661             checkin  => "true",
662             renewal  => "true",
663             checkout => "true",
664             timeout  => 100,
665             retries  => 5,
666         }
667     };
668     my $ils = C4::SIP::ILS->new( $instituation );
669
670     t::lib::Mocks::mock_preference('BlockReturnOfWithdrawnItems', '1');
671     my $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode );
672     is( $circ->{screen_msg}, 'Item withdrawn, return not allowed', "Got correct screen message" );
673
674     t::lib::Mocks::mock_preference('BlockReturnOfWithdrawnItems', '0');
675     $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp, undef, $library->branchcode );
676     is( $circ->{screen_msg}, 'Item not checked out', "Got 'Item not checked out' screen message" );
677 };
678
679 subtest _get_sort_bin => sub {
680     plan tests => 4;
681
682     my $library  = $builder->build_object( { class => 'Koha::Libraries' } );
683     my $branch   = $library->branchcode;
684     my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
685     my $branch2  = $library2->branchcode;
686
687     my $rules = <<"RULES";
688 $branch:homebranch:ne:\$holdingbranch:X\r
689 $branch:effective_itemtype:eq:CD:0\r
690 $branch:itemcallnumber:<:340:1\r
691 $branch:itemcallnumber:<:370:2\r
692 $branch:itemcallnumber:<:600:3\r
693 $branch2:homebranch:ne:\$holdingbranch:X\r
694 $branch2:effective_itemtype:eq:CD:4\r
695 $branch2:itemcallnumber:>:600:5\r
696 RULES
697     t::lib::Mocks::mock_preference('SIP2SortBinMapping', $rules);
698
699     my $item_cd = $builder->build_sample_item(
700         {
701             library     => $library->branchcode,
702             itype       => 'CD'
703         }
704     );
705
706     my $item_book = $builder->build_sample_item(
707         {
708             library        => $library->branchcode,
709             itype          => 'BOOK',
710             itemcallnumber => '200.01'
711         }
712     );
713
714     my $bin;
715
716     # Set holdingbranch as though item returned to library other than homebranch (As AddReturn would)
717     $item_cd->holdingbranch($library2->branchcode)->store();
718     $bin = C4::SIP::ILS::Transaction::Checkin::_get_sort_bin( $item_cd, $library2->branchcode );
719     is($bin, 'X', "Item parameter on RHS of comparison works (ne comparator)");
720
721     # Reset holdingbranch as though item returned to home library
722     $item_cd->holdingbranch($library->branchcode)->store();
723     $bin = C4::SIP::ILS::Transaction::Checkin::_get_sort_bin( $item_cd, $library->branchcode );
724     is($bin, '0', "Fixed value on RHS of comparison works (eq comparator)");
725     $bin = C4::SIP::ILS::Transaction::Checkin::_get_sort_bin( $item_book, $library->branchcode );
726     is($bin, '1', "Rules applied in order (< comparator)");
727     $item_book->itemcallnumber('350.20')->store();
728     $bin = C4::SIP::ILS::Transaction::Checkin::_get_sort_bin( $item_book, $library->branchcode );
729     is($bin, '2', "Rules applied in order (< comparator)");
730 };
731
732 subtest item_circulation_status => sub {
733     plan tests => 7;
734
735     my $library  = $builder->build_object( { class => 'Koha::Libraries' } );
736     my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
737
738     my $patron = $builder->build_object(
739         {
740             class => 'Koha::Patrons',
741             value => {
742                 branchcode => $library->branchcode,
743             }
744         }
745     );
746
747     t::lib::Mocks::mock_userenv(
748         { branchcode => $library->branchcode, flags => 1 } );
749
750     my $item = $builder->build_sample_item(
751         {
752             library => $library->branchcode,
753         }
754     );
755
756     my $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
757     my $status = $sip_item->sip_circulation_status;
758     is( $status, '03', "Item circulation status is available");
759
760     my $transfer = Koha::Item::Transfer->new({
761         itemnumber => $item->id,
762         datesent   => '2020-01-01',
763         frombranch => $library->branchcode,
764         tobranch   => $library2->branchcode,
765     })->store();
766
767     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
768     $status = $sip_item->sip_circulation_status;
769     is( $status, '10', "Item circulation status is in transit" );
770
771     $transfer->delete;
772
773     my $claim = Koha::Checkouts::ReturnClaim->new({
774         itemnumber     => $item->id,
775         borrowernumber => $patron->id,
776         created_by     => $patron->id,
777     })->store();
778
779     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
780     $status = $sip_item->sip_circulation_status;
781     is( $status, '11', "Item circulation status is claimed returned" );
782
783     $claim->delete;
784
785     $item->itemlost(1)->store();
786     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
787     $status = $sip_item->sip_circulation_status;
788     is( $status, '12', "Item circulation status is lost" );
789     $item->itemlost(0)->store();
790
791     my $location = $item->location;
792     $item->location("CART")->store();
793     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
794     $status = $sip_item->sip_circulation_status;
795     is( $status, '09', "Item circulation status is waiting to be re-shelved" );
796     $item->location($location)->store();
797
798     my $nfl = $item->notforloan;
799     $item->notforloan(-1)->store();
800     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
801     $status = $sip_item->sip_circulation_status;
802     is( $status, '02', "Item circulation status is on order" );
803     $item->notforloan($nfl)->store();
804
805     my $damaged = $item->damaged;
806     $item->damaged(1)->store();
807     $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
808     $status = $sip_item->sip_circulation_status;
809     is( $status, '01', "Item circulation status is damaged" );
810     $item->damaged(0)->store();
811 };
812 $schema->storage->txn_rollback;