|
Lines 44-49
use Koha::Holds;
Link Here
|
| 44 |
use Koha::Libraries; |
44 |
use Koha::Libraries; |
| 45 |
use Koha::Items; |
45 |
use Koha::Items; |
| 46 |
use Koha::ItemTypes; |
46 |
use Koha::ItemTypes; |
|
|
47 |
use Koha::Patrons; |
| 47 |
|
48 |
|
| 48 |
use List::MoreUtils qw( firstidx any ); |
49 |
use List::MoreUtils qw( firstidx any ); |
| 49 |
use Carp; |
50 |
use Carp; |
|
Lines 143-148
BEGIN {
Link Here
|
| 143 |
&GetReservesControlBranch |
144 |
&GetReservesControlBranch |
| 144 |
|
145 |
|
| 145 |
IsItemOnHoldAndFound |
146 |
IsItemOnHoldAndFound |
|
|
147 |
|
| 148 |
GetMaxPatronHoldsForRecord |
| 146 |
); |
149 |
); |
| 147 |
@EXPORT_OK = qw( MergeHolds ); |
150 |
@EXPORT_OK = qw( MergeHolds ); |
| 148 |
} |
151 |
} |
|
Lines 170-181
sub AddReserve {
Link Here
|
| 170 |
$title, $checkitem, $found, $itemtype |
173 |
$title, $checkitem, $found, $itemtype |
| 171 |
) = @_; |
174 |
) = @_; |
| 172 |
|
175 |
|
| 173 |
if ( Koha::Holds->search( { borrowernumber => $borrowernumber, biblionumber => $biblionumber } )->count() > 0 ) { |
176 |
my $dbh = C4::Context->dbh; |
| 174 |
carp("AddReserve: borrower $borrowernumber already has a hold for biblionumber $biblionumber"); |
|
|
| 175 |
return; |
| 176 |
} |
| 177 |
|
| 178 |
my $dbh = C4::Context->dbh; |
| 179 |
|
177 |
|
| 180 |
$resdate = output_pref( { str => dt_from_string( $resdate ), dateonly => 1, dateformat => 'iso' }) |
178 |
$resdate = output_pref( { str => dt_from_string( $resdate ), dateonly => 1, dateformat => 'iso' }) |
| 181 |
or output_pref({ dt => dt_from_string, dateonly => 1, dateformat => 'iso' }); |
179 |
or output_pref({ dt => dt_from_string, dateonly => 1, dateformat => 'iso' }); |
|
Lines 464-470
sub CanItemBeReserved {
Link Here
|
| 464 |
|
462 |
|
| 465 |
my $dbh = C4::Context->dbh; |
463 |
my $dbh = C4::Context->dbh; |
| 466 |
my $ruleitemtype; # itemtype of the matching issuing rule |
464 |
my $ruleitemtype; # itemtype of the matching issuing rule |
| 467 |
my $allowedreserves = 0; |
465 |
my $allowedreserves = 0; # Total number of holds allowed across all records |
|
|
466 |
my $holds_per_record = 1; # Total number of holds allowed for this one given record |
| 468 |
|
467 |
|
| 469 |
# we retrieve borrowers and items informations # |
468 |
# we retrieve borrowers and items informations # |
| 470 |
# item->{itype} will come for biblioitems if necessery |
469 |
# item->{itype} will come for biblioitems if necessery |
|
Lines 477-502
sub CanItemBeReserved {
Link Here
|
| 477 |
if ( $item->{damaged} |
476 |
if ( $item->{damaged} |
| 478 |
&& !C4::Context->preference('AllowHoldsOnDamagedItems') ); |
477 |
&& !C4::Context->preference('AllowHoldsOnDamagedItems') ); |
| 479 |
|
478 |
|
| 480 |
#Check for the age restriction |
479 |
# Check for the age restriction |
| 481 |
my ( $ageRestriction, $daysToAgeRestriction ) = |
480 |
my ( $ageRestriction, $daysToAgeRestriction ) = |
| 482 |
C4::Circulation::GetAgeRestriction( $biblioData->{agerestriction}, $borrower ); |
481 |
C4::Circulation::GetAgeRestriction( $biblioData->{agerestriction}, $borrower ); |
| 483 |
return 'ageRestricted' if $daysToAgeRestriction && $daysToAgeRestriction > 0; |
482 |
return 'ageRestricted' if $daysToAgeRestriction && $daysToAgeRestriction > 0; |
| 484 |
|
483 |
|
| 485 |
my $controlbranch = C4::Context->preference('ReservesControlBranch'); |
484 |
# Check that the patron doesn't have an item level hold on this item already |
|
|
485 |
return 'itemAlreadyOnHold' |
| 486 |
if Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count(); |
| 486 |
|
487 |
|
| 487 |
# we retrieve user rights on this itemtype and branchcode |
488 |
my $controlbranch = C4::Context->preference('ReservesControlBranch'); |
| 488 |
my $sth = $dbh->prepare( |
|
|
| 489 |
q{ |
| 490 |
SELECT categorycode, itemtype, branchcode, reservesallowed |
| 491 |
FROM issuingrules |
| 492 |
WHERE (categorycode in (?,'*') ) |
| 493 |
AND (itemtype IN (?,'*')) |
| 494 |
AND (branchcode IN (?,'*')) |
| 495 |
ORDER BY categorycode DESC, |
| 496 |
itemtype DESC, |
| 497 |
branchcode DESC |
| 498 |
} |
| 499 |
); |
| 500 |
|
489 |
|
| 501 |
my $querycount = q{ |
490 |
my $querycount = q{ |
| 502 |
SELECT count(*) AS count |
491 |
SELECT count(*) AS count |
|
Lines 520-534
sub CanItemBeReserved {
Link Here
|
| 520 |
} |
509 |
} |
| 521 |
|
510 |
|
| 522 |
# we retrieve rights |
511 |
# we retrieve rights |
| 523 |
$sth->execute( $borrower->{'categorycode'}, $item->{'itype'}, $branchcode ); |
512 |
if ( my $rights = GetHoldRule( $borrower->{'categorycode'}, $item->{'itype'}, $branchcode ) ) { |
| 524 |
if ( my $rights = $sth->fetchrow_hashref() ) { |
513 |
$ruleitemtype = $rights->{itemtype}; |
| 525 |
$ruleitemtype = $rights->{itemtype}; |
514 |
$allowedreserves = $rights->{reservesallowed}; |
| 526 |
$allowedreserves = $rights->{reservesallowed}; |
515 |
$holds_per_record = $rights->{holds_per_record}; |
| 527 |
} |
516 |
} |
| 528 |
else { |
517 |
else { |
| 529 |
$ruleitemtype = '*'; |
518 |
$ruleitemtype = '*'; |
| 530 |
} |
519 |
} |
| 531 |
|
520 |
|
|
|
521 |
my $item = Koha::Items->find( $itemnumber ); |
| 522 |
my $holds = Koha::Holds->search( |
| 523 |
{ |
| 524 |
borrowernumber => $borrowernumber, |
| 525 |
biblionumber => $item->biblionumber, |
| 526 |
found => undef, # Found holds don't count against a patron's holds limit |
| 527 |
} |
| 528 |
); |
| 529 |
if ( $holds->count() >= $holds_per_record ) { |
| 530 |
return "tooManyHoldsForThisRecord"; |
| 531 |
} |
| 532 |
|
| 532 |
# we retrieve count |
533 |
# we retrieve count |
| 533 |
|
534 |
|
| 534 |
$querycount .= "AND $branchfield = ?"; |
535 |
$querycount .= "AND $branchfield = ?"; |
|
Lines 758-765
sub GetReservesToBranch {
Link Here
|
| 758 |
my $dbh = C4::Context->dbh; |
759 |
my $dbh = C4::Context->dbh; |
| 759 |
my $sth = $dbh->prepare( |
760 |
my $sth = $dbh->prepare( |
| 760 |
"SELECT reserve_id,borrowernumber,reservedate,itemnumber,timestamp |
761 |
"SELECT reserve_id,borrowernumber,reservedate,itemnumber,timestamp |
| 761 |
FROM reserves |
762 |
FROM reserves |
| 762 |
WHERE priority='0' |
763 |
WHERE priority='0' |
| 763 |
AND branchcode=?" |
764 |
AND branchcode=?" |
| 764 |
); |
765 |
); |
| 765 |
$sth->execute( $frombranch ); |
766 |
$sth->execute( $frombranch ); |
|
Lines 784-790
sub GetReservesForBranch {
Link Here
|
| 784 |
|
785 |
|
| 785 |
my $query = " |
786 |
my $query = " |
| 786 |
SELECT reserve_id,borrowernumber,reservedate,itemnumber,waitingdate |
787 |
SELECT reserve_id,borrowernumber,reservedate,itemnumber,waitingdate |
| 787 |
FROM reserves |
788 |
FROM reserves |
| 788 |
WHERE priority='0' |
789 |
WHERE priority='0' |
| 789 |
AND found='W' |
790 |
AND found='W' |
| 790 |
"; |
791 |
"; |
|
Lines 1414-1420
sub ModReserveMinusPriority {
Link Here
|
| 1414 |
my $dbh = C4::Context->dbh; |
1415 |
my $dbh = C4::Context->dbh; |
| 1415 |
my $query = " |
1416 |
my $query = " |
| 1416 |
UPDATE reserves |
1417 |
UPDATE reserves |
| 1417 |
SET priority = 0 , itemnumber = ? |
1418 |
SET priority = 0 , itemnumber = ? |
| 1418 |
WHERE reserve_id = ? |
1419 |
WHERE reserve_id = ? |
| 1419 |
"; |
1420 |
"; |
| 1420 |
my $sth_upd = $dbh->prepare($query); |
1421 |
my $sth_upd = $dbh->prepare($query); |
|
Lines 1651-1657
sub ToggleLowestPriority {
Link Here
|
| 1651 |
|
1652 |
|
| 1652 |
my $sth = $dbh->prepare( "UPDATE reserves SET lowestPriority = NOT lowestPriority WHERE reserve_id = ?"); |
1653 |
my $sth = $dbh->prepare( "UPDATE reserves SET lowestPriority = NOT lowestPriority WHERE reserve_id = ?"); |
| 1653 |
$sth->execute( $reserve_id ); |
1654 |
$sth->execute( $reserve_id ); |
| 1654 |
|
1655 |
|
| 1655 |
_FixPriority({ reserve_id => $reserve_id, rank => '999999' }); |
1656 |
_FixPriority({ reserve_id => $reserve_id, rank => '999999' }); |
| 1656 |
} |
1657 |
} |
| 1657 |
|
1658 |
|
|
Lines 1835-1841
sub _FixPriority {
Link Here
|
| 1835 |
$priority[$j]->{'reserve_id'} |
1836 |
$priority[$j]->{'reserve_id'} |
| 1836 |
); |
1837 |
); |
| 1837 |
} |
1838 |
} |
| 1838 |
|
1839 |
|
| 1839 |
$sth = $dbh->prepare( "SELECT reserve_id FROM reserves WHERE lowestPriority = 1 ORDER BY priority" ); |
1840 |
$sth = $dbh->prepare( "SELECT reserve_id FROM reserves WHERE lowestPriority = 1 ORDER BY priority" ); |
| 1840 |
$sth->execute(); |
1841 |
$sth->execute(); |
| 1841 |
|
1842 |
|
|
Lines 2073-2079
sub _koha_notify_reserve {
Link Here
|
| 2073 |
if (! $notification_sent) { |
2074 |
if (! $notification_sent) { |
| 2074 |
&$send_notification('print', 'HOLD'); |
2075 |
&$send_notification('print', 'HOLD'); |
| 2075 |
} |
2076 |
} |
| 2076 |
|
2077 |
|
| 2077 |
} |
2078 |
} |
| 2078 |
|
2079 |
|
| 2079 |
=head2 _ShiftPriorityByDateAndPriority |
2080 |
=head2 _ShiftPriorityByDateAndPriority |
|
Lines 2502-2507
sub IsItemOnHoldAndFound {
Link Here
|
| 2502 |
return $found; |
2503 |
return $found; |
| 2503 |
} |
2504 |
} |
| 2504 |
|
2505 |
|
|
|
2506 |
=head2 GetMaxPatronHoldsForRecord |
| 2507 |
|
| 2508 |
my $holds_per_record = ReservesControlBranch( $borrowernumber, $biblionumber ); |
| 2509 |
|
| 2510 |
For multiple holds on a given record for a given patron, the max |
| 2511 |
number of record level holds that a patron can be placed is the highest |
| 2512 |
value of the holds_per_record rule for each item if the record for that |
| 2513 |
patron. This subroutine finds and returns the highest holds_per_record |
| 2514 |
rule value for a given patron id and record id. |
| 2515 |
|
| 2516 |
=cut |
| 2517 |
|
| 2518 |
sub GetMaxPatronHoldsForRecord { |
| 2519 |
my ( $borrowernumber, $biblionumber ) = @_; |
| 2520 |
|
| 2521 |
my $patron = Koha::Patrons->find($borrowernumber); |
| 2522 |
my @items = Koha::Items->search( { biblionumber => $biblionumber } ); |
| 2523 |
|
| 2524 |
my $controlbranch = C4::Context->preference('ReservesControlBranch'); |
| 2525 |
|
| 2526 |
my $categorycode = $patron->categorycode; |
| 2527 |
my $branchcode; |
| 2528 |
$branchcode = $patron->branchcode if ( $controlbranch eq "PatronLibrary" ); |
| 2529 |
|
| 2530 |
my $max = 0; |
| 2531 |
foreach my $item (@items) { |
| 2532 |
my $itemtype = $item->effective_itemtype(); |
| 2533 |
|
| 2534 |
$branchcode = $item->homebranch if ( $controlbranch eq "ItemHomeLibrary" ); |
| 2535 |
|
| 2536 |
my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode ); |
| 2537 |
my $holds_per_record = $rule ? $rule->{holds_per_record} : 0; |
| 2538 |
$max = $holds_per_record if $holds_per_record > $max; |
| 2539 |
} |
| 2540 |
|
| 2541 |
return $max; |
| 2542 |
} |
| 2543 |
|
| 2544 |
=head2 GetHoldRule |
| 2545 |
|
| 2546 |
my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode ); |
| 2547 |
|
| 2548 |
Returns the matching hold related issuingrule fields for a given |
| 2549 |
patron category, itemtype, and library. |
| 2550 |
|
| 2551 |
=cut |
| 2552 |
|
| 2553 |
sub GetHoldRule { |
| 2554 |
my ( $categorycode, $itemtype, $branchcode ) = @_; |
| 2555 |
|
| 2556 |
my $dbh = C4::Context->dbh; |
| 2557 |
|
| 2558 |
my $sth = $dbh->prepare( |
| 2559 |
q{ |
| 2560 |
SELECT categorycode, itemtype, branchcode, reservesallowed, holds_per_record |
| 2561 |
FROM issuingrules |
| 2562 |
WHERE (categorycode in (?,'*') ) |
| 2563 |
AND (itemtype IN (?,'*')) |
| 2564 |
AND (branchcode IN (?,'*')) |
| 2565 |
ORDER BY categorycode DESC, |
| 2566 |
itemtype DESC, |
| 2567 |
branchcode DESC |
| 2568 |
} |
| 2569 |
); |
| 2570 |
|
| 2571 |
$sth->execute( $categorycode, $itemtype, $branchcode ); |
| 2572 |
|
| 2573 |
return $sth->fetchrow_hashref(); |
| 2574 |
} |
| 2575 |
|
| 2505 |
=head1 AUTHOR |
2576 |
=head1 AUTHOR |
| 2506 |
|
2577 |
|
| 2507 |
Koha Development Team <http://koha-community.org/> |
2578 |
Koha Development Team <http://koha-community.org/> |