3 # Copyright 2017 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;
25 use t
::lib
::TestBuilder
;
32 use Koha
::DateUtils
qw(dt_from_string);
35 my $schema = Koha
::Database
->schema;
36 my $builder = t
::lib
::TestBuilder
->new;
38 subtest
'basket() tests' => sub {
42 $schema->storage->txn_begin;
44 my $basket = $builder->build_object(
46 class => 'Koha::Acquisition::Baskets'
49 my $order = $builder->build_object(
51 class => 'Koha::Acquisition::Orders',
52 value
=> { basketno
=> $basket->basketno }
56 my $retrieved_basket = $order->basket;
57 is
( ref($retrieved_basket), 'Koha::Acquisition::Basket',
58 'Type is correct for ->basket' );
59 is_deeply
( $retrieved_basket->unblessed,
60 $basket->unblessed, "Correct basket found and updated" );
62 $schema->storage->txn_rollback;
65 subtest
'biblio() tests' => sub {
69 $schema->storage->txn_begin;
71 my $order = $builder->build_object(
73 class => 'Koha::Acquisition::Orders',
74 value
=> { biblionumber
=> undef }
78 is
( $order->biblio, undef, 'If no linked biblio, undef is returned' );
80 # Add and link a biblio to the order
81 my $biblio = $builder->build_sample_biblio();
82 $order->set({ biblionumber
=> $biblio->biblionumber })->store->discard_changes;
84 my $THE_biblio = $order->biblio;
85 is
( ref($THE_biblio), 'Koha::Biblio', 'Returns a Koha::Biblio object' );
86 is
( $THE_biblio->biblionumber, $biblio->biblionumber, 'It is not cheating about the object' );
88 $order->biblio->delete;
89 $order = Koha
::Acquisition
::Orders
->find($order->ordernumber);
90 ok
( $order, 'The order is not deleted if the biblio is deleted' );
91 is
( $order->biblio, undef, 'order.biblio is correctly set to NULL when the biblio is deleted' );
93 $schema->storage->txn_rollback;
96 subtest
'store' => sub {
99 $schema->storage->txn_begin;
100 my $o = $builder->build_object(
102 class => 'Koha::Acquisition::Orders'
106 subtest
'entrydate' => sub {
111 t
::lib
::Mocks
::mock_preference
( 'TimeFormat', '12hr' );
112 $order = Koha
::Acquisition
::Order
->new(
114 basketno
=> $o->basketno,
115 biblionumber
=> $o->biblionumber,
116 budget_id
=> $o->budget_id,
120 $order->discard_changes;
121 like
( $order->entrydate, qr
|^\d
{4}-\d
{2}-\d
{2}$| );
123 t
::lib
::Mocks
::mock_preference
( 'TimeFormat', '24hr' );
124 $order = Koha
::Acquisition
::Order
->new(
126 basketno
=> $o->basketno,
127 biblionumber
=> $o->biblionumber,
128 budget_id
=> $o->budget_id,
132 $order->discard_changes;
133 like
( $order->entrydate, qr
|^\d
{4}-\d
{2}-\d
{2}$| );
135 $schema->storage->txn_rollback;
138 subtest
'fund' => sub {
141 $schema->storage->txn_begin;
142 my $o = $builder->build_object(
144 class => 'Koha::Acquisition::Orders',
148 my $order = Koha
::Acquisition
::Orders
->find( $o->ordernumber );
149 is
( ref( $order->fund ),
150 'Koha::Acquisition::Fund',
151 '->fund should return a Koha::Acquisition::Fund object' );
152 $schema->storage->txn_rollback;
155 subtest
'invoice' => sub {
158 $schema->storage->txn_begin;
159 my $o = $builder->build_object(
161 class => 'Koha::Acquisition::Orders',
162 value
=> { cancellationreason
=> 'XXXXXXXX', invoiceid
=> undef }, # not received yet
166 my $order = Koha
::Acquisition
::Orders
->find( $o->ordernumber );
167 is
( $order->invoice, undef,
168 '->invoice should return undef if no invoice defined yet');
170 my $invoice = $builder->build_object(
172 class => 'Koha::Acquisition::Invoices',
176 $o->invoiceid( $invoice->invoiceid )->store;
177 $order = Koha
::Acquisition
::Orders
->find( $o->ordernumber );
178 is
( ref( $order->invoice ), 'Koha::Acquisition::Invoice',
179 '->invoice should return a Koha::Acquisition::Invoice object if an invoice is defined');
181 $schema->storage->txn_rollback;
184 subtest
'subscription' => sub {
187 $schema->storage->txn_begin;
188 my $o = $builder->build_object(
190 class => 'Koha::Acquisition::Orders',
191 value
=> { subscriptionid
=> undef }, # not linked to a subscription
195 my $order = Koha
::Acquisition
::Orders
->find( $o->ordernumber );
196 is
( $order->subscription, undef,
197 '->subscription should return undef if not created from a subscription');
199 $o = $builder->build_object(
201 class => 'Koha::Acquisition::Orders',
202 # Will be linked to a subscription by TestBuilder
206 $order = Koha
::Acquisition
::Orders
->find( $o->ordernumber );
207 is
( ref( $order->subscription ), 'Koha::Subscription',
208 '->subscription should return a Koha::Subscription object if created from a subscription');
210 $schema->storage->txn_rollback;
213 subtest
'duplicate_to | add_item' => sub {
216 $schema->storage->txn_begin;
218 my $item = $builder->build_sample_item;
219 my $order_no_sub = $builder->build_object(
221 class => 'Koha::Acquisition::Orders',
224 biblionumber
=> $item->biblionumber,
225 subscriptionid
=> undef, # not linked to a subscription
229 $order_no_sub->basket->create_items(undef)->store; # use syspref
230 $order_no_sub->add_item( $item->itemnumber );
232 $item = $builder->build_sample_item;
233 my $order_from_sub = $builder->build_object(
235 class => 'Koha::Acquisition::Orders',
238 biblionumber
=> $item->biblionumber,
239 # Will be linked to a subscription by TestBuilder
243 $order_from_sub->basket->create_items(undef)->store; # use syspref
244 $order_from_sub->add_item( $item->itemnumber );
246 my $basket_to = $builder->build_object(
247 { class => 'Koha::Acquisition::Baskets' });
249 subtest
'Create item on receiving' => sub {
252 t
::lib
::Mocks
::mock_preference
('AcqCreateItem', 'receiving');
254 my $duplicated_order = $order_no_sub->duplicate_to($basket_to);
255 is
( $duplicated_order->items->count, 0,
256 'Items should not be copied if the original order did not create items on ordering'
259 $duplicated_order = $order_from_sub->duplicate_to($basket_to);
260 is
( $duplicated_order->items->count, 0,
261 'Items should not be copied if the original order is created from a subscription'
265 subtest
'Create item on ordering' => sub {
268 t
::lib
::Mocks
::mock_preference
('AcqCreateItem', 'ordering');
270 my $duplicated_order = $order_no_sub->duplicate_to($basket_to);
271 is
( $duplicated_order->items->count, 1,
272 'Items should be copied if items are created on ordering'
275 $duplicated_order = $order_from_sub->duplicate_to($basket_to);
276 is
( $duplicated_order->items->count, 0,
277 'Items should never be copied if the original order is created from a subscription'
281 subtest
'Regression tests' => sub {
284 my $duplicated_order = $order_no_sub->duplicate_to($basket_to);
285 is
($duplicated_order->invoiceid, undef, "invoiceid should be set to null for a new duplicated order");
288 $schema->storage->txn_rollback;
291 subtest
'current_item_level_holds() tests' => sub {
295 $schema->storage->txn_begin;
297 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
298 my $biblio = $builder->build_sample_biblio();
299 my $item_1 = $builder->build_sample_item( { biblionumber
=> $biblio->biblionumber } );
300 my $item_2 = $builder->build_sample_item( { biblionumber
=> $biblio->biblionumber } );
301 my $item_3 = $builder->build_sample_item( { biblionumber
=> $biblio->biblionumber } );
303 C4
::Reserves
::AddReserve
(
305 branchcode
=> $patron->branchcode,
306 borrowernumber
=> $patron->borrowernumber,
307 biblionumber
=> $biblio->biblionumber,
308 reservation_date
=> dt_from_string
->add( days
=> -2 ),
309 itemnumber
=> $item_1->itemnumber,
312 C4
::Reserves
::AddReserve
(
314 branchcode
=> $patron->branchcode,
315 borrowernumber
=> $patron->borrowernumber,
316 biblionumber
=> $biblio->biblionumber,
317 reservation_date
=> dt_from_string
->add( days
=> -2 ),
318 itemnumber
=> $item_2->itemnumber,
321 # Add a hold in the future
322 C4
::Reserves
::AddReserve
(
324 branchcode
=> $patron->branchcode,
325 borrowernumber
=> $patron->borrowernumber,
326 biblionumber
=> $biblio->biblionumber,
327 reservation_date
=> dt_from_string
->add( days
=> 2 ),
328 itemnumber
=> $item_3->itemnumber,
332 # Add an order with no biblionumber
333 my $order = $builder->build_object(
335 class => 'Koha::Acquisition::Orders',
337 biblionumber
=> undef
342 my $holds = $order->current_item_level_holds;
344 is
( ref($holds), 'Koha::Holds', 'Koha::Holds iterator returned if no linked biblio' );
345 is
( $holds->count, 0, 'Count is 0 if no linked biblio' );
347 $order->set({ biblionumber
=> $biblio->biblionumber })->store->discard_changes;
349 $holds = $order->current_item_level_holds;
351 is
( ref($holds), 'Koha::Holds', 'Koha::Holds iterator returned if no linked items' );
352 is
( $holds->count, 0, 'Count is 0 if no linked items' );
354 $order->add_item( $item_2->itemnumber );
355 $order->add_item( $item_3->itemnumber );
357 $holds = $order->current_item_level_holds;
358 is
( $holds->count, 1, 'Only current (not future) holds are returned');
360 $schema->storage->txn_rollback;
363 subtest
'claim*' => sub {
366 $schema->storage->txn_begin;
367 my $order = $builder->build_object(
369 class => 'Koha::Acquisition::Orders',
373 my $now = dt_from_string
;
374 is
( $order->claims->count, 0, 'No claim yet, ->claims should return an empty set');
375 is
( $order->claims_count, 0, 'No claim yet, ->claims_count should return 0');
376 is
( $order->claimed_date, undef, 'No claim yet, ->claimed_date should return undef');
378 my $claim_1 = $order->claim;
379 my $claim_2 = $order->claim;
381 $claim_1->claimed_on($now->clone->subtract(days
=> 1))->store;
382 $claim_2->claimed_on($now)->store;
384 is
( $order->claims->count, 2, '->claims should return the correct number of claims');
385 is
( $order->claims_count, 2, '->claims_count should return the correct number of claims');
386 is
( dt_from_string
($order->claimed_date), $now, '->claimed_date should return the date of the last claim');
388 $schema->storage->txn_rollback;
391 subtest
'filter_by_late' => sub {
394 $schema->storage->txn_begin;
395 my $now = dt_from_string
;
396 my $bookseller = $builder->build_object(
398 class => 'Koha::Acquisition::Booksellers',
399 value
=> { deliverytime
=> 2 }
402 my $basket_1 = $builder->build_object(
404 class => 'Koha::Acquisition::Baskets',
406 booksellerid
=> $bookseller->id,
411 my $order_1 = $builder->build_object(
413 class => 'Koha::Acquisition::Orders',
415 basketno
=> $basket_1->basketno,
416 datereceived
=> undef,
417 datecancellationprinted
=> undef,
421 my $basket_2 = $builder->build_object( # expected tomorrow
423 class => 'Koha::Acquisition::Baskets',
425 booksellerid
=> $bookseller->id,
426 closedate
=> $now->clone->subtract( days
=> 1 ),
430 my $order_2 = $builder->build_object(
432 class => 'Koha::Acquisition::Orders',
434 basketno
=> $basket_2->basketno,
435 datereceived
=> undef,
436 datecancellationprinted
=> undef,
440 my $basket_3 = $builder->build_object( # expected yesterday (1 day)
442 class => 'Koha::Acquisition::Baskets',
444 booksellerid
=> $bookseller->id,
445 closedate
=> $now->clone->subtract( days
=> 3 ),
449 my $order_3 = $builder->build_object(
451 class => 'Koha::Acquisition::Orders',
453 basketno
=> $basket_3->basketno,
454 datereceived
=> undef,
455 datecancellationprinted
=> undef,
459 my $basket_4 = $builder->build_object( # expected 3 days ago
461 class => 'Koha::Acquisition::Baskets',
463 booksellerid
=> $bookseller->id,
464 closedate
=> $now->clone->subtract( days
=> 5 ),
468 my $order_4 = $builder->build_object(
470 class => 'Koha::Acquisition::Orders',
472 basketno
=> $basket_4->basketno,
473 datereceived
=> undef,
474 datecancellationprinted
=> undef,
479 my $orders = Koha
::Acquisition
::Orders
->search(
483 $order_1->ordernumber, $order_2->ordernumber,
484 $order_3->ordernumber, $order_4->ordernumber,
490 my $late_orders = $orders->filter_by_lates;
491 is
( $late_orders->count, 3 );
493 $late_orders = $orders->filter_by_lates( { delay
=> 0 } );
494 is
( $late_orders->count, 3 );
496 $late_orders = $orders->filter_by_lates( { delay
=> 1 } );
497 is
( $late_orders->count, 3 );
499 $late_orders = $orders->filter_by_lates( { delay
=> 3 } );
500 is
( $late_orders->count, 2 );
502 $late_orders = $orders->filter_by_lates( { delay
=> 4 } );
503 is
( $late_orders->count, 1 );
505 $late_orders = $orders->filter_by_lates( { delay
=> 5 } );
506 is
( $late_orders->count, 1 );
508 $late_orders = $orders->filter_by_lates( { delay
=> 6 } );
509 is
( $late_orders->count, 0 );
511 $late_orders = $orders->filter_by_lates(
512 { estimated_from
=> $now->clone->subtract( days
=> 6 ) } );
513 is
( $late_orders->count, 2 );
514 is
( $late_orders->next->ordernumber, $order_3->ordernumber );
516 $late_orders = $orders->filter_by_lates(
517 { estimated_from
=> $now->clone->subtract( days
=> 5 ) } );
518 is
( $late_orders->count, 2 );
519 is
( $late_orders->next->ordernumber, $order_3->ordernumber );
521 $late_orders = $orders->filter_by_lates(
522 { estimated_from
=> $now->clone->subtract( days
=> 4 ) } );
523 is
( $late_orders->count, 2 );
524 is
( $late_orders->next->ordernumber, $order_3->ordernumber );
526 $late_orders = $orders->filter_by_lates(
527 { estimated_from
=> $now->clone->subtract( days
=> 3 ) } );
528 is
( $late_orders->count, 2 );
530 $late_orders = $orders->filter_by_lates(
531 { estimated_from
=> $now->clone->subtract( days
=> 1 ) } );
532 is
( $late_orders->count, 1 );
534 $late_orders = $orders->filter_by_lates(
536 estimated_from
=> $now->clone->subtract( days
=> 4 ),
537 estimated_to
=> $now->clone->subtract( days
=> 3 )
540 is
( $late_orders->count, 1 );
542 $schema->storage->txn_rollback;
545 subtest
'filter_by_current & filter_by_cancelled' => sub {
548 $schema->storage->txn_begin;
549 my $now = dt_from_string
;
550 my $order_1 = $builder->build_object(
552 class => 'Koha::Acquisition::Orders',
554 datecancellationprinted
=> undef,
558 my $order_2 = $builder->build_object(
560 class => 'Koha::Acquisition::Orders',
562 datecancellationprinted
=> undef,
566 my $order_3 = $builder->build_object(
568 class => 'Koha::Acquisition::Orders',
570 datecancellationprinted
=> dt_from_string
,
575 my $orders = Koha
::Acquisition
::Orders
->search(
579 $order_1->ordernumber, $order_2->ordernumber,
580 $order_3->ordernumber,
586 is
( $orders->filter_by_current->count, 2);
587 is
( $orders->filter_by_cancelled->count, 1);
590 $schema->storage->txn_rollback;
593 subtest
'cancel() tests' => sub {
597 $schema->storage->txn_begin;
600 # * order with one item attached
601 # * the item is on loan
602 # * delete_biblio is passed
603 # => order is not cancelled
604 # => item in order is not removed
605 # => biblio in order is not removed
606 # => message about not being able to delete
608 my $item = $builder->build_sample_item;
609 my $biblio_id = $item->biblio->id;
610 my $order = $builder->build_object(
612 class => 'Koha::Acquisition::Orders',
614 orderstatus
=> 'new',
615 biblionumber
=> $item->biblio->id,
616 datecancellationprinted
=> undef,
617 cancellationreason
=> undef,
620 )->reset_messages; # reset them as TestBuilder doesn't call new
621 $order->add_item( $item->id );
623 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
624 t
::lib
::Mocks
::mock_userenv
(
625 { patron
=> $patron, branchcode
=> $patron->branchcode } );
627 # Add a checkout so cancelling fails because od 'book_on_loan'
628 C4
::Circulation
::AddIssue
( $patron->unblessed, $item->barcode );
630 my $result = $order->cancel({ reason
=> 'Some reason' });
631 # refresh the order object
632 $order->discard_changes;
634 is
( $result, $order, 'self is returned' );
635 is
( $order->orderstatus, 'cancelled', 'Order is not marked as cancelled' );
636 isnt
( $order->datecancellationprinted, undef, 'datecancellationprinted is not undef' );
637 is
( $order->cancellationreason, 'Some reason', 'cancellationreason is set' );
638 is
( ref(Koha
::Items
->find($item->id)), 'Koha::Item', 'The item is present' );
639 is
( ref(Koha
::Biblios
->find($biblio_id)), 'Koha::Biblio', 'The biblio is present' );
640 my @messages = @
{ $order->messages };
641 is
( $messages[0]->message, 'error_delitem', 'An error message is attached to the order' );
644 # * order with one item attached
645 # * the item is no longer on loan
646 # * delete_biblio not passed
647 # => order is cancelled
648 # => item in order is removed
649 # => biblio remains untouched
651 C4
::Circulation
::AddReturn
( $item->barcode );
653 $order->reset_messages;
654 $order->cancel({ reason
=> 'Some reason' })
657 is
( $order->orderstatus, 'cancelled', 'Order is marked as cancelled' );
658 isnt
( $order->datecancellationprinted, undef, 'datecancellationprinted is set' );
659 is
( $order->cancellationreason, 'Some reason', 'cancellationreason is undef' );
660 is
( Koha
::Items
->find($item->id), undef, 'The item is no longer present' );
661 is
( ref(Koha
::Biblios
->find($biblio_id)), 'Koha::Biblio', 'The biblio is present' );
662 @messages = @
{ $order->messages };
663 is
( scalar @messages, 0, 'No messages' );
666 # * order with one item attached
667 # * biblio has another item
668 # => order is cancelled
669 # => item in order is removed
670 # => the extra item remains untouched
671 # => biblio remains untouched
673 my $item_1 = $builder->build_sample_item;
674 $biblio_id = $item_1->biblio->id;
675 my $item_2 = $builder->build_sample_item({ biblionumber
=> $biblio_id });
676 $order = $builder->build_object(
678 class => 'Koha::Acquisition::Orders',
680 orderstatus
=> 'new',
681 biblionumber
=> $biblio_id,
682 datecancellationprinted
=> undef,
683 cancellationreason
=> undef,
687 $order->add_item( $item_1->id );
689 $order->cancel({ reason
=> 'Some reason', delete_biblio
=> 1 })
692 is
( $order->orderstatus, 'cancelled', 'Order is marked as cancelled' );
693 isnt
( $order->datecancellationprinted, undef, 'datecancellationprinted is set' );
694 is
( $order->cancellationreason, 'Some reason', 'cancellationreason is undef' );
695 is
( Koha
::Items
->find($item_1->id), undef, 'The item is no longer present' );
696 is
( ref(Koha
::Items
->find($item_2->id)), 'Koha::Item', 'The item is still present' );
697 is
( ref(Koha
::Biblios
->find($biblio_id)), 'Koha::Biblio', 'The biblio is still present' );
698 @messages = @
{ $order->messages };
699 is
( $messages[0]->message, 'error_delbiblio', 'Cannot delete biblio and it gets notified' );
702 # * order with one item attached
703 # * there's another order pointing to the biblio
704 # => order is cancelled
705 # => item in order is removed
706 # => biblio remains untouched
707 # => biblio delete error notified
709 $item = $builder->build_sample_item;
710 $biblio_id = $item->biblio->id;
711 $order = $builder->build_object(
713 class => 'Koha::Acquisition::Orders',
715 orderstatus
=> 'new',
716 biblionumber
=> $biblio_id,
717 datecancellationprinted
=> undef,
718 cancellationreason
=> undef,
722 $order->add_item( $item->id );
725 $builder->build_object(
727 class => 'Koha::Acquisition::Orders',
729 orderstatus
=> 'new',
730 biblionumber
=> $biblio_id,
731 datecancellationprinted
=> undef,
732 cancellationreason
=> undef,
737 $order->cancel({ reason
=> 'Some reason', delete_biblio
=> 1 })
740 is
( $order->orderstatus, 'cancelled', 'Order is marked as cancelled' );
741 isnt
( $order->datecancellationprinted, undef, 'datecancellationprinted is set' );
742 is
( $order->cancellationreason, 'Some reason', 'cancellationreason is undef' );
743 is
( Koha
::Items
->find($item->id), undef, 'The item is no longer present' );
744 is
( ref(Koha
::Biblios
->find($biblio_id)), 'Koha::Biblio', 'The biblio is still present' );
745 @messages = @
{ $order->messages };
746 is
( $messages[0]->message, 'error_delbiblio', 'Cannot delete biblio and it gets notified' );
749 # * order with one item attached
750 # * there's a subscription on the biblio
751 # => order is cancelled
752 # => item in order is removed
753 # => biblio remains untouched
754 # => biblio delete error notified
756 $item = $builder->build_sample_item;
757 $biblio_id = $item->biblio->id;
758 $order = $builder->build_object(
760 class => 'Koha::Acquisition::Orders',
762 orderstatus
=> 'new',
763 biblionumber
=> $biblio_id,
764 datecancellationprinted
=> undef,
765 cancellationreason
=> undef,
769 $order->add_item( $item->id );
772 $builder->build_object(
774 class => 'Koha::Subscriptions',
776 biblionumber
=> $biblio_id,
781 $order->cancel({ reason
=> 'Some reason', delete_biblio
=> 1 })
784 is
( $order->orderstatus, 'cancelled', 'Order is marked as cancelled' );
785 isnt
( $order->datecancellationprinted, undef, 'datecancellationprinted is set' );
786 is
( $order->cancellationreason, 'Some reason', 'cancellationreason is undef' );
787 is
( Koha
::Items
->find($item->id), undef, 'The item is no longer present' );
788 is
( ref(Koha
::Biblios
->find($biblio_id)), 'Koha::Biblio', 'The biblio is still present' );
789 @messages = @
{ $order->messages };
790 is
( $messages[0]->message, 'error_delbiblio', 'Cannot delete biblio and it gets notified' );
792 $schema->storage->txn_rollback;