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