Lines 41-46
use Koha::Calendar;
Link Here
|
41 |
use Koha::Database; |
41 |
use Koha::Database; |
42 |
use Koha::Hold; |
42 |
use Koha::Hold; |
43 |
use Koha::Holds; |
43 |
use Koha::Holds; |
|
|
44 |
use Koha::Borrowers; |
44 |
|
45 |
|
45 |
use List::MoreUtils qw( firstidx any ); |
46 |
use List::MoreUtils qw( firstidx any ); |
46 |
use Carp; |
47 |
use Carp; |
Lines 141-146
BEGIN {
Link Here
|
141 |
&GetReservesControlBranch |
142 |
&GetReservesControlBranch |
142 |
|
143 |
|
143 |
IsItemOnHoldAndFound |
144 |
IsItemOnHoldAndFound |
|
|
145 |
|
146 |
GetMaxPatronHoldsForRecord |
144 |
); |
147 |
); |
145 |
@EXPORT_OK = qw( MergeHolds ); |
148 |
@EXPORT_OK = qw( MergeHolds ); |
146 |
} |
149 |
} |
Lines 158-169
sub AddReserve {
Link Here
|
158 |
$title, $checkitem, $found |
161 |
$title, $checkitem, $found |
159 |
) = @_; |
162 |
) = @_; |
160 |
|
163 |
|
161 |
if ( Koha::Holds->search( { borrowernumber => $borrowernumber, biblionumber => $biblionumber } )->count() > 0 ) { |
164 |
my $dbh = C4::Context->dbh; |
162 |
carp("AddReserve: borrower $borrowernumber already has a hold for biblionumber $biblionumber"); |
|
|
163 |
return; |
164 |
} |
165 |
|
166 |
my $dbh = C4::Context->dbh; |
167 |
|
165 |
|
168 |
$resdate = output_pref( { str => dt_from_string( $resdate ), dateonly => 1, dateformat => 'iso' }) |
166 |
$resdate = output_pref( { str => dt_from_string( $resdate ), dateonly => 1, dateformat => 'iso' }) |
169 |
or output_pref({ dt => dt_from_string, dateonly => 1, dateformat => 'iso' }); |
167 |
or output_pref({ dt => dt_from_string, dateonly => 1, dateformat => 'iso' }); |
Lines 441-447
sub CanItemBeReserved {
Link Here
|
441 |
|
439 |
|
442 |
my $dbh = C4::Context->dbh; |
440 |
my $dbh = C4::Context->dbh; |
443 |
my $ruleitemtype; # itemtype of the matching issuing rule |
441 |
my $ruleitemtype; # itemtype of the matching issuing rule |
444 |
my $allowedreserves = 0; |
442 |
my $allowedreserves = 0; # Total number of holds allowed across all records |
|
|
443 |
my $holds_per_record = 1; # Total number of holds allowed for this one given record |
445 |
|
444 |
|
446 |
# we retrieve borrowers and items informations # |
445 |
# we retrieve borrowers and items informations # |
447 |
# item->{itype} will come for biblioitems if necessery |
446 |
# item->{itype} will come for biblioitems if necessery |
Lines 454-479
sub CanItemBeReserved {
Link Here
|
454 |
if ( $item->{damaged} |
453 |
if ( $item->{damaged} |
455 |
&& !C4::Context->preference('AllowHoldsOnDamagedItems') ); |
454 |
&& !C4::Context->preference('AllowHoldsOnDamagedItems') ); |
456 |
|
455 |
|
457 |
#Check for the age restriction |
456 |
# Check for the age restriction |
458 |
my ( $ageRestriction, $daysToAgeRestriction ) = |
457 |
my ( $ageRestriction, $daysToAgeRestriction ) = |
459 |
C4::Circulation::GetAgeRestriction( $biblioData->{agerestriction}, $borrower ); |
458 |
C4::Circulation::GetAgeRestriction( $biblioData->{agerestriction}, $borrower ); |
460 |
return 'ageRestricted' if $daysToAgeRestriction && $daysToAgeRestriction > 0; |
459 |
return 'ageRestricted' if $daysToAgeRestriction && $daysToAgeRestriction > 0; |
461 |
|
460 |
|
462 |
my $controlbranch = C4::Context->preference('ReservesControlBranch'); |
461 |
# Check that the patron doesn't have an item level hold on this item already |
|
|
462 |
return 'itemAlreadyOnHold' |
463 |
if Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count(); |
463 |
|
464 |
|
464 |
# we retrieve user rights on this itemtype and branchcode |
465 |
my $controlbranch = C4::Context->preference('ReservesControlBranch'); |
465 |
my $sth = $dbh->prepare( |
|
|
466 |
q{ |
467 |
SELECT categorycode, itemtype, branchcode, reservesallowed |
468 |
FROM issuingrules |
469 |
WHERE (categorycode in (?,'*') ) |
470 |
AND (itemtype IN (?,'*')) |
471 |
AND (branchcode IN (?,'*')) |
472 |
ORDER BY categorycode DESC, |
473 |
itemtype DESC, |
474 |
branchcode DESC |
475 |
} |
476 |
); |
477 |
|
466 |
|
478 |
my $querycount = q{ |
467 |
my $querycount = q{ |
479 |
SELECT count(*) AS count |
468 |
SELECT count(*) AS count |
Lines 497-511
sub CanItemBeReserved {
Link Here
|
497 |
} |
486 |
} |
498 |
|
487 |
|
499 |
# we retrieve rights |
488 |
# we retrieve rights |
500 |
$sth->execute( $borrower->{'categorycode'}, $item->{'itype'}, $branchcode ); |
489 |
if ( my $rights = GetHoldRule( $borrower->{'categorycode'}, $item->{'itype'}, $branchcode ) ) { |
501 |
if ( my $rights = $sth->fetchrow_hashref() ) { |
490 |
$ruleitemtype = $rights->{itemtype}; |
502 |
$ruleitemtype = $rights->{itemtype}; |
491 |
$allowedreserves = $rights->{reservesallowed}; |
503 |
$allowedreserves = $rights->{reservesallowed}; |
492 |
$holds_per_record = $rights->{holds_per_record}; |
504 |
} |
493 |
} |
505 |
else { |
494 |
else { |
506 |
$ruleitemtype = '*'; |
495 |
$ruleitemtype = '*'; |
507 |
} |
496 |
} |
508 |
|
497 |
|
|
|
498 |
my $item = Koha::Items->find( $itemnumber ); |
499 |
my $holds = Koha::Holds->search( |
500 |
{ |
501 |
borrowernumber => $borrowernumber, |
502 |
biblionumber => $item->biblionumber, |
503 |
found => undef, # Found holds don't count against a patron's holds limit |
504 |
} |
505 |
); |
506 |
if ( $holds->count() >= $holds_per_record ) { |
507 |
return "tooManyHoldsForThisRecord"; |
508 |
} |
509 |
|
509 |
# we retrieve count |
510 |
# we retrieve count |
510 |
|
511 |
|
511 |
$querycount .= "AND $branchfield = ?"; |
512 |
$querycount .= "AND $branchfield = ?"; |
Lines 734-741
sub GetReservesToBranch {
Link Here
|
734 |
my $dbh = C4::Context->dbh; |
735 |
my $dbh = C4::Context->dbh; |
735 |
my $sth = $dbh->prepare( |
736 |
my $sth = $dbh->prepare( |
736 |
"SELECT reserve_id,borrowernumber,reservedate,itemnumber,timestamp |
737 |
"SELECT reserve_id,borrowernumber,reservedate,itemnumber,timestamp |
737 |
FROM reserves |
738 |
FROM reserves |
738 |
WHERE priority='0' |
739 |
WHERE priority='0' |
739 |
AND branchcode=?" |
740 |
AND branchcode=?" |
740 |
); |
741 |
); |
741 |
$sth->execute( $frombranch ); |
742 |
$sth->execute( $frombranch ); |
Lines 760-766
sub GetReservesForBranch {
Link Here
|
760 |
|
761 |
|
761 |
my $query = " |
762 |
my $query = " |
762 |
SELECT reserve_id,borrowernumber,reservedate,itemnumber,waitingdate |
763 |
SELECT reserve_id,borrowernumber,reservedate,itemnumber,waitingdate |
763 |
FROM reserves |
764 |
FROM reserves |
764 |
WHERE priority='0' |
765 |
WHERE priority='0' |
765 |
AND found='W' |
766 |
AND found='W' |
766 |
"; |
767 |
"; |
Lines 1377-1383
sub ModReserveMinusPriority {
Link Here
|
1377 |
my $dbh = C4::Context->dbh; |
1378 |
my $dbh = C4::Context->dbh; |
1378 |
my $query = " |
1379 |
my $query = " |
1379 |
UPDATE reserves |
1380 |
UPDATE reserves |
1380 |
SET priority = 0 , itemnumber = ? |
1381 |
SET priority = 0 , itemnumber = ? |
1381 |
WHERE reserve_id = ? |
1382 |
WHERE reserve_id = ? |
1382 |
"; |
1383 |
"; |
1383 |
my $sth_upd = $dbh->prepare($query); |
1384 |
my $sth_upd = $dbh->prepare($query); |
Lines 1592-1598
sub ToggleLowestPriority {
Link Here
|
1592 |
|
1593 |
|
1593 |
my $sth = $dbh->prepare( "UPDATE reserves SET lowestPriority = NOT lowestPriority WHERE reserve_id = ?"); |
1594 |
my $sth = $dbh->prepare( "UPDATE reserves SET lowestPriority = NOT lowestPriority WHERE reserve_id = ?"); |
1594 |
$sth->execute( $reserve_id ); |
1595 |
$sth->execute( $reserve_id ); |
1595 |
|
1596 |
|
1596 |
_FixPriority({ reserve_id => $reserve_id, rank => '999999' }); |
1597 |
_FixPriority({ reserve_id => $reserve_id, rank => '999999' }); |
1597 |
} |
1598 |
} |
1598 |
|
1599 |
|
Lines 1802-1808
sub _FixPriority {
Link Here
|
1802 |
$priority[$j]->{'reserve_id'} |
1803 |
$priority[$j]->{'reserve_id'} |
1803 |
); |
1804 |
); |
1804 |
} |
1805 |
} |
1805 |
|
1806 |
|
1806 |
$sth = $dbh->prepare( "SELECT reserve_id FROM reserves WHERE lowestPriority = 1 ORDER BY priority" ); |
1807 |
$sth = $dbh->prepare( "SELECT reserve_id FROM reserves WHERE lowestPriority = 1 ORDER BY priority" ); |
1807 |
$sth->execute(); |
1808 |
$sth->execute(); |
1808 |
|
1809 |
|
Lines 2017-2023
sub _koha_notify_reserve {
Link Here
|
2017 |
if (! $notification_sent) { |
2018 |
if (! $notification_sent) { |
2018 |
&$send_notification('print', 'HOLD'); |
2019 |
&$send_notification('print', 'HOLD'); |
2019 |
} |
2020 |
} |
2020 |
|
2021 |
|
2021 |
} |
2022 |
} |
2022 |
|
2023 |
|
2023 |
=head2 _ShiftPriorityByDateAndPriority |
2024 |
=head2 _ShiftPriorityByDateAndPriority |
Lines 2435-2440
sub IsItemOnHoldAndFound {
Link Here
|
2435 |
return $found; |
2436 |
return $found; |
2436 |
} |
2437 |
} |
2437 |
|
2438 |
|
|
|
2439 |
=head2 GetMaxPatronHoldsForRecord |
2440 |
|
2441 |
my $holds_per_record = ReservesControlBranch( $borrowernumber, $biblionumber ); |
2442 |
|
2443 |
For multiple holds on a given record for a given patron, the max |
2444 |
number of record level holds that a patron can be placed is the highest |
2445 |
value of the holds_per_record rule for each item if the record for that |
2446 |
patron. This subroutine finds and returns the highest holds_per_record |
2447 |
rule value for a given patron id and record id. |
2448 |
|
2449 |
=cut |
2450 |
|
2451 |
sub GetMaxPatronHoldsForRecord { |
2452 |
my ( $borrowernumber, $biblionumber ) = @_; |
2453 |
|
2454 |
my $patron = Koha::Borrowers->find($borrowernumber); |
2455 |
my @items = Koha::Items->search( { biblionumber => $biblionumber } ); |
2456 |
|
2457 |
my $controlbranch = C4::Context->preference('ReservesControlBranch'); |
2458 |
|
2459 |
my $categorycode = $patron->categorycode; |
2460 |
my $branchcode; |
2461 |
$branchcode = $patron->branchcode if ( $controlbranch eq "PatronLibrary" ); |
2462 |
|
2463 |
my $max = 0; |
2464 |
foreach my $item (@items) { |
2465 |
my $itemtype = $item->effective_itemtype(); |
2466 |
|
2467 |
$branchcode = $item->homebranch if ( $controlbranch eq "ItemHomeLibrary" ); |
2468 |
|
2469 |
my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode ); |
2470 |
my $holds_per_record = $rule ? $rule->{holds_per_record} : 0; |
2471 |
$max = $holds_per_record if $holds_per_record > $max; |
2472 |
} |
2473 |
|
2474 |
return $max; |
2475 |
} |
2476 |
|
2477 |
=head2 GetHoldRule |
2478 |
|
2479 |
my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode ); |
2480 |
|
2481 |
Returns the matching hold related issuingrule fields for a given |
2482 |
patron category, itemtype, and library. |
2483 |
|
2484 |
=cut |
2485 |
|
2486 |
sub GetHoldRule { |
2487 |
my ( $categorycode, $itemtype, $branchcode ) = @_; |
2488 |
|
2489 |
my $dbh = C4::Context->dbh; |
2490 |
|
2491 |
my $sth = $dbh->prepare( |
2492 |
q{ |
2493 |
SELECT categorycode, itemtype, branchcode, reservesallowed, holds_per_record |
2494 |
FROM issuingrules |
2495 |
WHERE (categorycode in (?,'*') ) |
2496 |
AND (itemtype IN (?,'*')) |
2497 |
AND (branchcode IN (?,'*')) |
2498 |
ORDER BY categorycode DESC, |
2499 |
itemtype DESC, |
2500 |
branchcode DESC |
2501 |
} |
2502 |
); |
2503 |
|
2504 |
$sth->execute( $categorycode, $itemtype, $branchcode ); |
2505 |
|
2506 |
return $sth->fetchrow_hashref(); |
2507 |
} |
2508 |
|
2438 |
=head1 AUTHOR |
2509 |
=head1 AUTHOR |
2439 |
|
2510 |
|
2440 |
Koha Development Team <http://koha-community.org/> |
2511 |
Koha Development Team <http://koha-community.org/> |