| Filename | /usr/share/koha/lib/C4/Reserves.pm |
| Statements | Executed 787 statements in 123ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 22.4ms | 185ms | C4::Reserves::BEGIN@27 |
| 1 | 1 | 1 | 14.7ms | 18.7ms | C4::Reserves::BEGIN@29 |
| 64 | 2 | 2 | 6.58ms | 184ms | C4::Reserves::GetReserveStatus |
| 1 | 1 | 1 | 4.77ms | 47.0ms | C4::Reserves::BEGIN@36 |
| 1 | 1 | 1 | 4.17ms | 4.87ms | C4::Reserves::BEGIN@31 |
| 1 | 1 | 1 | 1.11ms | 1.23ms | C4::Reserves::BEGIN@34 |
| 1 | 1 | 1 | 37µs | 43µs | C4::Reserves::BEGIN@28 |
| 1 | 1 | 1 | 26µs | 31µs | C4::Reserves::BEGIN@30 |
| 1 | 1 | 1 | 23µs | 23µs | C4::Reserves::BEGIN@89 |
| 1 | 1 | 1 | 21µs | 59µs | C4::Reserves::BEGIN@42 |
| 1 | 1 | 1 | 18µs | 23µs | C4::Reserves::BEGIN@24 |
| 1 | 1 | 1 | 15µs | 57µs | C4::Reserves::BEGIN@37 |
| 1 | 1 | 1 | 13µs | 46µs | C4::Reserves::BEGIN@38 |
| 1 | 1 | 1 | 13µs | 74µs | C4::Reserves::BEGIN@40 |
| 1 | 1 | 1 | 12µs | 142µs | C4::Reserves::BEGIN@44 |
| 1 | 1 | 1 | 10µs | 12µs | C4::Reserves::BEGIN@26 |
| 1 | 1 | 1 | 6µs | 6µs | C4::Reserves::BEGIN@35 |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::AddReserve |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::AlterPriority |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::AutoUnsuspendReserves |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::CanBookBeReserved |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::CanItemBeReserved |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::CancelExpiredReserves |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::CancelReserve |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::CheckReserves |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::GetOtherReserves |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::GetReserveCount |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::GetReserveFee |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::GetReserveInfo |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::GetReservesForBranch |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::GetReservesFromBiblionumber |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::GetReservesFromBorrowernumber |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::GetReservesFromItemnumber |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::GetReservesToBranch |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::IsAvailableForItemLevelRequest |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::MergeHolds |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::ModReserve |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::ModReserveAffect |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::ModReserveCancelAll |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::ModReserveFill |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::ModReserveMinusPriority |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::ModReserveStatus |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::MoveReserve |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::ReserveSlip |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::RevertWaitingStatus |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::SuspendAll |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::ToggleLowestPriority |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::ToggleSuspend |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::_Findgroupreserve |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::_FixPriority |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::_ShiftPriorityByDateAndPriority |
| 0 | 0 | 0 | 0s | 0s | C4::Reserves::_koha_notify_reserve |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package C4::Reserves; | ||||
| 2 | |||||
| 3 | # Copyright 2000-2002 Katipo Communications | ||||
| 4 | # 2006 SAN Ouest Provence | ||||
| 5 | # 2007-2010 BibLibre Paul POULAIN | ||||
| 6 | # 2011 Catalyst IT | ||||
| 7 | # | ||||
| 8 | # This file is part of Koha. | ||||
| 9 | # | ||||
| 10 | # Koha is free software; you can redistribute it and/or modify it under the | ||||
| 11 | # terms of the GNU General Public License as published by the Free Software | ||||
| 12 | # Foundation; either version 2 of the License, or (at your option) any later | ||||
| 13 | # version. | ||||
| 14 | # | ||||
| 15 | # Koha is distributed in the hope that it will be useful, but WITHOUT ANY | ||||
| 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||||
| 17 | # A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||||
| 18 | # | ||||
| 19 | # You should have received a copy of the GNU General Public License along | ||||
| 20 | # with Koha; if not, write to the Free Software Foundation, Inc., | ||||
| 21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
| 22 | |||||
| 23 | |||||
| 24 | 3 | 30µs | 2 | 27µs | # spent 23µs (18+4) within C4::Reserves::BEGIN@24 which was called:
# once (18µs+4µs) by C4::Circulation::BEGIN@27 at line 24 # spent 23µs making 1 call to C4::Reserves::BEGIN@24
# spent 4µs making 1 call to strict::import |
| 25 | #use warnings; FIXME - Bug 2505 | ||||
| 26 | 3 | 26µs | 2 | 14µs | # spent 12µs (10+2) within C4::Reserves::BEGIN@26 which was called:
# once (10µs+2µs) by C4::Circulation::BEGIN@27 at line 26 # spent 12µs making 1 call to C4::Reserves::BEGIN@26
# spent 2µs making 1 call to C4::Context::import |
| 27 | 3 | 171µs | 2 | 187ms | # spent 185ms (22.4+163) within C4::Reserves::BEGIN@27 which was called:
# once (22.4ms+163ms) by C4::Circulation::BEGIN@27 at line 27 # spent 185ms making 1 call to C4::Reserves::BEGIN@27
# spent 1.40ms making 1 call to Exporter::import |
| 28 | 3 | 72µs | 2 | 49µs | # spent 43µs (37+6) within C4::Reserves::BEGIN@28 which was called:
# once (37µs+6µs) by C4::Circulation::BEGIN@27 at line 28 # spent 43µs making 1 call to C4::Reserves::BEGIN@28
# spent 6µs making 1 call to UNIVERSAL::import |
| 29 | 3 | 234µs | 2 | 19.0ms | # spent 18.7ms (14.7+3.94) within C4::Reserves::BEGIN@29 which was called:
# once (14.7ms+3.94ms) by C4::Circulation::BEGIN@27 at line 29 # spent 18.7ms making 1 call to C4::Reserves::BEGIN@29
# spent 309µs making 1 call to Exporter::import |
| 30 | 3 | 42µs | 2 | 35µs | # spent 31µs (26+4) within C4::Reserves::BEGIN@30 which was called:
# once (26µs+4µs) by C4::Circulation::BEGIN@27 at line 30 # spent 31µs making 1 call to C4::Reserves::BEGIN@30
# spent 4µs making 1 call to UNIVERSAL::import |
| 31 | 3 | 155µs | 2 | 5.09ms | # spent 4.87ms (4.17+701µs) within C4::Reserves::BEGIN@31 which was called:
# once (4.17ms+701µs) by C4::Circulation::BEGIN@27 at line 31 # spent 4.87ms making 1 call to C4::Reserves::BEGIN@31
# spent 216µs making 1 call to Exporter::import |
| 32 | |||||
| 33 | # for _koha_notify_reserve | ||||
| 34 | 3 | 151µs | 2 | 1.23ms | # spent 1.23ms (1.11+125µs) within C4::Reserves::BEGIN@34 which was called:
# once (1.11ms+125µs) by C4::Circulation::BEGIN@27 at line 34 # spent 1.23ms making 1 call to C4::Reserves::BEGIN@34
# spent 3µs making 1 call to UNIVERSAL::import |
| 35 | 3 | 26µs | 1 | 6µs | # spent 6µs within C4::Reserves::BEGIN@35 which was called:
# once (6µs+0s) by C4::Circulation::BEGIN@27 at line 35 # spent 6µs making 1 call to C4::Reserves::BEGIN@35 |
| 36 | 3 | 146µs | 2 | 47.3ms | # spent 47.0ms (4.77+42.2) within C4::Reserves::BEGIN@36 which was called:
# once (4.77ms+42.2ms) by C4::Circulation::BEGIN@27 at line 36 # spent 47.0ms making 1 call to C4::Reserves::BEGIN@36
# spent 284µs making 1 call to Exporter::import |
| 37 | 3 | 35µs | 2 | 100µs | # spent 57µs (15+43) within C4::Reserves::BEGIN@37 which was called:
# once (15µs+43µs) by C4::Circulation::BEGIN@27 at line 37 # spent 57µs making 1 call to C4::Reserves::BEGIN@37
# spent 43µs making 1 call to Exporter::import |
| 38 | 3 | 34µs | 2 | 79µs | # spent 46µs (13+33) within C4::Reserves::BEGIN@38 which was called:
# once (13µs+33µs) by C4::Circulation::BEGIN@27 at line 38 # spent 46µs making 1 call to C4::Reserves::BEGIN@38
# spent 33µs making 1 call to Exporter::import |
| 39 | |||||
| 40 | 3 | 39µs | 2 | 134µs | # spent 74µs (13+61) within C4::Reserves::BEGIN@40 which was called:
# once (13µs+61µs) by C4::Circulation::BEGIN@27 at line 40 # spent 74µs making 1 call to C4::Reserves::BEGIN@40
# spent 61µs making 1 call to Exporter::import |
| 41 | |||||
| 42 | 3 | 60µs | 2 | 97µs | # spent 59µs (21+38) within C4::Reserves::BEGIN@42 which was called:
# once (21µs+38µs) by C4::Circulation::BEGIN@27 at line 42 # spent 59µs making 1 call to C4::Reserves::BEGIN@42
# spent 38µs making 1 call to Exporter::import |
| 43 | |||||
| 44 | 3 | 139µs | 2 | 271µs | # spent 142µs (12+129) within C4::Reserves::BEGIN@44 which was called:
# once (12µs+129µs) by C4::Circulation::BEGIN@27 at line 44 # spent 142µs making 1 call to C4::Reserves::BEGIN@44
# spent 129µs making 1 call to vars::import |
| 45 | |||||
| 46 | =head1 NAME | ||||
| 47 | |||||
| - - | |||||
| 89 | # spent 23µs within C4::Reserves::BEGIN@89 which was called:
# once (23µs+0s) by C4::Circulation::BEGIN@27 at line 135 | ||||
| 90 | # set the version for version checking | ||||
| 91 | 1 | 1µs | $VERSION = 3.07.00.049; | ||
| 92 | 1 | 900ns | require Exporter; | ||
| 93 | 1 | 9µs | @ISA = qw(Exporter); | ||
| 94 | 1 | 5µs | @EXPORT = qw( | ||
| 95 | &AddReserve | ||||
| 96 | |||||
| 97 | &GetReservesFromItemnumber | ||||
| 98 | &GetReservesFromBiblionumber | ||||
| 99 | &GetReservesFromBorrowernumber | ||||
| 100 | &GetReservesForBranch | ||||
| 101 | &GetReservesToBranch | ||||
| 102 | &GetReserveCount | ||||
| 103 | &GetReserveFee | ||||
| 104 | &GetReserveInfo | ||||
| 105 | &GetReserveStatus | ||||
| 106 | |||||
| 107 | &GetOtherReserves | ||||
| 108 | |||||
| 109 | &ModReserveFill | ||||
| 110 | &ModReserveAffect | ||||
| 111 | &ModReserve | ||||
| 112 | &ModReserveStatus | ||||
| 113 | &ModReserveCancelAll | ||||
| 114 | &ModReserveMinusPriority | ||||
| 115 | &MoveReserve | ||||
| 116 | |||||
| 117 | &CheckReserves | ||||
| 118 | &CanBookBeReserved | ||||
| 119 | &CanItemBeReserved | ||||
| 120 | &CancelReserve | ||||
| 121 | &CancelExpiredReserves | ||||
| 122 | |||||
| 123 | &AutoUnsuspendReserves | ||||
| 124 | |||||
| 125 | &IsAvailableForItemLevelRequest | ||||
| 126 | |||||
| 127 | &AlterPriority | ||||
| 128 | &ToggleLowestPriority | ||||
| 129 | |||||
| 130 | &ReserveSlip | ||||
| 131 | &ToggleSuspend | ||||
| 132 | &SuspendAll | ||||
| 133 | ); | ||||
| 134 | 1 | 6µs | @EXPORT_OK = qw( MergeHolds ); | ||
| 135 | 1 | 6.08ms | 1 | 23µs | } # spent 23µs making 1 call to C4::Reserves::BEGIN@89 |
| 136 | |||||
| 137 | =head2 AddReserve | ||||
| 138 | |||||
| - - | |||||
| 143 | sub AddReserve { | ||||
| 144 | my ( | ||||
| 145 | $branch, $borrowernumber, $biblionumber, | ||||
| 146 | $constraint, $bibitems, $priority, $resdate, $expdate, $notes, | ||||
| 147 | $title, $checkitem, $found | ||||
| 148 | ) = @_; | ||||
| 149 | my $fee = | ||||
| 150 | GetReserveFee($borrowernumber, $biblionumber, $constraint, | ||||
| 151 | $bibitems ); | ||||
| 152 | my $dbh = C4::Context->dbh; | ||||
| 153 | my $const = lc substr( $constraint, 0, 1 ); | ||||
| 154 | $resdate = format_date_in_iso( $resdate ) if ( $resdate ); | ||||
| 155 | $resdate = C4::Dates->today( 'iso' ) unless ( $resdate ); | ||||
| 156 | if ($expdate) { | ||||
| 157 | $expdate = format_date_in_iso( $expdate ); | ||||
| 158 | } else { | ||||
| 159 | undef $expdate; # make reserves.expirationdate default to null rather than '0000-00-00' | ||||
| 160 | } | ||||
| 161 | if ( C4::Context->preference( 'AllowHoldDateInFuture' ) ) { | ||||
| 162 | # Make room in reserves for this before those of a later reserve date | ||||
| 163 | $priority = _ShiftPriorityByDateAndPriority( $biblionumber, $resdate, $priority ); | ||||
| 164 | } | ||||
| 165 | my $waitingdate; | ||||
| 166 | |||||
| 167 | # If the reserv had the waiting status, we had the value of the resdate | ||||
| 168 | if ( $found eq 'W' ) { | ||||
| 169 | $waitingdate = $resdate; | ||||
| 170 | } | ||||
| 171 | |||||
| 172 | #eval { | ||||
| 173 | # updates take place here | ||||
| 174 | if ( $fee > 0 ) { | ||||
| 175 | my $nextacctno = &getnextacctno( $borrowernumber ); | ||||
| 176 | my $query = qq/ | ||||
| 177 | INSERT INTO accountlines | ||||
| 178 | (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding) | ||||
| 179 | VALUES | ||||
| 180 | (?,?,now(),?,?,'Res',?) | ||||
| 181 | /; | ||||
| 182 | my $usth = $dbh->prepare($query); | ||||
| 183 | $usth->execute( $borrowernumber, $nextacctno, $fee, | ||||
| 184 | "Reserve Charge - $title", $fee ); | ||||
| 185 | } | ||||
| 186 | |||||
| 187 | #if ($const eq 'a'){ | ||||
| 188 | my $query = qq/ | ||||
| 189 | INSERT INTO reserves | ||||
| 190 | (borrowernumber,biblionumber,reservedate,branchcode,constrainttype, | ||||
| 191 | priority,reservenotes,itemnumber,found,waitingdate,expirationdate) | ||||
| 192 | VALUES | ||||
| 193 | (?,?,?,?,?, | ||||
| 194 | ?,?,?,?,?,?) | ||||
| 195 | /; | ||||
| 196 | my $sth = $dbh->prepare($query); | ||||
| 197 | $sth->execute( | ||||
| 198 | $borrowernumber, $biblionumber, $resdate, $branch, | ||||
| 199 | $const, $priority, $notes, $checkitem, | ||||
| 200 | $found, $waitingdate, $expdate | ||||
| 201 | ); | ||||
| 202 | |||||
| 203 | # Send e-mail to librarian if syspref is active | ||||
| 204 | if(C4::Context->preference("emailLibrarianWhenHoldIsPlaced")){ | ||||
| 205 | my $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber); | ||||
| 206 | my $branch_details = C4::Branch::GetBranchDetail($borrower->{branchcode}); | ||||
| 207 | if ( my $letter = C4::Letters::GetPreparedLetter ( | ||||
| 208 | module => 'reserves', | ||||
| 209 | letter_code => 'HOLDPLACED', | ||||
| 210 | branchcode => $branch, | ||||
| 211 | tables => { | ||||
| 212 | 'branches' => $branch_details, | ||||
| 213 | 'borrowers' => $borrower, | ||||
| 214 | 'biblio' => $biblionumber, | ||||
| 215 | }, | ||||
| 216 | ) ) { | ||||
| 217 | |||||
| 218 | my $admin_email_address =$branch_details->{'branchemail'} || C4::Context->preference('KohaAdminEmailAddress'); | ||||
| 219 | |||||
| 220 | C4::Letters::EnqueueLetter( | ||||
| 221 | { letter => $letter, | ||||
| 222 | borrowernumber => $borrowernumber, | ||||
| 223 | message_transport_type => 'email', | ||||
| 224 | from_address => $admin_email_address, | ||||
| 225 | to_address => $admin_email_address, | ||||
| 226 | } | ||||
| 227 | ); | ||||
| 228 | } | ||||
| 229 | } | ||||
| 230 | |||||
| 231 | #} | ||||
| 232 | ($const eq "o" || $const eq "e") or return; # FIXME: why not have a useful return value? | ||||
| 233 | $query = qq/ | ||||
| 234 | INSERT INTO reserveconstraints | ||||
| 235 | (borrowernumber,biblionumber,reservedate,biblioitemnumber) | ||||
| 236 | VALUES | ||||
| 237 | (?,?,?,?) | ||||
| 238 | /; | ||||
| 239 | $sth = $dbh->prepare($query); # keep prepare outside the loop! | ||||
| 240 | foreach (@$bibitems) { | ||||
| 241 | $sth->execute($borrowernumber, $biblionumber, $resdate, $_); | ||||
| 242 | } | ||||
| 243 | |||||
| 244 | return; # FIXME: why not have a useful return value? | ||||
| 245 | } | ||||
| 246 | |||||
| 247 | =head2 GetReservesFromBiblionumber | ||||
| 248 | |||||
| - - | |||||
| 256 | sub GetReservesFromBiblionumber { | ||||
| 257 | my ($biblionumber) = shift or return (0, []); | ||||
| 258 | my ($all_dates) = shift; | ||||
| 259 | my $dbh = C4::Context->dbh; | ||||
| 260 | |||||
| 261 | # Find the desired items in the reserves | ||||
| 262 | my $query = " | ||||
| 263 | SELECT branchcode, | ||||
| 264 | timestamp AS rtimestamp, | ||||
| 265 | priority, | ||||
| 266 | biblionumber, | ||||
| 267 | borrowernumber, | ||||
| 268 | reservedate, | ||||
| 269 | constrainttype, | ||||
| 270 | found, | ||||
| 271 | itemnumber, | ||||
| 272 | reservenotes, | ||||
| 273 | expirationdate, | ||||
| 274 | lowestPriority, | ||||
| 275 | suspend, | ||||
| 276 | suspend_until | ||||
| 277 | FROM reserves | ||||
| 278 | WHERE biblionumber = ? "; | ||||
| 279 | unless ( $all_dates ) { | ||||
| 280 | $query .= "AND reservedate <= CURRENT_DATE()"; | ||||
| 281 | } | ||||
| 282 | $query .= "ORDER BY priority"; | ||||
| 283 | my $sth = $dbh->prepare($query); | ||||
| 284 | $sth->execute($biblionumber); | ||||
| 285 | my @results; | ||||
| 286 | my $i = 0; | ||||
| 287 | while ( my $data = $sth->fetchrow_hashref ) { | ||||
| 288 | |||||
| 289 | # FIXME - What is this doing? How do constraints work? | ||||
| 290 | if ($data->{constrainttype} eq 'o') { | ||||
| 291 | $query = ' | ||||
| 292 | SELECT biblioitemnumber | ||||
| 293 | FROM reserveconstraints | ||||
| 294 | WHERE biblionumber = ? | ||||
| 295 | AND borrowernumber = ? | ||||
| 296 | AND reservedate = ? | ||||
| 297 | '; | ||||
| 298 | my $csth = $dbh->prepare($query); | ||||
| 299 | $csth->execute($data->{biblionumber}, $data->{borrowernumber}, $data->{reservedate}); | ||||
| 300 | my @bibitemno; | ||||
| 301 | while ( my $bibitemnos = $csth->fetchrow_array ) { | ||||
| 302 | push( @bibitemno, $bibitemnos ); # FIXME: inefficient: use fetchall_arrayref | ||||
| 303 | } | ||||
| 304 | my $count = scalar @bibitemno; | ||||
| 305 | |||||
| 306 | # if we have two or more different specific itemtypes | ||||
| 307 | # reserved by same person on same day | ||||
| 308 | my $bdata; | ||||
| 309 | if ( $count > 1 ) { | ||||
| 310 | $bdata = GetBiblioItemData( $bibitemno[$i] ); # FIXME: This doesn't make sense. | ||||
| 311 | $i++; # $i can increase each pass, but the next @bibitemno might be smaller? | ||||
| 312 | } | ||||
| 313 | else { | ||||
| 314 | # Look up the book we just found. | ||||
| 315 | $bdata = GetBiblioItemData( $bibitemno[0] ); | ||||
| 316 | } | ||||
| 317 | # Add the results of this latest search to the current | ||||
| 318 | # results. | ||||
| 319 | # FIXME - An 'each' would probably be more efficient. | ||||
| 320 | foreach my $key ( keys %$bdata ) { | ||||
| 321 | $data->{$key} = $bdata->{$key}; | ||||
| 322 | } | ||||
| 323 | } | ||||
| 324 | push @results, $data; | ||||
| 325 | } | ||||
| 326 | return ( $#results + 1, \@results ); | ||||
| 327 | } | ||||
| 328 | |||||
| 329 | =head2 GetReservesFromItemnumber | ||||
| 330 | |||||
| - - | |||||
| 337 | sub GetReservesFromItemnumber { | ||||
| 338 | my ( $itemnumber, $all_dates ) = @_; | ||||
| 339 | my $dbh = C4::Context->dbh; | ||||
| 340 | my $query = " | ||||
| 341 | SELECT reservedate,borrowernumber,branchcode | ||||
| 342 | FROM reserves | ||||
| 343 | WHERE itemnumber=? | ||||
| 344 | "; | ||||
| 345 | unless ( $all_dates ) { | ||||
| 346 | $query .= " AND reservedate <= CURRENT_DATE()"; | ||||
| 347 | } | ||||
| 348 | my $sth_res = $dbh->prepare($query); | ||||
| 349 | $sth_res->execute($itemnumber); | ||||
| 350 | my ( $reservedate, $borrowernumber,$branchcode ) = $sth_res->fetchrow_array; | ||||
| 351 | return ( $reservedate, $borrowernumber, $branchcode ); | ||||
| 352 | } | ||||
| 353 | |||||
| 354 | =head2 GetReservesFromBorrowernumber | ||||
| 355 | |||||
| - - | |||||
| 362 | sub GetReservesFromBorrowernumber { | ||||
| 363 | my ( $borrowernumber, $status ) = @_; | ||||
| 364 | my $dbh = C4::Context->dbh; | ||||
| 365 | my $sth; | ||||
| 366 | if ($status) { | ||||
| 367 | $sth = $dbh->prepare(" | ||||
| 368 | SELECT * | ||||
| 369 | FROM reserves | ||||
| 370 | WHERE borrowernumber=? | ||||
| 371 | AND found =? | ||||
| 372 | ORDER BY reservedate | ||||
| 373 | "); | ||||
| 374 | $sth->execute($borrowernumber,$status); | ||||
| 375 | } else { | ||||
| 376 | $sth = $dbh->prepare(" | ||||
| 377 | SELECT * | ||||
| 378 | FROM reserves | ||||
| 379 | WHERE borrowernumber=? | ||||
| 380 | ORDER BY reservedate | ||||
| 381 | "); | ||||
| 382 | $sth->execute($borrowernumber); | ||||
| 383 | } | ||||
| 384 | my $data = $sth->fetchall_arrayref({}); | ||||
| 385 | return @$data; | ||||
| 386 | } | ||||
| 387 | #------------------------------------------------------------------------------------- | ||||
| 388 | =head2 CanBookBeReserved | ||||
| 389 | |||||
| - - | |||||
| 394 | sub CanBookBeReserved{ | ||||
| 395 | my ($borrowernumber, $biblionumber) = @_; | ||||
| 396 | |||||
| 397 | my $items = GetItemnumbersForBiblio($biblionumber); | ||||
| 398 | #get items linked via host records | ||||
| 399 | my @hostitems = get_hostitemnumbers_of($biblionumber); | ||||
| 400 | if (@hostitems){ | ||||
| 401 | push (@$items,@hostitems); | ||||
| 402 | } | ||||
| 403 | |||||
| 404 | foreach my $item (@$items){ | ||||
| 405 | return 1 if CanItemBeReserved($borrowernumber, $item); | ||||
| 406 | } | ||||
| 407 | return 0; | ||||
| 408 | } | ||||
| 409 | |||||
| 410 | =head2 CanItemBeReserved | ||||
| 411 | |||||
| - - | |||||
| 418 | sub CanItemBeReserved{ | ||||
| 419 | my ($borrowernumber, $itemnumber) = @_; | ||||
| 420 | |||||
| 421 | my $dbh = C4::Context->dbh; | ||||
| 422 | my $allowedreserves = 0; | ||||
| 423 | |||||
| 424 | my $controlbranch = C4::Context->preference('ReservesControlBranch'); | ||||
| 425 | my $itype = C4::Context->preference('item-level_itypes') ? "itype" : "itemtype"; | ||||
| 426 | |||||
| 427 | # we retrieve borrowers and items informations # | ||||
| 428 | my $item = GetItem($itemnumber); | ||||
| 429 | my $borrower = C4::Members::GetMember('borrowernumber'=>$borrowernumber); | ||||
| 430 | |||||
| 431 | # we retrieve user rights on this itemtype and branchcode | ||||
| 432 | my $sth = $dbh->prepare("SELECT categorycode, itemtype, branchcode, reservesallowed | ||||
| 433 | FROM issuingrules | ||||
| 434 | WHERE (categorycode in (?,'*') ) | ||||
| 435 | AND (itemtype IN (?,'*')) | ||||
| 436 | AND (branchcode IN (?,'*')) | ||||
| 437 | ORDER BY | ||||
| 438 | categorycode DESC, | ||||
| 439 | itemtype DESC, | ||||
| 440 | branchcode DESC;" | ||||
| 441 | ); | ||||
| 442 | |||||
| 443 | my $querycount ="SELECT | ||||
| 444 | count(*) as count | ||||
| 445 | FROM reserves | ||||
| 446 | LEFT JOIN items USING (itemnumber) | ||||
| 447 | LEFT JOIN biblioitems ON (reserves.biblionumber=biblioitems.biblionumber) | ||||
| 448 | LEFT JOIN borrowers USING (borrowernumber) | ||||
| 449 | WHERE borrowernumber = ? | ||||
| 450 | "; | ||||
| 451 | |||||
| 452 | |||||
| 453 | my $itemtype = $item->{$itype}; | ||||
| 454 | my $categorycode = $borrower->{categorycode}; | ||||
| 455 | my $branchcode = ""; | ||||
| 456 | my $branchfield = "reserves.branchcode"; | ||||
| 457 | |||||
| 458 | if( $controlbranch eq "ItemHomeLibrary" ){ | ||||
| 459 | $branchfield = "items.homebranch"; | ||||
| 460 | $branchcode = $item->{homebranch}; | ||||
| 461 | }elsif( $controlbranch eq "PatronLibrary" ){ | ||||
| 462 | $branchfield = "borrowers.branchcode"; | ||||
| 463 | $branchcode = $borrower->{branchcode}; | ||||
| 464 | } | ||||
| 465 | |||||
| 466 | # we retrieve rights | ||||
| 467 | $sth->execute($categorycode, $itemtype, $branchcode); | ||||
| 468 | if(my $rights = $sth->fetchrow_hashref()){ | ||||
| 469 | $itemtype = $rights->{itemtype}; | ||||
| 470 | $allowedreserves = $rights->{reservesallowed}; | ||||
| 471 | }else{ | ||||
| 472 | $itemtype = '*'; | ||||
| 473 | } | ||||
| 474 | |||||
| 475 | # we retrieve count | ||||
| 476 | |||||
| 477 | $querycount .= "AND $branchfield = ?"; | ||||
| 478 | |||||
| 479 | $querycount .= " AND $itype = ?" if ($itemtype ne "*"); | ||||
| 480 | my $sthcount = $dbh->prepare($querycount); | ||||
| 481 | |||||
| 482 | if($itemtype eq "*"){ | ||||
| 483 | $sthcount->execute($borrowernumber, $branchcode); | ||||
| 484 | }else{ | ||||
| 485 | $sthcount->execute($borrowernumber, $branchcode, $itemtype); | ||||
| 486 | } | ||||
| 487 | |||||
| 488 | my $reservecount = "0"; | ||||
| 489 | if(my $rowcount = $sthcount->fetchrow_hashref()){ | ||||
| 490 | $reservecount = $rowcount->{count}; | ||||
| 491 | } | ||||
| 492 | |||||
| 493 | # we check if it's ok or not | ||||
| 494 | if( $reservecount < $allowedreserves ){ | ||||
| 495 | return 1; | ||||
| 496 | }else{ | ||||
| 497 | return 0; | ||||
| 498 | } | ||||
| 499 | } | ||||
| 500 | #-------------------------------------------------------------------------------- | ||||
| 501 | =head2 GetReserveCount | ||||
| 502 | |||||
| - - | |||||
| 509 | sub GetReserveCount { | ||||
| 510 | my ($borrowernumber) = @_; | ||||
| 511 | |||||
| 512 | my $dbh = C4::Context->dbh; | ||||
| 513 | |||||
| 514 | my $query = ' | ||||
| 515 | SELECT COUNT(*) AS counter | ||||
| 516 | FROM reserves | ||||
| 517 | WHERE borrowernumber = ? | ||||
| 518 | '; | ||||
| 519 | my $sth = $dbh->prepare($query); | ||||
| 520 | $sth->execute($borrowernumber); | ||||
| 521 | my $row = $sth->fetchrow_hashref; | ||||
| 522 | return $row->{counter}; | ||||
| 523 | } | ||||
| 524 | |||||
| 525 | =head2 GetOtherReserves | ||||
| 526 | |||||
| - - | |||||
| 533 | sub GetOtherReserves { | ||||
| 534 | my ($itemnumber) = @_; | ||||
| 535 | my $messages; | ||||
| 536 | my $nextreservinfo; | ||||
| 537 | my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber); | ||||
| 538 | if ($checkreserves) { | ||||
| 539 | my $iteminfo = GetItem($itemnumber); | ||||
| 540 | if ( $iteminfo->{'holdingbranch'} ne $checkreserves->{'branchcode'} ) { | ||||
| 541 | $messages->{'transfert'} = $checkreserves->{'branchcode'}; | ||||
| 542 | #minus priorities of others reservs | ||||
| 543 | ModReserveMinusPriority( | ||||
| 544 | $itemnumber, | ||||
| 545 | $checkreserves->{'borrowernumber'}, | ||||
| 546 | $iteminfo->{'biblionumber'} | ||||
| 547 | ); | ||||
| 548 | |||||
| 549 | #launch the subroutine dotransfer | ||||
| 550 | C4::Items::ModItemTransfer( | ||||
| 551 | $itemnumber, | ||||
| 552 | $iteminfo->{'holdingbranch'}, | ||||
| 553 | $checkreserves->{'branchcode'} | ||||
| 554 | ), | ||||
| 555 | ; | ||||
| 556 | } | ||||
| 557 | |||||
| 558 | #step 2b : case of a reservation on the same branch, set the waiting status | ||||
| 559 | else { | ||||
| 560 | $messages->{'waiting'} = 1; | ||||
| 561 | ModReserveMinusPriority( | ||||
| 562 | $itemnumber, | ||||
| 563 | $checkreserves->{'borrowernumber'}, | ||||
| 564 | $iteminfo->{'biblionumber'} | ||||
| 565 | ); | ||||
| 566 | ModReserveStatus($itemnumber,'W'); | ||||
| 567 | } | ||||
| 568 | |||||
| 569 | $nextreservinfo = $checkreserves->{'borrowernumber'}; | ||||
| 570 | } | ||||
| 571 | |||||
| 572 | return ( $messages, $nextreservinfo ); | ||||
| 573 | } | ||||
| 574 | |||||
| 575 | =head2 GetReserveFee | ||||
| 576 | |||||
| - - | |||||
| 583 | sub GetReserveFee { | ||||
| 584 | my ($borrowernumber, $biblionumber, $constraint, $bibitems ) = @_; | ||||
| 585 | |||||
| 586 | #check for issues; | ||||
| 587 | my $dbh = C4::Context->dbh; | ||||
| 588 | my $const = lc substr( $constraint, 0, 1 ); | ||||
| 589 | my $query = qq/ | ||||
| 590 | SELECT * FROM borrowers | ||||
| 591 | LEFT JOIN categories ON borrowers.categorycode = categories.categorycode | ||||
| 592 | WHERE borrowernumber = ? | ||||
| 593 | /; | ||||
| 594 | my $sth = $dbh->prepare($query); | ||||
| 595 | $sth->execute($borrowernumber); | ||||
| 596 | my $data = $sth->fetchrow_hashref; | ||||
| 597 | $sth->finish(); | ||||
| 598 | my $fee = $data->{'reservefee'}; | ||||
| 599 | my $cntitems = @- > $bibitems; | ||||
| 600 | |||||
| 601 | if ( $fee > 0 ) { | ||||
| 602 | |||||
| 603 | # check for items on issue | ||||
| 604 | # first find biblioitem records | ||||
| 605 | my @biblioitems; | ||||
| 606 | my $sth1 = $dbh->prepare( | ||||
| 607 | "SELECT * FROM biblio LEFT JOIN biblioitems on biblio.biblionumber = biblioitems.biblionumber | ||||
| 608 | WHERE (biblio.biblionumber = ?)" | ||||
| 609 | ); | ||||
| 610 | $sth1->execute($biblionumber); | ||||
| 611 | while ( my $data1 = $sth1->fetchrow_hashref ) { | ||||
| 612 | if ( $const eq "a" ) { | ||||
| 613 | push @biblioitems, $data1; | ||||
| 614 | } | ||||
| 615 | else { | ||||
| 616 | my $found = 0; | ||||
| 617 | my $x = 0; | ||||
| 618 | while ( $x < $cntitems ) { | ||||
| 619 | if ( @$bibitems->{'biblioitemnumber'} == | ||||
| 620 | $data->{'biblioitemnumber'} ) | ||||
| 621 | { | ||||
| 622 | $found = 1; | ||||
| 623 | } | ||||
| 624 | $x++; | ||||
| 625 | } | ||||
| 626 | if ( $const eq 'o' ) { | ||||
| 627 | if ( $found == 1 ) { | ||||
| 628 | push @biblioitems, $data1; | ||||
| 629 | } | ||||
| 630 | } | ||||
| 631 | else { | ||||
| 632 | if ( $found == 0 ) { | ||||
| 633 | push @biblioitems, $data1; | ||||
| 634 | } | ||||
| 635 | } | ||||
| 636 | } | ||||
| 637 | } | ||||
| 638 | $sth1->finish; | ||||
| 639 | my $cntitemsfound = @biblioitems; | ||||
| 640 | my $issues = 0; | ||||
| 641 | my $x = 0; | ||||
| 642 | my $allissued = 1; | ||||
| 643 | while ( $x < $cntitemsfound ) { | ||||
| 644 | my $bitdata = $biblioitems[$x]; | ||||
| 645 | my $sth2 = $dbh->prepare( | ||||
| 646 | "SELECT * FROM items | ||||
| 647 | WHERE biblioitemnumber = ?" | ||||
| 648 | ); | ||||
| 649 | $sth2->execute( $bitdata->{'biblioitemnumber'} ); | ||||
| 650 | while ( my $itdata = $sth2->fetchrow_hashref ) { | ||||
| 651 | my $sth3 = $dbh->prepare( | ||||
| 652 | "SELECT * FROM issues | ||||
| 653 | WHERE itemnumber = ?" | ||||
| 654 | ); | ||||
| 655 | $sth3->execute( $itdata->{'itemnumber'} ); | ||||
| 656 | if ( my $isdata = $sth3->fetchrow_hashref ) { | ||||
| 657 | } | ||||
| 658 | else { | ||||
| 659 | $allissued = 0; | ||||
| 660 | } | ||||
| 661 | } | ||||
| 662 | $x++; | ||||
| 663 | } | ||||
| 664 | if ( $allissued == 0 ) { | ||||
| 665 | my $rsth = | ||||
| 666 | $dbh->prepare("SELECT * FROM reserves WHERE biblionumber = ?"); | ||||
| 667 | $rsth->execute($biblionumber); | ||||
| 668 | if ( my $rdata = $rsth->fetchrow_hashref ) { | ||||
| 669 | } | ||||
| 670 | else { | ||||
| 671 | $fee = 0; | ||||
| 672 | } | ||||
| 673 | } | ||||
| 674 | } | ||||
| 675 | return $fee; | ||||
| 676 | } | ||||
| 677 | |||||
| 678 | =head2 GetReservesToBranch | ||||
| 679 | |||||
| - - | |||||
| 686 | sub GetReservesToBranch { | ||||
| 687 | my ( $frombranch ) = @_; | ||||
| 688 | my $dbh = C4::Context->dbh; | ||||
| 689 | my $sth = $dbh->prepare( | ||||
| 690 | "SELECT borrowernumber,reservedate,itemnumber,timestamp | ||||
| 691 | FROM reserves | ||||
| 692 | WHERE priority='0' | ||||
| 693 | AND branchcode=?" | ||||
| 694 | ); | ||||
| 695 | $sth->execute( $frombranch ); | ||||
| 696 | my @transreserv; | ||||
| 697 | my $i = 0; | ||||
| 698 | while ( my $data = $sth->fetchrow_hashref ) { | ||||
| 699 | $transreserv[$i] = $data; | ||||
| 700 | $i++; | ||||
| 701 | } | ||||
| 702 | return (@transreserv); | ||||
| 703 | } | ||||
| 704 | |||||
| 705 | =head2 GetReservesForBranch | ||||
| 706 | |||||
| - - | |||||
| 711 | sub GetReservesForBranch { | ||||
| 712 | my ($frombranch) = @_; | ||||
| 713 | my $dbh = C4::Context->dbh; | ||||
| 714 | my $query = "SELECT borrowernumber,reservedate,itemnumber,waitingdate | ||||
| 715 | FROM reserves | ||||
| 716 | WHERE priority='0' | ||||
| 717 | AND found='W' "; | ||||
| 718 | if ($frombranch){ | ||||
| 719 | $query .= " AND branchcode=? "; | ||||
| 720 | } | ||||
| 721 | $query .= "ORDER BY waitingdate" ; | ||||
| 722 | my $sth = $dbh->prepare($query); | ||||
| 723 | if ($frombranch){ | ||||
| 724 | $sth->execute($frombranch); | ||||
| 725 | } | ||||
| 726 | else { | ||||
| 727 | $sth->execute(); | ||||
| 728 | } | ||||
| 729 | my @transreserv; | ||||
| 730 | my $i = 0; | ||||
| 731 | while ( my $data = $sth->fetchrow_hashref ) { | ||||
| 732 | $transreserv[$i] = $data; | ||||
| 733 | $i++; | ||||
| 734 | } | ||||
| 735 | return (@transreserv); | ||||
| 736 | } | ||||
| 737 | |||||
| 738 | =head2 GetReserveStatus | ||||
| 739 | |||||
| - - | |||||
| 747 | # spent 184ms (6.58+178) within C4::Reserves::GetReserveStatus which was called 64 times, avg 2.88ms/call:
# 32 times (4.15ms+113ms) by C4::Search::searchResults at line 1926 of /usr/share/koha/lib/C4/Search.pm, avg 3.67ms/call
# 32 times (2.43ms+64.6ms) by C4::XSLT::buildKohaItemsNamespace at line 267 of /usr/share/koha/lib/C4/XSLT.pm, avg 2.09ms/call | ||||
| 748 | 64 | 131µs | my ($itemnumber, $biblionumber) = @_; | ||
| 749 | |||||
| 750 | 64 | 406µs | 64 | 61.0ms | my $dbh = C4::Context->dbh; # spent 61.0ms making 64 calls to C4::Context::dbh, avg 954µs/call |
| 751 | |||||
| 752 | 64 | 69µs | my ($sth, $found, $priority); | ||
| 753 | 64 | 108µs | if ( $itemnumber ) { | ||
| 754 | 64 | 1.30ms | 128 | 11.5ms | $sth = $dbh->prepare("SELECT found, priority FROM reserves WHERE itemnumber = ? order by priority LIMIT 1"); # spent 6.26ms making 64 calls to DBI::db::prepare, avg 98µs/call
# spent 5.20ms making 64 calls to DBD::mysql::db::prepare, avg 81µs/call |
| 755 | 64 | 69.4ms | 64 | 68.5ms | $sth->execute($itemnumber); # spent 68.5ms making 64 calls to DBI::st::execute, avg 1.07ms/call |
| 756 | 64 | 1.81ms | 64 | 951µs | ($found, $priority) = $sth->fetchrow_array; # spent 951µs making 64 calls to DBI::st::fetchrow_array, avg 15µs/call |
| 757 | } | ||||
| 758 | |||||
| 759 | 64 | 104µs | if ( $biblionumber and not defined $found and not defined $priority ) { | ||
| 760 | 32 | 1.54ms | 64 | 5.58ms | $sth = $dbh->prepare("SELECT found, priority FROM reserves WHERE biblionumber = ? order by priority LIMIT 1"); # spent 2.99ms making 32 calls to DBI::db::prepare, avg 93µs/call
# spent 2.59ms making 32 calls to DBD::mysql::db::prepare, avg 81µs/call |
| 761 | 32 | 36.9ms | 128 | 36.8ms | $sth->execute($biblionumber); # spent 36.4ms making 32 calls to DBI::st::execute, avg 1.14ms/call
# spent 277µs making 64 calls to DBI::common::DESTROY, avg 4µs/call
# spent 75µs making 32 calls to DBD::_mem::common::DESTROY, avg 2µs/call |
| 762 | 32 | 706µs | 32 | 403µs | ($found, $priority) = $sth->fetchrow_array; # spent 403µs making 32 calls to DBI::st::fetchrow_array, avg 13µs/call |
| 763 | } | ||||
| 764 | |||||
| 765 | 64 | 47µs | if(defined $found) { | ||
| 766 | return 'Waiting' if $found eq 'W' and $priority == 0; | ||||
| 767 | return 'Finished' if $found eq 'F'; | ||||
| 768 | return 'Reserved' if $priority > 0; | ||||
| 769 | } | ||||
| 770 | 64 | 2.76ms | return ''; | ||
| 771 | #empty string here will remove need for checking undef, or less log lines | ||||
| 772 | } | ||||
| 773 | |||||
| 774 | =head2 CheckReserves | ||||
| 775 | |||||
| - - | |||||
| 801 | sub CheckReserves { | ||||
| 802 | my ( $item, $barcode ) = @_; | ||||
| 803 | my $dbh = C4::Context->dbh; | ||||
| 804 | my $sth; | ||||
| 805 | my $select; | ||||
| 806 | if (C4::Context->preference('item-level_itypes')){ | ||||
| 807 | $select = " | ||||
| 808 | SELECT items.biblionumber, | ||||
| 809 | items.biblioitemnumber, | ||||
| 810 | itemtypes.notforloan, | ||||
| 811 | items.notforloan AS itemnotforloan, | ||||
| 812 | items.itemnumber | ||||
| 813 | FROM items | ||||
| 814 | LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber | ||||
| 815 | LEFT JOIN itemtypes ON items.itype = itemtypes.itemtype | ||||
| 816 | "; | ||||
| 817 | } | ||||
| 818 | else { | ||||
| 819 | $select = " | ||||
| 820 | SELECT items.biblionumber, | ||||
| 821 | items.biblioitemnumber, | ||||
| 822 | itemtypes.notforloan, | ||||
| 823 | items.notforloan AS itemnotforloan, | ||||
| 824 | items.itemnumber | ||||
| 825 | FROM items | ||||
| 826 | LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber | ||||
| 827 | LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype | ||||
| 828 | "; | ||||
| 829 | } | ||||
| 830 | |||||
| 831 | if ($item) { | ||||
| 832 | $sth = $dbh->prepare("$select WHERE itemnumber = ?"); | ||||
| 833 | $sth->execute($item); | ||||
| 834 | } | ||||
| 835 | else { | ||||
| 836 | $sth = $dbh->prepare("$select WHERE barcode = ?"); | ||||
| 837 | $sth->execute($barcode); | ||||
| 838 | } | ||||
| 839 | # note: we get the itemnumber because we might have started w/ just the barcode. Now we know for sure we have it. | ||||
| 840 | my ( $biblio, $bibitem, $notforloan_per_itemtype, $notforloan_per_item, $itemnumber ) = $sth->fetchrow_array; | ||||
| 841 | |||||
| 842 | return ( '' ) unless $itemnumber; # bail if we got nothing. | ||||
| 843 | |||||
| 844 | # if item is not for loan it cannot be reserved either..... | ||||
| 845 | # execpt where items.notforloan < 0 : This indicates the item is holdable. | ||||
| 846 | return ( '' ) if ( $notforloan_per_item > 0 ) or $notforloan_per_itemtype; | ||||
| 847 | |||||
| 848 | # Find this item in the reserves | ||||
| 849 | my @reserves = _Findgroupreserve( $bibitem, $biblio, $itemnumber ); | ||||
| 850 | |||||
| 851 | # $priority and $highest are used to find the most important item | ||||
| 852 | # in the list returned by &_Findgroupreserve. (The lower $priority, | ||||
| 853 | # the more important the item.) | ||||
| 854 | # $highest is the most important item we've seen so far. | ||||
| 855 | my $highest; | ||||
| 856 | if (scalar @reserves) { | ||||
| 857 | my $priority = 10000000; | ||||
| 858 | foreach my $res (@reserves) { | ||||
| 859 | if ( $res->{'itemnumber'} == $itemnumber && $res->{'priority'} == 0) { | ||||
| 860 | return ( "Waiting", $res, \@reserves ); # Found it | ||||
| 861 | } else { | ||||
| 862 | # See if this item is more important than what we've got so far | ||||
| 863 | if ( $res->{'priority'} && $res->{'priority'} < $priority ) { | ||||
| 864 | my $borrowerinfo=C4::Members::GetMember(borrowernumber => $res->{'borrowernumber'}); | ||||
| 865 | my $iteminfo=C4::Items::GetItem($itemnumber); | ||||
| 866 | my $branch=C4::Circulation::_GetCircControlBranch($iteminfo,$borrowerinfo); | ||||
| 867 | my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$iteminfo->{'itype'}); | ||||
| 868 | next if ($branchitemrule->{'holdallowed'} == 0); | ||||
| 869 | next if (($branchitemrule->{'holdallowed'} == 1) && ($branch ne $borrowerinfo->{'branchcode'})); | ||||
| 870 | $priority = $res->{'priority'}; | ||||
| 871 | $highest = $res; | ||||
| 872 | } | ||||
| 873 | } | ||||
| 874 | } | ||||
| 875 | } | ||||
| 876 | |||||
| 877 | # If we get this far, then no exact match was found. | ||||
| 878 | # We return the most important (i.e. next) reservation. | ||||
| 879 | if ($highest) { | ||||
| 880 | $highest->{'itemnumber'} = $item; | ||||
| 881 | return ( "Reserved", $highest, \@reserves ); | ||||
| 882 | } | ||||
| 883 | |||||
| 884 | return ( '' ); | ||||
| 885 | } | ||||
| 886 | |||||
| 887 | =head2 CancelExpiredReserves | ||||
| 888 | |||||
| - - | |||||
| 895 | sub CancelExpiredReserves { | ||||
| 896 | |||||
| 897 | # Cancel reserves that have passed their expiration date. | ||||
| 898 | my $dbh = C4::Context->dbh; | ||||
| 899 | my $sth = $dbh->prepare( " | ||||
| 900 | SELECT * FROM reserves WHERE DATE(expirationdate) < DATE( CURDATE() ) | ||||
| 901 | AND expirationdate IS NOT NULL | ||||
| 902 | AND found IS NULL | ||||
| 903 | " ); | ||||
| 904 | $sth->execute(); | ||||
| 905 | |||||
| 906 | while ( my $res = $sth->fetchrow_hashref() ) { | ||||
| 907 | CancelReserve( $res->{'biblionumber'}, '', $res->{'borrowernumber'} ); | ||||
| 908 | } | ||||
| 909 | |||||
| 910 | # Cancel reserves that have been waiting too long | ||||
| 911 | if ( C4::Context->preference("ExpireReservesMaxPickUpDelay") ) { | ||||
| 912 | my $max_pickup_delay = C4::Context->preference("ReservesMaxPickUpDelay"); | ||||
| 913 | my $charge = C4::Context->preference("ExpireReservesMaxPickUpDelayCharge"); | ||||
| 914 | |||||
| 915 | my $query = "SELECT * FROM reserves WHERE TO_DAYS( NOW() ) - TO_DAYS( waitingdate ) > ? AND found = 'W' AND priority = 0"; | ||||
| 916 | $sth = $dbh->prepare( $query ); | ||||
| 917 | $sth->execute( $max_pickup_delay ); | ||||
| 918 | |||||
| 919 | while (my $res = $sth->fetchrow_hashref ) { | ||||
| 920 | if ( $charge ) { | ||||
| 921 | manualinvoice($res->{'borrowernumber'}, $res->{'itemnumber'}, 'Hold waiting too long', 'F', $charge); | ||||
| 922 | } | ||||
| 923 | |||||
| 924 | CancelReserve( $res->{'biblionumber'}, '', $res->{'borrowernumber'} ); | ||||
| 925 | } | ||||
| 926 | } | ||||
| 927 | |||||
| 928 | } | ||||
| 929 | |||||
| 930 | =head2 AutoUnsuspendReserves | ||||
| 931 | |||||
| - - | |||||
| 938 | sub AutoUnsuspendReserves { | ||||
| 939 | |||||
| 940 | my $dbh = C4::Context->dbh; | ||||
| 941 | |||||
| 942 | my $query = "UPDATE reserves SET suspend = 0, suspend_until = NULL WHERE DATE( suspend_until ) < DATE( CURDATE() )"; | ||||
| 943 | my $sth = $dbh->prepare( $query ); | ||||
| 944 | $sth->execute(); | ||||
| 945 | |||||
| 946 | } | ||||
| 947 | |||||
| 948 | =head2 CancelReserve | ||||
| 949 | |||||
| - - | |||||
| 966 | sub CancelReserve { | ||||
| 967 | my ( $biblio, $item, $borr ) = @_; | ||||
| 968 | my $dbh = C4::Context->dbh; | ||||
| 969 | if ( $item and $borr ) { | ||||
| 970 | # removing a waiting reserve record.... | ||||
| 971 | # update the database... | ||||
| 972 | my $query = " | ||||
| 973 | UPDATE reserves | ||||
| 974 | SET cancellationdate = now(), | ||||
| 975 | found = Null, | ||||
| 976 | priority = 0 | ||||
| 977 | WHERE itemnumber = ? | ||||
| 978 | AND borrowernumber = ? | ||||
| 979 | "; | ||||
| 980 | my $sth = $dbh->prepare($query); | ||||
| 981 | $sth->execute( $item, $borr ); | ||||
| 982 | $sth->finish; | ||||
| 983 | $query = " | ||||
| 984 | INSERT INTO old_reserves | ||||
| 985 | SELECT * FROM reserves | ||||
| 986 | WHERE itemnumber = ? | ||||
| 987 | AND borrowernumber = ? | ||||
| 988 | "; | ||||
| 989 | $sth = $dbh->prepare($query); | ||||
| 990 | $sth->execute( $item, $borr ); | ||||
| 991 | $query = " | ||||
| 992 | DELETE FROM reserves | ||||
| 993 | WHERE itemnumber = ? | ||||
| 994 | AND borrowernumber = ? | ||||
| 995 | "; | ||||
| 996 | $sth = $dbh->prepare($query); | ||||
| 997 | $sth->execute( $item, $borr ); | ||||
| 998 | } | ||||
| 999 | else { | ||||
| 1000 | # removing a reserve record.... | ||||
| 1001 | # get the prioritiy on this record.... | ||||
| 1002 | my $priority; | ||||
| 1003 | my $query = qq/ | ||||
| 1004 | SELECT priority FROM reserves | ||||
| 1005 | WHERE biblionumber = ? | ||||
| 1006 | AND borrowernumber = ? | ||||
| 1007 | AND cancellationdate IS NULL | ||||
| 1008 | AND itemnumber IS NULL | ||||
| 1009 | /; | ||||
| 1010 | my $sth = $dbh->prepare($query); | ||||
| 1011 | $sth->execute( $biblio, $borr ); | ||||
| 1012 | ($priority) = $sth->fetchrow_array; | ||||
| 1013 | $sth->finish; | ||||
| 1014 | $query = qq/ | ||||
| 1015 | UPDATE reserves | ||||
| 1016 | SET cancellationdate = now(), | ||||
| 1017 | found = Null, | ||||
| 1018 | priority = 0 | ||||
| 1019 | WHERE biblionumber = ? | ||||
| 1020 | AND borrowernumber = ? | ||||
| 1021 | /; | ||||
| 1022 | |||||
| 1023 | # update the database, removing the record... | ||||
| 1024 | $sth = $dbh->prepare($query); | ||||
| 1025 | $sth->execute( $biblio, $borr ); | ||||
| 1026 | $sth->finish; | ||||
| 1027 | |||||
| 1028 | $query = qq/ | ||||
| 1029 | INSERT INTO old_reserves | ||||
| 1030 | SELECT * FROM reserves | ||||
| 1031 | WHERE biblionumber = ? | ||||
| 1032 | AND borrowernumber = ? | ||||
| 1033 | /; | ||||
| 1034 | $sth = $dbh->prepare($query); | ||||
| 1035 | $sth->execute( $biblio, $borr ); | ||||
| 1036 | |||||
| 1037 | $query = qq/ | ||||
| 1038 | DELETE FROM reserves | ||||
| 1039 | WHERE biblionumber = ? | ||||
| 1040 | AND borrowernumber = ? | ||||
| 1041 | /; | ||||
| 1042 | $sth = $dbh->prepare($query); | ||||
| 1043 | $sth->execute( $biblio, $borr ); | ||||
| 1044 | |||||
| 1045 | # now fix the priority on the others.... | ||||
| 1046 | _FixPriority( $biblio, $borr ); | ||||
| 1047 | } | ||||
| 1048 | } | ||||
| 1049 | |||||
| 1050 | =head2 ModReserve | ||||
| 1051 | |||||
| - - | |||||
| 1081 | sub ModReserve { | ||||
| 1082 | #subroutine to update a reserve | ||||
| 1083 | my ( $rank, $biblio, $borrower, $branch , $itemnumber, $suspend_until) = @_; | ||||
| 1084 | return if $rank eq "W"; | ||||
| 1085 | return if $rank eq "n"; | ||||
| 1086 | my $dbh = C4::Context->dbh; | ||||
| 1087 | if ( $rank eq "del" ) { | ||||
| 1088 | my $query = qq/ | ||||
| 1089 | UPDATE reserves | ||||
| 1090 | SET cancellationdate=now() | ||||
| 1091 | WHERE biblionumber = ? | ||||
| 1092 | AND borrowernumber = ? | ||||
| 1093 | /; | ||||
| 1094 | my $sth = $dbh->prepare($query); | ||||
| 1095 | $sth->execute( $biblio, $borrower ); | ||||
| 1096 | $sth->finish; | ||||
| 1097 | $query = qq/ | ||||
| 1098 | INSERT INTO old_reserves | ||||
| 1099 | SELECT * | ||||
| 1100 | FROM reserves | ||||
| 1101 | WHERE biblionumber = ? | ||||
| 1102 | AND borrowernumber = ? | ||||
| 1103 | /; | ||||
| 1104 | $sth = $dbh->prepare($query); | ||||
| 1105 | $sth->execute( $biblio, $borrower ); | ||||
| 1106 | $query = qq/ | ||||
| 1107 | DELETE FROM reserves | ||||
| 1108 | WHERE biblionumber = ? | ||||
| 1109 | AND borrowernumber = ? | ||||
| 1110 | /; | ||||
| 1111 | $sth = $dbh->prepare($query); | ||||
| 1112 | $sth->execute( $biblio, $borrower ); | ||||
| 1113 | |||||
| 1114 | } | ||||
| 1115 | elsif ($rank =~ /^\d+/ and $rank > 0) { | ||||
| 1116 | my $query = " | ||||
| 1117 | UPDATE reserves SET priority = ? ,branchcode = ?, itemnumber = ?, found = NULL, waitingdate = NULL | ||||
| 1118 | WHERE biblionumber = ? | ||||
| 1119 | AND borrowernumber = ? | ||||
| 1120 | "; | ||||
| 1121 | my $sth = $dbh->prepare($query); | ||||
| 1122 | $sth->execute( $rank, $branch,$itemnumber, $biblio, $borrower); | ||||
| 1123 | $sth->finish; | ||||
| 1124 | |||||
| 1125 | if ( defined( $suspend_until ) ) { | ||||
| 1126 | if ( $suspend_until ) { | ||||
| 1127 | $suspend_until = C4::Dates->new( $suspend_until )->output("iso"); | ||||
| 1128 | $dbh->do("UPDATE reserves SET suspend = 1, suspend_until = ? WHERE biblionumber = ? AND borrowernumber = ?", undef, ( $suspend_until, $biblio, $borrower ) ); | ||||
| 1129 | } else { | ||||
| 1130 | $dbh->do("UPDATE reserves SET suspend_until = NULL WHERE biblionumber = ? AND borrowernumber = ?", undef, ( $biblio, $borrower ) ); | ||||
| 1131 | } | ||||
| 1132 | } | ||||
| 1133 | |||||
| 1134 | _FixPriority( $biblio, $borrower, $rank); | ||||
| 1135 | } | ||||
| 1136 | } | ||||
| 1137 | |||||
| 1138 | =head2 ModReserveFill | ||||
| 1139 | |||||
| - - | |||||
| 1150 | sub ModReserveFill { | ||||
| 1151 | my ($res) = @_; | ||||
| 1152 | my $dbh = C4::Context->dbh; | ||||
| 1153 | # fill in a reserve record.... | ||||
| 1154 | my $biblionumber = $res->{'biblionumber'}; | ||||
| 1155 | my $borrowernumber = $res->{'borrowernumber'}; | ||||
| 1156 | my $resdate = $res->{'reservedate'}; | ||||
| 1157 | |||||
| 1158 | # get the priority on this record.... | ||||
| 1159 | my $priority; | ||||
| 1160 | my $query = "SELECT priority | ||||
| 1161 | FROM reserves | ||||
| 1162 | WHERE biblionumber = ? | ||||
| 1163 | AND borrowernumber = ? | ||||
| 1164 | AND reservedate = ?"; | ||||
| 1165 | my $sth = $dbh->prepare($query); | ||||
| 1166 | $sth->execute( $biblionumber, $borrowernumber, $resdate ); | ||||
| 1167 | ($priority) = $sth->fetchrow_array; | ||||
| 1168 | $sth->finish; | ||||
| 1169 | |||||
| 1170 | # update the database... | ||||
| 1171 | $query = "UPDATE reserves | ||||
| 1172 | SET found = 'F', | ||||
| 1173 | priority = 0 | ||||
| 1174 | WHERE biblionumber = ? | ||||
| 1175 | AND reservedate = ? | ||||
| 1176 | AND borrowernumber = ? | ||||
| 1177 | "; | ||||
| 1178 | $sth = $dbh->prepare($query); | ||||
| 1179 | $sth->execute( $biblionumber, $resdate, $borrowernumber ); | ||||
| 1180 | $sth->finish; | ||||
| 1181 | |||||
| 1182 | # move to old_reserves | ||||
| 1183 | $query = "INSERT INTO old_reserves | ||||
| 1184 | SELECT * FROM reserves | ||||
| 1185 | WHERE biblionumber = ? | ||||
| 1186 | AND reservedate = ? | ||||
| 1187 | AND borrowernumber = ? | ||||
| 1188 | "; | ||||
| 1189 | $sth = $dbh->prepare($query); | ||||
| 1190 | $sth->execute( $biblionumber, $resdate, $borrowernumber ); | ||||
| 1191 | $query = "DELETE FROM reserves | ||||
| 1192 | WHERE biblionumber = ? | ||||
| 1193 | AND reservedate = ? | ||||
| 1194 | AND borrowernumber = ? | ||||
| 1195 | "; | ||||
| 1196 | $sth = $dbh->prepare($query); | ||||
| 1197 | $sth->execute( $biblionumber, $resdate, $borrowernumber ); | ||||
| 1198 | |||||
| 1199 | # now fix the priority on the others (if the priority wasn't | ||||
| 1200 | # already sorted!).... | ||||
| 1201 | unless ( $priority == 0 ) { | ||||
| 1202 | _FixPriority( $biblionumber, $borrowernumber ); | ||||
| 1203 | } | ||||
| 1204 | } | ||||
| 1205 | |||||
| 1206 | =head2 ModReserveStatus | ||||
| 1207 | |||||
| - - | |||||
| 1218 | sub ModReserveStatus { | ||||
| 1219 | |||||
| 1220 | #first : check if we have a reservation for this item . | ||||
| 1221 | my ($itemnumber, $newstatus) = @_; | ||||
| 1222 | my $dbh = C4::Context->dbh; | ||||
| 1223 | |||||
| 1224 | my $query = "UPDATE reserves SET found = ?, waitingdate = NOW() WHERE itemnumber = ? AND found IS NULL AND priority = 0"; | ||||
| 1225 | my $sth_set = $dbh->prepare($query); | ||||
| 1226 | $sth_set->execute( $newstatus, $itemnumber ); | ||||
| 1227 | |||||
| 1228 | if ( C4::Context->preference("ReturnToShelvingCart") && $newstatus ) { | ||||
| 1229 | CartToShelf( $itemnumber ); | ||||
| 1230 | } | ||||
| 1231 | } | ||||
| 1232 | |||||
| 1233 | =head2 ModReserveAffect | ||||
| 1234 | |||||
| - - | |||||
| 1248 | sub ModReserveAffect { | ||||
| 1249 | my ( $itemnumber, $borrowernumber,$transferToDo ) = @_; | ||||
| 1250 | my $dbh = C4::Context->dbh; | ||||
| 1251 | |||||
| 1252 | # we want to attach $itemnumber to $borrowernumber, find the biblionumber | ||||
| 1253 | # attached to $itemnumber | ||||
| 1254 | my $sth = $dbh->prepare("SELECT biblionumber FROM items WHERE itemnumber=?"); | ||||
| 1255 | $sth->execute($itemnumber); | ||||
| 1256 | my ($biblionumber) = $sth->fetchrow; | ||||
| 1257 | |||||
| 1258 | # get request - need to find out if item is already | ||||
| 1259 | # waiting in order to not send duplicate hold filled notifications | ||||
| 1260 | my $request = GetReserveInfo($borrowernumber, $biblionumber); | ||||
| 1261 | my $already_on_shelf = ($request && $request->{found} eq 'W') ? 1 : 0; | ||||
| 1262 | |||||
| 1263 | # If we affect a reserve that has to be transfered, don't set to Waiting | ||||
| 1264 | my $query; | ||||
| 1265 | if ($transferToDo) { | ||||
| 1266 | $query = " | ||||
| 1267 | UPDATE reserves | ||||
| 1268 | SET priority = 0, | ||||
| 1269 | itemnumber = ?, | ||||
| 1270 | found = 'T' | ||||
| 1271 | WHERE borrowernumber = ? | ||||
| 1272 | AND biblionumber = ? | ||||
| 1273 | "; | ||||
| 1274 | } | ||||
| 1275 | else { | ||||
| 1276 | # affect the reserve to Waiting as well. | ||||
| 1277 | $query = " | ||||
| 1278 | UPDATE reserves | ||||
| 1279 | SET priority = 0, | ||||
| 1280 | found = 'W', | ||||
| 1281 | waitingdate = NOW(), | ||||
| 1282 | itemnumber = ? | ||||
| 1283 | WHERE borrowernumber = ? | ||||
| 1284 | AND biblionumber = ? | ||||
| 1285 | "; | ||||
| 1286 | } | ||||
| 1287 | $sth = $dbh->prepare($query); | ||||
| 1288 | $sth->execute( $itemnumber, $borrowernumber,$biblionumber); | ||||
| 1289 | _koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf ); | ||||
| 1290 | |||||
| 1291 | if ( C4::Context->preference("ReturnToShelvingCart") ) { | ||||
| 1292 | CartToShelf( $itemnumber ); | ||||
| 1293 | } | ||||
| 1294 | |||||
| 1295 | return; | ||||
| 1296 | } | ||||
| 1297 | |||||
| 1298 | =head2 ModReserveCancelAll | ||||
| 1299 | |||||
| - - | |||||
| 1306 | sub ModReserveCancelAll { | ||||
| 1307 | my $messages; | ||||
| 1308 | my $nextreservinfo; | ||||
| 1309 | my ( $itemnumber, $borrowernumber ) = @_; | ||||
| 1310 | |||||
| 1311 | #step 1 : cancel the reservation | ||||
| 1312 | my $CancelReserve = CancelReserve( undef, $itemnumber, $borrowernumber ); | ||||
| 1313 | |||||
| 1314 | #step 2 launch the subroutine of the others reserves | ||||
| 1315 | ( $messages, $nextreservinfo ) = GetOtherReserves($itemnumber); | ||||
| 1316 | |||||
| 1317 | return ( $messages, $nextreservinfo ); | ||||
| 1318 | } | ||||
| 1319 | |||||
| 1320 | =head2 ModReserveMinusPriority | ||||
| 1321 | |||||
| - - | |||||
| 1328 | sub ModReserveMinusPriority { | ||||
| 1329 | my ( $itemnumber, $borrowernumber, $biblionumber ) = @_; | ||||
| 1330 | |||||
| 1331 | #first step update the value of the first person on reserv | ||||
| 1332 | my $dbh = C4::Context->dbh; | ||||
| 1333 | my $query = " | ||||
| 1334 | UPDATE reserves | ||||
| 1335 | SET priority = 0 , itemnumber = ? | ||||
| 1336 | WHERE borrowernumber=? | ||||
| 1337 | AND biblionumber=? | ||||
| 1338 | "; | ||||
| 1339 | my $sth_upd = $dbh->prepare($query); | ||||
| 1340 | $sth_upd->execute( $itemnumber, $borrowernumber, $biblionumber ); | ||||
| 1341 | # second step update all others reservs | ||||
| 1342 | _FixPriority($biblionumber, $borrowernumber, '0'); | ||||
| 1343 | } | ||||
| 1344 | |||||
| 1345 | =head2 GetReserveInfo | ||||
| 1346 | |||||
| - - | |||||
| 1354 | sub GetReserveInfo { | ||||
| 1355 | my ( $borrowernumber, $biblionumber ) = @_; | ||||
| 1356 | my $dbh = C4::Context->dbh; | ||||
| 1357 | my $strsth="SELECT | ||||
| 1358 | reservedate, | ||||
| 1359 | reservenotes, | ||||
| 1360 | reserves.borrowernumber, | ||||
| 1361 | reserves.biblionumber, | ||||
| 1362 | reserves.branchcode, | ||||
| 1363 | reserves.waitingdate, | ||||
| 1364 | notificationdate, | ||||
| 1365 | reminderdate, | ||||
| 1366 | priority, | ||||
| 1367 | found, | ||||
| 1368 | firstname, | ||||
| 1369 | surname, | ||||
| 1370 | phone, | ||||
| 1371 | email, | ||||
| 1372 | address, | ||||
| 1373 | address2, | ||||
| 1374 | cardnumber, | ||||
| 1375 | city, | ||||
| 1376 | zipcode, | ||||
| 1377 | biblio.title, | ||||
| 1378 | biblio.author, | ||||
| 1379 | items.holdingbranch, | ||||
| 1380 | items.itemcallnumber, | ||||
| 1381 | items.itemnumber, | ||||
| 1382 | items.location, | ||||
| 1383 | barcode, | ||||
| 1384 | notes | ||||
| 1385 | FROM reserves | ||||
| 1386 | LEFT JOIN items USING(itemnumber) | ||||
| 1387 | LEFT JOIN borrowers USING(borrowernumber) | ||||
| 1388 | LEFT JOIN biblio ON (reserves.biblionumber=biblio.biblionumber) | ||||
| 1389 | WHERE | ||||
| 1390 | reserves.borrowernumber=? | ||||
| 1391 | AND reserves.biblionumber=?"; | ||||
| 1392 | my $sth = $dbh->prepare($strsth); | ||||
| 1393 | $sth->execute($borrowernumber,$biblionumber); | ||||
| 1394 | |||||
| 1395 | my $data = $sth->fetchrow_hashref; | ||||
| 1396 | return $data; | ||||
| 1397 | |||||
| 1398 | } | ||||
| 1399 | |||||
| 1400 | =head2 IsAvailableForItemLevelRequest | ||||
| 1401 | |||||
| - - | |||||
| 1427 | sub IsAvailableForItemLevelRequest { | ||||
| 1428 | my $itemnumber = shift; | ||||
| 1429 | |||||
| 1430 | my $item = GetItem($itemnumber); | ||||
| 1431 | |||||
| 1432 | # must check the notforloan setting of the itemtype | ||||
| 1433 | # FIXME - a lot of places in the code do this | ||||
| 1434 | # or something similar - need to be | ||||
| 1435 | # consolidated | ||||
| 1436 | my $dbh = C4::Context->dbh; | ||||
| 1437 | my $notforloan_query; | ||||
| 1438 | if (C4::Context->preference('item-level_itypes')) { | ||||
| 1439 | $notforloan_query = "SELECT itemtypes.notforloan | ||||
| 1440 | FROM items | ||||
| 1441 | JOIN itemtypes ON (itemtypes.itemtype = items.itype) | ||||
| 1442 | WHERE itemnumber = ?"; | ||||
| 1443 | } else { | ||||
| 1444 | $notforloan_query = "SELECT itemtypes.notforloan | ||||
| 1445 | FROM items | ||||
| 1446 | JOIN biblioitems USING (biblioitemnumber) | ||||
| 1447 | JOIN itemtypes USING (itemtype) | ||||
| 1448 | WHERE itemnumber = ?"; | ||||
| 1449 | } | ||||
| 1450 | my $sth = $dbh->prepare($notforloan_query); | ||||
| 1451 | $sth->execute($itemnumber); | ||||
| 1452 | my $notforloan_per_itemtype = 0; | ||||
| 1453 | if (my ($notforloan) = $sth->fetchrow_array) { | ||||
| 1454 | $notforloan_per_itemtype = 1 if $notforloan; | ||||
| 1455 | } | ||||
| 1456 | |||||
| 1457 | my $available_per_item = 1; | ||||
| 1458 | $available_per_item = 0 if $item->{itemlost} or | ||||
| 1459 | ( $item->{notforloan} > 0 ) or | ||||
| 1460 | ($item->{damaged} and not C4::Context->preference('AllowHoldsOnDamagedItems')) or | ||||
| 1461 | $item->{wthdrawn} or | ||||
| 1462 | $notforloan_per_itemtype; | ||||
| 1463 | |||||
| 1464 | |||||
| 1465 | if (C4::Context->preference('AllowOnShelfHolds')) { | ||||
| 1466 | return $available_per_item; | ||||
| 1467 | } else { | ||||
| 1468 | return ($available_per_item and ($item->{onloan} or GetReserveStatus($itemnumber) eq "Waiting")); | ||||
| 1469 | } | ||||
| 1470 | } | ||||
| 1471 | |||||
| 1472 | =head2 AlterPriority | ||||
| 1473 | |||||
| - - | |||||
| 1481 | sub AlterPriority { | ||||
| 1482 | my ( $where, $borrowernumber, $biblionumber ) = @_; | ||||
| 1483 | |||||
| 1484 | my $dbh = C4::Context->dbh; | ||||
| 1485 | |||||
| 1486 | ## Find this reserve | ||||
| 1487 | my $sth = $dbh->prepare('SELECT * FROM reserves WHERE biblionumber = ? AND borrowernumber = ? AND cancellationdate IS NULL'); | ||||
| 1488 | $sth->execute( $biblionumber, $borrowernumber ); | ||||
| 1489 | my $reserve = $sth->fetchrow_hashref(); | ||||
| 1490 | $sth->finish(); | ||||
| 1491 | |||||
| 1492 | if ( $where eq 'up' || $where eq 'down' ) { | ||||
| 1493 | |||||
| 1494 | my $priority = $reserve->{'priority'}; | ||||
| 1495 | $priority = $where eq 'up' ? $priority - 1 : $priority + 1; | ||||
| 1496 | _FixPriority( $biblionumber, $borrowernumber, $priority ) | ||||
| 1497 | |||||
| 1498 | } elsif ( $where eq 'top' ) { | ||||
| 1499 | |||||
| 1500 | _FixPriority( $biblionumber, $borrowernumber, '1' ) | ||||
| 1501 | |||||
| 1502 | } elsif ( $where eq 'bottom' ) { | ||||
| 1503 | |||||
| 1504 | _FixPriority( $biblionumber, $borrowernumber, '999999' ) | ||||
| 1505 | |||||
| 1506 | } | ||||
| 1507 | } | ||||
| 1508 | |||||
| 1509 | =head2 ToggleLowestPriority | ||||
| 1510 | |||||
| - - | |||||
| 1517 | sub ToggleLowestPriority { | ||||
| 1518 | my ( $borrowernumber, $biblionumber ) = @_; | ||||
| 1519 | |||||
| 1520 | my $dbh = C4::Context->dbh; | ||||
| 1521 | |||||
| 1522 | my $sth = $dbh->prepare( | ||||
| 1523 | "UPDATE reserves SET lowestPriority = NOT lowestPriority | ||||
| 1524 | WHERE biblionumber = ? | ||||
| 1525 | AND borrowernumber = ?" | ||||
| 1526 | ); | ||||
| 1527 | $sth->execute( | ||||
| 1528 | $biblionumber, | ||||
| 1529 | $borrowernumber, | ||||
| 1530 | ); | ||||
| 1531 | $sth->finish; | ||||
| 1532 | |||||
| 1533 | _FixPriority( $biblionumber, $borrowernumber, '999999' ); | ||||
| 1534 | } | ||||
| 1535 | |||||
| 1536 | =head2 ToggleSuspend | ||||
| 1537 | |||||
| - - | |||||
| 1546 | sub ToggleSuspend { | ||||
| 1547 | my ( $borrowernumber, $biblionumber, $suspend_until ) = @_; | ||||
| 1548 | |||||
| 1549 | $suspend_until = output_pref( dt_from_string( $suspend_until ), 'iso' ) if ( $suspend_until ); | ||||
| 1550 | |||||
| 1551 | my $do_until = ( $suspend_until ) ? '?' : 'NULL'; | ||||
| 1552 | |||||
| 1553 | my $dbh = C4::Context->dbh; | ||||
| 1554 | |||||
| 1555 | my $sth = $dbh->prepare( | ||||
| 1556 | "UPDATE reserves SET suspend = NOT suspend, | ||||
| 1557 | suspend_until = CASE WHEN suspend = 0 THEN NULL ELSE $do_until END | ||||
| 1558 | WHERE biblionumber = ? | ||||
| 1559 | AND borrowernumber = ? | ||||
| 1560 | "); | ||||
| 1561 | |||||
| 1562 | my @params; | ||||
| 1563 | push( @params, $suspend_until ) if ( $suspend_until ); | ||||
| 1564 | push( @params, $biblionumber ); | ||||
| 1565 | push( @params, $borrowernumber ); | ||||
| 1566 | |||||
| 1567 | $sth->execute( @params ); | ||||
| 1568 | $sth->finish; | ||||
| 1569 | } | ||||
| 1570 | |||||
| 1571 | =head2 SuspendAll | ||||
| 1572 | |||||
| - - | |||||
| 1587 | sub SuspendAll { | ||||
| 1588 | my %params = @_; | ||||
| 1589 | |||||
| 1590 | my $borrowernumber = $params{'borrowernumber'} || undef; | ||||
| 1591 | my $biblionumber = $params{'biblionumber'} || undef; | ||||
| 1592 | my $suspend_until = $params{'suspend_until'} || undef; | ||||
| 1593 | my $suspend = defined( $params{'suspend'} ) ? $params{'suspend'} : 1; | ||||
| 1594 | |||||
| 1595 | $suspend_until = C4::Dates->new( $suspend_until )->output("iso") if ( defined( $suspend_until ) ); | ||||
| 1596 | |||||
| 1597 | return unless ( $borrowernumber || $biblionumber ); | ||||
| 1598 | |||||
| 1599 | my ( $query, $sth, $dbh, @query_params ); | ||||
| 1600 | |||||
| 1601 | $query = "UPDATE reserves SET suspend = ? "; | ||||
| 1602 | push( @query_params, $suspend ); | ||||
| 1603 | if ( !$suspend ) { | ||||
| 1604 | $query .= ", suspend_until = NULL "; | ||||
| 1605 | } elsif ( $suspend_until ) { | ||||
| 1606 | $query .= ", suspend_until = ? "; | ||||
| 1607 | push( @query_params, $suspend_until ); | ||||
| 1608 | } | ||||
| 1609 | $query .= " WHERE "; | ||||
| 1610 | if ( $borrowernumber ) { | ||||
| 1611 | $query .= " borrowernumber = ? "; | ||||
| 1612 | push( @query_params, $borrowernumber ); | ||||
| 1613 | } | ||||
| 1614 | $query .= " AND " if ( $borrowernumber && $biblionumber ); | ||||
| 1615 | if ( $biblionumber ) { | ||||
| 1616 | $query .= " biblionumber = ? "; | ||||
| 1617 | push( @query_params, $biblionumber ); | ||||
| 1618 | } | ||||
| 1619 | $query .= " AND found IS NULL "; | ||||
| 1620 | |||||
| 1621 | $dbh = C4::Context->dbh; | ||||
| 1622 | $sth = $dbh->prepare( $query ); | ||||
| 1623 | $sth->execute( @query_params ); | ||||
| 1624 | $sth->finish; | ||||
| 1625 | } | ||||
| 1626 | |||||
| 1627 | |||||
| 1628 | =head2 _FixPriority | ||||
| 1629 | |||||
| - - | |||||
| 1641 | sub _FixPriority { | ||||
| 1642 | my ( $biblio, $borrowernumber, $rank, $ignoreSetLowestRank ) = @_; | ||||
| 1643 | my $dbh = C4::Context->dbh; | ||||
| 1644 | if ( $rank eq "del" ) { | ||||
| 1645 | CancelReserve( $biblio, undef, $borrowernumber ); | ||||
| 1646 | } | ||||
| 1647 | if ( $rank eq "W" || $rank eq "0" ) { | ||||
| 1648 | |||||
| 1649 | # make sure priority for waiting or in-transit items is 0 | ||||
| 1650 | my $query = qq/ | ||||
| 1651 | UPDATE reserves | ||||
| 1652 | SET priority = 0 | ||||
| 1653 | WHERE biblionumber = ? | ||||
| 1654 | AND borrowernumber = ? | ||||
| 1655 | AND found IN ('W', 'T') | ||||
| 1656 | /; | ||||
| 1657 | my $sth = $dbh->prepare($query); | ||||
| 1658 | $sth->execute( $biblio, $borrowernumber ); | ||||
| 1659 | } | ||||
| 1660 | my @priority; | ||||
| 1661 | my @reservedates; | ||||
| 1662 | |||||
| 1663 | # get whats left | ||||
| 1664 | # FIXME adding a new security in returned elements for changing priority, | ||||
| 1665 | # now, we don't care anymore any reservations with itemnumber linked (suppose a waiting reserve) | ||||
| 1666 | # This is wrong a waiting reserve has W set | ||||
| 1667 | # The assumption that having an itemnumber set means waiting is wrong and should be corrected any place it occurs | ||||
| 1668 | my $query = qq/ | ||||
| 1669 | SELECT borrowernumber, reservedate, constrainttype | ||||
| 1670 | FROM reserves | ||||
| 1671 | WHERE biblionumber = ? | ||||
| 1672 | AND ((found <> 'W' AND found <> 'T') or found is NULL) | ||||
| 1673 | ORDER BY priority ASC | ||||
| 1674 | /; | ||||
| 1675 | my $sth = $dbh->prepare($query); | ||||
| 1676 | $sth->execute($biblio); | ||||
| 1677 | while ( my $line = $sth->fetchrow_hashref ) { | ||||
| 1678 | push( @reservedates, $line ); | ||||
| 1679 | push( @priority, $line ); | ||||
| 1680 | } | ||||
| 1681 | |||||
| 1682 | # To find the matching index | ||||
| 1683 | my $i; | ||||
| 1684 | my $key = -1; # to allow for 0 to be a valid result | ||||
| 1685 | for ( $i = 0 ; $i < @priority ; $i++ ) { | ||||
| 1686 | if ( $borrowernumber == $priority[$i]->{'borrowernumber'} ) { | ||||
| 1687 | $key = $i; # save the index | ||||
| 1688 | last; | ||||
| 1689 | } | ||||
| 1690 | } | ||||
| 1691 | |||||
| 1692 | # if index exists in array then move it to new position | ||||
| 1693 | if ( $key > -1 && $rank ne 'del' && $rank > 0 ) { | ||||
| 1694 | my $new_rank = $rank - | ||||
| 1695 | 1; # $new_rank is what you want the new index to be in the array | ||||
| 1696 | my $moving_item = splice( @priority, $key, 1 ); | ||||
| 1697 | splice( @priority, $new_rank, 0, $moving_item ); | ||||
| 1698 | } | ||||
| 1699 | |||||
| 1700 | # now fix the priority on those that are left.... | ||||
| 1701 | $query = " | ||||
| 1702 | UPDATE reserves | ||||
| 1703 | SET priority = ? | ||||
| 1704 | WHERE biblionumber = ? | ||||
| 1705 | AND borrowernumber = ? | ||||
| 1706 | AND reservedate = ? | ||||
| 1707 | AND found IS NULL | ||||
| 1708 | "; | ||||
| 1709 | $sth = $dbh->prepare($query); | ||||
| 1710 | for ( my $j = 0 ; $j < @priority ; $j++ ) { | ||||
| 1711 | $sth->execute( | ||||
| 1712 | $j + 1, $biblio, | ||||
| 1713 | $priority[$j]->{'borrowernumber'}, | ||||
| 1714 | $priority[$j]->{'reservedate'} | ||||
| 1715 | ); | ||||
| 1716 | $sth->finish; | ||||
| 1717 | } | ||||
| 1718 | |||||
| 1719 | $sth = $dbh->prepare( "SELECT borrowernumber FROM reserves WHERE lowestPriority = 1 ORDER BY priority" ); | ||||
| 1720 | $sth->execute(); | ||||
| 1721 | |||||
| 1722 | unless ( $ignoreSetLowestRank ) { | ||||
| 1723 | while ( my $res = $sth->fetchrow_hashref() ) { | ||||
| 1724 | _FixPriority( $biblio, $res->{'borrowernumber'}, '999999', 1 ); | ||||
| 1725 | } | ||||
| 1726 | } | ||||
| 1727 | } | ||||
| 1728 | |||||
| 1729 | =head2 _Findgroupreserve | ||||
| 1730 | |||||
| - - | |||||
| 1746 | sub _Findgroupreserve { | ||||
| 1747 | my ( $bibitem, $biblio, $itemnumber ) = @_; | ||||
| 1748 | my $dbh = C4::Context->dbh; | ||||
| 1749 | |||||
| 1750 | # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var. | ||||
| 1751 | # check for exact targetted match | ||||
| 1752 | my $item_level_target_query = qq/ | ||||
| 1753 | SELECT reserves.biblionumber AS biblionumber, | ||||
| 1754 | reserves.borrowernumber AS borrowernumber, | ||||
| 1755 | reserves.reservedate AS reservedate, | ||||
| 1756 | reserves.branchcode AS branchcode, | ||||
| 1757 | reserves.cancellationdate AS cancellationdate, | ||||
| 1758 | reserves.found AS found, | ||||
| 1759 | reserves.reservenotes AS reservenotes, | ||||
| 1760 | reserves.priority AS priority, | ||||
| 1761 | reserves.timestamp AS timestamp, | ||||
| 1762 | biblioitems.biblioitemnumber AS biblioitemnumber, | ||||
| 1763 | reserves.itemnumber AS itemnumber | ||||
| 1764 | FROM reserves | ||||
| 1765 | JOIN biblioitems USING (biblionumber) | ||||
| 1766 | JOIN hold_fill_targets USING (biblionumber, borrowernumber, itemnumber) | ||||
| 1767 | WHERE found IS NULL | ||||
| 1768 | AND priority > 0 | ||||
| 1769 | AND item_level_request = 1 | ||||
| 1770 | AND itemnumber = ? | ||||
| 1771 | AND reservedate <= CURRENT_DATE() | ||||
| 1772 | AND suspend = 0 | ||||
| 1773 | /; | ||||
| 1774 | my $sth = $dbh->prepare($item_level_target_query); | ||||
| 1775 | $sth->execute($itemnumber); | ||||
| 1776 | my @results; | ||||
| 1777 | if ( my $data = $sth->fetchrow_hashref ) { | ||||
| 1778 | push( @results, $data ); | ||||
| 1779 | } | ||||
| 1780 | return @results if @results; | ||||
| 1781 | |||||
| 1782 | # check for title-level targetted match | ||||
| 1783 | my $title_level_target_query = qq/ | ||||
| 1784 | SELECT reserves.biblionumber AS biblionumber, | ||||
| 1785 | reserves.borrowernumber AS borrowernumber, | ||||
| 1786 | reserves.reservedate AS reservedate, | ||||
| 1787 | reserves.branchcode AS branchcode, | ||||
| 1788 | reserves.cancellationdate AS cancellationdate, | ||||
| 1789 | reserves.found AS found, | ||||
| 1790 | reserves.reservenotes AS reservenotes, | ||||
| 1791 | reserves.priority AS priority, | ||||
| 1792 | reserves.timestamp AS timestamp, | ||||
| 1793 | biblioitems.biblioitemnumber AS biblioitemnumber, | ||||
| 1794 | reserves.itemnumber AS itemnumber | ||||
| 1795 | FROM reserves | ||||
| 1796 | JOIN biblioitems USING (biblionumber) | ||||
| 1797 | JOIN hold_fill_targets USING (biblionumber, borrowernumber) | ||||
| 1798 | WHERE found IS NULL | ||||
| 1799 | AND priority > 0 | ||||
| 1800 | AND item_level_request = 0 | ||||
| 1801 | AND hold_fill_targets.itemnumber = ? | ||||
| 1802 | AND reservedate <= CURRENT_DATE() | ||||
| 1803 | AND suspend = 0 | ||||
| 1804 | /; | ||||
| 1805 | $sth = $dbh->prepare($title_level_target_query); | ||||
| 1806 | $sth->execute($itemnumber); | ||||
| 1807 | @results = (); | ||||
| 1808 | if ( my $data = $sth->fetchrow_hashref ) { | ||||
| 1809 | push( @results, $data ); | ||||
| 1810 | } | ||||
| 1811 | return @results if @results; | ||||
| 1812 | |||||
| 1813 | my $query = qq/ | ||||
| 1814 | SELECT reserves.biblionumber AS biblionumber, | ||||
| 1815 | reserves.borrowernumber AS borrowernumber, | ||||
| 1816 | reserves.reservedate AS reservedate, | ||||
| 1817 | reserves.waitingdate AS waitingdate, | ||||
| 1818 | reserves.branchcode AS branchcode, | ||||
| 1819 | reserves.cancellationdate AS cancellationdate, | ||||
| 1820 | reserves.found AS found, | ||||
| 1821 | reserves.reservenotes AS reservenotes, | ||||
| 1822 | reserves.priority AS priority, | ||||
| 1823 | reserves.timestamp AS timestamp, | ||||
| 1824 | reserveconstraints.biblioitemnumber AS biblioitemnumber, | ||||
| 1825 | reserves.itemnumber AS itemnumber | ||||
| 1826 | FROM reserves | ||||
| 1827 | LEFT JOIN reserveconstraints ON reserves.biblionumber = reserveconstraints.biblionumber | ||||
| 1828 | WHERE reserves.biblionumber = ? | ||||
| 1829 | AND ( ( reserveconstraints.biblioitemnumber = ? | ||||
| 1830 | AND reserves.borrowernumber = reserveconstraints.borrowernumber | ||||
| 1831 | AND reserves.reservedate = reserveconstraints.reservedate ) | ||||
| 1832 | OR reserves.constrainttype='a' ) | ||||
| 1833 | AND (reserves.itemnumber IS NULL OR reserves.itemnumber = ?) | ||||
| 1834 | AND reserves.reservedate <= CURRENT_DATE() | ||||
| 1835 | AND suspend = 0 | ||||
| 1836 | /; | ||||
| 1837 | $sth = $dbh->prepare($query); | ||||
| 1838 | $sth->execute( $biblio, $bibitem, $itemnumber ); | ||||
| 1839 | @results = (); | ||||
| 1840 | while ( my $data = $sth->fetchrow_hashref ) { | ||||
| 1841 | push( @results, $data ); | ||||
| 1842 | } | ||||
| 1843 | return @results; | ||||
| 1844 | } | ||||
| 1845 | |||||
| 1846 | =head2 _koha_notify_reserve | ||||
| 1847 | |||||
| - - | |||||
| 1855 | sub _koha_notify_reserve { | ||||
| 1856 | my ($itemnumber, $borrowernumber, $biblionumber) = @_; | ||||
| 1857 | |||||
| 1858 | my $dbh = C4::Context->dbh; | ||||
| 1859 | my $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber); | ||||
| 1860 | |||||
| 1861 | # Try to get the borrower's email address | ||||
| 1862 | my $to_address = C4::Members::GetNoticeEmailAddress($borrowernumber); | ||||
| 1863 | |||||
| 1864 | my $letter_code; | ||||
| 1865 | my $print_mode = 0; | ||||
| 1866 | my $messagingprefs; | ||||
| 1867 | if ( $to_address || $borrower->{'smsalertnumber'} ) { | ||||
| 1868 | $messagingprefs = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $borrowernumber, message_name => 'Hold_Filled' } ); | ||||
| 1869 | } else { | ||||
| 1870 | $print_mode = 1; | ||||
| 1871 | } | ||||
| 1872 | |||||
| 1873 | my $sth = $dbh->prepare(" | ||||
| 1874 | SELECT * | ||||
| 1875 | FROM reserves | ||||
| 1876 | WHERE borrowernumber = ? | ||||
| 1877 | AND biblionumber = ? | ||||
| 1878 | "); | ||||
| 1879 | $sth->execute( $borrowernumber, $biblionumber ); | ||||
| 1880 | my $reserve = $sth->fetchrow_hashref; | ||||
| 1881 | my $branch_details = GetBranchDetail( $reserve->{'branchcode'} ); | ||||
| 1882 | |||||
| 1883 | my $admin_email_address = $branch_details->{'branchemail'} || C4::Context->preference('KohaAdminEmailAddress'); | ||||
| 1884 | |||||
| 1885 | my %letter_params = ( | ||||
| 1886 | module => 'reserves', | ||||
| 1887 | branchcode => $reserve->{branchcode}, | ||||
| 1888 | tables => { | ||||
| 1889 | 'branches' => $branch_details, | ||||
| 1890 | 'borrowers' => $borrower, | ||||
| 1891 | 'biblio' => $biblionumber, | ||||
| 1892 | 'reserves' => $reserve, | ||||
| 1893 | 'items', $reserve->{'itemnumber'}, | ||||
| 1894 | }, | ||||
| 1895 | substitute => { today => C4::Dates->new()->output() }, | ||||
| 1896 | ); | ||||
| 1897 | |||||
| 1898 | |||||
| 1899 | if ( $print_mode ) { | ||||
| 1900 | $letter_params{ 'letter_code' } = 'HOLD_PRINT'; | ||||
| 1901 | my $letter = C4::Letters::GetPreparedLetter ( %letter_params ) or die "Could not find a letter called '$letter_params{'letter_code'}' in the 'reserves' module"; | ||||
| 1902 | |||||
| 1903 | C4::Letters::EnqueueLetter( { | ||||
| 1904 | letter => $letter, | ||||
| 1905 | borrowernumber => $borrowernumber, | ||||
| 1906 | message_transport_type => 'print', | ||||
| 1907 | } ); | ||||
| 1908 | |||||
| 1909 | return; | ||||
| 1910 | } | ||||
| 1911 | |||||
| 1912 | if ( $to_address && defined $messagingprefs->{transports}->{'email'} ) { | ||||
| 1913 | $letter_params{ 'letter_code' } = $messagingprefs->{transports}->{'email'}; | ||||
| 1914 | my $letter = C4::Letters::GetPreparedLetter ( %letter_params ) or die "Could not find a letter called '$letter_params{'letter_code'}' in the 'reserves' module"; | ||||
| 1915 | |||||
| 1916 | C4::Letters::EnqueueLetter( | ||||
| 1917 | { letter => $letter, | ||||
| 1918 | borrowernumber => $borrowernumber, | ||||
| 1919 | message_transport_type => 'email', | ||||
| 1920 | from_address => $admin_email_address, | ||||
| 1921 | } | ||||
| 1922 | ); | ||||
| 1923 | } | ||||
| 1924 | |||||
| 1925 | if ( $borrower->{'smsalertnumber'} && defined $messagingprefs->{transports}->{'sms'} ) { | ||||
| 1926 | $letter_params{ 'letter_code' } = $messagingprefs->{transports}->{'sms'}; | ||||
| 1927 | my $letter = C4::Letters::GetPreparedLetter ( %letter_params ) or die "Could not find a letter called '$letter_params{'letter_code'}' in the 'reserves' module"; | ||||
| 1928 | |||||
| 1929 | C4::Letters::EnqueueLetter( | ||||
| 1930 | { letter => $letter, | ||||
| 1931 | borrowernumber => $borrowernumber, | ||||
| 1932 | message_transport_type => 'sms', | ||||
| 1933 | } | ||||
| 1934 | ); | ||||
| 1935 | } | ||||
| 1936 | } | ||||
| 1937 | |||||
| 1938 | =head2 _ShiftPriorityByDateAndPriority | ||||
| 1939 | |||||
| - - | |||||
| 1956 | sub _ShiftPriorityByDateAndPriority { | ||||
| 1957 | my ( $biblio, $resdate, $new_priority ) = @_; | ||||
| 1958 | |||||
| 1959 | my $dbh = C4::Context->dbh; | ||||
| 1960 | my $query = "SELECT priority FROM reserves WHERE biblionumber = ? AND ( reservedate > ? OR priority > ? ) ORDER BY priority ASC LIMIT 1"; | ||||
| 1961 | my $sth = $dbh->prepare( $query ); | ||||
| 1962 | $sth->execute( $biblio, $resdate, $new_priority ); | ||||
| 1963 | my $min_priority = $sth->fetchrow; | ||||
| 1964 | # if no such matches are found, $new_priority remains as original value | ||||
| 1965 | $new_priority = $min_priority if ( $min_priority ); | ||||
| 1966 | |||||
| 1967 | # Shift the priority up by one; works in conjunction with the next SQL statement | ||||
| 1968 | $query = "UPDATE reserves | ||||
| 1969 | SET priority = priority+1 | ||||
| 1970 | WHERE biblionumber = ? | ||||
| 1971 | AND borrowernumber = ? | ||||
| 1972 | AND reservedate = ? | ||||
| 1973 | AND found IS NULL"; | ||||
| 1974 | my $sth_update = $dbh->prepare( $query ); | ||||
| 1975 | |||||
| 1976 | # Select all reserves for the biblio with priority greater than $new_priority, and order greatest to least | ||||
| 1977 | $query = "SELECT borrowernumber, reservedate FROM reserves WHERE priority >= ? AND biblionumber = ? ORDER BY priority DESC"; | ||||
| 1978 | $sth = $dbh->prepare( $query ); | ||||
| 1979 | $sth->execute( $new_priority, $biblio ); | ||||
| 1980 | while ( my $row = $sth->fetchrow_hashref ) { | ||||
| 1981 | $sth_update->execute( $biblio, $row->{borrowernumber}, $row->{reservedate} ); | ||||
| 1982 | } | ||||
| 1983 | |||||
| 1984 | return $new_priority; # so the caller knows what priority they wind up receiving | ||||
| 1985 | } | ||||
| 1986 | |||||
| 1987 | =head2 MoveReserve | ||||
| 1988 | |||||
| - - | |||||
| 1996 | sub MoveReserve { | ||||
| 1997 | my ( $itemnumber, $borrowernumber, $cancelreserve ) = @_; | ||||
| 1998 | |||||
| 1999 | my ( $restype, $res, $all_reserves ) = CheckReserves( $itemnumber ); | ||||
| 2000 | return unless $res; | ||||
| 2001 | |||||
| 2002 | my $biblionumber = $res->{biblionumber}; | ||||
| 2003 | my $biblioitemnumber = $res->{biblioitemnumber}; | ||||
| 2004 | |||||
| 2005 | if ($res->{borrowernumber} == $borrowernumber) { | ||||
| 2006 | ModReserveFill($res); | ||||
| 2007 | } | ||||
| 2008 | else { | ||||
| 2009 | # warn "Reserved"; | ||||
| 2010 | # The item is reserved by someone else. | ||||
| 2011 | # Find this item in the reserves | ||||
| 2012 | |||||
| 2013 | my $borr_res; | ||||
| 2014 | foreach (@$all_reserves) { | ||||
| 2015 | $_->{'borrowernumber'} == $borrowernumber or next; | ||||
| 2016 | $_->{'biblionumber'} == $biblionumber or next; | ||||
| 2017 | |||||
| 2018 | $borr_res = $_; | ||||
| 2019 | last; | ||||
| 2020 | } | ||||
| 2021 | |||||
| 2022 | if ( $borr_res ) { | ||||
| 2023 | # The item is reserved by the current patron | ||||
| 2024 | ModReserveFill($borr_res); | ||||
| 2025 | } | ||||
| 2026 | |||||
| 2027 | if ( $cancelreserve eq 'revert' ) { ## Revert waiting reserve to priority 1 | ||||
| 2028 | RevertWaitingStatus({ itemnumber => $itemnumber }); | ||||
| 2029 | } | ||||
| 2030 | elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item | ||||
| 2031 | CancelReserve(0, $res->{'itemnumber'}, $res->{'borrowernumber'}); | ||||
| 2032 | CancelReserve($res->{'biblionumber'}, 0, $res->{'borrowernumber'}); | ||||
| 2033 | } | ||||
| 2034 | } | ||||
| 2035 | } | ||||
| 2036 | |||||
| 2037 | =head2 MergeHolds | ||||
| 2038 | |||||
| - - | |||||
| 2045 | sub MergeHolds { | ||||
| 2046 | my ( $dbh, $to_biblio, $from_biblio ) = @_; | ||||
| 2047 | my $sth = $dbh->prepare( | ||||
| 2048 | "SELECT count(*) as reservenumber FROM reserves WHERE biblionumber = ?" | ||||
| 2049 | ); | ||||
| 2050 | $sth->execute($from_biblio); | ||||
| 2051 | if ( my $data = $sth->fetchrow_hashref() ) { | ||||
| 2052 | |||||
| 2053 | # holds exist on old record, if not we don't need to do anything | ||||
| 2054 | $sth = $dbh->prepare( | ||||
| 2055 | "UPDATE reserves SET biblionumber = ? WHERE biblionumber = ?"); | ||||
| 2056 | $sth->execute( $to_biblio, $from_biblio ); | ||||
| 2057 | |||||
| 2058 | # Reorder by date | ||||
| 2059 | # don't reorder those already waiting | ||||
| 2060 | |||||
| 2061 | $sth = $dbh->prepare( | ||||
| 2062 | "SELECT * FROM reserves WHERE biblionumber = ? AND (found <> ? AND found <> ? OR found is NULL) ORDER BY reservedate ASC" | ||||
| 2063 | ); | ||||
| 2064 | my $upd_sth = $dbh->prepare( | ||||
| 2065 | "UPDATE reserves SET priority = ? WHERE biblionumber = ? AND borrowernumber = ? | ||||
| 2066 | AND reservedate = ? AND constrainttype = ? AND (itemnumber = ? or itemnumber is NULL) " | ||||
| 2067 | ); | ||||
| 2068 | $sth->execute( $to_biblio, 'W', 'T' ); | ||||
| 2069 | my $priority = 1; | ||||
| 2070 | while ( my $reserve = $sth->fetchrow_hashref() ) { | ||||
| 2071 | $upd_sth->execute( | ||||
| 2072 | $priority, $to_biblio, | ||||
| 2073 | $reserve->{'borrowernumber'}, $reserve->{'reservedate'}, | ||||
| 2074 | $reserve->{'constrainttype'}, $reserve->{'itemnumber'} | ||||
| 2075 | ); | ||||
| 2076 | $priority++; | ||||
| 2077 | } | ||||
| 2078 | } | ||||
| 2079 | } | ||||
| 2080 | |||||
| 2081 | =head2 RevertWaitingStatus | ||||
| 2082 | |||||
| - - | |||||
| 2095 | sub RevertWaitingStatus { | ||||
| 2096 | my ( $params ) = @_; | ||||
| 2097 | my $itemnumber = $params->{'itemnumber'}; | ||||
| 2098 | |||||
| 2099 | return unless ( $itemnumber ); | ||||
| 2100 | |||||
| 2101 | my $dbh = C4::Context->dbh; | ||||
| 2102 | |||||
| 2103 | ## Get the waiting reserve we want to revert | ||||
| 2104 | my $query = " | ||||
| 2105 | SELECT * FROM reserves | ||||
| 2106 | WHERE itemnumber = ? | ||||
| 2107 | AND found IS NOT NULL | ||||
| 2108 | "; | ||||
| 2109 | my $sth = $dbh->prepare( $query ); | ||||
| 2110 | $sth->execute( $itemnumber ); | ||||
| 2111 | my $reserve = $sth->fetchrow_hashref(); | ||||
| 2112 | |||||
| 2113 | ## Increment the priority of all other non-waiting | ||||
| 2114 | ## reserves for this bib record | ||||
| 2115 | $query = " | ||||
| 2116 | UPDATE reserves | ||||
| 2117 | SET | ||||
| 2118 | priority = priority + 1 | ||||
| 2119 | WHERE | ||||
| 2120 | biblionumber = ? | ||||
| 2121 | AND | ||||
| 2122 | priority > 0 | ||||
| 2123 | "; | ||||
| 2124 | $sth = $dbh->prepare( $query ); | ||||
| 2125 | $sth->execute( $reserve->{'biblionumber'} ); | ||||
| 2126 | |||||
| 2127 | ## Fix up the currently waiting reserve | ||||
| 2128 | $query = " | ||||
| 2129 | UPDATE reserves | ||||
| 2130 | SET | ||||
| 2131 | priority = 1, | ||||
| 2132 | found = NULL, | ||||
| 2133 | waitingdate = NULL | ||||
| 2134 | WHERE | ||||
| 2135 | reserve_id = ? | ||||
| 2136 | "; | ||||
| 2137 | $sth = $dbh->prepare( $query ); | ||||
| 2138 | return $sth->execute( $reserve->{'reserve_id'} ); | ||||
| 2139 | } | ||||
| 2140 | |||||
| 2141 | =head2 ReserveSlip | ||||
| 2142 | |||||
| - - | |||||
| 2149 | sub ReserveSlip { | ||||
| 2150 | my ($branch, $borrowernumber, $biblionumber) = @_; | ||||
| 2151 | |||||
| 2152 | # return unless ( C4::Context->boolean_preference('printreserveslips') ); | ||||
| 2153 | |||||
| 2154 | my $reserve = GetReserveInfo($borrowernumber,$biblionumber ) | ||||
| 2155 | or return; | ||||
| 2156 | |||||
| 2157 | return C4::Letters::GetPreparedLetter ( | ||||
| 2158 | module => 'circulation', | ||||
| 2159 | letter_code => 'RESERVESLIP', | ||||
| 2160 | branchcode => $branch, | ||||
| 2161 | tables => { | ||||
| 2162 | 'reserves' => $reserve, | ||||
| 2163 | 'branches' => $reserve->{branchcode}, | ||||
| 2164 | 'borrowers' => $reserve->{borrowernumber}, | ||||
| 2165 | 'biblio' => $reserve->{biblionumber}, | ||||
| 2166 | 'items' => $reserve->{itemnumber}, | ||||
| 2167 | }, | ||||
| 2168 | ); | ||||
| 2169 | } | ||||
| 2170 | |||||
| 2171 | =head1 AUTHOR | ||||
| 2172 | |||||
| - - | |||||
| 2177 | 1 | 4µs | 1; |