|
Lines 167-192
sub AddReserve {
Link Here
|
| 167 |
# Make room in reserves for this before those of a later reserve date |
167 |
# Make room in reserves for this before those of a later reserve date |
| 168 |
$priority = _ShiftPriorityByDateAndPriority( $biblionumber, $resdate, $priority ); |
168 |
$priority = _ShiftPriorityByDateAndPriority( $biblionumber, $resdate, $priority ); |
| 169 |
} |
169 |
} |
| 170 |
my $waitingdate; |
170 |
my ($waitingdate, $lastpickupdate); |
| 171 |
|
171 |
|
|
|
172 |
my $item = C4::Items::GetItem( $checkitem ); |
| 172 |
# If the reserv had the waiting status, we had the value of the resdate |
173 |
# If the reserv had the waiting status, we had the value of the resdate |
| 173 |
if ( $found eq 'W' ) { |
174 |
if ( $found eq 'W' ) { |
| 174 |
$waitingdate = $resdate; |
175 |
$waitingdate = $resdate; |
|
|
176 |
|
| 177 |
#The reserve-object doesn't exist yet in DB, so we must supply what information we have to GetLastPickupDate() so it can do it's work. |
| 178 |
my $reserve = {borrowernumber => $borrowernumber, waitingdate => $waitingdate, branchcode => $branch}; |
| 179 |
$lastpickupdate = GetLastPickupDate( $reserve, $item ); |
| 175 |
} |
180 |
} |
| 176 |
|
181 |
|
| 177 |
# updates take place here |
182 |
# updates take place here |
| 178 |
my $query = qq{ |
183 |
my $query = qq{ |
| 179 |
INSERT INTO reserves |
184 |
INSERT INTO reserves |
| 180 |
(borrowernumber,biblionumber,reservedate,branchcode, |
185 |
(borrowernumber,biblionumber,reservedate,branchcode, |
| 181 |
priority,reservenotes,itemnumber,found,waitingdate,expirationdate) |
186 |
priority,reservenotes,itemnumber,found,waitingdate,expirationdate,lastpickupdate) |
| 182 |
VALUES |
187 |
VALUES |
| 183 |
(?,?,?,?,?, |
188 |
(?,?,?,?,?, |
| 184 |
?,?,?,?,?) |
189 |
?,?,?,?,?,?) |
| 185 |
}; |
190 |
}; |
| 186 |
my $sth = $dbh->prepare($query); |
191 |
my $sth = $dbh->prepare($query); |
| 187 |
$sth->execute( |
192 |
$sth->execute( |
| 188 |
$borrowernumber, $biblionumber, $resdate, $branch, $priority, |
193 |
$borrowernumber, $biblionumber, $resdate, $branch, $priority, |
| 189 |
$notes, $checkitem, $found, $waitingdate, $expdate |
194 |
$notes, $checkitem, $found, $waitingdate, $expdate, |
|
|
195 |
$lastpickupdate |
| 190 |
); |
196 |
); |
| 191 |
my $reserve_id = $sth->{mysql_insertid}; |
197 |
my $reserve_id = $sth->{mysql_insertid}; |
| 192 |
# add a reserve fee if needed |
198 |
# add a reserve fee if needed |
|
Lines 738-744
sub GetReservesForBranch {
Link Here
|
| 738 |
my $dbh = C4::Context->dbh; |
744 |
my $dbh = C4::Context->dbh; |
| 739 |
|
745 |
|
| 740 |
my $query = " |
746 |
my $query = " |
| 741 |
SELECT reserve_id,borrowernumber,reservedate,itemnumber,waitingdate |
747 |
SELECT reserve_id,borrowernumber,reservedate,itemnumber,waitingdate, lastpickupdate |
| 742 |
FROM reserves |
748 |
FROM reserves |
| 743 |
WHERE priority='0' |
749 |
WHERE priority='0' |
| 744 |
AND found='W' |
750 |
AND found='W' |
|
Lines 762-767
sub GetReservesForBranch {
Link Here
|
| 762 |
return (@transreserv); |
768 |
return (@transreserv); |
| 763 |
} |
769 |
} |
| 764 |
|
770 |
|
|
|
771 |
=head2 GetLastPickupDate |
| 772 |
|
| 773 |
my $lastpickupdate = GetLastPickupDate($reserve, $item); |
| 774 |
my $lastpickupdate = GetLastPickupDate($reserve, $item, $borrower); |
| 775 |
my $lastpickupdate = GetLastPickupDate(undef, $item); |
| 776 |
|
| 777 |
Gets the last pickup date from the issuingrules for the given reserves-row and sets the |
| 778 |
$reserve->{lastpickupdate}.-value. |
| 779 |
If the reserves-row is not passed, function tries to figure it out from the item-row. |
| 780 |
|
| 781 |
Calculating the last pickup date respects Calendar holidays and skips to the next open day. |
| 782 |
|
| 783 |
If the issuingrule's holdspickupwait is 0 or less, means that the lastpickupdate-feature |
| 784 |
is disabled for this kind of material. |
| 785 |
|
| 786 |
@PARAM1 koha.reserves-row |
| 787 |
@PARAM2 koha.items-row, If the reserve is not given, an item must be given to be |
| 788 |
able to find a reservation |
| 789 |
@PARAM3 koha.borrowers-row, OPTIONAL |
| 790 |
RETURNS DateTime, depicting the last pickup date. |
| 791 |
OR undef if there is an error or if the issuingrules disable this feature for this material. |
| 792 |
=cut |
| 793 |
|
| 794 |
sub GetLastPickupDate { |
| 795 |
my ($reserve, $item, $borrower) = @_; |
| 796 |
|
| 797 |
##Verify parameters |
| 798 |
if ( not defined $reserve and not defined $item ) { |
| 799 |
warn "C4::Reserves::GetMaxPickupDate(), is called without a reserve and an item"; |
| 800 |
return; |
| 801 |
} |
| 802 |
if ( defined $reserve and not defined $item ) { |
| 803 |
$item = C4::Items::GetItem( $reserve->{itemnumber} ); |
| 804 |
} |
| 805 |
unless ( defined $reserve ) { |
| 806 |
my $reserve = GetReservesFromItemnumber( $item->{itemnumber} ); |
| 807 |
} |
| 808 |
|
| 809 |
my $date = $reserve->{waitingdate}; |
| 810 |
unless ( $date ) { #It is possible that a reserve is just caught and it doesn't have a waitingdate yet. |
| 811 |
$date = DateTime->now( time_zone => C4::Context->tz() ); #So default to NOW() |
| 812 |
} |
| 813 |
else { |
| 814 |
$date = (ref $reserve->{waitingdate} eq 'DateTime') ? $reserve->{waitingdate} : dt_from_string($reserve->{waitingdate}); |
| 815 |
} |
| 816 |
$borrower = C4::Members::GetMember( 'borrowernumber' => $reserve->{borrowernumber} ) unless $borrower; |
| 817 |
|
| 818 |
##Get churning the LastPickupDate |
| 819 |
my $controlbranch = GetReservesControlBranch( $item, $borrower ); |
| 820 |
|
| 821 |
my $issuingrule = C4::Circulation::GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $controlbranch ); |
| 822 |
|
| 823 |
if ( defined($issuingrule) |
| 824 |
&& defined $issuingrule->{holdspickupwait} |
| 825 |
&& $issuingrule->{holdspickupwait} > 0 ) { #If holdspickupwait is <= 0, it means this feature is disabled for this type of material. |
| 826 |
|
| 827 |
$date->add( days => $issuingrule->{holdspickupwait} ); |
| 828 |
|
| 829 |
my $calendar = Koha::Calendar->new( branchcode => $reserve->{'branchcode'} ); |
| 830 |
my $is_holiday = $calendar->is_holiday( $date ); |
| 831 |
|
| 832 |
while ( $is_holiday ) { |
| 833 |
$date->add( days => 1 ); |
| 834 |
$is_holiday = $calendar->is_holiday( $date ); |
| 835 |
} |
| 836 |
|
| 837 |
$reserve->{lastpickupdate} = $date->ymd(); |
| 838 |
return $date; |
| 839 |
} |
| 840 |
#Without explicitly setting the return value undef, the lastpickupdate-column is |
| 841 |
# set as 0000-00-00 instead of NULL in DBD::MySQL. |
| 842 |
#This causes this hold to always expire any lastpickupdate check, |
| 843 |
# effectively canceling it as soon as cancel_expired_holds.pl is ran. |
| 844 |
#This is exactly the opposite of disabling the autoexpire feature. |
| 845 |
#So please let me explicitly return undef, because Perl cant always handle everything. |
| 846 |
delete $reserve->{lastpickupdate}; |
| 847 |
return undef; |
| 848 |
} |
| 849 |
=head2 GetReservesControlBranch |
| 850 |
|
| 851 |
$branchcode = &GetReservesControlBranch($borrower, $item) |
| 852 |
|
| 853 |
Returns the branchcode to consider to check hold rules against |
| 854 |
|
| 855 |
=cut |
| 856 |
|
| 857 |
sub GetReservesControlBranch { |
| 858 |
my ( $borrower, $item ) = @_; |
| 859 |
my $controlbranch = C4::Context->preference('ReservesControlBranch'); |
| 860 |
my $hbr = C4::Context->preference('HomeOrHoldingBranch') || "homebranch"; |
| 861 |
my $branchcode = "*"; |
| 862 |
if ( $controlbranch eq "ItemHomeLibrary" ) { |
| 863 |
$branchcode = $item->{$hbr}; |
| 864 |
} elsif ( $controlbranch eq "PatronLibrary" ) { |
| 865 |
$branchcode = $borrower->{branchcode}; |
| 866 |
} |
| 867 |
return $branchcode; |
| 868 |
} |
| 869 |
|
| 765 |
=head2 GetReserveStatus |
870 |
=head2 GetReserveStatus |
| 766 |
|
871 |
|
| 767 |
$reservestatus = GetReserveStatus($itemnumber); |
872 |
$reservestatus = GetReserveStatus($itemnumber); |
|
Lines 971-999
sub CancelExpiredReserves {
Link Here
|
| 971 |
|
1076 |
|
| 972 |
# Cancel reserves that have been waiting too long |
1077 |
# Cancel reserves that have been waiting too long |
| 973 |
if ( C4::Context->preference("ExpireReservesMaxPickUpDelay") ) { |
1078 |
if ( C4::Context->preference("ExpireReservesMaxPickUpDelay") ) { |
| 974 |
my $max_pickup_delay = C4::Context->preference("ReservesMaxPickUpDelay"); |
|
|
| 975 |
my $cancel_on_holidays = C4::Context->preference('ExpireReservesOnHolidays'); |
| 976 |
|
1079 |
|
| 977 |
my $today = dt_from_string(); |
1080 |
my $query = "SELECT * FROM reserves WHERE NOW() > lastpickupdate AND found = 'W' AND priority = 0"; |
| 978 |
|
|
|
| 979 |
my $query = "SELECT * FROM reserves WHERE TO_DAYS( NOW() ) - TO_DAYS( waitingdate ) > ? AND found = 'W' AND priority = 0"; |
| 980 |
$sth = $dbh->prepare( $query ); |
1081 |
$sth = $dbh->prepare( $query ); |
| 981 |
$sth->execute( $max_pickup_delay ); |
1082 |
$sth->execute(); |
| 982 |
|
1083 |
|
| 983 |
while ( my $res = $sth->fetchrow_hashref ) { |
1084 |
while ( my $res = $sth->fetchrow_hashref ) { |
| 984 |
my $do_cancel = 1; |
|
|
| 985 |
unless ( $cancel_on_holidays ) { |
| 986 |
my $calendar = Koha::Calendar->new( branchcode => $res->{'branchcode'} ); |
| 987 |
my $is_holiday = $calendar->is_holiday( $today ); |
| 988 |
|
| 989 |
if ( $is_holiday ) { |
| 990 |
$do_cancel = 0; |
| 991 |
} |
| 992 |
} |
| 993 |
|
| 994 |
if ( $do_cancel ) { |
| 995 |
CancelReserve({ reserve_id => $res->{'reserve_id'}, charge_cancel_fee => 1 }); |
1085 |
CancelReserve({ reserve_id => $res->{'reserve_id'}, charge_cancel_fee => 1 }); |
| 996 |
} |
|
|
| 997 |
} |
1086 |
} |
| 998 |
} |
1087 |
} |
| 999 |
|
1088 |
|
|
Lines 1239-1248
sub ModReserveStatus {
Link Here
|
| 1239 |
#first : check if we have a reservation for this item . |
1328 |
#first : check if we have a reservation for this item . |
| 1240 |
my ($itemnumber, $newstatus) = @_; |
1329 |
my ($itemnumber, $newstatus) = @_; |
| 1241 |
my $dbh = C4::Context->dbh; |
1330 |
my $dbh = C4::Context->dbh; |
|
|
1331 |
|
| 1332 |
my $now = dt_from_string; |
| 1333 |
my $reserve = $dbh->selectrow_hashref(q{ |
| 1334 |
SELECT * |
| 1335 |
FROM reserves |
| 1336 |
WHERE itemnumber = ? |
| 1337 |
AND found IS NULL |
| 1338 |
AND priority = 0 |
| 1339 |
}, {}, $itemnumber); |
| 1340 |
return unless $reserve; |
| 1341 |
|
| 1342 |
my $lastpickupdate = GetLastPickupDate( $reserve ); |
| 1242 |
|
1343 |
|
| 1243 |
my $query = "UPDATE reserves SET found = ?, waitingdate = NOW() WHERE itemnumber = ? AND found IS NULL AND priority = 0"; |
1344 |
my $query = q{ |
|
|
1345 |
UPDATE reserves |
| 1346 |
SET found = ?, |
| 1347 |
waitingdate = ?, |
| 1348 |
lastpickupdate = ? |
| 1349 |
WHERE itemnumber = ? |
| 1350 |
AND found IS NULL |
| 1351 |
AND priority = 0 |
| 1352 |
}; |
| 1244 |
my $sth_set = $dbh->prepare($query); |
1353 |
my $sth_set = $dbh->prepare($query); |
| 1245 |
$sth_set->execute( $newstatus, $itemnumber ); |
1354 |
$sth_set->execute( $newstatus, $now, $lastpickupdate, $itemnumber ); |
| 1246 |
|
1355 |
|
| 1247 |
if ( C4::Context->preference("ReturnToShelvingCart") && $newstatus ) { |
1356 |
if ( C4::Context->preference("ReturnToShelvingCart") && $newstatus ) { |
| 1248 |
CartToShelf( $itemnumber ); |
1357 |
CartToShelf( $itemnumber ); |
|
Lines 1295-1315
sub ModReserveAffect {
Link Here
|
| 1295 |
WHERE borrowernumber = ? |
1404 |
WHERE borrowernumber = ? |
| 1296 |
AND biblionumber = ? |
1405 |
AND biblionumber = ? |
| 1297 |
"; |
1406 |
"; |
|
|
1407 |
$sth = $dbh->prepare($query); |
| 1408 |
$sth->execute( $itemnumber, $borrowernumber,$biblionumber); |
| 1298 |
} |
1409 |
} |
| 1299 |
else { |
1410 |
else { |
| 1300 |
# affect the reserve to Waiting as well. |
1411 |
# affect the reserve to Waiting as well. |
|
|
1412 |
my $item = C4::Items::GetItem( $itemnumber ); |
| 1413 |
my $lastpickupdate = GetLastPickupDate( $request, $item ); |
| 1301 |
$query = " |
1414 |
$query = " |
| 1302 |
UPDATE reserves |
1415 |
UPDATE reserves |
| 1303 |
SET priority = 0, |
1416 |
SET priority = 0, |
| 1304 |
found = 'W', |
1417 |
found = 'W', |
| 1305 |
waitingdate = NOW(), |
1418 |
waitingdate = NOW(), |
|
|
1419 |
lastpickupdate = ?, |
| 1306 |
itemnumber = ? |
1420 |
itemnumber = ? |
| 1307 |
WHERE borrowernumber = ? |
1421 |
WHERE borrowernumber = ? |
| 1308 |
AND biblionumber = ? |
1422 |
AND biblionumber = ? |
| 1309 |
"; |
1423 |
"; |
|
|
1424 |
$sth = $dbh->prepare($query); |
| 1425 |
$sth->execute( $lastpickupdate, $itemnumber, $borrowernumber,$biblionumber); |
| 1310 |
} |
1426 |
} |
| 1311 |
$sth = $dbh->prepare($query); |
1427 |
|
| 1312 |
$sth->execute( $itemnumber, $borrowernumber,$biblionumber); |
|
|
| 1313 |
_koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf ); |
1428 |
_koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf ); |
| 1314 |
_FixPriority( { biblionumber => $biblionumber } ); |
1429 |
_FixPriority( { biblionumber => $biblionumber } ); |
| 1315 |
if ( C4::Context->preference("ReturnToShelvingCart") ) { |
1430 |
if ( C4::Context->preference("ReturnToShelvingCart") ) { |
|
Lines 1385-1390
sub GetReserveInfo {
Link Here
|
| 1385 |
reserves.biblionumber, |
1500 |
reserves.biblionumber, |
| 1386 |
reserves.branchcode, |
1501 |
reserves.branchcode, |
| 1387 |
reserves.waitingdate, |
1502 |
reserves.waitingdate, |
|
|
1503 |
reserves.lastpickupdate, |
| 1388 |
notificationdate, |
1504 |
notificationdate, |
| 1389 |
reminderdate, |
1505 |
reminderdate, |
| 1390 |
priority, |
1506 |
priority, |
|
Lines 1821-1826
sub _Findgroupreserve {
Link Here
|
| 1821 |
reserves.borrowernumber AS borrowernumber, |
1937 |
reserves.borrowernumber AS borrowernumber, |
| 1822 |
reserves.reservedate AS reservedate, |
1938 |
reserves.reservedate AS reservedate, |
| 1823 |
reserves.branchcode AS branchcode, |
1939 |
reserves.branchcode AS branchcode, |
|
|
1940 |
reserves.lastpickupdate AS lastpickupdate, |
| 1824 |
reserves.cancellationdate AS cancellationdate, |
1941 |
reserves.cancellationdate AS cancellationdate, |
| 1825 |
reserves.found AS found, |
1942 |
reserves.found AS found, |
| 1826 |
reserves.reservenotes AS reservenotes, |
1943 |
reserves.reservenotes AS reservenotes, |
|
Lines 1855-1860
sub _Findgroupreserve {
Link Here
|
| 1855 |
reserves.borrowernumber AS borrowernumber, |
1972 |
reserves.borrowernumber AS borrowernumber, |
| 1856 |
reserves.reservedate AS reservedate, |
1973 |
reserves.reservedate AS reservedate, |
| 1857 |
reserves.branchcode AS branchcode, |
1974 |
reserves.branchcode AS branchcode, |
|
|
1975 |
reserves.lastpickupdate AS lastpickupdate, |
| 1858 |
reserves.cancellationdate AS cancellationdate, |
1976 |
reserves.cancellationdate AS cancellationdate, |
| 1859 |
reserves.found AS found, |
1977 |
reserves.found AS found, |
| 1860 |
reserves.reservenotes AS reservenotes, |
1978 |
reserves.reservenotes AS reservenotes, |
|
Lines 1889-1894
sub _Findgroupreserve {
Link Here
|
| 1889 |
reserves.reservedate AS reservedate, |
2007 |
reserves.reservedate AS reservedate, |
| 1890 |
reserves.waitingdate AS waitingdate, |
2008 |
reserves.waitingdate AS waitingdate, |
| 1891 |
reserves.branchcode AS branchcode, |
2009 |
reserves.branchcode AS branchcode, |
|
|
2010 |
reserves.lastpickupdate AS lastpickupdate, |
| 1892 |
reserves.cancellationdate AS cancellationdate, |
2011 |
reserves.cancellationdate AS cancellationdate, |
| 1893 |
reserves.found AS found, |
2012 |
reserves.found AS found, |
| 1894 |
reserves.reservenotes AS reservenotes, |
2013 |
reserves.reservenotes AS reservenotes, |
|
Lines 2145-2150
sub MoveReserve {
Link Here
|
| 2145 |
} |
2264 |
} |
| 2146 |
} |
2265 |
} |
| 2147 |
|
2266 |
|
|
|
2267 |
=head MoveWaitingdate |
| 2268 |
|
| 2269 |
#Move waitingdate two months and fifteen days forward. |
| 2270 |
my $dateDuration = DateTime::Duration->new( months => 2, days => 15 ); |
| 2271 |
$reserve = MoveWaitingdate( $reserve, $dateDuration); |
| 2272 |
|
| 2273 |
#Move waitingdate one year and eleven days backwards. |
| 2274 |
my $dateDuration = DateTime::Duration->new( years => -1, days => -11 ); |
| 2275 |
$reserve = MoveWaitingdate( $reserve, $dateDuration); |
| 2276 |
|
| 2277 |
Moves the waitingdate and updates the lastpickupdate to match. |
| 2278 |
If waitingdate is not defined, uses today. |
| 2279 |
Is intended to be used from automated tests, because under normal library |
| 2280 |
operations there should be NO REASON to move the waitingdate. |
| 2281 |
|
| 2282 |
@PARAM1 koha.reserves-row, with waitingdate set. |
| 2283 |
@PARAM2 DateTime::Duration, with the desired offset. |
| 2284 |
RETURNS koha.reserve-row, with keys waitingdate and lastpickupdate updated. |
| 2285 |
=cut |
| 2286 |
sub MoveWaitingdate { |
| 2287 |
my ($reserve, $dateDuration) = @_; |
| 2288 |
|
| 2289 |
my $dt = dt_from_string( $reserve->{waitingdate} ); |
| 2290 |
$dt->add_duration( $dateDuration ); |
| 2291 |
$reserve->{waitingdate} = $dt->ymd(); |
| 2292 |
|
| 2293 |
GetLastPickupDate( $reserve ); #Update the $reserve->{lastpickupdate} |
| 2294 |
|
| 2295 |
#UPDATE the DB part |
| 2296 |
my $dbh = C4::Context->dbh(); |
| 2297 |
my $sth = $dbh->prepare( "UPDATE reserves SET waitingdate=?, lastpickupdate=? WHERE reserve_id=?" ); |
| 2298 |
$sth->execute( $reserve->{waitingdate}, $reserve->{lastpickupdate}, $reserve->{reserve_id} ); |
| 2299 |
|
| 2300 |
return $reserve; |
| 2301 |
} |
| 2302 |
|
| 2148 |
=head2 MergeHolds |
2303 |
=head2 MergeHolds |
| 2149 |
|
2304 |
|
| 2150 |
MergeHolds($dbh,$to_biblio, $from_biblio); |
2305 |
MergeHolds($dbh,$to_biblio, $from_biblio); |
|
Lines 2241-2247
sub RevertWaitingStatus {
Link Here
|
| 2241 |
SET |
2396 |
SET |
| 2242 |
priority = 1, |
2397 |
priority = 1, |
| 2243 |
found = NULL, |
2398 |
found = NULL, |
| 2244 |
waitingdate = NULL |
2399 |
waitingdate = NULL, |
|
|
2400 |
lastpickupdate = NULL, |
| 2245 |
WHERE |
2401 |
WHERE |
| 2246 |
reserve_id = ? |
2402 |
reserve_id = ? |
| 2247 |
"; |
2403 |
"; |