3 # Copyright 2016 Koha Development team
5 # This file is part of Koha
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
22 use Test::More tests => 12;
29 use Koha::Item::Transfer::Limits;
32 use Koha::DateUtils qw( dt_from_string );
34 use t::lib::TestBuilder;
38 my $schema = Koha::Database->new->schema;
39 $schema->storage->txn_begin;
41 my $dbh = C4::Context->dbh;
43 my $builder = t::lib::TestBuilder->new;
44 my $library = $builder->build( { source => 'Branch' } );
45 my $nb_of_items = Koha::Items->search->count;
46 my $biblio = $builder->build_sample_biblio();
47 my $new_item_1 = $builder->build_sample_item({
48 biblionumber => $biblio->biblionumber,
49 homebranch => $library->{branchcode},
50 holdingbranch => $library->{branchcode},
52 my $new_item_2 = $builder->build_sample_item({
53 biblionumber => $biblio->biblionumber,
54 homebranch => $library->{branchcode},
55 holdingbranch => $library->{branchcode},
59 t::lib::Mocks::mock_userenv({ branchcode => $library->{branchcode} });
61 like( $new_item_1->itemnumber, qr|^\d+$|, 'Adding a new item should have set the itemnumber' );
62 is( Koha::Items->search->count, $nb_of_items + 2, 'The 2 items should have been added' );
64 my $retrieved_item_1 = Koha::Items->find( $new_item_1->itemnumber );
65 is( $retrieved_item_1->barcode, $new_item_1->barcode, 'Find a item by id should return the correct item' );
67 subtest 'store' => sub {
70 my $biblio = $builder->build_sample_biblio;
71 my $today = dt_from_string->set( hour => 0, minute => 0, second => 0 );
72 my $item = Koha::Item->new(
74 homebranch => $library->{branchcode},
75 holdingbranch => $library->{branchcode},
76 biblionumber => $biblio->biblionumber,
79 )->store->get_from_storage;
81 is( t::lib::Dates::compare( $item->replacementpricedate, $today ),
82 0, 'replacementpricedate must have been set to today if not given' );
83 is( t::lib::Dates::compare( $item->datelastseen, $today ),
84 0, 'datelastseen must have been set to today if not given' );
87 $biblio->biblioitem->itemtype,
88 'items.itype must have been set to biblioitem.itemtype is not given'
90 is( $item->permanent_location, $item->location,
91 'permanent_location must have been set to location if not given' );
94 subtest '*_on updates' => sub {
97 # Once the '_on' value is set (triggered by the related field turning from false to true)
98 # it should not be re-set for any changes outside of the related field being 'unset'.
100 my @fields = qw( itemlost withdrawn damaged );
101 my $today = dt_from_string();
102 my $yesterday = $today->clone()->subtract( days => 1 );
104 for my $field ( @fields ) {
105 my $item = $builder->build_sample_item(
108 itemlost_on => undef,
110 withdrawn_on => undef,
115 my $field_on = $field . '_on';
117 # Set field for the first time
118 Time::Fake->offset( $yesterday->epoch );
119 $item->$field(1)->store;
120 $item->get_from_storage;
121 is( t::lib::Dates::compare( $item->$field_on, $yesterday ),
122 0, $field_on . " was set upon first truthy setting" );
124 # Update the field to a new 'true' value
125 Time::Fake->offset( $today->epoch );
126 $item->$field(2)->store;
127 $item->get_from_storage;
128 is( t::lib::Dates::compare( $item->$field_on, $yesterday ),
129 0, $field_on . " was not updated upon second truthy setting" );
131 # Update the field to a new 'false' value
132 $item->$field(0)->store;
133 $item->get_from_storage;
134 is($item->$field_on, undef, $field_on . " was unset upon untruthy setting");
140 subtest '_lost_found_trigger' => sub {
143 t::lib::Mocks::mock_preference( 'WhenLostChargeReplacementFee', 1 );
144 t::lib::Mocks::mock_preference( 'WhenLostForgiveFine', 0 );
146 my $processfee_amount = 20;
147 my $replacement_amount = 99.00;
148 my $item_type = $builder->build_object(
150 class => 'Koha::ItemTypes',
154 defaultreplacecost => undef,
155 processfee => $processfee_amount,
156 rentalcharge_daily => 0,
160 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
162 $biblio = $builder->build_sample_biblio( { author => 'Hall, Daria' } );
164 subtest 'Full write-off tests' => sub {
168 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
170 $builder->build_object( { class => "Koha::Patrons" } );
171 t::lib::Mocks::mock_userenv(
172 { patron => $manager, branchcode => $manager->branchcode } );
174 my $item = $builder->build_sample_item(
176 biblionumber => $biblio->biblionumber,
177 library => $library->branchcode,
178 replacementprice => $replacement_amount,
179 itype => $item_type->itemtype,
183 C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
185 # Simulate item marked as lost
186 $item->itemlost(3)->store;
187 C4::Circulation::LostItem( $item->itemnumber, 1 );
189 my $processing_fee_lines = Koha::Account::Lines->search(
191 borrowernumber => $patron->id,
192 itemnumber => $item->itemnumber,
193 debit_type_code => 'PROCESSING'
196 is( $processing_fee_lines->count,
197 1, 'Only one processing fee produced' );
198 my $processing_fee_line = $processing_fee_lines->next;
199 is( $processing_fee_line->amount + 0,
201 'The right PROCESSING amount is generated' );
202 is( $processing_fee_line->amountoutstanding + 0,
204 'The right PROCESSING amountoutstanding is generated' );
206 my $lost_fee_lines = Koha::Account::Lines->search(
208 borrowernumber => $patron->id,
209 itemnumber => $item->itemnumber,
210 debit_type_code => 'LOST'
213 is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
214 my $lost_fee_line = $lost_fee_lines->next;
215 is( $lost_fee_line->amount + 0,
216 $replacement_amount, 'The right LOST amount is generated' );
217 is( $lost_fee_line->amountoutstanding + 0,
219 'The right LOST amountoutstanding is generated' );
220 is( $lost_fee_line->status, undef, 'The LOST status was not set' );
222 my $account = $patron->account;
223 my $debts = $account->outstanding_debits;
226 my $credit = $account->add_credit(
228 amount => $account->balance,
234 { debits => [ $debts->as_list ], offset_type => 'Writeoff' } );
236 # Simulate item marked as found
237 $item->itemlost(0)->store;
238 is( $item->{_refunded}, undef, 'No LOST_FOUND account line added' );
240 $lost_fee_line->discard_changes; # reload from DB
241 is( $lost_fee_line->amountoutstanding + 0,
242 0, 'Lost fee has no outstanding amount' );
243 is( $lost_fee_line->debit_type_code,
244 'LOST', 'Lost fee now still has account type of LOST' );
245 is( $lost_fee_line->status, 'FOUND',
246 "Lost fee now has account status of FOUND - No Refund" );
248 is( $patron->account->balance,
249 -0, 'The patron balance is 0, everything was written off' );
252 subtest 'Full payment tests' => sub {
256 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
258 my $item = $builder->build_sample_item(
260 biblionumber => $biblio->biblionumber,
261 library => $library->branchcode,
262 replacementprice => $replacement_amount,
263 itype => $item_type->itemtype
268 C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
270 # Simulate item marked as lost
271 $item->itemlost(1)->store;
272 C4::Circulation::LostItem( $item->itemnumber, 1 );
274 my $processing_fee_lines = Koha::Account::Lines->search(
276 borrowernumber => $patron->id,
277 itemnumber => $item->itemnumber,
278 debit_type_code => 'PROCESSING'
281 is( $processing_fee_lines->count,
282 1, 'Only one processing fee produced' );
283 my $processing_fee_line = $processing_fee_lines->next;
284 is( $processing_fee_line->amount + 0,
286 'The right PROCESSING amount is generated' );
287 is( $processing_fee_line->amountoutstanding + 0,
289 'The right PROCESSING amountoutstanding is generated' );
291 my $lost_fee_lines = Koha::Account::Lines->search(
293 borrowernumber => $patron->id,
294 itemnumber => $item->itemnumber,
295 debit_type_code => 'LOST'
298 is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
299 my $lost_fee_line = $lost_fee_lines->next;
300 is( $lost_fee_line->amount + 0,
301 $replacement_amount, 'The right LOST amount is generated' );
302 is( $lost_fee_line->amountoutstanding + 0,
304 'The right LOST amountountstanding is generated' );
306 my $account = $patron->account;
307 my $debts = $account->outstanding_debits;
310 my $credit = $account->add_credit(
312 amount => $account->balance,
318 { debits => [ $debts->as_list ], offset_type => 'Payment' } );
320 # Simulate item marked as found
321 $item->itemlost(0)->store;
322 is( $item->{_refunded}, 1, 'Refund triggered' );
324 my $credit_return = Koha::Account::Lines->search(
326 itemnumber => $item->itemnumber,
327 credit_type_code => 'LOST_FOUND'
332 ok( $credit_return, 'An account line of type LOST_FOUND is added' );
333 is( $credit_return->amount + 0,
335 'The account line of type LOST_FOUND has an amount of -99' );
337 $credit_return->amountoutstanding + 0,
339 'The account line of type LOST_FOUND has an amountoutstanding of -99'
342 $lost_fee_line->discard_changes;
343 is( $lost_fee_line->amountoutstanding + 0,
344 0, 'Lost fee has no outstanding amount' );
345 is( $lost_fee_line->debit_type_code,
346 'LOST', 'Lost fee now still has account type of LOST' );
347 is( $lost_fee_line->status, 'FOUND',
348 "Lost fee now has account status of FOUND" );
350 is( $patron->account->balance, -99,
351 'The patron balance is -99, a credit that equals the lost fee payment'
355 subtest 'Test without payment or write off' => sub {
359 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
361 my $item = $builder->build_sample_item(
363 biblionumber => $biblio->biblionumber,
364 library => $library->branchcode,
365 replacementprice => 23.00,
366 replacementprice => $replacement_amount,
367 itype => $item_type->itemtype
372 C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
374 # Simulate item marked as lost
375 $item->itemlost(3)->store;
376 C4::Circulation::LostItem( $item->itemnumber, 1 );
378 my $processing_fee_lines = Koha::Account::Lines->search(
380 borrowernumber => $patron->id,
381 itemnumber => $item->itemnumber,
382 debit_type_code => 'PROCESSING'
385 is( $processing_fee_lines->count,
386 1, 'Only one processing fee produced' );
387 my $processing_fee_line = $processing_fee_lines->next;
388 is( $processing_fee_line->amount + 0,
390 'The right PROCESSING amount is generated' );
391 is( $processing_fee_line->amountoutstanding + 0,
393 'The right PROCESSING amountoutstanding is generated' );
395 my $lost_fee_lines = Koha::Account::Lines->search(
397 borrowernumber => $patron->id,
398 itemnumber => $item->itemnumber,
399 debit_type_code => 'LOST'
402 is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
403 my $lost_fee_line = $lost_fee_lines->next;
404 is( $lost_fee_line->amount + 0,
405 $replacement_amount, 'The right LOST amount is generated' );
406 is( $lost_fee_line->amountoutstanding + 0,
408 'The right LOST amountountstanding is generated' );
410 # Simulate item marked as found
411 $item->itemlost(0)->store;
412 is( $item->{_refunded}, 1, 'Refund triggered' );
414 my $credit_return = Koha::Account::Lines->search(
416 itemnumber => $item->itemnumber,
417 credit_type_code => 'LOST_FOUND'
422 ok( $credit_return, 'An account line of type LOST_FOUND is added' );
423 is( $credit_return->amount + 0,
425 'The account line of type LOST_FOUND has an amount of -99' );
427 $credit_return->amountoutstanding + 0,
429 'The account line of type LOST_FOUND has an amountoutstanding of 0'
432 $lost_fee_line->discard_changes;
433 is( $lost_fee_line->amountoutstanding + 0,
434 0, 'Lost fee has no outstanding amount' );
435 is( $lost_fee_line->debit_type_code,
436 'LOST', 'Lost fee now still has account type of LOST' );
437 is( $lost_fee_line->status, 'FOUND',
438 "Lost fee now has account status of FOUND" );
440 is( $patron->account->balance,
441 20, 'The patron balance is 20, still owes the processing fee' );
445 'Test with partial payement and write off, and remaining debt' =>
450 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
451 my $item = $builder->build_sample_item(
453 biblionumber => $biblio->biblionumber,
454 library => $library->branchcode,
455 replacementprice => $replacement_amount,
456 itype => $item_type->itemtype
461 C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
463 # Simulate item marked as lost
464 $item->itemlost(1)->store;
465 C4::Circulation::LostItem( $item->itemnumber, 1 );
467 my $processing_fee_lines = Koha::Account::Lines->search(
469 borrowernumber => $patron->id,
470 itemnumber => $item->itemnumber,
471 debit_type_code => 'PROCESSING'
474 is( $processing_fee_lines->count,
475 1, 'Only one processing fee produced' );
476 my $processing_fee_line = $processing_fee_lines->next;
477 is( $processing_fee_line->amount + 0,
479 'The right PROCESSING amount is generated' );
480 is( $processing_fee_line->amountoutstanding + 0,
482 'The right PROCESSING amountoutstanding is generated' );
484 my $lost_fee_lines = Koha::Account::Lines->search(
486 borrowernumber => $patron->id,
487 itemnumber => $item->itemnumber,
488 debit_type_code => 'LOST'
491 is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
492 my $lost_fee_line = $lost_fee_lines->next;
493 is( $lost_fee_line->amount + 0,
494 $replacement_amount, 'The right LOST amount is generated' );
495 is( $lost_fee_line->amountoutstanding + 0,
497 'The right LOST amountountstanding is generated' );
499 my $account = $patron->account;
502 $processfee_amount + $replacement_amount,
503 'Balance is PROCESSING + L'
507 my $payment_amount = 27;
508 my $payment = $account->add_credit(
510 amount => $payment_amount,
517 { debits => [$lost_fee_line], offset_type => 'Payment' } );
519 # Partially write off fee
520 my $write_off_amount = 25;
521 my $write_off = $account->add_credit(
523 amount => $write_off_amount,
529 { debits => [$lost_fee_line], offset_type => 'Writeoff' } );
534 $replacement_amount -
537 'Payment and write off applied'
540 # Store the amountoutstanding value
541 $lost_fee_line->discard_changes;
542 my $outstanding = $lost_fee_line->amountoutstanding;
544 # Simulate item marked as found
545 $item->itemlost(0)->store;
546 is( $item->{_refunded}, 1, 'Refund triggered' );
548 my $credit_return = Koha::Account::Lines->search(
550 itemnumber => $item->itemnumber,
551 credit_type_code => 'LOST_FOUND'
556 ok( $credit_return, 'An account line of type LOST_FOUND is added' );
560 $processfee_amount - $payment_amount,
561 'Balance is PROCESSING - PAYMENT (LOST_FOUND)'
564 $lost_fee_line->discard_changes;
565 is( $lost_fee_line->amountoutstanding + 0,
566 0, 'Lost fee has no outstanding amount' );
567 is( $lost_fee_line->debit_type_code,
568 'LOST', 'Lost fee now still has account type of LOST' );
569 is( $lost_fee_line->status, 'FOUND',
570 "Lost fee now has account status of FOUND" );
573 $credit_return->amount + 0,
574 ( $payment_amount + $outstanding ) * -1,
575 'The account line of type LOST_FOUND has an amount equal to the payment + outstanding'
578 $credit_return->amountoutstanding + 0,
579 $payment_amount * -1,
580 'The account line of type LOST_FOUND has an amountoutstanding equal to the payment'
585 $processfee_amount - $payment_amount,
586 'The patron balance is the difference between the PROCESSING and the credit'
590 subtest 'Partial payment, existing debits and AccountAutoReconcile' =>
595 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
596 my $barcode = 'KD123456793';
597 my $replacement_amount = 100;
598 my $processfee_amount = 20;
600 my $item_type = $builder->build_object(
602 class => 'Koha::ItemTypes',
606 defaultreplacecost => undef,
608 rentalcharge_daily => 0,
612 my $item = Koha::Item->new(
614 biblionumber => $biblio->biblionumber,
615 homebranch => $library->branchcode,
616 holdingbranch => $library->branchcode,
618 replacementprice => $replacement_amount,
619 itype => $item_type->itemtype
624 C4::Circulation::AddIssue( $patron->unblessed, $barcode );
626 # Simulate item marked as lost
627 $item->itemlost(1)->store;
628 C4::Circulation::LostItem( $item->itemnumber, 1 );
630 my $lost_fee_lines = Koha::Account::Lines->search(
632 borrowernumber => $patron->id,
633 itemnumber => $item->itemnumber,
634 debit_type_code => 'LOST'
637 is( $lost_fee_lines->count, 1, 'Only one lost item fee produced' );
638 my $lost_fee_line = $lost_fee_lines->next;
639 is( $lost_fee_line->amount + 0,
640 $replacement_amount, 'The right LOST amount is generated' );
641 is( $lost_fee_line->amountoutstanding + 0,
643 'The right LOST amountountstanding is generated' );
645 my $account = $patron->account;
646 is( $account->balance, $replacement_amount, 'Balance is L' );
649 my $payment_amount = 27;
650 my $payment = $account->add_credit(
652 amount => $payment_amount,
658 { debits => [$lost_fee_line], offset_type => 'Payment' } );
662 $replacement_amount - $payment_amount,
666 my $manual_debit_amount = 80;
669 amount => $manual_debit_amount,
677 $manual_debit_amount + $replacement_amount - $payment_amount,
678 'Manual debit applied'
681 t::lib::Mocks::mock_preference( 'AccountAutoReconcile', 1 );
683 # Simulate item marked as found
684 $item->itemlost(0)->store;
685 is( $item->{_refunded}, 1, 'Refund triggered' );
687 my $credit_return = Koha::Account::Lines->search(
689 itemnumber => $item->itemnumber,
690 credit_type_code => 'LOST_FOUND'
695 ok( $credit_return, 'An account line of type LOST_FOUND is added' );
699 $manual_debit_amount - $payment_amount,
700 'Balance is PROCESSING - payment (LOST_FOUND)'
703 my $manual_debit = Koha::Account::Lines->search(
705 borrowernumber => $patron->id,
706 debit_type_code => 'OVERDUE',
707 status => 'UNRETURNED'
711 $manual_debit->amountoutstanding + 0,
712 $manual_debit_amount - $payment_amount,
713 'reconcile_balance was called'
717 subtest 'Patron deleted' => sub {
720 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
721 my $barcode = 'KD123456794';
722 my $replacement_amount = 100;
723 my $processfee_amount = 20;
725 my $item_type = $builder->build_object(
727 class => 'Koha::ItemTypes',
731 defaultreplacecost => undef,
733 rentalcharge_daily => 0,
737 my $item = Koha::Item->new(
739 biblionumber => $biblio->biblionumber,
740 homebranch => $library->branchcode,
741 holdingbranch => $library->branchcode,
743 replacementprice => $replacement_amount,
744 itype => $item_type->itemtype
749 C4::Circulation::AddIssue( $patron->unblessed, $barcode );
751 # Simulate item marked as lost
752 $item->itemlost(1)->store;
753 C4::Circulation::LostItem( $item->itemnumber, 1 );
758 # Simulate item marked as found
759 $item->itemlost(0)->store;
760 is( $item->{_refunded}, undef, 'No refund triggered' );
764 subtest 'Continue when userenv is not set' => sub {
767 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
768 my $barcode = 'KD123456795';
769 my $replacement_amount = 100;
770 my $processfee_amount = 20;
772 my $item_type = $builder->build_object(
774 class => 'Koha::ItemTypes',
778 defaultreplacecost => undef,
780 rentalcharge_daily => 0,
784 my $item = $builder->build_sample_item(
786 biblionumber => $biblio->biblionumber,
787 homebranch => $library->branchcode,
788 holdingbranch => $library->branchcode,
790 replacementprice => $replacement_amount,
791 itype => $item_type->itemtype
796 C4::Circulation::AddIssue( $patron->unblessed, $barcode );
798 # Simulate item marked as lost
799 $item->itemlost(1)->store;
800 C4::Circulation::LostItem( $item->itemnumber, 1 );
803 C4::Context->_new_userenv(undef);
805 # Simluate item marked as found
806 $item->itemlost(0)->store;
807 is( $item->{_refunded}, 1, 'No refund triggered' );
813 subtest 'get_transfer' => sub {
816 my $transfer = $new_item_1->get_transfer();
817 is( $transfer, undef, 'Koha::Item->get_transfer should return undef if the item is not in transit' );
819 my $library_to = $builder->build( { source => 'Branch' } );
821 C4::Circulation::transferbook({
822 from_branch => $new_item_1->holdingbranch,
823 to_branch => $library_to->{branchcode},
824 barcode => $new_item_1->barcode,
827 $transfer = $new_item_1->get_transfer();
828 is( ref($transfer), 'Koha::Item::Transfer', 'Koha::Item->get_transfer should return a Koha::Item::Transfers object' );
830 is( $transfer->itemnumber, $new_item_1->itemnumber, 'Koha::Item->get_transfer should return a valid Koha::Item::Transfers object' );
833 subtest 'holds' => sub {
836 my $biblio = $builder->build_sample_biblio();
837 my $item = $builder->build_sample_item({
838 biblionumber => $biblio->biblionumber,
840 is($item->holds->count, 0, "Nothing returned if no holds");
841 my $hold1 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'T' }});
842 my $hold2 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'W' }});
843 my $hold3 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'W' }});
845 is($item->holds()->count,3,"Three holds found");
846 is($item->holds({found => 'W'})->count,2,"Two waiting holds found");
847 is_deeply($item->holds({found => 'T'})->next->unblessed,$hold1,"Found transit holds matches the hold");
848 is($item->holds({found => undef})->count, 0,"Nothing returned if no matching holds");
851 subtest 'biblio' => sub {
854 my $biblio = $retrieved_item_1->biblio;
855 is( ref( $biblio ), 'Koha::Biblio', 'Koha::Item->biblio should return a Koha::Biblio' );
856 is( $biblio->biblionumber, $retrieved_item_1->biblionumber, 'Koha::Item->biblio should return the correct biblio' );
859 subtest 'biblioitem' => sub {
862 my $biblioitem = $retrieved_item_1->biblioitem;
863 is( ref( $biblioitem ), 'Koha::Biblioitem', 'Koha::Item->biblioitem should return a Koha::Biblioitem' );
864 is( $biblioitem->biblionumber, $retrieved_item_1->biblionumber, 'Koha::Item->biblioitem should return the correct biblioitem' );
868 t::lib::Mocks::mock_userenv({ branchcode => $library->{branchcode} });
869 subtest 'checkout' => sub {
871 my $item = Koha::Items->find( $new_item_1->itemnumber );
873 my $checkout = $item->checkout;
874 is( $checkout, undef, 'Koha::Item->checkout should return undef if there is no current checkout on this item' );
877 my $patron = $builder->build({ source => 'Borrower' });
878 C4::Circulation::AddIssue( $patron, $item->barcode );
879 $checkout = $retrieved_item_1->checkout;
880 is( ref( $checkout ), 'Koha::Checkout', 'Koha::Item->checkout should return a Koha::Checkout' );
881 is( $checkout->itemnumber, $item->itemnumber, 'Koha::Item->checkout should return the correct checkout' );
882 is( $checkout->borrowernumber, $patron->{borrowernumber}, 'Koha::Item->checkout should return the correct checkout' );
885 C4::Circulation::AddReturn( $item->barcode );
887 # There is no more checkout on this item, making sure it will not return old checkouts
888 $checkout = $item->checkout;
889 is( $checkout, undef, 'Koha::Item->checkout should return undef if there is no *current* checkout on this item' );
892 subtest 'can_be_transferred' => sub {
895 t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1);
896 t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype');
898 my $biblio = $builder->build_sample_biblio();
899 my $library1 = $builder->build_object( { class => 'Koha::Libraries' } );
900 my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
901 my $item = $builder->build_sample_item({
902 biblionumber => $biblio->biblionumber,
903 homebranch => $library1->branchcode,
904 holdingbranch => $library1->branchcode,
907 is(Koha::Item::Transfer::Limits->search({
908 fromBranch => $library1->branchcode,
909 toBranch => $library2->branchcode,
910 })->count, 0, 'There are no transfer limits between libraries.');
911 ok($item->can_be_transferred({ to => $library2 }),
912 'Item can be transferred between libraries.');
914 my $limit = Koha::Item::Transfer::Limit->new({
915 fromBranch => $library1->branchcode,
916 toBranch => $library2->branchcode,
917 itemtype => $item->effective_itemtype,
919 is(Koha::Item::Transfer::Limits->search({
920 fromBranch => $library1->branchcode,
921 toBranch => $library2->branchcode,
922 })->count, 1, 'Given we have added a transfer limit,');
923 is($item->can_be_transferred({ to => $library2 }), 0,
924 'Item can no longer be transferred between libraries.');
925 is($item->can_be_transferred({ to => $library2, from => $library1 }), 0,
926 'We get the same result also if we pass the from-library parameter.');
929 subtest 'filter_by_for_loan' => sub {
932 my $biblio = $builder->build_sample_biblio;
933 is( $biblio->items->filter_by_for_loan->count, 0, 'no item yet' );
934 $builder->build_sample_item( { biblionumber => $biblio->biblionumber, notforloan => 1 } );
935 is( $biblio->items->filter_by_for_loan->count, 0, 'no item for loan' );
936 $builder->build_sample_item( { biblionumber => $biblio->biblionumber, notforloan => 0 } );
937 is( $biblio->items->filter_by_for_loan->count, 1, '1 item for loan' );
942 # Reset nb_of_items prior to testing delete
943 $nb_of_items = Koha::Items->search->count;
946 $retrieved_item_1->delete;
947 is( Koha::Items->search->count, $nb_of_items - 1, 'Delete should have deleted the item' );
949 $schema->storage->txn_rollback;