Bug 29843: Use in batch_anonymise.pl
[koha.git] / t / db_dependent / StockRotationItems.t
1 #!/usr/bin/perl
2
3 # Copyright PTFS Europe 2016
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 DateTime;
23 use DateTime::Duration;
24 use Koha::Database;
25 use Koha::DateUtils qw( dt_from_string );
26 use Koha::Item::Transfer;
27
28 use Test::Warn;
29 use t::lib::TestBuilder;
30 use t::lib::Mocks;
31
32 use Test::More tests => 9;
33
34 my $schema = Koha::Database->new->schema;
35
36 use_ok('Koha::StockRotationItems');
37 use_ok('Koha::StockRotationItem');
38
39 my $builder = t::lib::TestBuilder->new;
40
41 subtest 'Basic object tests' => sub {
42
43     plan tests => 5;
44
45     $schema->storage->txn_begin;
46
47     my $itm = $builder->build_sample_item;
48     my $stage = $builder->build({ source => 'Stockrotationstage' });
49
50     my $item = $builder->build({
51         source => 'Stockrotationitem',
52         value  => {
53             itemnumber_id => $itm->itemnumber,
54             stage_id      => $stage->{stage_id},
55         },
56     });
57
58     my $sritem = Koha::StockRotationItems->find($item->{itemnumber_id});
59     isa_ok(
60         $sritem,
61         'Koha::StockRotationItem',
62         "Correctly create and load a stock rotation item."
63     );
64
65     # Relationship to rota
66     isa_ok( $sritem->item, 'Koha::Item', "Fetched related item." );
67     is( $sritem->item->itemnumber, $itm->itemnumber, "Related rota OK." );
68
69     # Relationship to stage
70     isa_ok( $sritem->stage, 'Koha::StockRotationStage', "Fetched related stage." );
71     is( $sritem->stage->stage_id, $stage->{stage_id}, "Related stage OK." );
72
73
74     $schema->storage->txn_rollback;
75 };
76
77 subtest 'Tests for needs_repatriating' => sub {
78
79     plan tests => 4;
80
81     $schema->storage->txn_begin;
82
83     # Setup a pristine stockrotation context.
84     my $sritem = $builder->build(
85         {
86             source => 'Stockrotationitem',
87             value =>
88               { itemnumber_id => $builder->build_sample_item->itemnumber }
89         }
90     );
91     my $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
92     $dbitem->item->homebranch($dbitem->stage->branchcode_id);
93     $dbitem->item->holdingbranch($dbitem->stage->branchcode_id);
94     $dbitem->stage->position(1);
95
96     my $dbrota = $dbitem->stage->rota;
97     my $newstage = $builder->build({
98         source => 'Stockrotationstage',
99         value => {
100             rota_id => $dbrota->rota_id,
101             position => 2,
102         }
103     });
104
105     # - homebranch == holdingbranch [0]
106     is(
107         $dbitem->needs_repatriating, 0,
108         "Homebranch == Holdingbranch."
109     );
110
111     my $branch = $builder->build({ source => 'Branch' });
112     $dbitem->item->holdingbranch($branch->{branchcode});
113
114     # - homebranch != holdingbranch [1]
115     is(
116         $dbitem->needs_repatriating, 1,
117         "Homebranch != holdingbranch."
118     );
119
120     # Set to incorrect homebranch.
121     $dbitem->item->holdingbranch($dbitem->stage->branchcode_id);
122     $dbitem->item->homebranch($branch->{branchcode});
123     # - homebranch != stockrotationstage.branch & not in transit [1]
124     is(
125         $dbitem->needs_repatriating, 1,
126         "Homebranch != StockRotationStage.Branchcode_id & not in transit."
127     );
128
129     # Set to in transit (by implication).
130     $dbitem->stage($newstage->{stage_id});
131     # - homebranch != stockrotaitonstage.branch & in transit [0]
132     is(
133         $dbitem->needs_repatriating, 1,
134         "homebranch != stockrotaitonstage.branch & in transit."
135     );
136
137     $schema->storage->txn_rollback;
138 };
139
140 subtest "Tests for repatriate." => sub {
141     plan tests => 9;
142     $schema->storage->txn_begin;
143
144     my $sritem_1 = $builder->build_object(
145         {
146             class => 'Koha::StockRotationItems',
147             value  => {
148                 itemnumber_id => $builder->build_sample_item->itemnumber
149             }
150         }
151     );
152     my $item_id = $sritem_1->item->itemnumber;
153     my $srstage_1 = $sritem_1->stage;
154     $sritem_1->discard_changes;
155     $sritem_1->stage->position(1);
156     $sritem_1->stage->duration(50);
157     my $branch = $builder->build({ source => 'Branch' });
158     $sritem_1->item->holdingbranch($branch->{branchcode});
159
160     # Test a straight up repatriate
161     ok($sritem_1->repatriate, "Repatriation done.");
162     my $intransfer = $sritem_1->item->get_transfer;
163     is($intransfer->frombranch, $branch->{branchcode}, "Origin correct.");
164     is($intransfer->tobranch, $sritem_1->stage->branchcode_id, "Target Correct.");
165
166     # Reset
167     $intransfer->datearrived(dt_from_string())->store;
168     $sritem_1->item->holdingbranch($branch->{branchcode});
169
170     # Setup a conflicting manual transfer
171     my $item = Koha::Items->find($item_id);
172     $item->request_transfer({ to => $srstage_1->branchcode, reason => "Manual" });
173     $intransfer = $item->get_transfer;
174     is (ref($intransfer), 'Koha::Item::Transfer', "Conflicting transfer added");
175     is ($intransfer->reason, 'Manual', "Conflicting transfer reason is 'Manual'");
176
177     # Stockrotation should handle transfer clashes
178     is($sritem_1->repatriate, 0, "Repatriation skipped if transfer in progress.");
179
180     # Reset
181     $intransfer->datearrived(dt_from_string())->store;
182     $sritem_1->item->holdingbranch($branch->{branchcode});
183
184     # Confirm that stockrotation ignores transfer limits
185     t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1);
186     t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype');
187     my $limit = Koha::Item::Transfer::Limit->new(
188         {
189             fromBranch => $branch->{branchcode},
190             toBranch   => $srstage_1->branchcode_id,
191             itemtype   => $sritem_1->item->effective_itemtype,
192         }
193     )->store;
194
195     # Stockrotation should overrule transfer limits
196     ok($sritem_1->repatriate, "Repatriation done regardless of transfer limits.");
197     $intransfer = $sritem_1->item->get_transfer;
198     is($intransfer->frombranch, $branch->{branchcode}, "Origin correct.");
199     is($intransfer->tobranch, $sritem_1->stage->branchcode_id, "Target Correct.");
200
201     $schema->storage->txn_rollback;
202 };
203
204 subtest "Tests for needs_advancing." => sub {
205     plan tests => 7;
206     $schema->storage->txn_begin;
207
208     # Test behaviour of item freshly added to rota.
209     my $sritem = $builder->build(
210         {
211             source => 'Stockrotationitem',
212             value  => {
213                 'fresh'       => 1,
214                 itemnumber_id => $builder->build_sample_item->itemnumber
215             },
216         }
217     );
218     my $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
219     is($dbitem->needs_advancing, 1, "An item that is fresh will always need advancing.");
220
221     # Setup a pristine stockrotation context.
222     $sritem = $builder->build(
223         {
224             source => 'Stockrotationitem',
225             value  => {
226                 'fresh'       => 0,
227                 itemnumber_id => $builder->build_sample_item->itemnumber
228             }
229         }
230     );
231     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
232     $dbitem->item->homebranch($dbitem->stage->branchcode_id);
233     $dbitem->item->holdingbranch($dbitem->stage->branchcode_id);
234     $dbitem->stage->position(1);
235     $dbitem->stage->duration(50);
236
237     my $dbtransfer = Koha::Item::Transfer->new({
238         'itemnumber'  => $dbitem->itemnumber_id,
239         'frombranch'  => $dbitem->stage->branchcode_id,
240         'tobranch'    => $dbitem->stage->branchcode_id,
241         'datesent'    => dt_from_string(),
242         'datearrived' => undef,
243         'reason'      => "StockrotationAdvance",
244     })->store;
245
246     # Test item will not be advanced if in transit.
247     is($dbitem->needs_advancing, 0, "Not ready to advance: in transfer.");
248     # Test item will not be advanced if in transit even if fresh.
249     $dbitem->fresh(1)->store;
250     is($dbitem->needs_advancing, 0, "Not ready to advance: in transfer (fresh).");
251     $dbitem->fresh(0)->store;
252
253     # Test item will not be advanced if it has not spent enough time.
254     $dbtransfer->datearrived(dt_from_string())->store;
255     is($dbitem->needs_advancing, 0, "Not ready to advance: Not spent enough time.");
256     # Test item will be advanced if it has not spent enough time, but is fresh.
257     $dbitem->fresh(1)->store;
258     is($dbitem->needs_advancing, 1, "Advance: Not spent enough time, but fresh.");
259     $dbitem->fresh(0)->store;
260
261     # Test item will be advanced if it has spent enough time.
262     $dbtransfer->datesent(      # Item was sent 100 days ago...
263         dt_from_string() - DateTime::Duration->new( days => 100 )
264     )->store;
265     $dbtransfer->datearrived(   # And arrived 75 days ago.
266         dt_from_string() - DateTime::Duration->new( days => 75 )
267     )->store;
268     is($dbitem->needs_advancing, 1, "Ready to be advanced.");
269     $dbtransfer->delete;
270     warning_is {$dbitem->needs_advancing} "We have no historical branch transfer for item " . $dbitem->item->itemnumber . "; This should not have happened!", "Missing transfer is warned.";
271
272     $schema->storage->txn_rollback;
273 };
274
275 subtest "Tests for advance." => sub {
276     plan tests => 48;
277     $schema->storage->txn_begin;
278
279     my $sritem_1 = $builder->build_object(
280         {
281             class => 'Koha::StockRotationItems',
282             value  => {
283                 'fresh'       => 1,
284                 itemnumber_id => $builder->build_sample_item->itemnumber
285             }
286         }
287     );
288     $sritem_1->discard_changes;
289     $sritem_1->item->holdingbranch($sritem_1->stage->branchcode_id);
290     my $item_id = $sritem_1->item->itemnumber;
291     my $srstage_1 = $sritem_1->stage;
292     $srstage_1->position(1)->duration(50)->store; # Configure stage.
293     # Configure item
294     $sritem_1->item->holdingbranch($srstage_1->branchcode_id)->store;
295     $sritem_1->item->homebranch($srstage_1->branchcode_id)->store;
296     # Sanity check
297     is($sritem_1->stage->stage_id, $srstage_1->stage_id, "Stage sanity check.");
298
299     # Test if an item is fresh, always move to first stage.
300     is($sritem_1->fresh, 1, "Fresh is correct.");
301     $sritem_1->advance;
302     is($sritem_1->stage->stage_id, $srstage_1->stage_id, "Stage is first stage after fresh advance.");
303     is($sritem_1->fresh, 0, "Fresh reset after advance.");
304
305     # Test cases of single stage
306     $srstage_1->rota->cyclical(1)->store;         # Set Rota to cyclical.
307     ok($sritem_1->advance, "Single stage cyclical advance done.");
308     ## Refetch sritem_1
309     $sritem_1->discard_changes;
310     is($sritem_1->stage->stage_id, $srstage_1->stage_id, "Single stage cyclical stage OK.");
311
312     # Test with indemand advance
313     $sritem_1->indemand(1)->store;
314     ok($sritem_1->advance, "Indemand item advance done.");
315     ## Refetch sritem_1
316     $sritem_1->discard_changes;
317     is($sritem_1->indemand, 0, "Indemand OK.");
318     is($sritem_1->stage->stage_id, $srstage_1->stage_id, "Indemand item advance stage OK.");
319
320     # Multi stages
321     my $srstage_2 = $builder->build_object({
322         class => 'Koha::StockRotationStages',
323         value => { duration => 50 }
324     });
325     $srstage_2->discard_changes;
326     $srstage_2->move_to_group($sritem_1->stage->rota_id);
327     $srstage_2->move_last;
328
329     # Test a straight up advance
330     ok($sritem_1->advance, "Advancement done.");
331     ## Refetch sritem_1
332     $sritem_1->discard_changes;
333     ## Test results
334     is($sritem_1->stage->stage_id, $srstage_2->stage_id, "Stage updated.");
335     is(
336         $sritem_1->item->homebranch,
337         $srstage_2->branchcode_id,
338         "Item homebranch updated"
339     );
340     my $transfer_request = $sritem_1->item->get_transfer;
341     is($transfer_request->frombranch, $srstage_1->branchcode_id, "Origin correct.");
342     is($transfer_request->tobranch, $srstage_2->branchcode_id, "Target Correct.");
343     is($transfer_request->datesent, undef, "Transfer requested, but not sent.");
344
345     # Arrive at new branch
346     $transfer_request->datearrived(dt_from_string())->store;
347     $sritem_1->item->holdingbranch($srstage_2->branchcode_id)->store;
348
349     # Test a cyclical advance
350     ok($sritem_1->advance, "Cyclical advancement done.");
351     ## Refetch sritem_1
352     $sritem_1->discard_changes;
353     ## Test results
354     is($sritem_1->stage->stage_id, $srstage_1->stage_id, "Stage updated.");
355     is(
356         $sritem_1->item->homebranch,
357         $srstage_1->branchcode_id,
358         "Item homebranch updated"
359     );
360     $transfer_request = $sritem_1->item->get_transfer;
361     is($transfer_request->frombranch, $srstage_2->branchcode_id, "Origin correct.");
362     is($transfer_request->tobranch, $srstage_1->branchcode_id, "Target correct.");
363
364     # Arrive at new branch
365     $transfer_request->datearrived(dt_from_string())->store;
366     $sritem_1->item->holdingbranch($srstage_1->branchcode_id)->store;
367
368     # Confirm that stockrotation ignores transfer limits
369     t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1);
370     t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype');
371     my $limit = Koha::Item::Transfer::Limit->new(
372         {
373             fromBranch => $srstage_1->branchcode_id,
374             toBranch   => $srstage_2->branchcode_id,
375             itemtype   => $sritem_1->item->effective_itemtype,
376         }
377     )->store;
378
379     ok($sritem_1->advance, "Advancement overrules transfer limits.");
380     ## Refetch sritem_1
381     $sritem_1->discard_changes;
382     ## Test results
383     is($sritem_1->stage->stage_id, $srstage_2->stage_id, "Stage updated ignoring transfer limits.");
384     is(
385         $sritem_1->item->homebranch,
386         $srstage_2->branchcode_id,
387         "Item homebranch updated ignoring transfer limits"
388     );
389     $transfer_request = $sritem_1->item->get_transfer;
390     is($transfer_request->frombranch, $srstage_1->branchcode_id, "Origin correct ignoring transfer limits.");
391     is($transfer_request->tobranch, $srstage_2->branchcode_id, "Target correct ignoring transfer limits.");
392
393     # Arrive at new branch
394     $transfer_request->datearrived(dt_from_string())->store;
395     $sritem_1->item->holdingbranch($srstage_2->branchcode_id)->store;
396
397     # Setup a conflicting manual transfer
398     my $item = Koha::Items->find($item_id);
399     $item->request_transfer({ to => $srstage_1->branchcode, reason => "Manual" });
400     $transfer_request = $item->get_transfer;
401     is (ref($transfer_request), 'Koha::Item::Transfer', "Conflicting transfer added");
402     is ($transfer_request->reason, 'Manual', "Conflicting transfer reason is 'Manual'");
403
404     # Advance item whilst conflicting manual transfer exists
405     ok($sritem_1->advance, "Advancement done.");
406     ## Refetch sritem_1
407     $sritem_1->discard_changes;
408
409     ## Refetch conflicted transfer
410     $transfer_request->discard_changes;
411
412     # Conflicted transfer should have been cancelled
413     isnt($transfer_request->datecancelled, undef, "Conflicting manual transfer was cancelled");
414
415     # StockRotationAdvance transfer added
416     $transfer_request = $sritem_1->item->get_transfer;
417     is($transfer_request->reason, 'StockrotationAdvance', "StockrotationAdvance transfer added");
418     is($transfer_request->frombranch, $srstage_2->branchcode_id, "Origin correct.");
419     is($transfer_request->tobranch, $srstage_1->branchcode_id, "Target correct.");
420
421     # Arrive at new branch
422     $transfer_request->datearrived(dt_from_string())->store;
423     $sritem_1->item->holdingbranch($srstage_1->branchcode_id)->store;
424
425     # Setup a conflicting reserve transfer
426     $item->request_transfer({ to => $srstage_2->branchcode, reason => "Reserve" });
427     $transfer_request = $item->get_transfer;
428     is (ref($transfer_request), 'Koha::Item::Transfer', "Conflicting transfer added");
429     is ($transfer_request->reason, 'Reserve', "Conflicting transfer reason is 'Reserve'");
430
431     # Advance item whilst conflicting reserve transfer exists
432     ok($sritem_1->advance, "Advancement done.");
433     ## Refetch sritem_1
434     $sritem_1->discard_changes;
435
436     ## Refetch conflicted transfer
437     $transfer_request->discard_changes;
438
439     # Conflicted transfer should not been cancelled
440     is($transfer_request->datecancelled, undef, "Conflicting reserve transfer was not cancelled");
441
442     # StockRotationAdvance transfer added
443     my $transfer_requests = Koha::Item::Transfers->search(
444         {
445             itemnumber    => $sritem_1->item->itemnumber,
446             datearrived   => undef,
447             datecancelled => undef
448         }
449     );
450     is($transfer_requests->count, '2', "StockrotationAdvance transfer queued");
451
452     # Arrive at new branch
453     $transfer_request->datearrived(dt_from_string())->store;
454     $sritem_1->item->holdingbranch($srstage_2->branchcode_id)->store;
455
456     # StockRotationAdvance transfer added
457     $transfer_request = $sritem_1->item->get_transfer;
458     is($transfer_request->reason, 'StockrotationAdvance', "StockrotationAdvance transfer remains after reserve is met");
459     is($transfer_request->frombranch, $srstage_1->branchcode_id, "Origin correct.");
460     is($transfer_request->tobranch, $srstage_2->branchcode_id, "Target correct.");
461
462     # Arrive at new branch
463     $transfer_request->datearrived(dt_from_string())->store;
464     $sritem_1->item->holdingbranch($srstage_2->branchcode_id)->store;
465
466     # Checked out item, advanced to next stage, checkedout from next stage
467     # transfer should be generated, but not initiated
468     my $issue = $builder->build_object({
469         class => 'Koha::Checkouts',
470         value => {
471              branchcode => $srstage_1->branchcode_id,
472              itemnumber => $sritem_1->item->itemnumber,
473              returndate => undef
474         }
475     });
476     $sritem_1->item->holdingbranch($srstage_1->branchcode_id)->store;
477     ok($sritem_1->advance, "Advancement done.");
478     $transfer_request = $sritem_1->item->get_transfer;
479     is($transfer_request->frombranch, $srstage_1->branchcode_id, "Origin correct.");
480     is($transfer_request->tobranch, $srstage_1->branchcode_id, "Target correct.");
481     is($transfer_request->datesent, undef, "Transfer waiting to initiate until return.");
482
483     $issue->delete; #remove issue
484     $sritem_1->advance; #advance back to second stage
485     # Set arrived
486     $transfer_request->datearrived(dt_from_string())->store;
487     $sritem_1->item->holdingbranch($srstage_2->branchcode_id)->store;
488
489
490     $srstage_1->rota->cyclical(0)->store;         # Set Rota to non-cyclical.
491
492     my $srstage_3 = $builder->build_object({
493         class => 'Koha::StockRotationStages',
494         value => { duration => 50 }
495     });
496     $srstage_3->discard_changes;
497     $srstage_3->move_to_group($sritem_1->stage->rota_id);
498     $srstage_3->move_last;
499
500     # Advance again, to end of rota.
501     ok($sritem_1->advance, "Non-cyclical advance to last stage.");
502
503     # Arrive at new branch
504     $transfer_request->datearrived(dt_from_string())->store;
505     $sritem_1->item->holdingbranch($srstage_3->branchcode_id)->store;
506
507     # Advance again, Remove from rota.
508     ok($sritem_1->advance, "Non-cyclical advance.");
509     ## Refetch sritem_1
510     $sritem_1 = Koha::StockRotationItems->find({ itemnumber_id => $item_id });
511     is($sritem_1, undef, "StockRotationItem has been removed.");
512     $item = Koha::Items->find($item_id);
513     is($item->homebranch, $srstage_3->branchcode_id, "Item homebranch remains");
514
515     $schema->storage->txn_rollback;
516 };
517
518 subtest "Tests for investigate (singular)." => sub {
519     plan tests => 7;
520     $schema->storage->txn_begin;
521
522     # Test brand new item's investigation ['initiation']
523     my $sritem = $builder->build(
524         {
525             source => 'Stockrotationitem',
526             value  => {
527                 fresh         => 1,
528                 itemnumber_id => $builder->build_sample_item->itemnumber
529             }
530         }
531     );
532     my $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
533     is($dbitem->investigate->{reason}, 'initiation', "fresh item initiates.");
534
535     # Test brand new item at stagebranch ['initiation']
536     $sritem = $builder->build(
537         {
538             source => 'Stockrotationitem',
539             value  => {
540                 fresh         => 1,
541                 itemnumber_id => $builder->build_sample_item->itemnumber
542             }
543         }
544     );
545     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
546     $dbitem->item->homebranch($dbitem->stage->branchcode_id)->store;
547     $dbitem->item->holdingbranch($dbitem->stage->branchcode_id)->store;
548     is($dbitem->investigate->{reason}, 'initiation', "fresh item at stagebranch initiates.");
549
550     # Test item not at stagebranch with branchtransfer history ['repatriation']
551     $sritem = $builder->build(
552         {
553             source => 'Stockrotationitem',
554             value  => {
555                 'fresh'       => 0,
556                 itemnumber_id => $builder->build_sample_item->itemnumber
557             }
558         }
559     );
560     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
561     my $dbtransfer = Koha::Item::Transfer->new({
562         'itemnumber'  => $dbitem->itemnumber_id,
563         'frombranch'  => $dbitem->item->homebranch,
564         'tobranch'    => $dbitem->item->homebranch,
565         'datesent'    => dt_from_string(),
566         'datearrived' => dt_from_string(),
567         'reason'      => "StockrotationAdvance",
568     })->store;
569     is($dbitem->investigate->{reason}, 'repatriation', "older item repatriates.");
570
571     # Test item at stagebranch with branchtransfer history ['not-ready']
572     $sritem = $builder->build(
573         {
574             source => 'Stockrotationitem',
575             value  => {
576                 'fresh'       => 0,
577                 itemnumber_id => $builder->build_sample_item->itemnumber
578             }
579         }
580     );
581     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
582     $dbtransfer = Koha::Item::Transfer->new({
583         'itemnumber'  => $dbitem->itemnumber_id,
584         'frombranch'  => $dbitem->item->homebranch,
585         'tobranch'    => $dbitem->stage->branchcode_id,
586         'datesent'    => dt_from_string(),
587         'datearrived' => dt_from_string(),
588         'reason'      => "StockrotationAdvance",
589     })->store;
590     $dbitem->item->homebranch($dbitem->stage->branchcode_id)->store;
591     $dbitem->item->holdingbranch($dbitem->stage->branchcode_id)->store;
592     is($dbitem->investigate->{reason}, 'not-ready', "older item at stagebranch not-ready.");
593
594     # Test item due for advancement ['advancement']
595     $sritem = $builder->build(
596         {
597             source => 'Stockrotationitem',
598             value  => {
599                 fresh         => 0,
600                 itemnumber_id => $builder->build_sample_item->itemnumber
601             }
602         }
603     );
604     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
605     $dbitem->indemand(0)->store;
606     $dbitem->stage->duration(50)->store;
607     my $sent_duration =  DateTime::Duration->new( days => 55);
608     my $arrived_duration =  DateTime::Duration->new( days => 52);
609     $dbtransfer = Koha::Item::Transfer->new({
610         'itemnumber'  => $dbitem->itemnumber_id,
611         'frombranch'  => $dbitem->item->homebranch,
612         'tobranch'    => $dbitem->stage->branchcode_id,
613         'datesent'    => dt_from_string() - $sent_duration,
614         'datearrived' => dt_from_string() - $arrived_duration,
615         'reason'      => "StockrotationAdvance",
616     })->store;
617     $dbitem->item->homebranch($dbitem->stage->branchcode_id)->store;
618     $dbitem->item->holdingbranch($dbitem->stage->branchcode_id)->store;
619     is($dbitem->investigate->{reason}, 'advancement',
620        "Item ready for advancement.");
621
622     # Test item due for advancement but in-demand ['in-demand']
623     $sritem = $builder->build(
624         {
625             source => 'Stockrotationitem',
626             value  => {
627                 fresh         => 0,
628                 itemnumber_id => $builder->build_sample_item->itemnumber
629             }
630         }
631     );
632     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
633     $dbitem->indemand(1)->store;
634     $dbitem->stage->duration(50)->store;
635     $sent_duration =  DateTime::Duration->new( days => 55);
636     $arrived_duration =  DateTime::Duration->new( days => 52);
637     $dbtransfer = Koha::Item::Transfer->new({
638         'itemnumber'  => $dbitem->itemnumber_id,
639         'frombranch'  => $dbitem->item->homebranch,
640         'tobranch'    => $dbitem->stage->branchcode_id,
641         'datesent'    => dt_from_string() - $sent_duration,
642         'datearrived' => dt_from_string() - $arrived_duration,
643         'reason'      => "StockrotationAdvance",
644     })->store;
645     $dbitem->item->homebranch($dbitem->stage->branchcode_id)->store;
646     $dbitem->item->holdingbranch($dbitem->stage->branchcode_id)->store;
647     is($dbitem->investigate->{reason}, 'in-demand',
648        "Item advances, but in-demand.");
649
650     # Test item ready for advancement, but at wrong library ['repatriation']
651     $sritem = $builder->build(
652         {
653             source => 'Stockrotationitem',
654             value  => {
655                 fresh         => 0,
656                 itemnumber_id => $builder->build_sample_item->itemnumber
657             }
658         }
659     );
660     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
661     $dbitem->indemand(0)->store;
662     $dbitem->stage->duration(50)->store;
663     $sent_duration =  DateTime::Duration->new( days => 55);
664     $arrived_duration =  DateTime::Duration->new( days => 52);
665     $dbtransfer = Koha::Item::Transfer->new({
666         'itemnumber'  => $dbitem->itemnumber_id,
667         'frombranch'  => $dbitem->item->homebranch,
668         'tobranch'    => $dbitem->stage->branchcode_id,
669         'datesent'    => dt_from_string() - $sent_duration,
670         'datearrived' => dt_from_string() - $arrived_duration,
671         'reason'      => "StockrotationAdvance",
672     })->store;
673     is($dbitem->investigate->{reason}, 'repatriation',
674        "Item advances, but not at stage branch.");
675
676     $schema->storage->txn_rollback;
677 };
678
679 subtest "Tests for toggle_indemand" => sub {
680     plan tests => 15;
681     $schema->storage->txn_begin;
682
683     my $sritem = $builder->build({
684         source => 'Stockrotationitem',
685         value => { 'fresh' => 0, 'indemand' => 0 }
686     });
687     my $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
688     my $firstbranch = $dbitem->stage->branchcode_id;
689     $dbitem->item->holdingbranch($firstbranch)->store;
690     my $dbstage = $dbitem->stage;
691     $dbstage->position(1)->duration(50)->store; # Configure stage.
692     # Configure item
693     $dbitem->item->holdingbranch($firstbranch)->store;
694     $dbitem->item->homebranch($firstbranch)->store;
695     # Sanity check
696     is($dbitem->stage->stage_id, $dbstage->stage_id, "Stage sanity check.");
697
698     # Test if an item is not in transfer, toggle always acts.
699     is($dbitem->indemand, 0, "Item not in transfer starts with indemand disabled.");
700     $dbitem->toggle_indemand;
701     is($dbitem->indemand, 1, "Item not in transfer toggled correctly first time.");
702     $dbitem->toggle_indemand;
703     is($dbitem->indemand, 0, "Item not in transfer toggled correctly second time.");
704
705     # Add stages
706     my $srstage = $builder->build({
707         source => 'Stockrotationstage',
708         value => { duration => 50 }
709     });
710     my $dbstage2 = Koha::StockRotationStages->find($srstage->{stage_id});
711     $dbstage2->move_to_group($dbitem->stage->rota_id);
712     $dbstage2->position(2)->store;
713     my $secondbranch = $dbstage2->branchcode_id;
714
715     # Test an item in transfer, toggle cancels transfer and resets indemand.
716     ok($dbitem->advance, "Advancement done.");
717     $dbitem->get_from_storage;
718     my $transfer = $dbitem->item->get_transfer;
719     is(ref($transfer), 'Koha::Item::Transfer', 'Item set to in transfer as expected');
720     is($transfer->frombranch, $firstbranch, 'Transfer from set correctly');
721     is($transfer->tobranch, $secondbranch, 'Transfer to set correctly');
722     is($transfer->datearrived, undef, 'Transfer datearrived not set');
723     $dbitem->toggle_indemand;
724     my $updated_transfer = $transfer->get_from_storage;
725     is($updated_transfer->frombranch, $firstbranch, 'Transfer from retained correctly');
726     is($updated_transfer->tobranch, $firstbranch, 'Transfer to updated correctly');
727     isnt($updated_transfer->datearrived, undef, 'Transfer datearrived set as expected');
728     is($dbitem->indemand, 0, "Item retains indemand as expected.");
729     is($dbitem->stage_id, $dbstage->id, 'Item stage reset as expected.');
730     is($dbitem->item->homebranch, $firstbranch, 'Item homebranch reset as expected.');
731
732     $schema->storage->txn_rollback;
733 };
734
735 1;