Bugzilla – Attachment 48798 Details for
Bug 14695
Add ability to place multiple item holds on a given record per patron
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 14695 - Add ability to place multiple item holds on a given record per patron
Bug-14695---Add-ability-to-place-multiple-item-hol.patch (text/plain), 30.30 KB, created by
Kyle M Hall (khall)
on 2016-03-08 16:08:44 UTC
(
hide
)
Description:
Bug 14695 - Add ability to place multiple item holds on a given record per patron
Filename:
MIME Type:
Creator:
Kyle M Hall (khall)
Created:
2016-03-08 16:08:44 UTC
Size:
30.30 KB
patch
obsolete
>From 9926f5640bf270a055d1068026dabc786b3d8f71 Mon Sep 17 00:00:00 2001 >From: Kyle M Hall <kyle@bywatersolutions.com> >Date: Tue, 29 Dec 2015 19:14:19 +0000 >Subject: [PATCH] Bug 14695 - Add ability to place multiple item holds on a > given record per patron > >Signed-off-by: Nick Clemens <nick@bywatersolutions.com> >--- > C4/Reserves.pm | 137 ++++++++++++++++----- > Koha/Holds.pm | 32 +++++ > .../prog/en/modules/reserve/request.tt | 117 ++++++++++++------ > opac/opac-reserve.pl | 44 ++++--- > reserve/placerequest.pl | 68 +++++----- > reserve/request.pl | 75 ++++++----- > 6 files changed, 322 insertions(+), 151 deletions(-) > >diff --git a/C4/Reserves.pm b/C4/Reserves.pm >index fc14ffe..2790edf 100644 >--- a/C4/Reserves.pm >+++ b/C4/Reserves.pm >@@ -41,6 +41,7 @@ use Koha::Database; > use Koha::Hold; > use Koha::Holds; > use Koha::Libraries; >+use Koha::Patrons; > > use List::MoreUtils qw( firstidx any ); > use Carp; >@@ -141,6 +142,8 @@ BEGIN { > &GetReservesControlBranch > > IsItemOnHoldAndFound >+ >+ GetMaxPatronHoldsForRecord > ); > @EXPORT_OK = qw( MergeHolds ); > } >@@ -168,12 +171,7 @@ sub AddReserve { > $title, $checkitem, $found > ) = @_; > >- if ( Koha::Holds->search( { borrowernumber => $borrowernumber, biblionumber => $biblionumber } )->count() > 0 ) { >- carp("AddReserve: borrower $borrowernumber already has a hold for biblionumber $biblionumber"); >- return; >- } >- >- my $dbh = C4::Context->dbh; >+ my $dbh = C4::Context->dbh; > > $resdate = output_pref( { str => dt_from_string( $resdate ), dateonly => 1, dateformat => 'iso' }) > or output_pref({ dt => dt_from_string, dateonly => 1, dateformat => 'iso' }); >@@ -453,7 +451,8 @@ sub CanItemBeReserved { > > my $dbh = C4::Context->dbh; > my $ruleitemtype; # itemtype of the matching issuing rule >- my $allowedreserves = 0; >+ my $allowedreserves = 0; # Total number of holds allowed across all records >+ my $holds_per_record = 1; # Total number of holds allowed for this one given record > > # we retrieve borrowers and items informations # > # item->{itype} will come for biblioitems if necessery >@@ -466,26 +465,16 @@ sub CanItemBeReserved { > if ( $item->{damaged} > && !C4::Context->preference('AllowHoldsOnDamagedItems') ); > >- #Check for the age restriction >+ # Check for the age restriction > my ( $ageRestriction, $daysToAgeRestriction ) = > C4::Circulation::GetAgeRestriction( $biblioData->{agerestriction}, $borrower ); > return 'ageRestricted' if $daysToAgeRestriction && $daysToAgeRestriction > 0; > >- my $controlbranch = C4::Context->preference('ReservesControlBranch'); >+ # Check that the patron doesn't have an item level hold on this item already >+ return 'itemAlreadyOnHold' >+ if Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count(); > >- # we retrieve user rights on this itemtype and branchcode >- my $sth = $dbh->prepare( >- q{ >- SELECT categorycode, itemtype, branchcode, reservesallowed >- FROM issuingrules >- WHERE (categorycode in (?,'*') ) >- AND (itemtype IN (?,'*')) >- AND (branchcode IN (?,'*')) >- ORDER BY categorycode DESC, >- itemtype DESC, >- branchcode DESC >- } >- ); >+ my $controlbranch = C4::Context->preference('ReservesControlBranch'); > > my $querycount = q{ > SELECT count(*) AS count >@@ -509,15 +498,27 @@ sub CanItemBeReserved { > } > > # we retrieve rights >- $sth->execute( $borrower->{'categorycode'}, $item->{'itype'}, $branchcode ); >- if ( my $rights = $sth->fetchrow_hashref() ) { >- $ruleitemtype = $rights->{itemtype}; >- $allowedreserves = $rights->{reservesallowed}; >+ if ( my $rights = GetHoldRule( $borrower->{'categorycode'}, $item->{'itype'}, $branchcode ) ) { >+ $ruleitemtype = $rights->{itemtype}; >+ $allowedreserves = $rights->{reservesallowed}; >+ $holds_per_record = $rights->{holds_per_record}; > } > else { > $ruleitemtype = '*'; > } > >+ my $item = Koha::Items->find( $itemnumber ); >+ my $holds = Koha::Holds->search( >+ { >+ borrowernumber => $borrowernumber, >+ biblionumber => $item->biblionumber, >+ found => undef, # Found holds don't count against a patron's holds limit >+ } >+ ); >+ if ( $holds->count() >= $holds_per_record ) { >+ return "tooManyHoldsForThisRecord"; >+ } >+ > # we retrieve count > > $querycount .= "AND $branchfield = ?"; >@@ -747,8 +748,8 @@ sub GetReservesToBranch { > my $dbh = C4::Context->dbh; > my $sth = $dbh->prepare( > "SELECT reserve_id,borrowernumber,reservedate,itemnumber,timestamp >- FROM reserves >- WHERE priority='0' >+ FROM reserves >+ WHERE priority='0' > AND branchcode=?" > ); > $sth->execute( $frombranch ); >@@ -773,7 +774,7 @@ sub GetReservesForBranch { > > my $query = " > SELECT reserve_id,borrowernumber,reservedate,itemnumber,waitingdate >- FROM reserves >+ FROM reserves > WHERE priority='0' > AND found='W' > "; >@@ -1395,7 +1396,7 @@ sub ModReserveMinusPriority { > my $dbh = C4::Context->dbh; > my $query = " > UPDATE reserves >- SET priority = 0 , itemnumber = ? >+ SET priority = 0 , itemnumber = ? > WHERE reserve_id = ? > "; > my $sth_upd = $dbh->prepare($query); >@@ -1610,7 +1611,7 @@ sub ToggleLowestPriority { > > my $sth = $dbh->prepare( "UPDATE reserves SET lowestPriority = NOT lowestPriority WHERE reserve_id = ?"); > $sth->execute( $reserve_id ); >- >+ > _FixPriority({ reserve_id => $reserve_id, rank => '999999' }); > } > >@@ -1794,7 +1795,7 @@ sub _FixPriority { > $priority[$j]->{'reserve_id'} > ); > } >- >+ > $sth = $dbh->prepare( "SELECT reserve_id FROM reserves WHERE lowestPriority = 1 ORDER BY priority" ); > $sth->execute(); > >@@ -2029,7 +2030,7 @@ sub _koha_notify_reserve { > if (! $notification_sent) { > &$send_notification('print', 'HOLD'); > } >- >+ > } > > =head2 _ShiftPriorityByDateAndPriority >@@ -2458,6 +2459,76 @@ sub IsItemOnHoldAndFound { > return $found; > } > >+=head2 GetMaxPatronHoldsForRecord >+ >+my $holds_per_record = ReservesControlBranch( $borrowernumber, $biblionumber ); >+ >+For multiple holds on a given record for a given patron, the max >+number of record level holds that a patron can be placed is the highest >+value of the holds_per_record rule for each item if the record for that >+patron. This subroutine finds and returns the highest holds_per_record >+rule value for a given patron id and record id. >+ >+=cut >+ >+sub GetMaxPatronHoldsForRecord { >+ my ( $borrowernumber, $biblionumber ) = @_; >+ >+ my $patron = Koha::Patrons->find($borrowernumber); >+ my @items = Koha::Items->search( { biblionumber => $biblionumber } ); >+ >+ my $controlbranch = C4::Context->preference('ReservesControlBranch'); >+ >+ my $categorycode = $patron->categorycode; >+ my $branchcode; >+ $branchcode = $patron->branchcode if ( $controlbranch eq "PatronLibrary" ); >+ >+ my $max = 0; >+ foreach my $item (@items) { >+ my $itemtype = $item->effective_itemtype(); >+ >+ $branchcode = $item->homebranch if ( $controlbranch eq "ItemHomeLibrary" ); >+ >+ my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode ); >+ my $holds_per_record = $rule ? $rule->{holds_per_record} : 0; >+ $max = $holds_per_record if $holds_per_record > $max; >+ } >+ >+ return $max; >+} >+ >+=head2 GetHoldRule >+ >+my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode ); >+ >+Returns the matching hold related issuingrule fields for a given >+patron category, itemtype, and library. >+ >+=cut >+ >+sub GetHoldRule { >+ my ( $categorycode, $itemtype, $branchcode ) = @_; >+ >+ my $dbh = C4::Context->dbh; >+ >+ my $sth = $dbh->prepare( >+ q{ >+ SELECT categorycode, itemtype, branchcode, reservesallowed, holds_per_record >+ FROM issuingrules >+ WHERE (categorycode in (?,'*') ) >+ AND (itemtype IN (?,'*')) >+ AND (branchcode IN (?,'*')) >+ ORDER BY categorycode DESC, >+ itemtype DESC, >+ branchcode DESC >+ } >+ ); >+ >+ $sth->execute( $categorycode, $itemtype, $branchcode ); >+ >+ return $sth->fetchrow_hashref(); >+} >+ > =head1 AUTHOR > > Koha Development Team <http://koha-community.org/> >diff --git a/Koha/Holds.pm b/Koha/Holds.pm >index d1d8b29..b5c24aa 100644 >--- a/Koha/Holds.pm >+++ b/Koha/Holds.pm >@@ -49,6 +49,38 @@ sub waiting { > return $self->search( { found => 'W' } ); > } > >+=head3 forced_hold_level >+ >+If a patron has multiple holds for a single record, >+those holds must be either all record level holds, >+or they must all be item level holds. >+ >+This method should be used with Hold sets where all >+Hold objects share the same patron and record. >+ >+This method will return 'item' if the patron has >+at least one item level hold. It will return 'record' >+if the patron has holds but none are item level, >+Finally, if the patron has no holds, it will return >+undef which indicateds the patron may select either >+record or item level holds, barring any other rules >+that would prevent one or the other. >+=cut >+ >+sub forced_hold_level { >+ my ($self) = @_; >+ >+ my $force_hold_level; >+ >+ if ( $self->count() ) { >+ my $has_item_level_holds; >+ map { $has_item_level_holds ||= $_->itemnumber } $self->as_list(); >+ $force_hold_level = $has_item_level_holds ? 'item' : 'record'; >+ } >+ >+ return $force_hold_level; >+} >+ > =head3 type > > =cut >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt >index 473cfb4..6814dc6 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt >@@ -61,49 +61,39 @@ $(document).ready(function() { > }); > > function check() { >- var msg = ""; >- var count_reserv = 0; >- var alreadyreserved = 0; >+ var msg = ""; >+ var count_reserv = 0; > > // check if we have checkitem form > if (document.form.checkitem){ > for (i=0;i<document.form.checkitem.length;i++){ > if (document.form.checkitem[i].checked == true) { >- count_reserv++ ; >- } >+ count_reserv++ ; >+ } > } > // for only one item, check the checkitem without consider the loop checkitem > if (i==0){ >- if (document.form.checkitem.checked == true) { >- count_reserv++; >- } >- } >- } >- >- if (document.form.request.checked == true){ >- count_reserv++ ; >+ if (document.form.checkitem.checked == true) { >+ count_reserv++; >+ } >+ } > } > >- if (document.form.alreadyreserved && document.form.alreadyreserved.value == "1"){ >- alreadyreserved++ ; >+ if (document.form.requestany.checked == true){ >+ count_reserv++ ; > } > > if (count_reserv == "0"){ >- msg += (_("- Please select an item to place a hold") + "\n"); >- } >- if (count_reserv >= "2"){ >- msg += (_("- You may only place a hold on one item at a time") + "\n"); >+ msg += (_("- Please select an item to place a hold") + "\n"); > } > >- if (alreadyreserved > "0"){ >- msg += (_("- This patron had already placed a hold on this item") + "\n" + _("Please cancel the previous hold first") + "\n"); >+ if (msg == "") { >+ $('#hold-request-form').preventDoubleFormSubmit(); >+ return(true); >+ } else { >+ alert(msg); >+ return(false); > } >- >- if (msg == "") return(true); >- else { >- alert(msg); >- return(false); >- } > } > > function checkMultiHold() { >@@ -129,6 +119,8 @@ function checkMultiHold() { > $("#multi_hold_bibs").val(biblionumbers); > $("#bad_bibs").val(badBibs); > >+ $('#hold-request-form').preventDoubleFormSubmit(); >+ > return true; > } > >@@ -176,7 +168,6 @@ function checkMultiHold() { > $("#" + fieldID).val(""); > }); > >- $('#hold-request-form').preventDoubleFormSubmit(); > > [% UNLESS ( borrowernumber || borrowers || noitems ) %] > [% IF ( CircAutocompl ) %] >@@ -308,7 +299,7 @@ function checkMultiHold() { > [% IF ( exceeded_maxreserves ) %] > <li><strong>Too many holds: </strong> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %] </a> can only place a maximum of [% maxreserves %] total holds.</li> > [% ELSIF ( alreadypossession ) %] >- <li> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>is already in possession</strong> of one item</li> >+ <li> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>is already in possession</strong> of one item</lie > [% ELSIF ( alreadyreserved ) %] > <li><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>already has a hold</strong> on this item </li> > [% ELSIF ( ageRestricted ) %] >@@ -425,11 +416,34 @@ function checkMultiHold() { > </li> > > [% UNLESS ( multi_hold ) %] >- <li> <label for="requestany">Place a hold on the next available item </label> >- <input type="checkbox" id="requestany" name="request" checked="checked" value="Any" /> >+ <li> <label for="requestany">Hold next available item </label> >+ [% IF force_hold_level == 'item' %] >+ <input type="checkbox" id="requestany" name="request" disabled="true" /> >+ [% ELSIF force_hold_level == 'record' %] >+ <input type="checkbox" id="requestany" checked="checked" value="Any" disabled="true"/> >+ <input type="hidden" name="request" value="Any"/> >+ [% ELSE %] >+ <input type="checkbox" id="requestany" name="request" checked="checked" value="Any" /> >+ [% END %] > <input type="hidden" name="biblioitem" value="[% biblioitemnumber %]" /> > <input type="hidden" name="alreadyreserved" value="[% alreadyreserved %]" /> > </li> >+ >+ [% IF max_holds_for_record > 1 %] >+ [% SET count = 1 %] >+ <li> >+ <label for="holds_to_place_count">Holds to place (count)</label> >+ <select name="holds_to_place_count" id="holds_to_place_count"> >+ [% WHILE count <= max_holds_for_record %] >+ <option value="[% count %]">[% count %]</option> >+ [% SET count = count + 1 %] >+ [% END %] >+ >+ </select> >+ </li> >+ [% ELSE %] >+ <input type="hidden" name="holds_to_place_count" value="1"; >+ [% END %] > [% END %] > > </ol> >@@ -454,7 +468,12 @@ function checkMultiHold() { > [% IF ( bibitemloo.publicationyear ) %]<li><span class="label">Publication year:</span> [% bibitemloo.publicationyear %]</li>[% END %] > </ol> > >- <h2 style="padding: 0 1em;">Place a hold on a specific item</h2> >+ <h2 style="padding: 0 1em;"> >+ Place a hold on a specific item >+ [% IF bibitemloo.force_hold_level == 'item' %] >+ <span class="error"><i>(Required)</i></span> >+ [% END %] >+ </h2> > <table id="requestspecific"> > <thead> > <tr> >@@ -474,18 +493,44 @@ function checkMultiHold() { > </tr> > </thead> > <tbody> >+ [% SET selected = 0 %] > [% FOREACH itemloo IN bibitemloo.itemloop %] > [% UNLESS ( itemloo.hide ) %] > <tr class="[% itemloo.backgroundcolor %]"> > <td> >- [% IF ( itemloo.available ) %] >+ [% IF itemloo.force_hold_level == 'record' # Patron has placed a record level hold previously for this record %] >+ <span class="error"> >+ <i class="fa fa-times fa-lg" alt="Cannot be put on hold"></i> >+ Hold must be record level >+ </span> >+ [% ELSIF ( itemloo.available ) %] > <input type="radio" name="checkitem" value="[% itemloo.itemnumber %]" /> > [% ELSIF ( itemloo.override ) %] > <input type="radio" name="checkitem" class="needsoverride" value="[% itemloo.itemnumber %]" /> >- <img src="[% interface %]/[% theme %]/img/famfamfam/silk/error.png" alt="Requires override of hold policy" /> >+ <i class="fa fa-exclamation-triangle fa-lg" style="color:gold" alt="Requires override of hold policy"/></i> > [% ELSE %] >- <input disabled="disabled" type="radio" name="checkitem" value="[% itemloo.itemnumber %]" /> >- <img src="[% interface %]/[% theme %]/img/famfamfam/silk/cross.png" alt="Cannot be put on hold" /> >+ <span class="error"> >+ <i class="fa fa-times fa-lg" alt="Cannot be put on hold"></i> >+ [% IF itemloo.not_holdable %] >+ [% IF itemloo.not_holdable == 'damaged' %] >+ Item damaged >+ [% ELSIF itemloo.not_holdable == 'ageRestricted' %] >+ Age restricted >+ [% ELSIF itemloo.not_holdable == 'tooManyHoldsForThisRecord' %] >+ Exceeded max holds per record >+ [% ELSIF itemloo.not_holdable == 'tooManyReserves' %] >+ Too many holds >+ [% ELSIF itemloo.not_holdable == 'notReservable' %] >+ Not holdable >+ [% ELSIF itemloo.not_holdable == 'cannotReserveFromOtherBranches' %] >+ Patron is from different library >+ [% ELSIF itemloo.not_holdable == 'itemAlreadyOnHold' %] >+ Patron already has hold for this item >+ [% ELSE %] >+ [% itemloo.not_holdable %] >+ [% END %] >+ [% END %] >+ </span> > [% END %] > </td> > [% IF ( item_level_itypes ) %] >diff --git a/opac/opac-reserve.pl b/opac/opac-reserve.pl >index 0f753d8..4e1e93f 100755 >--- a/opac/opac-reserve.pl >+++ b/opac/opac-reserve.pl >@@ -357,17 +357,6 @@ unless ( $noreserves ) { > } > } > >-foreach my $res (@reserves) { >- foreach my $biblionumber (@biblionumbers) { >- if ( $res->{'biblionumber'} == $biblionumber && $res->{'borrowernumber'} == $borrowernumber) { >-# $template->param( message => 1 ); >-# $noreserves = 1; >-# $template->param( already_reserved => 1 ); >- $biblioDataHash{$biblionumber}->{already_reserved} = 1; >- } >- } >-} >- > unless ($noreserves) { > $template->param( select_item_types => 1 ); > } >@@ -465,9 +454,6 @@ foreach my $biblioNum (@biblionumbers) { > > # the item could be reserved for this borrower vi a host record, flag this > $reservedfor //= ''; >- if ($reservedfor eq $borrowernumber){ >- $itemLoopIter->{already_reserved} = 1; >- } > > if ( defined $reservedate ) { > $itemLoopIter->{backgroundcolor} = 'reserved'; >@@ -512,12 +498,12 @@ foreach my $biblioNum (@biblionumbers) { > $itemLoopIter->{nocancel} = 1; > } > >- # if the items belongs to a host record, show link to host record >- if ($itemInfo->{biblionumber} ne $biblioNum){ >- $biblioLoopIter{hostitemsflag} = 1; >- $itemLoopIter->{hostbiblionumber} = $itemInfo->{biblionumber}; >- $itemLoopIter->{hosttitle} = GetBiblioData($itemInfo->{biblionumber})->{title}; >- } >+ # if the items belongs to a host record, show link to host record >+ if ( $itemInfo->{biblionumber} ne $biblioNum ) { >+ $biblioLoopIter{hostitemsflag} = 1; >+ $itemLoopIter->{hostbiblionumber} = $itemInfo->{biblionumber}; >+ $itemLoopIter->{hosttitle} = GetBiblioData( $itemInfo->{biblionumber} )->{title}; >+ } > > # If there is no loan, return and transfer, we show a checkbox. > $itemLoopIter->{notforloan} = $itemLoopIter->{notforloan} || 0; >@@ -566,6 +552,24 @@ foreach my $biblioNum (@biblionumbers) { > > $biblioLoopIter{holdable} &&= CanBookBeReserved($borrowernumber,$biblioNum) eq 'OK'; > >+ # For multiple holds per record, if a patron has previously placed a hold, >+ # the patron can only place more holds of the same type. That is, if the >+ # patron placed a record level hold, all the holds the patron places must >+ # be record level. If the patron placed an item level hold, all holds >+ # the patron places must be item level >+ my $forced_hold_level = Koha::Holds->search( >+ { >+ borrowernumber => $borrowernumber, >+ biblionumber => $biblioNum, >+ found => undef, >+ } >+ )->forced_hold_level(); >+ if ($forced_hold_level) { >+ $biblioLoopIter{force_hold} = 1 if $forced_hold_level eq 'item'; >+ $biblioLoopIter{itemholdable} = 0 if $forced_hold_level eq 'record'; >+ } >+ >+ > push @$biblioLoop, \%biblioLoopIter; > > $anyholdable = 1 if $biblioLoopIter{holdable}; >diff --git a/reserve/placerequest.pl b/reserve/placerequest.pl >index 28e8868..411c31b 100755 >--- a/reserve/placerequest.pl >+++ b/reserve/placerequest.pl >@@ -54,6 +54,7 @@ my $expirationdate = $input->param('expiration_date'); > my $multi_hold = $input->param('multi_hold'); > my $biblionumbers = $multi_hold ? $input->param('biblionumbers') : ($biblionumber . '/'); > my $bad_bibs = $input->param('bad_bibs'); >+my $holds_to_place_count = $input->param('holds_to_place_count') || 1; > > my %bibinfos = (); > my @biblionumbers = split '/', $biblionumbers; >@@ -77,38 +78,42 @@ if (defined $checkitem && $checkitem ne ''){ > } > } > >-if ($type eq 'str8' && $borrower){ >+if ( $type eq 'str8' && $borrower ) { > >- foreach my $biblionumber (keys %bibinfos) { >- my $count=@bibitems; >- @bibitems=sort @bibitems; >- my $i2=1; >+ foreach my $biblionumber ( keys %bibinfos ) { >+ my $count = @bibitems; >+ @bibitems = sort @bibitems; >+ my $i2 = 1; > my @realbi; >- $realbi[0]=$bibitems[0]; >- for (my $i=1;$i<$count;$i++) { >- my $i3=$i2-1; >- if ($realbi[$i3] ne $bibitems[$i]) { >- $realbi[$i2]=$bibitems[$i]; >+ $realbi[0] = $bibitems[0]; >+ for ( my $i = 1 ; $i < $count ; $i++ ) { >+ my $i3 = $i2 - 1; >+ if ( $realbi[$i3] ne $bibitems[$i] ) { >+ $realbi[$i2] = $bibitems[$i]; > $i2++; > } > } > >- if (defined $checkitem && $checkitem ne ''){ >- my $item = GetItem($checkitem); >- if ($item->{'biblionumber'} ne $biblionumber) { >- $biblionumber = $item->{'biblionumber'}; >- } >- } >- >- >+ if ( defined $checkitem && $checkitem ne '' ) { >+ my $item = GetItem($checkitem); >+ if ( $item->{'biblionumber'} ne $biblionumber ) { >+ $biblionumber = $item->{'biblionumber'}; >+ } >+ } > > if ($multi_hold) { > my $bibinfo = $bibinfos{$biblionumber}; >- AddReserve($branch,$borrower->{'borrowernumber'},$biblionumber,[$biblionumber], >- $bibinfo->{rank},$startdate,$expirationdate,$notes,$bibinfo->{title},$checkitem,$found); >- } else { >- # place a request on 1st available >- AddReserve($branch,$borrower->{'borrowernumber'},$biblionumber,\@realbi,$rank[0],$startdate,$expirationdate,$notes,$title,$checkitem,$found); >+ AddReserve( $branch, $borrower->{'borrowernumber'}, >+ $biblionumber, [$biblionumber], >+ $bibinfo->{rank}, $startdate, $expirationdate, $notes, $bibinfo->{title}, $checkitem, >+ $found ); >+ } >+ else { >+ for ( my $i = 0 ; $i < $holds_to_place_count ; $i++ ) { >+ AddReserve( $branch, $borrower->{'borrowernumber'}, >+ $biblionumber, \@realbi, $rank[0], $startdate, $expirationdate, $notes, $title, >+ $checkitem, $found ); >+ } > } > } > >@@ -117,13 +122,16 @@ if ($type eq 'str8' && $borrower){ > $biblionumbers .= $bad_bibs; > } > print $input->redirect("request.pl?biblionumbers=$biblionumbers&multi_hold=1"); >- } else { >+ } >+ else { > print $input->redirect("request.pl?biblionumber=$biblionumber"); > } >-} elsif ($borrower eq ''){ >- print $input->header(); >- print "Invalid borrower number please try again"; >-# Not sure that Dump() does HTML escaping. Use firebug or something to trace >-# instead. >-# print $input->Dump; >+} >+elsif ( $borrower eq '' ) { >+ print $input->header(); >+ print "Invalid borrower number please try again"; >+ >+ # Not sure that Dump() does HTML escaping. Use firebug or something to trace >+ # instead. >+ # print $input->Dump; > } >diff --git a/reserve/request.pl b/reserve/request.pl >index 970596f..be28af3 100755 >--- a/reserve/request.pl >+++ b/reserve/request.pl >@@ -26,8 +26,8 @@ script to place reserves/requests > > =cut > >-use strict; >-use warnings; >+use Modern::Perl; >+ > use C4::Branch; > use CGI qw ( -utf8 ); > use List::MoreUtils qw/uniq/; >@@ -234,38 +234,44 @@ foreach my $biblionumber (@biblionumbers) { > $biblioloopiter{$canReserve} = 1; > } > >- my $alreadypossession; >- if (not C4::Context->preference('AllowHoldsOnPatronsPossessions') and CheckIfIssuedToPatron($borrowerinfo->{borrowernumber},$biblionumber)) { >- $alreadypossession = 1; >+ my $force_hold_level; >+ if ( $borrowerinfo->{borrowernumber} ) { >+ # For multiple holds per record, if a patron has previously placed a hold, >+ # the patron can only place more holds of the same type. That is, if the >+ # patron placed a record level hold, all the holds the patron places must >+ # be record level. If the patron placed an item level hold, all holds >+ # the patron places must be item level >+ my $holds = Koha::Holds->search( >+ { >+ borrowernumber => $borrowerinfo->{borrowernumber}, >+ biblionumber => $biblionumber, >+ found => undef, >+ } >+ ); >+ $force_hold_level = $holds->forced_hold_level(); >+ $biblioloopiter{force_hold_level} = $force_hold_level; >+ $template->param( force_hold_level => $force_hold_level ); >+ >+ # For a librarian to be able to place multiple record holds for a patron for a record, >+ # we must find out what the maximum number of holds they can place for the patron is >+ my $max_holds_for_record = GetMaxPatronHoldsForRecord( $borrowerinfo->{borrowernumber}, $biblionumber ); >+ $max_holds_for_record = $max_holds_for_record - $holds->count(); >+ $biblioloopiter{max_holds_for_record} = $max_holds_for_record; >+ $template->param( max_holds_for_record => $max_holds_for_record ); > } > >- # get existing reserves ..... >- my $reserves = GetReservesFromBiblionumber({ biblionumber => $biblionumber, all_dates => 1 }); >- my $count = scalar( @$reserves ); >- my $totalcount = $count; >- my $holds_count = 0; >- my $alreadyreserved = 0; >- >- foreach my $res (@$reserves) { >- if ( defined $res->{found} ) { # found can be 'W' or 'T' >- $count--; >- } >- >- if ( defined $borrowerinfo && defined($borrowerinfo->{borrowernumber}) && ($borrowerinfo->{borrowernumber} eq $res->{borrowernumber}) ) { >- $holds_count++; >- } >+ # Check to see if patron is allowed to place holds on records where the >+ # patron already has an item from that record checked out >+ my $alreadypossession; >+ if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions') >+ && CheckIfIssuedToPatron( $borrowerinfo->{borrowernumber}, $biblionumber ) ) >+ { >+ $template->param( alreadypossession => $alreadypossession, ); > } > >- if ( $holds_count ) { >- $alreadyreserved = 1; >- $biblioloopiter{warn} = 1; >- $biblioloopiter{alreadyres} = 1; >- } > >- $template->param( >- alreadyreserved => $alreadyreserved, >- alreadypossession => $alreadypossession, >- ); >+ my $count = Koha::Holds->search( { biblionumber => $biblionumber } )->count(); >+ my $totalcount = $count; > > # FIXME think @optionloop, is maybe obsolete, or must be switchable by a systeme preference fixed rank or not > # make priorities options >@@ -327,6 +333,8 @@ foreach my $biblionumber (@biblionumbers) { > my $num_override = 0; > my $hiddencount = 0; > >+ $biblioitem->{force_hold_level} = $force_hold_level; >+ > if ( $biblioitem->{biblioitemnumber} ne $biblionumber ) { > $biblioitem->{hostitemsflag} = 1; > } >@@ -346,6 +354,8 @@ foreach my $biblionumber (@biblionumbers) { > foreach my $itemnumber ( @{ $itemnumbers_of_biblioitem{$biblioitemnumber} } ) { > my $item = $iteminfos_of->{$itemnumber}; > >+ $item->{force_hold_level} = $force_hold_level; >+ > unless (C4::Context->preference('item-level_itypes')) { > $item->{itype} = $biblioitem->{itemtype}; > } >@@ -443,13 +453,14 @@ foreach my $biblionumber (@biblionumbers) { > > $item->{'holdallowed'} = $branchitemrule->{'holdallowed'}; > >+ my $can_item_be_reserved = CanItemBeReserved( $borrowerinfo->{borrowernumber}, $itemnumber ); >+ $item->{not_holdable} = $can_item_be_reserved unless ( $can_item_be_reserved eq 'OK' ); >+ > if ( > !$item->{cantreserve} > && !$exceeded_maxreserves > && IsAvailableForItemLevelRequest($item, $borrowerinfo) >- && CanItemBeReserved( >- $borrowerinfo->{borrowernumber}, $itemnumber >- ) eq 'OK' >+ && $can_item_be_reserved eq 'OK' > ) > { > $item->{available} = 1; >-- >2.1.4
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 14695
:
44143
|
44144
|
44145
|
45058
|
45059
|
45060
|
45061
|
45063
|
45064
|
46548
|
46549
|
46550
|
46551
|
46552
|
46553
|
46554
|
46555
|
46556
|
46557
|
46914
|
46915
|
46916
|
46917
|
46918
|
46919
|
46920
|
47183
|
47184
|
47185
|
47186
|
47187
|
47188
|
47189
|
47190
|
47191
|
47196
|
47227
|
47228
|
47229
|
47230
|
47231
|
47232
|
47233
|
47234
|
47355
|
47372
|
47606
|
47607
|
47608
|
47609
|
47610
|
47611
|
47612
|
47613
|
47614
|
47615
|
48792
|
48795
|
48796
|
48797
|
48798
|
48799
|
48800
|
48801
|
48802
|
48803
|
50056
|
50057
|
50058
|
50059
|
50060
|
50061
|
50062
|
50063
|
50064
|
50065
|
50327
|
50391
|
51006
|
51007
|
51008
|
51009
|
51010
|
51011
|
51012
|
51013
|
51014
|
51015
|
51016
|
51017
|
51027
|
51030
|
51031
|
51032
|
51033
|
51034
|
51035
|
51036
|
51037
|
51038
|
51039
|
51040
|
51041
|
51042
|
51277
|
51278
|
51279
|
51280
|
51281
|
51282
|
51283
|
51284
|
51285
|
51286
|
51287
|
51288
|
51289
|
52457
|
54546
|
54547
|
54548
|
54549
|
54550
|
54551
|
54552
|
54553
|
54554
|
54555
|
54556
|
54557
|
54558
|
54559
|
55114
|
55115
|
55116
|
55117
|
55118
|
55119
|
55120
|
55121
|
55122
|
55123
|
55124
|
55125
|
55126
|
55127
|
55128
|
55148
|
55149
|
55150
|
55151
|
55152
|
55153
|
55154
|
55155
|
55156
|
55157
|
55158
|
55159
|
55160
|
55161
|
55162
|
55163
|
55299
|
55332
|
55730
|
55731