Bug 23816: Add tests
[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::Item::Transfer;
26 use t::lib::TestBuilder;
27
28 use Test::More tests => 8;
29
30 my $schema = Koha::Database->new->schema;
31
32 use_ok('Koha::StockRotationItems');
33 use_ok('Koha::StockRotationItem');
34
35 my $builder = t::lib::TestBuilder->new;
36
37 subtest 'Basic object tests' => sub {
38
39     plan tests => 5;
40
41     $schema->storage->txn_begin;
42
43     my $itm = $builder->build_sample_item;
44     my $stage = $builder->build({ source => 'Stockrotationstage' });
45
46     my $item = $builder->build({
47         source => 'Stockrotationitem',
48         value  => {
49             itemnumber_id => $itm->itemnumber,
50             stage_id      => $stage->{stage_id},
51         },
52     });
53
54     my $sritem = Koha::StockRotationItems->find($item->{itemnumber_id});
55     isa_ok(
56         $sritem,
57         'Koha::StockRotationItem',
58         "Correctly create and load a stock rotation item."
59     );
60
61     # Relationship to rota
62     isa_ok( $sritem->itemnumber, 'Koha::Item', "Fetched related item." );
63     is( $sritem->itemnumber->itemnumber, $itm->itemnumber, "Related rota OK." );
64
65     # Relationship to stage
66     isa_ok( $sritem->stage, 'Koha::StockRotationStage', "Fetched related stage." );
67     is( $sritem->stage->stage_id, $stage->{stage_id}, "Related stage OK." );
68
69
70     $schema->storage->txn_rollback;
71 };
72
73 subtest 'Tests for needs_repatriating' => sub {
74
75     plan tests => 4;
76
77     $schema->storage->txn_begin;
78
79     # Setup a pristine stockrotation context.
80     my $sritem = $builder->build(
81         {
82             source => 'Stockrotationitem',
83             value =>
84               { itemnumber_id => $builder->build_sample_item->itemnumber }
85         }
86     );
87     my $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
88     $dbitem->itemnumber->homebranch($dbitem->stage->branchcode_id);
89     $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id);
90     $dbitem->stage->position(1);
91
92     my $dbrota = $dbitem->stage->rota;
93     my $newstage = $builder->build({
94         source => 'Stockrotationstage',
95         value => {
96             rota_id => $dbrota->rota_id,
97             position => 2,
98         }
99     });
100
101     # - homebranch == holdingbranch [0]
102     is(
103         $dbitem->needs_repatriating, 0,
104         "Homebranch == Holdingbranch."
105     );
106
107     my $branch = $builder->build({ source => 'Branch' });
108     $dbitem->itemnumber->holdingbranch($branch->{branchcode});
109
110     # - homebranch != holdingbranch [1]
111     is(
112         $dbitem->needs_repatriating, 1,
113         "Homebranch != holdingbranch."
114     );
115
116     # Set to incorrect homebranch.
117     $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id);
118     $dbitem->itemnumber->homebranch($branch->{branchcode});
119     # - homebranch != stockrotationstage.branch & not in transit [1]
120     is(
121         $dbitem->needs_repatriating, 1,
122         "Homebranch != StockRotationStage.Branchcode_id & not in transit."
123     );
124
125     # Set to in transit (by implication).
126     $dbitem->stage($newstage->{stage_id});
127     # - homebranch != stockrotaitonstage.branch & in transit [0]
128     is(
129         $dbitem->needs_repatriating, 1,
130         "homebranch != stockrotaitonstage.branch & in transit."
131     );
132
133     $schema->storage->txn_rollback;
134 };
135
136 subtest "Tests for repatriate." => sub {
137     plan tests => 3;
138     $schema->storage->txn_begin;
139     my $sritem = $builder->build(
140         {
141             source => 'Stockrotationitem',
142             value =>
143               { itemnumber_id => $builder->build_sample_item->itemnumber }
144         }
145     );
146     my $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
147     $dbitem->stage->position(1);
148     $dbitem->stage->duration(50);
149     my $branch = $builder->build({ source => 'Branch' });
150     $dbitem->itemnumber->holdingbranch($branch->{branchcode});
151
152     # Test a straight up repatriate
153     ok($dbitem->repatriate, "Repatriation done.");
154     my $intransfer = $dbitem->itemnumber->get_transfer;
155     is($intransfer->frombranch, $branch->{branchcode}, "Origin correct.");
156     is($intransfer->tobranch, $dbitem->stage->branchcode_id, "Target Correct.");
157
158     $schema->storage->txn_rollback;
159 };
160
161 subtest "Tests for needs_advancing." => sub {
162     plan tests => 6;
163     $schema->storage->txn_begin;
164
165     # Test behaviour of item freshly added to rota.
166     my $sritem = $builder->build(
167         {
168             source => 'Stockrotationitem',
169             value  => {
170                 'fresh'       => 1,
171                 itemnumber_id => $builder->build_sample_item->itemnumber
172             },
173         }
174     );
175     my $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
176     is($dbitem->needs_advancing, 1, "An item that is fresh will always need advancing.");
177
178     # Setup a pristine stockrotation context.
179     $sritem = $builder->build(
180         {
181             source => 'Stockrotationitem',
182             value  => {
183                 'fresh'       => 0,
184                 itemnumber_id => $builder->build_sample_item->itemnumber
185             }
186         }
187     );
188     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
189     $dbitem->itemnumber->homebranch($dbitem->stage->branchcode_id);
190     $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id);
191     $dbitem->stage->position(1);
192     $dbitem->stage->duration(50);
193
194     my $dbtransfer = Koha::Item::Transfer->new({
195         'itemnumber'  => $dbitem->itemnumber_id,
196         'frombranch'  => $dbitem->stage->branchcode_id,
197         'tobranch'    => $dbitem->stage->branchcode_id,
198         'datesent'    => DateTime->now,
199         'datearrived' => undef,
200         'reason'      => "StockrotationAdvance",
201     })->store;
202
203     # Test item will not be advanced if in transit.
204     is($dbitem->needs_advancing, 0, "Not ready to advance: in transfer.");
205     # Test item will not be advanced if in transit even if fresh.
206     $dbitem->fresh(1)->store;
207     is($dbitem->needs_advancing, 0, "Not ready to advance: in transfer (fresh).");
208     $dbitem->fresh(0)->store;
209
210     # Test item will not be advanced if it has not spent enough time.
211     $dbtransfer->datearrived(DateTime->now)->store;
212     is($dbitem->needs_advancing, 0, "Not ready to advance: Not spent enough time.");
213     # Test item will be advanced if it has not spent enough time, but is fresh.
214     $dbitem->fresh(1)->store;
215     is($dbitem->needs_advancing, 1, "Advance: Not spent enough time, but fresh.");
216     $dbitem->fresh(0)->store;
217
218     # Test item will be advanced if it has spent enough time.
219     $dbtransfer->datesent(      # Item was sent 100 days ago...
220         DateTime->now - DateTime::Duration->new( days => 100 )
221     )->store;
222     $dbtransfer->datearrived(   # And arrived 75 days ago.
223         DateTime->now - DateTime::Duration->new( days => 75 )
224     )->store;
225     is($dbitem->needs_advancing, 1, "Ready to be advanced.");
226
227     $schema->storage->txn_rollback;
228 };
229
230 subtest "Tests for advance." => sub {
231     plan tests => 15;
232     $schema->storage->txn_begin;
233
234     my $sritem = $builder->build(
235         {
236             source => 'Stockrotationitem',
237             value  => {
238                 'fresh'       => 1,
239                 itemnumber_id => $builder->build_sample_item->itemnumber
240             }
241         }
242     );
243     my $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
244     $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id);
245     my $dbstage = $dbitem->stage;
246     $dbstage->position(1)->duration(50)->store; # Configure stage.
247     # Configure item
248     $dbitem->itemnumber->holdingbranch($dbstage->branchcode_id)->store;
249     $dbitem->itemnumber->homebranch($dbstage->branchcode_id)->store;
250     # Sanity check
251     is($dbitem->stage->stage_id, $dbstage->stage_id, "Stage sanity check.");
252
253     # Test if an item is fresh, always move to first stage.
254     is($dbitem->fresh, 1, "Fresh is correct.");
255     $dbitem->advance;
256     is($dbitem->stage->stage_id, $dbstage->stage_id, "Stage is first stage after fresh advance.");
257     is($dbitem->fresh, 0, "Fresh reset after advance.");
258
259     # Test cases of single stage
260     $dbstage->rota->cyclical(1)->store;         # Set Rota to cyclical.
261     ok($dbitem->advance, "Single stage cyclical advance done.");
262     ## Refetch dbitem
263     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
264     is($dbitem->stage->stage_id, $dbstage->stage_id, "Single stage cyclical stage OK.");
265
266     # Test with indemand advance
267     $dbitem->indemand(1)->store;
268     ok($dbitem->advance, "Indemand item advance done.");
269     ## Refetch dbitem
270     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
271     is($dbitem->indemand, 0, "Indemand OK.");
272     is($dbitem->stage->stage_id, $dbstage->stage_id, "Indemand item advance stage OK.");
273
274     # Multi stages
275     my $srstage = $builder->build({
276         source => 'Stockrotationstage',
277         value => { duration => 50 }
278     });
279     my $dbstage2 = Koha::StockRotationStages->find($srstage->{stage_id});
280     $dbstage2->move_to_group($dbitem->stage->rota_id);
281     $dbstage2->move_last;
282
283     # Test a straight up advance
284     ok($dbitem->advance, "Advancement done.");
285     ## Refetch dbitem
286     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
287     ## Test results
288     is($dbitem->stage->stage_id, $dbstage2->stage_id, "Stage updated.");
289     my $intransfer = $dbitem->itemnumber->get_transfer;
290     is($intransfer->frombranch, $dbstage->branchcode_id, "Origin correct.");
291     is($intransfer->tobranch, $dbstage2->branchcode_id, "Target Correct.");
292
293     $dbstage->rota->cyclical(0)->store;         # Set Rota to non-cyclical.
294
295     # Arrive at new branch
296     $intransfer->datearrived(DateTime->now)->store;
297     $dbitem->itemnumber->holdingbranch($srstage->{branchcode_id})->store;
298     $dbitem->itemnumber->homebranch($srstage->{branchcode_id})->store;
299
300     # Advance again, Remove from rota.
301     ok($dbitem->advance, "Non-cyclical advance.");
302     ## Refetch dbitem
303     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
304     is($dbitem, undef, "StockRotationItem has been removed.");
305
306     $schema->storage->txn_rollback;
307 };
308
309 subtest "Tests for investigate (singular)." => sub {
310     plan tests => 7;
311     $schema->storage->txn_begin;
312
313     # Test brand new item's investigation ['initiation']
314     my $sritem = $builder->build(
315         {
316             source => 'Stockrotationitem',
317             value  => {
318                 fresh         => 1,
319                 itemnumber_id => $builder->build_sample_item->itemnumber
320             }
321         }
322     );
323     my $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
324     is($dbitem->investigate->{reason}, 'initiation', "fresh item initiates.");
325
326     # Test brand new item at stagebranch ['initiation']
327     $sritem = $builder->build(
328         {
329             source => 'Stockrotationitem',
330             value  => {
331                 fresh         => 1,
332                 itemnumber_id => $builder->build_sample_item->itemnumber
333             }
334         }
335     );
336     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
337     $dbitem->itemnumber->homebranch($dbitem->stage->branchcode_id)->store;
338     $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id)->store;
339     is($dbitem->investigate->{reason}, 'initiation', "fresh item at stagebranch initiates.");
340
341     # Test item not at stagebranch with branchtransfer history ['repatriation']
342     $sritem = $builder->build(
343         {
344             source => 'Stockrotationitem',
345             value  => {
346                 'fresh'       => 0,
347                 itemnumber_id => $builder->build_sample_item->itemnumber
348             }
349         }
350     );
351     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
352     my $dbtransfer = Koha::Item::Transfer->new({
353         'itemnumber'  => $dbitem->itemnumber_id,
354         'frombranch'  => $dbitem->itemnumber->homebranch,
355         'tobranch'    => $dbitem->itemnumber->homebranch,
356         'datesent'    => DateTime->now,
357         'datearrived' => DateTime->now,
358         'reason'      => "StockrotationAdvance",
359     })->store;
360     is($dbitem->investigate->{reason}, 'repatriation', "older item repatriates.");
361
362     # Test item at stagebranch with branchtransfer history ['not-ready']
363     $sritem = $builder->build(
364         {
365             source => 'Stockrotationitem',
366             value  => {
367                 'fresh'       => 0,
368                 itemnumber_id => $builder->build_sample_item->itemnumber
369             }
370         }
371     );
372     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
373     $dbtransfer = Koha::Item::Transfer->new({
374         'itemnumber'  => $dbitem->itemnumber_id,
375         'frombranch'  => $dbitem->itemnumber->homebranch,
376         'tobranch'    => $dbitem->stage->branchcode_id,
377         'datesent'    => DateTime->now,
378         'datearrived' => DateTime->now,
379         'reason'      => "StockrotationAdvance",
380     })->store;
381     $dbitem->itemnumber->homebranch($dbitem->stage->branchcode_id)->store;
382     $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id)->store;
383     is($dbitem->investigate->{reason}, 'not-ready', "older item at stagebranch not-ready.");
384
385     # Test item due for advancement ['advancement']
386     $sritem = $builder->build(
387         {
388             source => 'Stockrotationitem',
389             value  => {
390                 fresh         => 0,
391                 itemnumber_id => $builder->build_sample_item->itemnumber
392             }
393         }
394     );
395     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
396     $dbitem->indemand(0)->store;
397     $dbitem->stage->duration(50)->store;
398     my $sent_duration =  DateTime::Duration->new( days => 55);
399     my $arrived_duration =  DateTime::Duration->new( days => 52);
400     $dbtransfer = Koha::Item::Transfer->new({
401         'itemnumber'  => $dbitem->itemnumber_id,
402         'frombranch'  => $dbitem->itemnumber->homebranch,
403         'tobranch'    => $dbitem->stage->branchcode_id,
404         'datesent'    => DateTime->now - $sent_duration,
405         'datearrived' => DateTime->now - $arrived_duration,
406         'reason'      => "StockrotationAdvance",
407     })->store;
408     $dbitem->itemnumber->homebranch($dbitem->stage->branchcode_id)->store;
409     $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id)->store;
410     is($dbitem->investigate->{reason}, 'advancement',
411        "Item ready for advancement.");
412
413     # Test item due for advancement but in-demand ['in-demand']
414     $sritem = $builder->build(
415         {
416             source => 'Stockrotationitem',
417             value  => {
418                 fresh         => 0,
419                 itemnumber_id => $builder->build_sample_item->itemnumber
420             }
421         }
422     );
423     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
424     $dbitem->indemand(1)->store;
425     $dbitem->stage->duration(50)->store;
426     $sent_duration =  DateTime::Duration->new( days => 55);
427     $arrived_duration =  DateTime::Duration->new( days => 52);
428     $dbtransfer = Koha::Item::Transfer->new({
429         'itemnumber'  => $dbitem->itemnumber_id,
430         'frombranch'  => $dbitem->itemnumber->homebranch,
431         'tobranch'    => $dbitem->stage->branchcode_id,
432         'datesent'    => DateTime->now - $sent_duration,
433         'datearrived' => DateTime->now - $arrived_duration,
434         'reason'      => "StockrotationAdvance",
435     })->store;
436     $dbitem->itemnumber->homebranch($dbitem->stage->branchcode_id)->store;
437     $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id)->store;
438     is($dbitem->investigate->{reason}, 'in-demand',
439        "Item advances, but in-demand.");
440
441     # Test item ready for advancement, but at wrong library ['repatriation']
442     $sritem = $builder->build(
443         {
444             source => 'Stockrotationitem',
445             value  => {
446                 fresh         => 0,
447                 itemnumber_id => $builder->build_sample_item->itemnumber
448             }
449         }
450     );
451     $dbitem = Koha::StockRotationItems->find($sritem->{itemnumber_id});
452     $dbitem->indemand(0)->store;
453     $dbitem->stage->duration(50)->store;
454     $sent_duration =  DateTime::Duration->new( days => 55);
455     $arrived_duration =  DateTime::Duration->new( days => 52);
456     $dbtransfer = Koha::Item::Transfer->new({
457         'itemnumber'  => $dbitem->itemnumber_id,
458         'frombranch'  => $dbitem->itemnumber->homebranch,
459         'tobranch'    => $dbitem->stage->branchcode_id,
460         'datesent'    => DateTime->now - $sent_duration,
461         'datearrived' => DateTime->now - $arrived_duration,
462         'reason'      => "StockrotationAdvance",
463     })->store;
464     is($dbitem->investigate->{reason}, 'repatriation',
465        "Item advances, but not at stage branch.");
466
467     $schema->storage->txn_rollback;
468 };
469
470 1;