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