Bug 17600: Standardize our EXPORT_OK
[srvgit] / t / db_dependent / Koha / Acquisition / Order.t
1 #!/usr/bin/perl
2
3 # Copyright 2017 Koha Development team
4 #
5 # This file is part of Koha
6 #
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.
11 #
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.
16 #
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>.
19
20 use Modern::Perl;
21
22 use Test::More tests => 12;
23 use Test::Exception;
24
25 use t::lib::TestBuilder;
26 use t::lib::Mocks;
27
28 use C4::Circulation qw( AddIssue AddReturn );
29
30 use Koha::Biblios;
31 use Koha::Database;
32 use Koha::DateUtils qw(dt_from_string);
33 use Koha::Items;
34
35 my $schema  = Koha::Database->schema;
36 my $builder = t::lib::TestBuilder->new;
37
38 subtest 'basket() tests' => sub {
39
40     plan tests => 2;
41
42     $schema->storage->txn_begin;
43
44     my $basket = $builder->build_object(
45         {
46             class => 'Koha::Acquisition::Baskets'
47         }
48     );
49     my $order = $builder->build_object(
50         {
51             class => 'Koha::Acquisition::Orders',
52             value => { basketno => $basket->basketno }
53         }
54     );
55
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" );
61
62     $schema->storage->txn_rollback;
63 };
64
65 subtest 'biblio() tests' => sub {
66
67     plan tests => 5;
68
69     $schema->storage->txn_begin;
70
71     my $order = $builder->build_object(
72         {
73             class => 'Koha::Acquisition::Orders',
74             value => { biblionumber => undef }
75         }
76     );
77
78     is( $order->biblio, undef, 'If no linked biblio, undef is returned' );
79
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;
83
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' );
87
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' );
92
93     $schema->storage->txn_rollback;
94 };
95
96 subtest 'store' => sub {
97     plan tests => 1;
98
99     $schema->storage->txn_begin;
100     my $o = $builder->build_object(
101         {
102             class => 'Koha::Acquisition::Orders'
103         }
104     );
105
106     subtest 'entrydate' => sub {
107         plan tests => 2;
108
109         my $order;
110
111         t::lib::Mocks::mock_preference( 'TimeFormat', '12hr' );
112         $order = Koha::Acquisition::Order->new(
113             {
114                 basketno     => $o->basketno,
115                 biblionumber => $o->biblionumber,
116                 budget_id    => $o->budget_id,
117                 quantity     => 1,
118             }
119         )->store;
120         $order->discard_changes;
121         like( $order->entrydate, qr|^\d{4}-\d{2}-\d{2}$| );
122
123         t::lib::Mocks::mock_preference( 'TimeFormat', '24hr' );
124         $order = Koha::Acquisition::Order->new(
125             {
126                 basketno     => $o->basketno,
127                 biblionumber => $o->biblionumber,
128                 budget_id    => $o->budget_id,
129                 quantity     => 1,
130             }
131         )->store;
132         $order->discard_changes;
133         like( $order->entrydate, qr|^\d{4}-\d{2}-\d{2}$| );
134     };
135     $schema->storage->txn_rollback;
136 };
137
138 subtest 'fund' => sub {
139     plan tests => 1;
140
141     $schema->storage->txn_begin;
142     my $o = $builder->build_object(
143         {
144             class => 'Koha::Acquisition::Orders',
145         }
146     );
147
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;
153 };
154
155 subtest 'invoice' => sub {
156     plan tests => 2;
157
158     $schema->storage->txn_begin;
159     my $o = $builder->build_object(
160         {
161             class => 'Koha::Acquisition::Orders',
162             value => { cancellationreason => 'XXXXXXXX', invoiceid => undef }, # not received yet
163         }
164     );
165
166     my $order = Koha::Acquisition::Orders->find( $o->ordernumber );
167     is( $order->invoice, undef,
168         '->invoice should return undef if no invoice defined yet');
169
170     my $invoice = $builder->build_object(
171         {
172             class => 'Koha::Acquisition::Invoices',
173         },
174     );
175
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');
180
181     $schema->storage->txn_rollback;
182 };
183
184 subtest 'subscription' => sub {
185     plan tests => 2;
186
187     $schema->storage->txn_begin;
188     my $o = $builder->build_object(
189         {
190             class => 'Koha::Acquisition::Orders',
191             value => { subscriptionid => undef }, # not linked to a subscription
192         }
193     );
194
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');
198
199     $o = $builder->build_object(
200         {
201             class => 'Koha::Acquisition::Orders',
202             # Will be linked to a subscription by TestBuilder
203         }
204     );
205
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');
209
210     $schema->storage->txn_rollback;
211 };
212
213 subtest 'duplicate_to | add_item' => sub {
214     plan tests => 3;
215
216     $schema->storage->txn_begin;
217
218     my $item = $builder->build_sample_item;
219     my $order_no_sub = $builder->build_object(
220         {
221             class => 'Koha::Acquisition::Orders',
222             value =>
223               {
224                   biblionumber => $item->biblionumber,
225                   subscriptionid => undef, # not linked to a subscription
226               }
227         }
228     );
229     $order_no_sub->basket->create_items(undef)->store; # use syspref
230     $order_no_sub->add_item( $item->itemnumber );
231
232     $item = $builder->build_sample_item;
233     my $order_from_sub = $builder->build_object(
234         {
235             class => 'Koha::Acquisition::Orders',
236             value =>
237               {
238                   biblionumber => $item->biblionumber,
239                   # Will be linked to a subscription by TestBuilder
240               }
241         }
242     );
243     $order_from_sub->basket->create_items(undef)->store; # use syspref
244     $order_from_sub->add_item( $item->itemnumber );
245
246     my $basket_to = $builder->build_object(
247          { class => 'Koha::Acquisition::Baskets' });
248
249     subtest 'Create item on receiving' => sub {
250         plan tests => 2;
251
252         t::lib::Mocks::mock_preference('AcqCreateItem', 'receiving');
253
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'
257         );
258
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'
262         );
263     };
264
265     subtest 'Create item on ordering' => sub {
266         plan tests => 2;
267
268         t::lib::Mocks::mock_preference('AcqCreateItem', 'ordering');
269
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'
273         );
274
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'
278         );
279     };
280
281     subtest 'Regression tests' => sub {
282         plan tests => 1;
283
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");
286     };
287
288     $schema->storage->txn_rollback;
289 };
290
291 subtest 'current_item_level_holds() tests' => sub {
292
293     plan tests => 5;
294
295     $schema->storage->txn_begin;
296
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 } );
302
303     C4::Reserves::AddReserve(
304         {
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,
310         }
311     );
312     C4::Reserves::AddReserve(
313         {
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,
319         }
320     );
321     # Add a hold in the future
322     C4::Reserves::AddReserve(
323         {
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,
329         }
330     );
331
332     # Add an order with no biblionumber
333     my $order = $builder->build_object(
334         {
335             class => 'Koha::Acquisition::Orders',
336             value => {
337                 biblionumber => undef
338             }
339         }
340     );
341
342     my $holds = $order->current_item_level_holds;
343
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' );
346
347     $order->set({ biblionumber => $biblio->biblionumber })->store->discard_changes;
348
349     $holds = $order->current_item_level_holds;
350
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' );
353
354     $order->add_item( $item_2->itemnumber );
355     $order->add_item( $item_3->itemnumber );
356
357     $holds = $order->current_item_level_holds;
358     is( $holds->count, 1, 'Only current (not future) holds are returned');
359
360     $schema->storage->txn_rollback;
361 };
362
363 subtest 'claim*' => sub {
364     plan tests => 6;
365
366     $schema->storage->txn_begin;
367     my $order = $builder->build_object(
368         {
369             class => 'Koha::Acquisition::Orders',
370         }
371     );
372
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');
377
378     my $claim_1 = $order->claim;
379     my $claim_2 = $order->claim;
380
381     $claim_1->claimed_on($now->clone->subtract(days => 1))->store;
382     $claim_2->claimed_on($now)->store;
383
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');
387
388     $schema->storage->txn_rollback;
389 };
390
391 subtest 'filter_by_late' => sub {
392     plan tests => 16;
393
394     $schema->storage->txn_begin;
395     my $now        = dt_from_string;
396     my $bookseller = $builder->build_object(
397         {
398             class => 'Koha::Acquisition::Booksellers',
399             value => { deliverytime => 2 }
400         }
401     );
402     my $basket_1 = $builder->build_object(
403         {
404             class => 'Koha::Acquisition::Baskets',
405             value => {
406                 booksellerid => $bookseller->id,
407                 closedate    => undef,
408             }
409         }
410     );
411     my $order_1 = $builder->build_object(
412         {
413             class => 'Koha::Acquisition::Orders',
414             value => {
415                 basketno                => $basket_1->basketno,
416                 datereceived            => undef,
417                 datecancellationprinted => undef,
418             }
419         }
420     );
421     my $basket_2 = $builder->build_object(    # expected tomorrow
422         {
423             class => 'Koha::Acquisition::Baskets',
424             value => {
425                 booksellerid => $bookseller->id,
426                 closedate    => $now->clone->subtract( days => 1 ),
427             }
428         }
429     );
430     my $order_2 = $builder->build_object(
431         {
432             class => 'Koha::Acquisition::Orders',
433             value => {
434                 basketno                => $basket_2->basketno,
435                 datereceived            => undef,
436                 datecancellationprinted => undef,
437             }
438         }
439     );
440     my $basket_3 = $builder->build_object(    # expected yesterday (1 day)
441         {
442             class => 'Koha::Acquisition::Baskets',
443             value => {
444                 booksellerid => $bookseller->id,
445                 closedate    => $now->clone->subtract( days => 3 ),
446             }
447         }
448     );
449     my $order_3 = $builder->build_object(
450         {
451             class => 'Koha::Acquisition::Orders',
452             value => {
453                 basketno                => $basket_3->basketno,
454                 datereceived            => undef,
455                 datecancellationprinted => undef,
456             }
457         }
458     );
459     my $basket_4 = $builder->build_object(    # expected 3 days ago
460         {
461             class => 'Koha::Acquisition::Baskets',
462             value => {
463                 booksellerid => $bookseller->id,
464                 closedate    => $now->clone->subtract( days => 5 ),
465             }
466         }
467     );
468     my $order_4 = $builder->build_object(
469         {
470             class => 'Koha::Acquisition::Orders',
471             value => {
472                 basketno                => $basket_4->basketno,
473                 datereceived            => undef,
474                 datecancellationprinted => undef,
475             }
476         }
477     );
478
479     my $orders = Koha::Acquisition::Orders->search(
480         {
481             ordernumber => {
482                 -in => [
483                     $order_1->ordernumber, $order_2->ordernumber,
484                     $order_3->ordernumber, $order_4->ordernumber,
485                 ]
486             }
487         }
488     );
489
490     my $late_orders = $orders->filter_by_lates;
491     is( $late_orders->count, 3 );
492
493     $late_orders = $orders->filter_by_lates( { delay => 0 } );
494     is( $late_orders->count, 3 );
495
496     $late_orders = $orders->filter_by_lates( { delay => 1 } );
497     is( $late_orders->count, 3 );
498
499     $late_orders = $orders->filter_by_lates( { delay => 3 } );
500     is( $late_orders->count, 2 );
501
502     $late_orders = $orders->filter_by_lates( { delay => 4 } );
503     is( $late_orders->count, 1 );
504
505     $late_orders = $orders->filter_by_lates( { delay => 5 } );
506     is( $late_orders->count, 1 );
507
508     $late_orders = $orders->filter_by_lates( { delay => 6 } );
509     is( $late_orders->count, 0 );
510
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 );
515
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 );
520
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 );
525
526     $late_orders = $orders->filter_by_lates(
527         { estimated_from => $now->clone->subtract( days => 3 ) } );
528     is( $late_orders->count, 2 );
529
530     $late_orders = $orders->filter_by_lates(
531         { estimated_from => $now->clone->subtract( days => 1 ) } );
532     is( $late_orders->count, 1 );
533
534     $late_orders = $orders->filter_by_lates(
535         {
536             estimated_from => $now->clone->subtract( days => 4 ),
537             estimated_to   => $now->clone->subtract( days => 3 )
538         }
539     );
540     is( $late_orders->count, 1 );
541
542     $schema->storage->txn_rollback;
543 };
544
545 subtest 'filter_by_current & filter_by_cancelled' => sub {
546     plan tests => 2;
547
548     $schema->storage->txn_begin;
549     my $now        = dt_from_string;
550     my $order_1 = $builder->build_object(
551         {
552             class => 'Koha::Acquisition::Orders',
553             value => {
554                 datecancellationprinted => undef,
555             }
556         }
557     );
558     my $order_2 = $builder->build_object(
559         {
560             class => 'Koha::Acquisition::Orders',
561             value => {
562                 datecancellationprinted => undef,
563             }
564         }
565     );
566     my $order_3 = $builder->build_object(
567         {
568             class => 'Koha::Acquisition::Orders',
569             value => {
570                 datecancellationprinted => dt_from_string,
571             }
572         }
573     );
574
575     my $orders = Koha::Acquisition::Orders->search(
576         {
577             ordernumber => {
578                 -in => [
579                     $order_1->ordernumber, $order_2->ordernumber,
580                     $order_3->ordernumber,
581                 ]
582             }
583         }
584     );
585
586     is( $orders->filter_by_current->count, 2);
587     is( $orders->filter_by_cancelled->count, 1);
588
589
590     $schema->storage->txn_rollback;
591 };
592
593 subtest 'cancel() tests' => sub {
594
595     plan tests => 52;
596
597     $schema->storage->txn_begin;
598
599     my $reason = 'Some reason';
600
601     # Scenario:
602     # * order with one item attached
603     # * the item is on loan
604     # * delete_biblio is passed
605     # => order is not cancelled
606     # => item in order is not removed
607     # => biblio in order is not removed
608     # => message about not being able to delete
609
610     my $item      = $builder->build_sample_item;
611     my $biblio_id = $item->biblionumber;
612     my $order     = $builder->build_object(
613         {
614             class => 'Koha::Acquisition::Orders',
615             value => {
616                 orderstatus             => 'new',
617                 biblionumber            => $item->biblionumber,
618                 datecancellationprinted => undef,
619                 cancellationreason      => undef,
620             }
621         }
622     );
623     $order->add_item( $item->id );
624
625     my $patron = $builder->build_object({ class => 'Koha::Patrons' });
626     t::lib::Mocks::mock_userenv({ patron => $patron });
627
628     # Add a checkout so deleting the item fails because od 'book_on_loan'
629     C4::Circulation::AddIssue( $patron->unblessed, $item->barcode );
630
631     my $result = $order->cancel({ reason => $reason });
632     # refresh the order object
633     $order->discard_changes;
634
635     is( $result, $order, 'self is returned' );
636     is( $order->orderstatus, 'cancelled', 'Order is not marked as cancelled' );
637     isnt( $order->datecancellationprinted, undef, 'datecancellationprinted is not undef' );
638     is( $order->cancellationreason, $reason, 'cancellationreason is set' );
639     is( ref(Koha::Items->find($item->id)), 'Koha::Item', 'The item is present' );
640     is( ref(Koha::Biblios->find($biblio_id)), 'Koha::Biblio', 'The biblio is present' );
641     my @messages = @{ $order->messages };
642     is( $messages[0]->message, 'error_delitem', 'An error message is attached to the order' );
643
644     # Scenario:
645     # * order with one item attached
646     # * the item is no longer on loan
647     # * delete_biblio not passed
648     # => order is cancelled
649     # => item in order is removed
650     # => biblio remains untouched
651
652     C4::Circulation::AddReturn( $item->barcode );
653
654     $order = Koha::Acquisition::Orders->find($order->ordernumber);
655     $order->cancel({ reason => $reason })
656           ->discard_changes;
657
658     is( $order->orderstatus, 'cancelled', 'Order is marked as cancelled' );
659     isnt( $order->datecancellationprinted, undef, 'datecancellationprinted is set' );
660     is( $order->cancellationreason, $reason, 'cancellationreason is undef' );
661     is( Koha::Items->find($item->id), undef, 'The item is no longer present' );
662     is( ref(Koha::Biblios->find($biblio_id)), 'Koha::Biblio', 'The biblio is present' );
663     @messages = @{ $order->messages };
664     is( scalar @messages, 0, 'No messages' );
665
666     # Scenario:
667     # * order with one item attached
668     # * biblio has another item
669     # => order is cancelled
670     # => item in order is removed
671     # => the extra item remains untouched
672     # => biblio remains untouched
673
674     my $item_1 = $builder->build_sample_item;
675     $biblio_id = $item_1->biblionumber;
676     my $item_2 = $builder->build_sample_item({ biblionumber => $biblio_id });
677     $order     = $builder->build_object(
678         {
679             class => 'Koha::Acquisition::Orders',
680             value => {
681                 orderstatus             => 'new',
682                 biblionumber            => $biblio_id,
683                 datecancellationprinted => undef,
684                 cancellationreason      => undef,
685             }
686         }
687     );
688     $order->add_item( $item_1->id );
689
690     $order->cancel({ reason => $reason, delete_biblio => 1 })
691           ->discard_changes;
692
693     is( $order->orderstatus, 'cancelled', 'Order is marked as cancelled' );
694     isnt( $order->datecancellationprinted, undef, 'datecancellationprinted is set' );
695     is( $order->cancellationreason, $reason, 'cancellationreason is undef' );
696     is( Koha::Items->find($item_1->id), undef, 'The item is no longer present' );
697     is( ref(Koha::Items->find($item_2->id)), 'Koha::Item', 'The item is still present' );
698     is( ref(Koha::Biblios->find($biblio_id)), 'Koha::Biblio', 'The biblio is still present' );
699     @messages = @{ $order->messages };
700     is( $messages[0]->message, 'error_delbiblio_items', 'Cannot delete biblio and it gets notified' );
701
702     # Scenario:
703     # * order with one item attached
704     # * there's another order pointing to the biblio
705     # => order is cancelled
706     # => item in order is removed
707     # => biblio remains untouched
708     # => biblio delete error notified
709
710     $item      = $builder->build_sample_item;
711     $biblio_id = $item->biblionumber;
712     $order     = $builder->build_object(
713         {
714             class => 'Koha::Acquisition::Orders',
715             value => {
716                 orderstatus             => 'new',
717                 biblionumber            => $biblio_id,
718                 datecancellationprinted => undef,
719                 cancellationreason      => undef,
720             }
721         }
722     );
723     $order->add_item( $item->id );
724
725     # Add another order
726     $builder->build_object(
727         {
728             class => 'Koha::Acquisition::Orders',
729             value => {
730                 orderstatus             => 'new',
731                 biblionumber            => $biblio_id,
732                 datecancellationprinted => undef,
733                 cancellationreason      => undef,
734             }
735         }
736     );
737
738     $order->cancel({ reason => $reason, delete_biblio => 1 })
739           ->discard_changes;
740
741     is( $order->orderstatus, 'cancelled', 'Order is marked as cancelled' );
742     isnt( $order->datecancellationprinted, undef, 'datecancellationprinted is set' );
743     is( $order->cancellationreason, $reason, 'cancellationreason is undef' );
744     is( Koha::Items->find($item->id), undef, 'The item is no longer present' );
745     is( ref(Koha::Biblios->find($biblio_id)), 'Koha::Biblio', 'The biblio is still present' );
746     @messages = @{ $order->messages };
747     is( $messages[0]->message, 'error_delbiblio_active_orders', 'Cannot delete biblio and it gets notified' );
748
749     # Scenario:
750     # * order with one item attached
751     # * there's a subscription on the biblio
752     # => order is cancelled
753     # => item in order is removed
754     # => biblio remains untouched
755     # => biblio delete error notified
756
757     $item      = $builder->build_sample_item;
758     $biblio_id = $item->biblionumber;
759     $order     = $builder->build_object(
760         {
761             class => 'Koha::Acquisition::Orders',
762             value => {
763                 orderstatus             => 'new',
764                 biblionumber            => $biblio_id,
765                 datecancellationprinted => undef,
766                 cancellationreason      => undef,
767             }
768         }
769     );
770     $order->add_item( $item->id );
771
772     # Add a subscription
773     $builder->build_object(
774         {
775             class => 'Koha::Subscriptions',
776             value => {
777                 biblionumber => $biblio_id,
778             }
779         }
780     );
781
782     $order->cancel({ reason => $reason, delete_biblio => 1 })
783           ->discard_changes;
784
785     is( $order->orderstatus, 'cancelled', 'Order is marked as cancelled' );
786     isnt( $order->datecancellationprinted, undef, 'datecancellationprinted is set' );
787     is( $order->cancellationreason, $reason, 'cancellationreason is undef' );
788     is( Koha::Items->find($item->id), undef, 'The item is no longer present' );
789     is( ref(Koha::Biblios->find($biblio_id)), 'Koha::Biblio', 'The biblio is still present' );
790     @messages = @{ $order->messages };
791     is( $messages[0]->message, 'error_delbiblio_subscriptions', 'Cannot delete biblio and it gets notified' );
792
793     # Scenario:
794     # * order with one item attached
795     # * delete_biblio is passed
796     # => order is cancelled
797     # => item in order is removed
798     # => biblio in order is removed
799
800     $item      = $builder->build_sample_item;
801     $biblio_id = $item->biblionumber;
802     $order     = $builder->build_object(
803         {
804             class => 'Koha::Acquisition::Orders',
805             value => {
806                 orderstatus             => 'new',
807                 biblionumber            => $item->biblionumber,
808                 datecancellationprinted => undef,
809                 cancellationreason      => undef,
810             }
811         }
812     );
813     $order->add_item( $item->id );
814
815     $order->cancel({ reason => $reason, delete_biblio => 1 })
816           ->discard_changes;
817
818     is( $order->orderstatus, 'cancelled', 'Order is not marked as cancelled' );
819     isnt( $order->datecancellationprinted, undef, 'datecancellationprinted is not undef' );
820     is( $order->cancellationreason, $reason, 'cancellationreason is set' );
821     is( Koha::Items->find($item->id), undef, 'The item is not present' );
822     is( Koha::Biblios->find($biblio_id), undef, 'The biblio is not present' );
823     @messages = @{ $order->messages };
824     is( scalar @messages, 0, 'No errors' );
825
826     # Scenario:
827     # * order with two items attached
828     # * one of the items is on loan
829     # => order is cancelled
830     # => item on loan is kept
831     # => the other item is removed
832     # => biblio remains untouched
833     # => biblio delete error notified
834     # => item delete error notified
835
836     $item_1    = $builder->build_sample_item;
837     $item_2    = $builder->build_sample_item({ biblionumber => $item_1->biblionumber });
838     my $item_3 = $builder->build_sample_item({ biblionumber => $item_1->biblionumber });
839     $biblio_id = $item_1->biblionumber;
840     $order     = $builder->build_object(
841         {
842             class => 'Koha::Acquisition::Orders',
843             value => {
844                 orderstatus             => 'new',
845                 biblionumber            => $biblio_id,
846                 datecancellationprinted => undef,
847                 cancellationreason      => undef,
848             }
849         }
850     );
851     $order->add_item( $item_1->id );
852     $order->add_item( $item_2->id );
853     $order->add_item( $item_3->id );
854
855     # Add a checkout so deleting the item fails because od 'book_on_loan'
856     C4::Circulation::AddIssue( $patron->unblessed, $item_2->barcode );
857     C4::Reserves::AddReserve(
858         {
859             branchcode     => $item_3->holdingbranch,
860             borrowernumber => $patron->borrowernumber,
861             biblionumber   => $biblio_id,
862             itemnumber     => $item_3->id,
863             found          => 'W',
864         }
865     );
866
867     $order->cancel({ reason => $reason, delete_biblio => 1 })
868           ->discard_changes;
869
870     is( $order->orderstatus, 'cancelled', 'Order is marked as cancelled' );
871     isnt( $order->datecancellationprinted, undef, 'datecancellationprinted is set' );
872     is( $order->cancellationreason, $reason, 'cancellationreason is undef' );
873     is( Koha::Items->find($item_1->id), undef, 'The item is no longer present' );
874     is( ref(Koha::Items->find($item_2->id)), 'Koha::Item', 'The on loan item is still present' );
875     is( ref(Koha::Biblios->find($biblio_id)), 'Koha::Biblio', 'The biblio is still present' );
876     @messages = @{ $order->messages };
877     is( $messages[0]->message, 'error_delitem', 'Cannot delete on loan item' );
878     is( $messages[0]->payload->{item}->id, $item_2->id, 'Cannot delete on loan item' );
879     is( $messages[0]->payload->{reason}, 'book_on_loan', 'Item on loan notified' );
880     is( $messages[1]->message, 'error_delitem', 'Cannot delete reserved and found item' );
881     is( $messages[1]->payload->{item}->id, $item_3->id, 'Cannot delete reserved and found item' );
882     is( $messages[1]->payload->{reason}, 'book_reserved', 'Item reserved notified' );
883     is( $messages[2]->message, 'error_delbiblio_items', 'Cannot delete on loan item' );
884     is( $messages[2]->payload->{biblio}->id, $biblio_id, 'The right biblio is attached' );
885
886     $schema->storage->txn_rollback;
887 };