Bug 18936: Convert issuingrules fields to circulation_rules
[koha.git] / t / db_dependent / Reserves / MultiplePerRecord.t
1 #!/usr/bin/perl
2
3 # Copyright 2016 ByWater Solutions
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 Test::More tests => 39;
23 use t::lib::TestBuilder;
24 use t::lib::Mocks;
25
26 use C4::Reserves qw( GetMaxPatronHoldsForRecord AddReserve CanBookBeReserved );
27 use Koha::Database;
28 use Koha::Holds;
29
30 my $schema = Koha::Database->new->schema;
31 $schema->storage->txn_begin;
32
33 my $builder = t::lib::TestBuilder->new();
34 my $library = $builder->build(
35     {
36         source => 'Branch',
37     }
38 );
39
40 my $category = $builder->build(
41     {
42         source => 'Category',
43     }
44 );
45 my $patron = $builder->build(
46     {
47         source => 'Borrower',
48         value  => {
49             categorycode => $category->{categorycode},
50             branchcode   => $library->{branchcode},
51         },
52     }
53 );
54
55 my $itemtype1 = $builder->build(
56     {
57         source => 'Itemtype'
58     }
59 );
60
61 my $itemtype2 = $builder->build(
62     {
63         source => 'Itemtype'
64     }
65 );
66
67 my $biblio = $builder->build(
68     {
69         source => 'Biblio',
70         value  => {
71             title => 'Title 1',
72         },
73     }
74 );
75 my $biblioitem = $builder->build(
76     {
77         source => 'Biblioitem',
78         value  => { biblionumber => $biblio->{biblionumber} }
79     }
80 );
81 my $item1 = $builder->build(
82     {
83         source => 'Item',
84         value  => {
85             biblionumber  => $biblio->{biblionumber},
86             itype         => $itemtype1->{itemtype},
87             homebranch    => $library->{branchcode},
88             holdingbranch => $library->{branchcode},
89             damaged       => 0,
90         },
91     }
92 );
93 my $item2 = $builder->build(
94     {
95         source => 'Item',
96         value  => {
97             biblionumber  => $biblio->{biblionumber},
98             itype         => $itemtype2->{itemtype},
99             homebranch    => $library->{branchcode},
100             holdingbranch => $library->{branchcode},
101             damaged       => 0,
102         },
103     }
104 );
105 my $item3 = $builder->build(
106     {
107         source => 'Item',
108         value  => {
109             biblionumber  => $biblio->{biblionumber},
110             itype         => $itemtype2->{itemtype},
111             homebranch    => $library->{branchcode},
112             holdingbranch => $library->{branchcode},
113             damaged       => 0,
114         },
115     }
116 );
117
118 Koha::CirculationRules->delete();
119
120 # Test GetMaxPatronHoldsForRecord and GetHoldRule
121 Koha::CirculationRules->set_rules(
122     {
123         categorycode => '*',
124         itemtype     => '*',
125         branchcode   => '*',
126         rules        => {
127             reservesallowed  => 1,
128             holds_per_record => 1,
129         }
130     }
131 );
132
133 t::lib::Mocks::mock_preference('item-level_itypes', 1); # Assuming the item type is defined at item level
134
135 my $max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
136 is( $max, 1, 'GetMaxPatronHoldsForRecord returns max of 1' );
137 my $rule = C4::Reserves::GetHoldRule(
138     $category->{categorycode},
139     $itemtype1->{itemtype},
140     $library->{branchcode}
141 );
142 is( $rule->{categorycode},     '*', 'Got rule with universal categorycode' );
143 is( $rule->{itemtype},         '*', 'Got rule with universal itemtype' );
144 is( $rule->{branchcode},       '*', 'Got rule with universal branchcode' );
145 is( $rule->{reservesallowed},  1,   'Got reservesallowed of 1' );
146 is( $rule->{holds_per_record}, 1,   'Got holds_per_record of 1' );
147
148 Koha::CirculationRules->set_rules(
149     {
150         categorycode => $category->{categorycode},
151         itemtype     => '*',
152         branchcode   => '*',
153         rules        => {
154             reservesallowed  => 2,
155             holds_per_record => 2,
156         }
157     }
158 );
159
160 $max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
161 is( $max, 2, 'GetMaxPatronHoldsForRecord returns max of 2' );
162 $rule = C4::Reserves::GetHoldRule(
163     $category->{categorycode},
164     $itemtype1->{itemtype},
165     $library->{branchcode}
166 );
167 is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
168 is( $rule->{itemtype},         '*',                       'Got rule with universal itemtype' );
169 is( $rule->{branchcode},       '*',                       'Got rule with universal branchcode' );
170 is( $rule->{reservesallowed},  2,                         'Got reservesallowed of 2' );
171 is( $rule->{holds_per_record}, 2,                         'Got holds_per_record of 2' );
172
173 Koha::CirculationRules->set_rules(
174     {
175         categorycode => $category->{categorycode},
176         itemtype     => $itemtype1->{itemtype},
177         branchcode   => '*',
178         rules        => {
179             reservesallowed  => 3,
180             holds_per_record => 3,
181         }
182     }
183 );
184
185 $max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
186 is( $max, 3, 'GetMaxPatronHoldsForRecord returns max of 3' );
187 $rule = C4::Reserves::GetHoldRule(
188     $category->{categorycode},
189     $itemtype1->{itemtype},
190     $library->{branchcode}
191 );
192 is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
193 is( $rule->{itemtype},         $itemtype1->{itemtype},    'Got rule with universal itemtype' );
194 is( $rule->{branchcode},       '*',                       'Got rule with universal branchcode' );
195 is( $rule->{reservesallowed},  3,                         'Got reservesallowed of 3' );
196 is( $rule->{holds_per_record}, 3,                         'Got holds_per_record of 3' );
197
198 Koha::CirculationRules->set_rules(
199     {
200         categorycode => $category->{categorycode},
201         itemtype     => $itemtype2->{itemtype},
202         branchcode   => '*',
203         rules        => {
204             reservesallowed  => 4,
205             holds_per_record => 4,
206         }
207     }
208 );
209
210 $max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
211 is( $max, 4, 'GetMaxPatronHoldsForRecord returns max of 4' );
212 $rule = C4::Reserves::GetHoldRule(
213     $category->{categorycode},
214     $itemtype2->{itemtype},
215     $library->{branchcode}
216 );
217 is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
218 is( $rule->{itemtype},         $itemtype2->{itemtype},    'Got rule with universal itemtype' );
219 is( $rule->{branchcode},       '*',                       'Got rule with universal branchcode' );
220 is( $rule->{reservesallowed},  4,                         'Got reservesallowed of 4' );
221 is( $rule->{holds_per_record}, 4,                         'Got holds_per_record of 4' );
222
223 Koha::CirculationRules->set_rules(
224     {
225         categorycode => $category->{categorycode},
226         itemtype     => $itemtype2->{itemtype},
227         branchcode   => $library->{branchcode},
228         rules        => {
229             reservesallowed  => 5,
230             holds_per_record => 5,
231         }
232     }
233 );
234
235 $max = GetMaxPatronHoldsForRecord( $patron->{borrowernumber}, $biblio->{biblionumber} );
236 is( $max, 5, 'GetMaxPatronHoldsForRecord returns max of 1' );
237 $rule = C4::Reserves::GetHoldRule(
238     $category->{categorycode},
239     $itemtype2->{itemtype},
240     $library->{branchcode}
241 );
242 is( $rule->{categorycode},     $category->{categorycode}, 'Got rule with specific categorycode' );
243 is( $rule->{itemtype},         $itemtype2->{itemtype},    'Got rule with universal itemtype' );
244 is( $rule->{branchcode},       $library->{branchcode},    'Got rule with specific branchcode' );
245 is( $rule->{reservesallowed},  5,                         'Got reservesallowed of 5' );
246 is( $rule->{holds_per_record}, 5,                         'Got holds_per_record of 5' );
247
248 Koha::CirculationRules->delete();
249
250 my $holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
251 is( $holds->forced_hold_level, undef, "No holds does not force an item or record level hold" );
252
253 # Test Koha::Holds::forced_hold_level
254 my $hold = Koha::Hold->new({
255     borrowernumber => $patron->{borrowernumber},
256     reservedate => '1981-06-10',
257     biblionumber => $biblio->{biblionumber},
258     branchcode => $library->{branchcode},
259     priority => 1,
260 })->store();
261
262 $holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
263 is( $holds->forced_hold_level, 'record', "Record level hold forces record level holds" );
264
265 $hold->itemnumber( $item1->{itemnumber} );
266 $hold->store();
267
268 $holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
269 is( $holds->forced_hold_level, 'item', "Item level hold forces item level holds" );
270
271 $hold->delete();
272
273 # Test multi-hold via AddReserve
274 Koha::CirculationRules->set_rules(
275     {
276         categorycode => '*',
277         itemtype     => '*',
278         branchcode   => '*',
279         rules        => {
280             reservesallowed  => 2,
281             holds_per_record => 2,
282         }
283     }
284 );
285
286 my $can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
287 is( $can->{status}, 'OK', 'Hold can be placed with 0 holds' );
288 my $hold_id = AddReserve( $library->{branchcode}, $patron->{borrowernumber}, $biblio->{biblionumber}, '', 1 );
289 ok( $hold_id, 'First hold was placed' );
290
291 $can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
292 is( $can->{status}, 'OK', 'Hold can be placed with 1 hold' );
293 $hold_id = AddReserve( $library->{branchcode}, $patron->{borrowernumber}, $biblio->{biblionumber}, '', 1 );
294 ok( $hold_id, 'Second hold was placed' );
295
296 $can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
297 is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
298
299 Koha::Holds->find($hold_id)->found("W")->store;
300 $can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
301 is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
302
303 $schema->storage->txn_rollback;