Bug 7567: (code cleanup) remove excess line
[koha.git] / t / db_dependent / Circulation.t
blob73c0bf36b5fb41bfd32edad9e0c41e9314004c8a
1 #!/usr/bin/perl
3 use Modern::Perl;
5 use DateTime;
6 use C4::Biblio;
7 use C4::Branch;
8 use C4::Items;
9 use C4::Members;
10 use C4::Reserves;
12 use Test::More tests => 45;
14 BEGIN {
15 use_ok('C4::Circulation');
18 my $dbh = C4::Context->dbh;
20 # Start transaction
21 $dbh->{AutoCommit} = 0;
22 $dbh->{RaiseError} = 1;
24 # Start with a clean slate
25 $dbh->do('DELETE FROM issues');
27 my $CircControl = C4::Context->preference('CircControl');
28 my $HomeOrHoldingBranch = C4::Context->preference('HomeOrHoldingBranch');
30 my $item = {
31 homebranch => 'MPL',
32 holdingbranch => 'MPL'
35 my $borrower = {
36 branchcode => 'MPL'
39 # No userenv, PickupLibrary
40 C4::Context->set_preference('CircControl', 'PickupLibrary');
41 is(
42 C4::Context->preference('CircControl'),
43 'PickupLibrary',
44 'CircControl changed to PickupLibrary'
46 is(
47 C4::Circulation::_GetCircControlBranch($item, $borrower),
48 $item->{$HomeOrHoldingBranch},
49 '_GetCircControlBranch returned item branch (no userenv defined)'
52 # No userenv, PatronLibrary
53 C4::Context->set_preference('CircControl', 'PatronLibrary');
54 is(
55 C4::Context->preference('CircControl'),
56 'PatronLibrary',
57 'CircControl changed to PatronLibrary'
59 is(
60 C4::Circulation::_GetCircControlBranch($item, $borrower),
61 $borrower->{branchcode},
62 '_GetCircControlBranch returned borrower branch'
65 # No userenv, ItemHomeLibrary
66 C4::Context->set_preference('CircControl', 'ItemHomeLibrary');
67 is(
68 C4::Context->preference('CircControl'),
69 'ItemHomeLibrary',
70 'CircControl changed to ItemHomeLibrary'
72 is(
73 $item->{$HomeOrHoldingBranch},
74 C4::Circulation::_GetCircControlBranch($item, $borrower),
75 '_GetCircControlBranch returned item branch'
78 diag('Now, set a userenv');
79 C4::Context->_new_userenv('xxx');
80 C4::Context::set_userenv(0,0,0,'firstname','surname', 'MPL', 'Midway Public Library', '', '', '');
81 is(C4::Context->userenv->{branch}, 'MPL', 'userenv set');
83 # Userenv set, PickupLibrary
84 C4::Context->set_preference('CircControl', 'PickupLibrary');
85 is(
86 C4::Context->preference('CircControl'),
87 'PickupLibrary',
88 'CircControl changed to PickupLibrary'
90 is(
91 C4::Circulation::_GetCircControlBranch($item, $borrower),
92 'MPL',
93 '_GetCircControlBranch returned current branch'
96 # Userenv set, PatronLibrary
97 C4::Context->set_preference('CircControl', 'PatronLibrary');
98 is(
99 C4::Context->preference('CircControl'),
100 'PatronLibrary',
101 'CircControl changed to PatronLibrary'
104 C4::Circulation::_GetCircControlBranch($item, $borrower),
105 $borrower->{branchcode},
106 '_GetCircControlBranch returned borrower branch'
109 # Userenv set, ItemHomeLibrary
110 C4::Context->set_preference('CircControl', 'ItemHomeLibrary');
112 C4::Context->preference('CircControl'),
113 'ItemHomeLibrary',
114 'CircControl changed to ItemHomeLibrary'
117 C4::Circulation::_GetCircControlBranch($item, $borrower),
118 $item->{$HomeOrHoldingBranch},
119 '_GetCircControlBranch returned item branch'
122 # Reset initial configuration
123 C4::Context->set_preference('CircControl', $CircControl);
125 C4::Context->preference('CircControl'),
126 $CircControl,
127 'CircControl reset to its initial value'
130 # Set a simple circ policy
131 $dbh->do('DELETE FROM issuingrules');
132 $dbh->do(
133 q{INSERT INTO issuingrules (categorycode, branchcode, itemtype, reservesallowed,
134 maxissueqty, issuelength, lengthunit,
135 renewalsallowed, renewalperiod,
136 fine, chargeperiod)
137 VALUES (?, ?, ?, ?,
138 ?, ?, ?,
139 ?, ?,
140 ?, ?
144 '*', '*', '*', 25,
145 20, 14, 'days',
146 1, 7,
147 .10, 1
150 # Test C4::Circulation::ProcessOfflinePayment
151 my $sth = C4::Context->dbh->prepare("SELECT COUNT(*) FROM accountlines WHERE amount = '-123.45' AND accounttype = 'Pay'");
152 $sth->execute();
153 my ( $original_count ) = $sth->fetchrow_array();
155 C4::Context->dbh->do("INSERT INTO borrowers ( cardnumber, surname, firstname, categorycode, branchcode ) VALUES ( '99999999999', 'Hall', 'Kyle', 'S', 'MPL' )");
157 C4::Circulation::ProcessOfflinePayment({ cardnumber => '99999999999', amount => '123.45' });
159 $sth->execute();
160 my ( $new_count ) = $sth->fetchrow_array();
162 ok( $new_count == $original_count + 1, 'ProcessOfflinePayment makes payment correctly' );
164 C4::Context->dbh->do("DELETE FROM accountlines WHERE borrowernumber IN ( SELECT borrowernumber FROM borrowers WHERE cardnumber = '99999999999' )");
165 C4::Context->dbh->do("DELETE FROM borrowers WHERE cardnumber = '99999999999'");
166 C4::Context->dbh->do("DELETE FROM accountlines");
168 # CanBookBeRenewed tests
170 # Generate test biblio
171 my $biblio = MARC::Record->new();
172 my $title = 'Silence in the library';
173 $biblio->append_fields(
174 MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'),
175 MARC::Field->new('245', ' ', ' ', a => $title),
178 my ($biblionumber, $biblioitemnumber) = AddBiblio($biblio, '');
180 my $barcode = 'R00000342';
181 my $branch = 'MPL';
183 my ( $item_bibnum, $item_bibitemnum, $itemnumber ) = AddItem(
185 homebranch => $branch,
186 holdingbranch => $branch,
187 barcode => $barcode,
188 replacementprice => 12.00
190 $biblionumber
193 my $barcode2 = 'R00000343';
194 my ( $item_bibnum2, $item_bibitemnum2, $itemnumber2 ) = AddItem(
196 homebranch => $branch,
197 holdingbranch => $branch,
198 barcode => $barcode2,
199 replacementprice => 23.00
201 $biblionumber
204 my $barcode3 = 'R00000346';
205 my ( $item_bibnum3, $item_bibitemnum3, $itemnumber3 ) = AddItem(
207 homebranch => $branch,
208 holdingbranch => $branch,
209 barcode => $barcode3,
210 replacementprice => 23.00
212 $biblionumber
215 # Create 2 borrowers
216 my %renewing_borrower_data = (
217 firstname => 'John',
218 surname => 'Renewal',
219 categorycode => 'S',
220 branchcode => $branch,
223 my %reserving_borrower_data = (
224 firstname => 'Katrin',
225 surname => 'Reservation',
226 categorycode => 'S',
227 branchcode => $branch,
230 my $renewing_borrowernumber = AddMember(%renewing_borrower_data);
231 my $reserving_borrowernumber = AddMember(%reserving_borrower_data);
233 my $renewing_borrower = GetMember( borrowernumber => $renewing_borrowernumber );
235 my $constraint = 'a';
236 my $bibitems = '';
237 my $priority = '1';
238 my $resdate = undef;
239 my $expdate = undef;
240 my $notes = '';
241 my $checkitem = undef;
242 my $found = undef;
244 my $datedue = AddIssue( $renewing_borrower, $barcode);
245 is (defined $datedue, 1, "Item 1 checked out, due date: $datedue");
247 my $datedue2 = AddIssue( $renewing_borrower, $barcode2);
248 is (defined $datedue2, 1, "Item 2 checked out, due date: $datedue2");
250 my $borrowing_borrowernumber = GetItemIssue($itemnumber)->{borrowernumber};
251 is ($borrowing_borrowernumber, $renewing_borrowernumber, "Item checked out to $renewing_borrower->{firstname} $renewing_borrower->{surname}");
253 my ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $itemnumber, 1);
254 is( $renewokay, 1, 'Can renew, no holds for this title or item');
257 diag("Biblio-level hold, renewal test");
258 AddReserve(
259 $branch, $reserving_borrowernumber, $biblionumber,
260 $constraint, $bibitems, $priority, $resdate, $expdate, $notes,
261 $title, $checkitem, $found
264 ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $itemnumber);
265 is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
266 is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
268 ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $itemnumber2);
269 is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
270 is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
272 my $reserveid = C4::Reserves::GetReserveId({ biblionumber => $biblionumber, borrowernumber => $reserving_borrowernumber});
273 my $reserving_borrower = GetMember( borrowernumber => $reserving_borrowernumber );
274 AddIssue($reserving_borrower, $barcode3);
275 my $reserve = $dbh->selectrow_hashref(
276 'SELECT * FROM old_reserves WHERE reserve_id = ?',
277 { Slice => {} },
278 $reserveid
280 is($reserve->{found}, 'F', 'hold marked completed when checking out item that fills it');
282 diag("Item-level hold, renewal test");
283 AddReserve(
284 $branch, $reserving_borrowernumber, $biblionumber,
285 $constraint, $bibitems, $priority, $resdate, $expdate, $notes,
286 $title, $itemnumber, $found
289 ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $itemnumber, 1);
290 is( $renewokay, 0, '(Bug 10663) Cannot renew, item reserved');
291 is( $error, 'on_reserve', '(Bug 10663) Cannot renew, item reserved (returned error is on_reserve)');
293 ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $itemnumber2, 1);
294 is( $renewokay, 1, 'Can renew item 2, item-level hold is on item 1');
297 diag("Items can't fill hold for reasons");
298 ModItem({ notforloan => 1 }, $biblionumber, $itemnumber);
299 ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $itemnumber, 1);
300 is( $renewokay, 1, 'Can renew, item is marked not for loan, hold does not block');
301 ModItem({ notforloan => 0, itype => '' }, $biblionumber, $itemnumber,1);
303 # FIXME: Add more for itemtype not for loan etc.
305 $reserveid = C4::Reserves::GetReserveId({ biblionumber => $biblionumber, itemnumber => $itemnumber, borrowernumber => $reserving_borrowernumber});
306 CancelReserve({ reserve_id => $reserveid });
308 diag("Too many renewals");
310 # set policy to forbid renewals
311 $dbh->do('UPDATE issuingrules SET renewalsallowed = 0');
313 ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $itemnumber);
314 is( $renewokay, 0, 'Cannot renew, 0 renewals allowed');
315 is( $error, 'too_many', 'Cannot renew, 0 renewals allowed (returned code is too_many)');
317 # Test WhenLostForgiveFine and WhenLostChargeReplacementFee
318 diag("WhenLostForgiveFine and WhenLostChargeReplacementFee");
319 C4::Context->set_preference('WhenLostForgiveFine','1');
320 C4::Context->set_preference('WhenLostChargeReplacementFee','1');
322 C4::Overdues::UpdateFine( $itemnumber, $renewing_borrower->{borrowernumber},
323 15.00, q{}, Koha::DateUtils::output_pref($datedue) );
325 LostItem( $itemnumber, 1 );
327 my $total_due = $dbh->selectrow_array(
328 'SELECT SUM( amountoutstanding ) FROM accountlines WHERE borrowernumber = ?',
329 undef, $renewing_borrower->{borrowernumber}
332 ok( $total_due == 12, 'Borrower only charged replacement fee with both WhenLostForgiveFine and WhenLostChargeReplacementFee enabled' );
334 C4::Context->dbh->do("DELETE FROM accountlines");
336 C4::Context->set_preference('WhenLostForgiveFine','0');
337 C4::Context->set_preference('WhenLostChargeReplacementFee','0');
339 C4::Overdues::UpdateFine( $itemnumber2, $renewing_borrower->{borrowernumber},
340 15.00, q{}, Koha::DateUtils::output_pref($datedue) );
342 LostItem( $itemnumber2, 1 );
344 $total_due = $dbh->selectrow_array(
345 'SELECT SUM( amountoutstanding ) FROM accountlines WHERE borrowernumber = ?',
346 undef, $renewing_borrower->{borrowernumber}
349 ok( $total_due == 15, 'Borrower only charged fine with both WhenLostForgiveFine and WhenLostChargeReplacementFee disabled' );
353 # GetUpcomingDueIssues tests
354 my $barcode = 'R00000342';
355 my $barcode2 = 'R00000343';
356 my $barcode3 = 'R00000344';
357 my $branch = 'MPL';
359 #Create another record
360 my $biblio2 = MARC::Record->new();
361 my $title2 = 'Something is worng here';
362 $biblio2->append_fields(
363 MARC::Field->new('100', ' ', ' ', a => 'Anonymous'),
364 MARC::Field->new('245', ' ', ' ', a => $title2),
366 my ($biblionumber2, $biblioitemnumber2) = AddBiblio($biblio2, '');
368 #Create third item
369 AddItem(
371 homebranch => $branch,
372 holdingbranch => $branch,
373 barcode => $barcode3
375 $biblionumber2
378 # Create a borrower
379 my %a_borrower_data = (
380 firstname => 'Fridolyn',
381 surname => 'SOMERS',
382 categorycode => 'S',
383 branchcode => $branch,
386 my $a_borrower_borrowernumber = AddMember(%a_borrower_data);
387 my $a_borrower = GetMember( borrowernumber => $a_borrower_borrowernumber );
389 my $yesterday = DateTime->today(time_zone => C4::Context->tz())->add( days => -1 );
390 my $two_days_ahead = DateTime->today(time_zone => C4::Context->tz())->add( days => 2 );
391 my $today = DateTime->today(time_zone => C4::Context->tz());
393 my $datedue = AddIssue( $a_borrower, $barcode, $yesterday );
394 my $datedue2 = AddIssue( $a_borrower, $barcode2, $two_days_ahead );
396 my $upcoming_dues;
398 diag( "GetUpcomingDueIssues tests" );
400 for my $i(0..1) {
401 $upcoming_dues = C4::Circulation::GetUpcomingDueIssues( { days_in_advance => $i } );
402 is ( scalar( @$upcoming_dues ), 0, "No items due in less than one day ($i days in advance)" );
405 #days_in_advance needs to be inclusive, so 1 matches items due tomorrow, 0 items due today etc.
406 $upcoming_dues = C4::Circulation::GetUpcomingDueIssues( { days_in_advance => 2 } );
407 is ( scalar ( @$upcoming_dues), 1, "Only one item due in 2 days or less" );
409 for my $i(3..5) {
410 $upcoming_dues = C4::Circulation::GetUpcomingDueIssues( { days_in_advance => $i } );
411 is ( scalar( @$upcoming_dues ), 1,
412 "Bug 9362: Only one item due in more than 2 days ($i days in advance)" );
415 # Bug 11218 - Due notices not generated - GetUpcomingDueIssues needs to select due today items as well
417 my $datedue3 = AddIssue( $a_borrower, $barcode3, $today );
419 $upcoming_dues = C4::Circulation::GetUpcomingDueIssues( { days_in_advance => -1 } );
420 is ( scalar ( @$upcoming_dues), 0, "Overdues can not be selected" );
422 $upcoming_dues = C4::Circulation::GetUpcomingDueIssues( { days_in_advance => 0 } );
423 is ( scalar ( @$upcoming_dues), 1, "1 item is due today" );
425 $upcoming_dues = C4::Circulation::GetUpcomingDueIssues( { days_in_advance => 1 } );
426 is ( scalar ( @$upcoming_dues), 1, "1 item is due today, none tomorrow" );
428 $upcoming_dues = C4::Circulation::GetUpcomingDueIssues( { days_in_advance => 2 } );
429 is ( scalar ( @$upcoming_dues), 2, "2 items are due withing 2 days" );
431 $upcoming_dues = C4::Circulation::GetUpcomingDueIssues( { days_in_advance => 3 } );
432 is ( scalar ( @$upcoming_dues), 2, "2 items are due withing 2 days" );
434 $upcoming_dues = C4::Circulation::GetUpcomingDueIssues();
435 is ( scalar ( @$upcoming_dues), 2, "days_in_advance is 7 in GetUpcomingDueIssues if not provided" );
439 $dbh->rollback;