Bug 31147: Recalls should not adjust due time for related checkouts
[koha.git] / t / db_dependent / Koha / Recalls.t
1 #!/usr/bin/perl
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20 use Test::More tests => 20;
21 use t::lib::Dates;
22 use t::lib::TestBuilder;
23 use t::lib::Mocks;
24
25 use Koha::DateUtils qw( dt_from_string );
26
27 BEGIN {
28     require_ok('Koha::Recall');
29     require_ok('Koha::Recalls');
30 }
31
32 # Start transaction
33
34 my $database = Koha::Database->new();
35 my $schema = $database->schema();
36 $schema->storage->txn_begin();
37 my $dbh = C4::Context->dbh;
38
39 my $builder = t::lib::TestBuilder->new;
40
41 # Setup test variables
42
43 my $item1 = $builder->build_sample_item();
44 my $biblio1 = $item1->biblio;
45 my $branch1 = $item1->holdingbranch;
46 my $itemtype1 = $item1->effective_itemtype;
47 my $item2 = $builder->build_sample_item({ biblionumber => $biblio1->biblionumber });
48 my $biblio2 = $item1->biblio;
49 my $branch2 = $item1->holdingbranch;
50 my $itemtype2 = $item1->effective_itemtype;
51
52 my $category1 = $builder->build({ source => 'Category' })->{ categorycode };
53 my $patron1 = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category1, branchcode => $branch1 } });
54 my $patron2 = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category1, branchcode => $branch2 } });
55 my $patron3 = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $category1, branchcode => $branch1 } });
56 t::lib::Mocks::mock_userenv({ patron => $patron1 });
57
58 Koha::CirculationRules->set_rules({
59     branchcode => undef,
60     categorycode => undef,
61     itemtype => undef,
62     rules => {
63         'recall_due_date_interval' => undef,
64         'recalls_allowed' => 10,
65     }
66 });
67
68 C4::Circulation::AddIssue( $patron3->unblessed, $item1->barcode );
69 C4::Circulation::AddIssue( $patron3->unblessed, $item2->barcode );
70
71 my ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall({
72     patron => undef,
73     biblio => $biblio1,
74     branchcode => $branch1,
75     item => $item1,
76     expirationdate => undef,
77     interface => 'COMMANDLINE',
78 });
79 ok( !defined $recall, "Can't add a recall without specifying a patron" );
80
81 ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall({
82     patron => $patron1,
83     biblio => undef,
84     branchcode => $branch1,
85     item => $item1,
86     expirationdate => undef,
87     interface => 'COMMANDLINE',
88 });
89 ok( !defined $recall, "Can't add a recall without specifying a biblio" );
90
91 ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall({
92     patron => $patron1,
93     biblio => undef,
94     branchcode => $branch1,
95     item => $item1,
96     expirationdate => undef,
97     interface => 'COMMANDLINE',
98 });
99 ok( !defined $recall, "Can't add a recall without specifying a biblio" );
100
101 ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall({
102     patron => $patron2,
103     biblio => $biblio1,
104     branchcode => undef,
105     item => $item2,
106     expirationdate => undef,
107     interface => 'COMMANDLINE',
108 });
109 is( $recall->pickup_library_id, $branch2, "No pickup branch specified so patron branch used" );
110 is( $due_interval, 5, "Recall due date interval defaults to 5 if not specified" );
111
112 Koha::CirculationRules->set_rule({
113     branchcode => undef,
114     categorycode => undef,
115     itemtype => undef,
116     rule_name => 'recall_due_date_interval',
117     rule_value => 3,
118 });
119 ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall({
120     patron => $patron1,
121     biblio => $biblio1,
122     branchcode => undef,
123     item => $item1,
124     expirationdate => undef,
125     interface => 'COMMANDLINE',
126 });
127 is( $due_interval, 3, "Recall due date interval is based on circulation rules" );
128
129 ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall({
130     patron => $patron1,
131     biblio => $biblio1,
132     branchcode => $branch1,
133     item => undef,
134     expirationdate => undef,
135     interface => 'COMMANDLINE',
136 });
137 is( $recall->item_level, 0, "No item provided so recall not flagged as item-level" );
138
139 my $checkout_timestamp = dt_from_string( $recall->checkout->date_due );
140 my $expected_due_date  = dt_from_string->set(
141     { hour => $checkout_timestamp->hour, minute => $checkout_timestamp->minute, second => $checkout_timestamp->second }
142 )->add( days => 3 );
143 is(
144     t::lib::Dates::compare( $recall->checkout->date_due, $expected_due_date ), 0,
145     "Checkout due date has correctly been extended by recall_due_date_interval days"
146 );
147 is( t::lib::Dates::compare( $due_date, $expected_due_date ), 0, "Due date correctly returned" );
148
149 my $messages_count = Koha::Notice::Messages->search({ borrowernumber => $patron3->borrowernumber, letter_code => 'RETURN_RECALLED_ITEM' })->count;
150 is( $messages_count, 3, "RETURN_RECALLED_ITEM notice successfully sent to checkout borrower" );
151
152 my $message = Koha::Recalls->move_recall;
153 is( $message, 'no recall_id provided', "Can't move a recall without specifying which recall" );
154
155 $message = Koha::Recalls->move_recall({ recall_id => $recall->recall_id });
156 is( $message, 'no action provided', "No clear action to perform on recall" );
157 $message = Koha::Recalls->move_recall({ recall_id => $recall->recall_id, action => 'whatever' });
158 is( $message, 'no action provided', "Legal action not provided to perform on recall" );
159
160 $recall->set_waiting({ item => $item1 });
161 ok( $recall->waiting, "Recall is waiting" );
162 Koha::Recalls->move_recall({ recall_id => $recall->recall_id, action => 'revert' });
163 $recall = Koha::Recalls->find( $recall->recall_id );
164 ok( $recall->requested, "Recall reverted to requested with move_recall" );
165
166 Koha::Recalls->move_recall({ recall_id => $recall->recall_id, action => 'cancel' });
167 $recall = Koha::Recalls->find( $recall->recall_id );
168 ok( $recall->cancelled, "Recall cancelled with move_recall" );
169
170 ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall({
171     patron => $patron1,
172     biblio => $biblio1,
173     branchcode => $branch1,
174     item => $item2,
175     expirationdate => undef,
176     interface => 'COMMANDLINE',
177 });
178 $message = Koha::Recalls->move_recall({ recall_id => $recall->recall_id, item => $item2, borrowernumber => $patron1->borrowernumber });
179 $recall = Koha::Recalls->find( $recall->recall_id );
180 ok( $recall->fulfilled, "Recall fulfilled with move_recall" );
181
182 $schema->storage->txn_rollback();
183
184 subtest 'filter_by_current() and filter_by_finished() tests' => sub {
185
186     plan tests => 10;
187
188     $schema->storage->txn_begin;
189
190     my $in_transit = $builder->build_object( { class => 'Koha::Recalls', value => { status => 'in_transit' } } );
191     my $overdue    = $builder->build_object( { class => 'Koha::Recalls', value => { status => 'overdue' } } );
192     my $requested  = $builder->build_object( { class => 'Koha::Recalls', value => { status => 'requested' } } );
193     my $waiting    = $builder->build_object( { class => 'Koha::Recalls', value => { status => 'waiting' } } );
194     my $cancelled  = $builder->build_object( { class => 'Koha::Recalls', value => { status => 'cancelled' } } );
195     my $expired    = $builder->build_object( { class => 'Koha::Recalls', value => { status => 'expired' } } );
196     my $fulfilled  = $builder->build_object( { class => 'Koha::Recalls', value => { status => 'fulfilled' } } );
197
198     my $recalls = Koha::Recalls->search(
199         {
200             recall_id => [
201                 $in_transit->id,
202                 $overdue->id,
203                 $requested->id,
204                 $waiting->id,
205                 $cancelled->id,
206                 $expired->id,
207                 $fulfilled->id,
208             ]
209         },
210         { order_by => [ 'recall_id' ] }
211     );
212
213     is( $recalls->count, 7, 'Resultset count is correct' );
214
215     my $current_recalls = $recalls->filter_by_current;
216     is( $current_recalls->count, 4, 'Current recalls count correct' );
217
218     is( $current_recalls->next->status, 'in_transit', 'Resultset correctly includes in_transit recall');
219     is( $current_recalls->next->status, 'overdue', 'Resultset correctly includes overdue recall');
220     is( $current_recalls->next->status, 'requested', 'Resultset correctly includes requested recall');
221     is( $current_recalls->next->status, 'waiting', 'Resultset correctly includes waiting recall');
222
223     my $finished_recalls = $recalls->filter_by_finished;
224     is( $finished_recalls->count, 3, 'Finished recalls count correct' );
225
226     is( $finished_recalls->next->status, 'cancelled', 'Resultset correctly includes cancelled recall');
227     is( $finished_recalls->next->status, 'expired', 'Resultset correctly includes expired recall');
228     is( $finished_recalls->next->status, 'fulfilled', 'Resultset correctly includes fulfilled recall');
229
230     $schema->storage->txn_rollback;
231 };