Bug 36687: (RM follow-up) Fix unit tests
[koha.git] / t / db_dependent / Circulation / issue.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 => 67;
21 use DateTime::Duration;
22
23 use t::lib::Mocks;
24 use t::lib::TestBuilder;
25
26 use C4::Biblio qw( AddBiblio );
27 use C4::Circulation qw( AddIssue AddIssuingCharge AddRenewal AddReturn GetIssuingCharges GetRenewCount GetUpcomingDueIssues );
28 use C4::Context;
29 use C4::Items;
30 use C4::Reserves qw( AddReserve );
31 use Koha::Checkouts;
32 use Koha::Database;
33 use Koha::DateUtils qw( dt_from_string output_pref );
34 use Koha::Holds;
35 use Koha::Items;
36 use Koha::Library;
37 use Koha::Patrons;
38 use Koha::CirculationRules;
39 use Koha::Statistics;
40
41 BEGIN {
42     require_ok('C4::Circulation');
43 }
44
45 can_ok(
46     'C4::Circulation',
47     qw(AddIssue
48       AddIssuingCharge
49       AddRenewal
50       AddReturn
51       GetIssuingCharges
52       GetRenewCount
53       GetUpcomingDueIssues
54       )
55 );
56
57 #Start transaction
58 my $schema = Koha::Database->schema;
59 $schema->storage->txn_begin;
60 my $dbh = C4::Context->dbh;
61
62 my $builder = t::lib::TestBuilder->new();
63
64 $dbh->do(q|DELETE FROM issues|);
65 $dbh->do(q|DELETE FROM items|);
66 $dbh->do(q|DELETE FROM borrowers|);
67 $dbh->do(q|DELETE FROM categories|);
68 $dbh->do(q|DELETE FROM accountlines|);
69 $dbh->do(q|DELETE FROM circulation_rules|);
70 $dbh->do(q|DELETE FROM reserves|);
71 $dbh->do(q|DELETE FROM old_reserves|);
72 $dbh->do(q|DELETE FROM statistics|);
73
74 # Generate sample datas
75 my $itemtype = $builder->build(
76     {
77         source => 'Itemtype',
78         value  => { notforloan => 0, rentalcharge => 0 }
79     }
80 )->{itemtype};
81 my $itemtype2 = $builder->build(
82     {
83         source => 'Itemtype',
84         value  => { notforloan => 0 }
85     }
86 )->{itemtype};
87 my $branchcode_1 = $builder->build({ source => 'Branch' })->{branchcode};
88 my $branchcode_2 = $builder->build({ source => 'Branch' })->{branchcode};
89 my $branchcode_3 = $builder->build({ source => 'Branch' })->{branchcode};
90 my $categorycode = $builder->build({
91         source => 'Category',
92         value => { enrolmentfee => undef }
93     })->{categorycode};
94
95 # A default issuingrule should always be present
96 Koha::CirculationRules->set_rules(
97     {
98         itemtype     => '*',
99         categorycode => '*',
100         branchcode   => '*',
101         rules        => {
102             lengthunit      => 'days',
103             issuelength     => 0,
104             renewalperiod   => 0,
105             renewalsallowed => 0
106         }
107     }
108 );
109
110 # Add Dates
111 my $dt_today = dt_from_string;
112 my $today    = output_pref(
113     {   dt         => $dt_today,
114         dateformat => 'iso',
115         timeformat => '24hr',
116         dateonly   => 1
117     }
118 );
119
120 my $dt_today2 = dt_from_string;
121 my $dur10 = DateTime::Duration->new( days => -10 );
122 $dt_today2->add_duration($dur10);
123 my $daysago10 = output_pref(
124     {   dt         => $dt_today2,
125         dateformat => 'iso',
126         timeformat => '24hr',
127         dateonly   => 1
128     }
129 );
130
131 # Add biblio and item
132 my $record = MARC::Record->new();
133 my $record2 = MARC::Record->new();
134 $record->append_fields(
135     MARC::Field->new( '942', '0', '0', c => $itemtype ),
136     MARC::Field->new( '952', '0', '0', a => $branchcode_1 ) );
137
138 $record2->append_fields(
139     MARC::Field->new( '942', '0', '0', c => $itemtype2 ),
140     MARC::Field->new( '952', '0', '0', a => $branchcode_1 ) );
141
142 my ( $biblionumber, $biblioitemnumber ) = C4::Biblio::AddBiblio( $record, '' );
143 my ( $biblionumber2, $biblioitemnumber2 ) = C4::Biblio::AddBiblio( $record2, '' );
144
145 my $barcode_1 = 'barcode_1';
146 my $barcode_2 = 'barcode_2';
147 my $item_id1 = Koha::Item->new(
148     {
149         biblionumber   => $biblionumber,
150         barcode        => $barcode_1,
151         itemcallnumber => 'callnumber1',
152         homebranch     => $branchcode_1,
153         holdingbranch  => $branchcode_1,
154         itype          => $itemtype
155     },
156 )->store->itemnumber;
157 my $item_id2 = Koha::Item->new(
158     {
159         biblionumber   => $biblionumber,
160         barcode        => $barcode_2,
161         itemcallnumber => 'callnumber2',
162         homebranch     => $branchcode_2,
163         holdingbranch  => $branchcode_2,
164         notforloan     => 1,
165         itype          => $itemtype
166     },
167 )->store->itemnumber;
168
169 #Add borrower
170 my $borrower_id1 = Koha::Patron->new({
171     firstname    => 'firstname1',
172     surname      => 'surname1 ',
173     categorycode => $categorycode,
174     branchcode   => $branchcode_1
175 })->store->borrowernumber;
176 my $patron_1 = Koha::Patrons->find( $borrower_id1 );
177 my $borrower_id2 = Koha::Patron->new({
178     firstname    => 'firstname2',
179     surname      => 'surname2 ',
180     categorycode => $categorycode,
181     branchcode   => $branchcode_2,
182 })->store->borrowernumber;
183 my $patron_2 = Koha::Patrons->find( $borrower_id2 );
184
185 t::lib::Mocks::mock_userenv({ patron => $patron_1 });
186
187 #Begin Tests
188
189 #Test AddIssue
190 my $query = " SELECT count(*) FROM issues";
191 my $sth = $dbh->prepare($query);
192 $sth->execute;
193 my $countissue = $sth->fetchrow_array;
194 is ($countissue ,0, "there is no issue");
195 my $issue1 = C4::Circulation::AddIssue( $patron_1, $barcode_1, $daysago10, 0, $today, '' );
196 is( ref $issue1, 'Koha::Checkout',
197        'AddIssue returns a Koha::Checkout object' );
198 my $datedue1 = dt_from_string( $issue1->date_due() );
199 like(
200     $datedue1,
201     qr/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/,
202     "Koha::Checkout->date_due() returns a date"
203 );
204 my $issue_id1 = $issue1->issue_id;
205
206 my $issue2 = C4::Circulation::AddIssue( $patron_1, 'nonexistent_barcode' );
207 is( $issue2, undef, "AddIssue returns undef if no datedue is specified" );
208
209 $sth->execute;
210 $countissue = $sth->fetchrow_array;
211 is ($countissue,1,"1 issues have been added");
212
213 #Test AddIssuingCharge
214 $query = " SELECT count(*) FROM accountlines";
215 $sth = $dbh->prepare($query);
216 $sth->execute;
217 my $countaccount = $sth->fetchrow_array;
218 is ($countaccount,0,"0 accountline exists");
219 my $checkout = Koha::Checkouts->find( $issue_id1 );
220 my $charge = C4::Circulation::AddIssuingCharge( $checkout, 10, 'RENT' );
221 is( ref( $charge ), 'Koha::Account::Line', "An issuing charge has been added" );
222 is( $charge->issue_id, $issue_id1, 'Issue id is set correctly for issuing charge' );
223 my $offset = Koha::Account::Offsets->find( { debit_id => $charge->id } );
224 is( $offset->credit_id, undef, 'Offset was created');
225 $sth->execute;
226 $countaccount = $sth->fetchrow_array;
227 is ($countaccount,1,"1 accountline has been added");
228
229 # Test AddRenewal
230
231 my $se = Test::MockModule->new( 'C4::Context' );
232 $se->mock( 'interface', sub {return 'intranet'});
233
234 # Let's renew this one at a different library for statistical purposes to test Bug 17781
235 # Mocking userenv with a different branchcode
236 t::lib::Mocks::mock_userenv({ patron => $patron_2, branchcode => $branchcode_3 });
237
238 my $datedue3 = AddRenewal(
239     {
240         borrowernumber  => $borrower_id1,
241         itemnumber      => $item_id1,
242         branch          => $branchcode_1,
243         datedue         => $datedue1,
244         lastreneweddate => $daysago10
245     }
246 );
247
248 # Restoring the userenv with the original branchcode
249 t::lib::Mocks::mock_userenv({ patron => $patron_1});
250
251 like(
252     $datedue3,
253     qr/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/,
254     "AddRenewal returns a date"
255 );
256
257 my $stat = $dbh->selectrow_hashref("SELECT * FROM statistics WHERE type = 'renew' AND borrowernumber = ? AND itemnumber = ? AND branch = ?", undef, $borrower_id1, $item_id1, $branchcode_3 );
258 ok( $stat, "Bug 17781 - 'Improper branchcode set during renewal' still fixed" );
259
260 subtest 'Show that AddRenewal respects OpacRenewalBranch and interface' => sub {
261     plan tests => 10;
262
263     my $item_library = $builder->build_object( { class => 'Koha::Libraries' } );
264     my $patron       = $builder->build_object( { class => 'Koha::Patrons' } );
265     my $logged_in_user = $builder->build_object( { class => 'Koha::Patrons' } );
266     t::lib::Mocks::mock_userenv( { patron => $logged_in_user } );
267
268     my $OpacRenewalBranch = {
269         opacrenew        => "OPACRenew",
270         checkoutbranch   => $logged_in_user->branchcode,
271         patronhomebranch => $patron->branchcode,
272         itemhomebranch   => $item_library->branchcode,
273         none             => "",
274     };
275
276     while ( my ( $syspref, $expected_branchcode ) = each %$OpacRenewalBranch ) {
277
278         t::lib::Mocks::mock_preference( 'OpacRenewalBranch', $syspref );
279
280         {
281             $se->mock( 'interface', sub { return 'opac' } );
282
283             my $item = $builder->build_sample_item(
284                 { library => $item_library->branchcode, itype => $itemtype } );
285             my $opac_renew_issue =
286               C4::Circulation::AddIssue( $patron, $item->barcode );
287
288             AddRenewal(
289                 {
290                     borrowernumber  => $patron->borrowernumber,
291                     itemnumber      => $item->itemnumber,
292                     branch          => "Stavromula",
293                     datedue         => $datedue1,
294                     lastreneweddate => $daysago10
295                 }
296             );
297
298             my $stat = Koha::Statistics->search(
299                 { itemnumber => $item->itemnumber, type => 'renew' } )->next;
300             is( $stat->branch, $expected_branchcode,
301                 "->renewal_branchcode is respected for OpacRenewalBranch = $syspref"
302             );
303         }
304
305         {
306             $se->mock( 'interface', sub { return 'intranet' } );
307
308             my $item = $builder->build_sample_item(
309                 { library => $item_library->branchcode, itype => $itemtype } );
310             my $opac_renew_issue =
311               C4::Circulation::AddIssue( $patron, $item->barcode );
312
313             AddRenewal(
314                 {
315                     borrowernumber  => $patron->borrowernumber,
316                     itemnumber      => $item->itemnumber,
317                     branch          => "Stavromula",
318                     datedue         => $datedue1,
319                     lastreneweddate => $daysago10
320                 }
321             );
322
323             my $stat = Koha::Statistics->search(
324                 { itemnumber => $item->itemnumber, type => 'renew' } )->next;
325             is( $stat->branch, $logged_in_user->branchcode,
326                 "->renewal_branchcode is always logged in branch for intranet"
327             );
328         }
329     }
330 };
331
332
333 my @renewcount;
334 #Test GetRenewCount
335 my $issue3 = C4::Circulation::AddIssue( $patron_1, $barcode_1 );
336 #Without anything in DB
337 @renewcount = C4::Circulation::GetRenewCount();
338 is_deeply(
339     \@renewcount,
340     [ 0, 0, 0, 0, 0, 0 ], # FIXME Need to be fixed, see FIXME in GetRenewCount
341     "Without issuing rules and without parameter, GetRenewCount returns renewcount = 0, renewsallowed = undef, renewsleft = 0"
342 );
343 @renewcount = C4::Circulation::GetRenewCount(-1);
344 is_deeply(
345     \@renewcount,
346     [ 0, 0, 0, 0, 0, 0 ], # FIXME Need to be fixed
347     "Without issuing rules and without wrong parameter, GetRenewCount returns renewcount = 0, renewsallowed = undef, renewsleft = 0"
348 );
349 @renewcount = C4::Circulation::GetRenewCount($borrower_id1, $item_id1);
350 is_deeply(
351     \@renewcount,
352     [ 2, 0, 0, 0, 0, 0 ],
353     "Without issuing rules and with a valid parameter, renewcount = 2, renewsallowed = undef, renewsleft = 0"
354 );
355
356 #With something in DB
357 @renewcount = C4::Circulation::GetRenewCount();
358 is_deeply(
359     \@renewcount,
360     [ 0, 0, 0, 0, 0, 0 ],
361     "With issuing rules (renewal disallowed) and without parameter, GetRenewCount returns renewcount = 0, renewsallowed = 0, renewsleft = 0"
362 );
363 @renewcount = C4::Circulation::GetRenewCount(-1);
364 is_deeply(
365     \@renewcount,
366     [ 0, 0, 0, 0, 0, 0 ],
367     "With issuing rules (renewal disallowed) and without wrong parameter, GetRenewCount returns renewcount = 0, renewsallowed = 0, renewsleft = 0"
368 );
369 @renewcount = C4::Circulation::GetRenewCount($borrower_id1, $item_id1);
370 is_deeply(
371     \@renewcount,
372     [ 2, 0, 0, 0, 0, 0 ],
373     "With issuing rules (renewal disallowed) and with a valid parameter, Getrenewcount returns renewcount = 2, renewsallowed = 0, renewsleft = 0"
374 );
375
376 # Add a default rule: renewal is allowed
377 Koha::CirculationRules->set_rules(
378     {
379         categorycode => undef,
380         itemtype     => undef,
381         branchcode   => undef,
382         rules        => {
383             renewalsallowed => 3,
384         }
385     }
386 );
387 @renewcount = C4::Circulation::GetRenewCount($borrower_id1, $item_id1);
388 is_deeply(
389     \@renewcount,
390     [ 2, 3, 1, 0, 0, 0 ],
391     "With issuing rules (renewal allowed) and with a valid parameter, Getrenewcount of item1 returns 3 renews left"
392 );
393
394 AddRenewal(
395     {
396         borrowernumber  => $borrower_id1,
397         itemnumber      => $item_id1,
398         branch          => $branchcode_1,
399         datedue         => $datedue3,
400         lastreneweddate => $daysago10
401     }
402 );
403 @renewcount = C4::Circulation::GetRenewCount($borrower_id1, $item_id1);
404 is_deeply(
405     \@renewcount,
406     [ 3, 3, 0, 0, 0, 0 ],
407     "With issuing rules (renewal allowed, 1 remaining) and with a valid parameter, Getrenewcount of item1 returns 0 renews left"
408 );
409
410 $dbh->do("DELETE FROM old_issues");
411 AddReturn($barcode_1);
412 my $return = $dbh->selectrow_hashref("SELECT DATE(returndate) AS return_date, CURRENT_DATE() AS today FROM old_issues LIMIT 1" );
413 ok( $return->{return_date} eq $return->{today}, "Item returned with no return date specified has todays date" );
414
415 $dbh->do("DELETE FROM old_issues");
416 C4::Circulation::AddIssue( $patron_1, $barcode_1, $daysago10, 0, $today );
417 AddReturn($barcode_1, undef, undef, dt_from_string('2014-04-01 23:42'));
418 $return = $dbh->selectrow_hashref("SELECT * FROM old_issues LIMIT 1" );
419 ok( $return->{returndate} eq '2014-04-01 23:42:00', "Item returned with a return date of '2014-04-01 23:42' has that return date" );
420
421 my $itemnumber = Koha::Item->new(
422     {
423         biblionumber   => $biblionumber,
424         barcode        => 'barcode_3',
425         itemcallnumber => 'callnumber3',
426         homebranch     => $branchcode_1,
427         holdingbranch  => $branchcode_1,
428         notforloan     => 1,
429         itype          => $itemtype,
430         biblioitemnumber => $biblioitemnumber
431     },
432 )->store->itemnumber;
433
434 t::lib::Mocks::mock_preference( 'UpdateNotForLoanStatusOnCheckin', q{} );
435 t::lib::Mocks::mock_preference( 'CataloguingLog', 1 );
436 my $log_count_before = $schema->resultset('ActionLog')->search({module => 'CATALOGUING'})->count();
437
438 AddReturn( 'barcode_3', $branchcode_1 );
439 my $item = Koha::Items->find( $itemnumber );
440 ok( $item->notforloan eq 1, 'UpdateNotForLoanStatusOnCheckin does not modify value when not enabled' );
441
442 my $updatenotforloanstatusoncheckin = "
443 _ALL_:\n
444  1: 0\n
445  9: 1\n\n
446 $itemtype:\n
447   1: 9
448 ";
449 t::lib::Mocks::mock_preference( 'UpdateNotForLoanStatusOnCheckin', $updatenotforloanstatusoncheckin );
450 AddReturn( 'barcode_3', $branchcode_1 );
451 $item = Koha::Items->find( $itemnumber );
452 ok( $item->notforloan eq 9, q{UpdateNotForLoanStatusOnCheckin prioritises item type specific rule over _ALL_ rules} );
453 my $log_count_after = $schema->resultset('ActionLog')->search({module => 'CATALOGUING'})->count();
454 is($log_count_before, $log_count_after, "Change from UpdateNotForLoanStatusOnCheckin is not logged");
455
456 AddReturn( 'barcode_3', $branchcode_1 );
457 $item = Koha::Items->find( $itemnumber );
458 ok( $item->notforloan eq 9, q{UpdateNotForLoanStatusOnCheckin uses item type specific rules even if they do not target the returned items' notforloan value} );
459
460 # Change the returning item to an item type without a rule
461 Koha::Items->find( $itemnumber )->itype( $itemtype2 )->store;
462 Koha::Items->find( $itemnumber )->notforloan( 1 )->store;
463 AddReturn( 'barcode_3', $branchcode_1 );
464 $item = Koha::Items->find( $itemnumber );
465 ok( $item->notforloan eq 0, q{UpdateNotForLoanStatusOnCheckin _ALL_ rules are applied if there are no specific item type rule matching the returned item} );
466
467 t::lib::Mocks::mock_preference(
468     'UpdateNotForLoanStatusOnCheckin', q{_ALL_:
469         1: ONLYMESSAGE
470 }
471 );
472 $item->notforloan(1)->store;
473 AddReturn( 'barcode_3', $branchcode_1 );
474 $item->discard_changes;
475 is(
476     $item->notforloan, 1,
477     q{UpdateNotForLoanStatusOnCheckin does not update notforloan value from 1 for _ALL_ with setting "1: ONLYMESSAGE"}
478 );
479
480
481 t::lib::Mocks::mock_preference(
482     'UpdateNotForLoanStatusOnCheckin',  "$itemtype:\n
483         1: ONLYMESSAGE
484 "
485 );
486 AddReturn( 'barcode_3', $branchcode_1 );
487 $item->discard_changes;
488 is(
489     $item->notforloan, 1,
490     q{UpdateNotForLoanStatusOnCheckin does not update notforloan value for specific itemtype from 1 with setting "1: ONLYMESSAGE"}
491 );
492
493 my $itemnumber2 = Koha::Item->new(
494     {
495         biblionumber   => $biblionumber,
496         barcode        => 'barcode_4',
497         itemcallnumber => 'callnumber4',
498         homebranch     => $branchcode_1,
499         holdingbranch  => $branchcode_1,
500         location       => 'FIC',
501         itype          => $itemtype
502     }
503 )->store->itemnumber;
504
505 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckout', q{} );
506 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckin',  q{} );
507
508 AddReturn( 'barcode_4', $branchcode_1 );
509 my $item2 = Koha::Items->find( $itemnumber2 );
510 ok( $item2->location eq 'FIC', 'UpdateItemLocationOnCheckin does not modify value when not enabled' );
511
512 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckin', 'FIC: GEN' );
513 $log_count_before = $schema->resultset('ActionLog')->search({module => 'CATALOGUING'})->count();
514 AddReturn( 'barcode_4', $branchcode_1 );
515 $item2 = Koha::Items->find( $itemnumber2 );
516 is( $item2->location, 'GEN', q{UpdateItemLocationOnCheckin updates location value from 'FIC' to 'GEN' with setting "FIC: GEN"} );
517 is( $item2->permanent_location, 'GEN', q{UpdateItemLocationOnCheckin updates permanent_location value from 'FIC' to 'GEN' with setting "FIC: GEN"} );
518 $log_count_after = $schema->resultset('ActionLog')->search({module => 'CATALOGUING'})->count();
519 is($log_count_before, $log_count_after, "Change from UpdateNotForLoanStatusOnCheckin is not logged");
520 AddReturn( 'barcode_4', $branchcode_1 );
521 $item2 = Koha::Items->find( $itemnumber2 );
522 ok( $item2->location eq 'GEN', q{UpdateItemLocationOnCheckin does not update location value from 'GEN' with setting "FIC: GEN"} );
523
524 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckin', '_ALL_: CART' );
525 AddReturn( 'barcode_4', $branchcode_1 );
526 $item2 = Koha::Items->find( $itemnumber2 );
527 ok( $item2->location eq 'CART', q{UpdateItemLocationOnCheckin updates location value from 'GEN' with setting "_ALL_: CART"} );
528 Koha::Item::Transfer->new({
529     itemnumber => $itemnumber2,
530     frombranch => $branchcode_2,
531     tobranch => $branchcode_1,
532     datesent => '2020-01-01'
533 })->store;
534 AddReturn( 'barcode_4', $branchcode_1 );
535 $item2 = Koha::Items->find( $itemnumber2 );
536 ok( $item2->location eq 'CART', q{UpdateItemLocationOnCheckin updates location value from 'GEN' with setting "_ALL_: CART" when transfer filled} );
537
538 ok( $item2->permanent_location eq 'GEN', q{UpdateItemLocationOnCheckin does not update permanent_location value from 'GEN' with setting "_ALL_: CART"} );
539 AddIssue( $patron_1, 'barcode_4', $daysago10,0, $today, '' );
540 $item2 = Koha::Items->find( $itemnumber2 );
541 ok( $item2->location eq 'GEN', q{Location updates from 'CART' to permanent location on issue} );
542
543 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckin', "GEN: _BLANK_\n_BLANK_: PROC\nPROC: _PERM_" );
544 AddReturn( 'barcode_4', $branchcode_1 );
545 $item2 = Koha::Items->find( $itemnumber2 );
546 ok( $item2->location eq '', q{UpdateItemLocationOnCheckin updates location value from 'GEN' to '' with setting "GEN: _BLANK_"} );
547 AddReturn( 'barcode_4', $branchcode_1 );
548 $item2 = Koha::Items->find( $itemnumber2 );
549 ok( $item2->location eq 'PROC' , q{UpdateItemLocationOnCheckin updates location value from '' to 'PROC' with setting "_BLANK_: PROC"} );
550 ok( $item2->permanent_location eq '' , q{UpdateItemLocationOnCheckin does not update permanent_location value from '' to 'PROC' with setting "_BLANK_: PROC"} );
551 AddReturn( 'barcode_4', $branchcode_1 );
552 $item2 = Koha::Items->find( $itemnumber2 );
553 ok( $item2->location eq '' , q{UpdateItemLocationOnCheckin updates location value from 'PROC' to '' with setting "PROC: _PERM_" } );
554 ok( $item2->permanent_location eq '' , q{UpdateItemLocationOnCheckin does not update permanent_location from '' with setting "PROC: _PERM_" } );
555
556 # Bug 28472
557 my $itemnumber3 = Koha::Item->new(
558     {
559         biblionumber   => $biblionumber,
560         barcode        => 'barcode_5',
561         itemcallnumber => 'callnumber5',
562         homebranch     => $branchcode_1,
563         holdingbranch  => $branchcode_1,
564         location       => undef,
565         itype          => $itemtype
566     }
567 )->store->itemnumber;
568
569 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckin', '_ALL_: CART' );
570 AddReturn( 'barcode_5', $branchcode_1 );
571 my $item3 = Koha::Items->find( $itemnumber3 );
572 is( $item3->location, 'CART', q{UpdateItemLocationOnCheckin updates location value from NULL (i.e. the item has no shelving location set) to 'CART' with setting "_ALL_: CART"} );
573
574
575
576 # Bug 14640 - Cancel the hold on checking out if asked
577 Koha::Items->find({ barcode => $barcode_1 })->notforloan('0')->store;
578 my $reserve_id = AddReserve(
579     {
580         branchcode     => $branchcode_1,
581         borrowernumber => $borrower_id1,
582         biblionumber   => $biblionumber,
583         priority       => 1,
584         notes          => "a note",
585         title          => "a title",
586     }
587 );
588 ok( $reserve_id, 'The reserve should have been inserted' );
589 AddIssue( $patron_2, $barcode_1, dt_from_string, 'cancel' );
590 my $hold = Koha::Holds->find( $reserve_id );
591 is( $hold, undef, 'The reserve should have been correctly cancelled' );
592
593 # Unseen rewnewals
594 t::lib::Mocks::mock_preference('UnseenRenewals', 1);
595 # Add a default circ rule: 3 unseen renewals allowed
596 Koha::CirculationRules->set_rules(
597     {
598         categorycode => undef,
599         itemtype     => undef,
600         branchcode   => undef,
601         rules        => {
602             renewalsallowed => 10,
603             unseen_renewals_allowed => 3
604         }
605     }
606 );
607
608 my $unseen_library = $builder->build_object( { class => 'Koha::Libraries' } );
609 my $unseen_patron  = $builder->build_object( { class => 'Koha::Patrons' } );
610 my $unseen_item = $builder->build_sample_item(
611     { library => $unseen_library->branchcode, itype => $itemtype } );
612 my $unseen_issue = C4::Circulation::AddIssue( $unseen_patron, $unseen_item->barcode );
613
614 # Does an unseen renewal increment the issue's count
615 my ( $unseen_before ) = ( C4::Circulation::GetRenewCount( $unseen_patron->borrowernumber, $unseen_item->itemnumber ) )[3];
616 AddRenewal(
617     {
618         borrowernumber => $unseen_patron->borrowernumber,
619         itemnumber     => $unseen_item->itemnumber,
620         branch         => $branchcode_1,
621         seen           => 0
622     }
623 );
624 my ( $unseen_after ) = ( C4::Circulation::GetRenewCount( $unseen_patron->borrowernumber, $unseen_item->itemnumber ) )[3];
625 is( $unseen_after, $unseen_before + 1, 'unseen_renewals increments' );
626
627 # Does a seen renewal reset the unseen count
628 AddRenewal(
629     {
630         borrowernumber => $unseen_patron->borrowernumber,
631         itemnumber     => $unseen_item->itemnumber,
632         branch         => $branchcode_1,
633         seen           => 1
634     }
635 );
636 my ( $unseen_reset ) = ( C4::Circulation::GetRenewCount( $unseen_patron->borrowernumber, $unseen_item->itemnumber ) )[3];
637 is( $unseen_reset, 0, 'seen renewal resets the unseen count' );
638
639 my $itemnumber4 = Koha::Item->new(
640     {
641         biblionumber   => $biblionumber,
642         barcode        => 'barcode_6',
643         itemcallnumber => 'callnumber6',
644         homebranch     => $branchcode_1,
645         holdingbranch  => $branchcode_1,
646         notforloan     => -1,
647         itype          => $itemtype,
648         location       => 'loc1'
649     },
650 )->store->itemnumber;
651
652 t::lib::Mocks::mock_preference( 'UpdateNotForLoanStatusOnCheckout', q{} );
653 AddIssue( $patron_2, 'barcode_6', dt_from_string );
654 $item = Koha::Items->find( $itemnumber4 );
655 ok( $item->notforloan eq -1, 'UpdateNotForLoanStatusOnCheckout does not modify value when not enabled' );
656
657 t::lib::Mocks::mock_preference( 'UpdateNotForLoanStatusOnCheckout', '-1: 0' );
658 AddReturn( 'barcode_6', $branchcode_1 );
659 my $test = AddIssue( $patron_2, 'barcode_6', dt_from_string );
660 $item = Koha::Items->find( $itemnumber4 );
661 ok( $item->notforloan eq 0, q{UpdateNotForLoanStatusOnCheckout updates notforloan value from -1 to 0 with setting "-1: 0"} );
662
663 AddIssue( $patron_2, 'barcode_6', dt_from_string );
664 AddReturn( 'barcode_6', $branchcode_1 );
665 $item = Koha::Items->find( $itemnumber4 );
666 ok( $item->notforloan eq 0, q{UpdateNotForLoanStatusOnCheckout does not update notforloan value from 0 with setting "-1: 0"} );
667
668 # Bug 21159 - Update item shelving location on checkout
669 my $itemnumber5 = Koha::Item->new(
670     {
671         biblionumber   => $biblionumber,
672         barcode        => 'barcode_7',
673         itemcallnumber => 'callnumber3',
674         homebranch     => $branchcode_1,
675         holdingbranch  => $branchcode_1,
676         location       => 'FIC',
677         itype          => $itemtype
678     },
679 )->store->itemnumber;
680
681 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckout', q{} );
682 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckin',  q{} );
683 AddIssue( $patron_1, 'barcode_7' );
684 my $item5 = Koha::Items->find($itemnumber5);
685 ok( $item5->location eq 'FIC', 'UpdateItemLocationOnCheckout does not modify value when not enabled' );
686
687 #---
688 AddReturn( 'barcode_7', $branchcode_1 );
689 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckout', 'FIC: GEN' );
690 $log_count_before = $schema->resultset('ActionLog')->search( { module => 'CATALOGUING' } )->count();
691 AddIssue( $patron_1, 'barcode_7' );
692 $item5 = Koha::Items->find($itemnumber5);
693 is(
694     $item5->location, 'GEN',
695     q{UpdateItemLocationOnCheckout updates location value from 'FIC' to 'GEN' with setting "FIC: GEN"}
696 );
697 is(
698     $item5->permanent_location, 'GEN',
699     q{UpdateItemLocationOnCheckout updates permanent_location value from 'FIC' to 'GEN' with setting "FIC: GEN"}
700 );
701 $log_count_after = $schema->resultset('ActionLog')->search( { module => 'CATALOGUING' } )->count();
702 is( $log_count_before, $log_count_after, "Change from UpdateNotForLoanStatusOnCheckout is not logged" );
703 AddReturn( 'barcode_7', $branchcode_1 );
704 AddIssue( $patron_1, 'barcode_7' );
705 $item5 = Koha::Items->find($itemnumber5);
706 ok(
707     $item5->location eq 'GEN',
708     q{UpdateItemLocationOnCheckout does not update location value from 'GEN' with setting "FIC: GEN"}
709 );
710
711 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckout', '_ALL_: CART' );
712 AddReturn( 'barcode_7', $branchcode_1 );
713 AddIssue( $patron_1, 'barcode_7' );
714 $item5 = Koha::Items->find($itemnumber5);
715 ok(
716     $item5->location eq 'CART',
717     q{UpdateItemLocationOnCheckout updates location value from 'GEN' with setting "_ALL_: CART"}
718 );
719 ok(
720     $item5->permanent_location eq 'GEN',
721     q{UpdateItemLocationOnCheckout does not update permanent_location value from 'GEN' with setting "_ALL_: CART"}
722 );
723
724 $item5->location('GEN')->store;
725 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckout', "GEN: _BLANK_\n_BLANK_: PROC\nPROC: _PERM_" );
726 AddReturn( 'barcode_7', $branchcode_1 );
727 AddIssue( $patron_1, 'barcode_7' );
728 $item5 = Koha::Items->find($itemnumber5);
729 ok(
730     $item5->location eq '',
731     q{UpdateItemLocationOnCheckout updates location value from 'GEN' to '' with setting "GEN: _BLANK_"}
732 );
733 AddReturn( 'barcode_7', $branchcode_1 );
734 AddIssue( $patron_1, 'barcode_7' );
735 $item5 = Koha::Items->find($itemnumber5);
736 ok(
737     $item5->location eq 'PROC',
738     q{UpdateItemLocationOnCheckout updates location value from '' to 'PROC' with setting "_BLANK_: PROC"}
739 );
740 ok(
741     $item5->permanent_location eq '',
742     q{UpdateItemLocationOnCheckout does not update permanent_location value from '' to 'PROC' with setting "_BLANK_: PROC"}
743 );
744 AddReturn( 'barcode_7', $branchcode_1 );
745 AddIssue( $patron_1, 'barcode_7' );
746 $item5 = Koha::Items->find($itemnumber5);
747 ok(
748     $item5->location eq '',
749     q{UpdateItemLocationOnCheckout updates location value from 'PROC' to '' with setting "PROC: _PERM_" }
750 );
751 ok(
752     $item5->permanent_location eq '',
753     q{UpdateItemLocationOnCheckout does not update permanent_location from '' with setting "PROC: _PERM_" }
754 );
755
756 # Bug 28472
757 my $itemnumber6 = Koha::Item->new(
758     {
759         biblionumber   => $biblionumber,
760         barcode        => 'barcode_8',
761         itemcallnumber => 'callnumber5',
762         homebranch     => $branchcode_1,
763         holdingbranch  => $branchcode_1,
764         location       => undef,
765         itype          => $itemtype
766     }
767 )->store->itemnumber;
768
769 t::lib::Mocks::mock_preference( 'UpdateItemLocationOnCheckout', '_ALL_: CART' );
770 AddIssue( $patron_1, 'barcode_8' );
771 my $item6 = Koha::Items->find($itemnumber6);
772 is(
773     $item6->location, 'CART',
774     q{UpdateItemLocationOnCheckout updates location value from NULL (i.e. the item has no shelving location set) to 'CART' with setting "_ALL_: CART"}
775 );
776
777 #End transaction
778 $schema->storage->txn_rollback;