Lines 168-178
sub AddReserve {
Link Here
|
168 |
# Make room in reserves for this before those of a later reserve date |
168 |
# Make room in reserves for this before those of a later reserve date |
169 |
$priority = _ShiftPriorityByDateAndPriority( $biblionumber, $resdate, $priority ); |
169 |
$priority = _ShiftPriorityByDateAndPriority( $biblionumber, $resdate, $priority ); |
170 |
} |
170 |
} |
171 |
my $waitingdate; |
171 |
my ($waitingdate, $lastpickupdate); |
172 |
|
172 |
|
|
|
173 |
my $item = C4::Items::GetItem( $checkitem ); |
173 |
# If the reserv had the waiting status, we had the value of the resdate |
174 |
# If the reserv had the waiting status, we had the value of the resdate |
174 |
if ( $found eq 'W' ) { |
175 |
if ( $found eq 'W' ) { |
175 |
$waitingdate = $resdate; |
176 |
$waitingdate = $resdate; |
|
|
177 |
|
178 |
#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. |
179 |
my $reserve = {borrowernumber => $borrowernumber, waitingdate => $waitingdate, branchcode => $branch}; |
180 |
$lastpickupdate = GetLastPickupDate( $reserve, $item ); |
176 |
} |
181 |
} |
177 |
|
182 |
|
178 |
#eval { |
183 |
#eval { |
Lines 194-209
sub AddReserve {
Link Here
|
194 |
my $query = qq/ |
199 |
my $query = qq/ |
195 |
INSERT INTO reserves |
200 |
INSERT INTO reserves |
196 |
(borrowernumber,biblionumber,reservedate,branchcode,constrainttype, |
201 |
(borrowernumber,biblionumber,reservedate,branchcode,constrainttype, |
197 |
priority,reservenotes,itemnumber,found,waitingdate,expirationdate) |
202 |
priority,reservenotes,itemnumber,found,waitingdate,expirationdate,lastpickupdate) |
198 |
VALUES |
203 |
VALUES |
199 |
(?,?,?,?,?, |
204 |
(?,?,?,?,?, |
200 |
?,?,?,?,?,?) |
205 |
?,?,?,?,?,?,?) |
201 |
/; |
206 |
/; |
202 |
my $sth = $dbh->prepare($query); |
207 |
my $sth = $dbh->prepare($query); |
203 |
$sth->execute( |
208 |
$sth->execute( |
204 |
$borrowernumber, $biblionumber, $resdate, $branch, |
209 |
$borrowernumber, $biblionumber, $resdate, $branch, |
205 |
$const, $priority, $notes, $checkitem, |
210 |
$const, $priority, $notes, $checkitem, |
206 |
$found, $waitingdate, $expdate |
211 |
$found, $waitingdate, $expdate, $lastpickupdate |
207 |
); |
212 |
); |
208 |
|
213 |
|
209 |
# Send e-mail to librarian if syspref is active |
214 |
# Send e-mail to librarian if syspref is active |
Lines 806-815
sub GetReservesToBranch {
Link Here
|
806 |
|
811 |
|
807 |
sub GetReservesForBranch { |
812 |
sub GetReservesForBranch { |
808 |
my ($frombranch) = @_; |
813 |
my ($frombranch) = @_; |
809 |
my $dbh = C4::Context->dbh; |
|
|
810 |
|
814 |
|
811 |
my $query = " |
815 |
my $dbh = C4::Context->dbh; |
812 |
SELECT reserve_id,borrowernumber,reservedate,itemnumber,waitingdate |
816 |
my $query = " |
|
|
817 |
SELECT reserve_id, borrowernumber, reservedate, itemnumber, waitingdate, lastpickupdate |
813 |
FROM reserves |
818 |
FROM reserves |
814 |
WHERE priority='0' |
819 |
WHERE priority='0' |
815 |
AND found='W' |
820 |
AND found='W' |
Lines 874-879
sub GetReserveStatus {
Link Here
|
874 |
return ''; # empty string here will remove need for checking undef, or less log lines |
879 |
return ''; # empty string here will remove need for checking undef, or less log lines |
875 |
} |
880 |
} |
876 |
|
881 |
|
|
|
882 |
=head2 GetLastPickupDate |
883 |
|
884 |
my $lastpickupdate = GetLastPickupDate($reserve, $item); |
885 |
my $lastpickupdate = GetLastPickupDate($reserve, $item, $borrower); |
886 |
my $lastpickupdate = GetLastPickupDate(undef, $item); |
887 |
|
888 |
Gets the last pickup date from the issuingrules for the given reserves-row and sets the |
889 |
$reserve->{lastpickupdate}.-value. |
890 |
If the reserves-row is not passed, function tries to figure it out from the item-row. |
891 |
|
892 |
Calculating the last pickup date respects Calendar holidays and skips to the next open day. |
893 |
|
894 |
If the issuingrule's holdspickupwait is 0 or less, means that the lastpickupdate-feature |
895 |
is disabled for this kind of material. |
896 |
|
897 |
@PARAM1 koha.reserves-row |
898 |
@PARAM2 koha.items-row, If the reserve is not given, an item must be given to be |
899 |
able to find a reservation |
900 |
@PARAM3 koha.borrowers-row, OPTIONAL |
901 |
RETURNS DateTime, depicting the last pickup date. |
902 |
OR undef if there is an error or if the issuingrules disable this feature for this material. |
903 |
=cut |
904 |
|
905 |
sub GetLastPickupDate { |
906 |
my ($reserve, $item, $borrower) = @_; |
907 |
|
908 |
##Verify parameters |
909 |
if ( not defined $reserve and not defined $item ) { |
910 |
warn "C4::Reserves::GetMaxPickupDate(), is called without a reserve and an item"; |
911 |
return; |
912 |
} |
913 |
if ( defined $reserve and not defined $item ) { |
914 |
$item = C4::Items::GetItem( $reserve->{itemnumber} ); |
915 |
} |
916 |
unless ( defined $reserve ) { |
917 |
my $reserve = GetReservesFromItemnumber( $item->{itemnumber} ); |
918 |
} |
919 |
|
920 |
my $date = $reserve->{waitingdate}; |
921 |
unless ( $date ) { #It is possible that a reserve is just caught and it doesn't have a waitingdate yet. |
922 |
$date = DateTime->now( time_zone => C4::Context->tz() ); #So default to NOW() |
923 |
} |
924 |
else { |
925 |
$date = (ref $reserve->{waitingdate} eq 'DateTime') ? $reserve->{waitingdate} : dt_from_string($reserve->{waitingdate}); |
926 |
} |
927 |
$borrower = C4::Members::GetMember( 'borrowernumber' => $reserve->{borrowernumber} ) unless $borrower; |
928 |
|
929 |
##Get churning the LastPickupDate |
930 |
my $controlbranch = GetReservesControlBranch( $item, $borrower ); |
931 |
|
932 |
my $issuingrule = C4::Circulation::GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $controlbranch ); |
933 |
|
934 |
if ( defined($issuingrule) |
935 |
&& defined $issuingrule->{holdspickupwait} |
936 |
&& $issuingrule->{holdspickupwait} > 0 ) { #If holdspickupwait is <= 0, it means this feature is disabled for this type of material. |
937 |
|
938 |
$date->add( days => $issuingrule->{holdspickupwait} ); |
939 |
|
940 |
my $calendar = Koha::Calendar->new( branchcode => $reserve->{'branchcode'} ); |
941 |
my $is_holiday = $calendar->is_holiday( $date ); |
942 |
|
943 |
while ( $is_holiday ) { |
944 |
$date->add( days => 1 ); |
945 |
$is_holiday = $calendar->is_holiday( $date ); |
946 |
} |
947 |
|
948 |
$reserve->{lastpickupdate} = $date->ymd(); |
949 |
return $date; |
950 |
} |
951 |
#Without explicitly setting the return value undef, the lastpickupdate-column is |
952 |
# set as 0000-00-00 instead of NULL in DBD::MySQL. |
953 |
#This causes this hold to always expire any lastpickupdate check, |
954 |
# effectively canceling it as soon as cancel_expired_holds.pl is ran. |
955 |
#This is exactly the opposite of disabling the autoexpire feature. |
956 |
#So please let me explicitly return undef, because Perl cant always handle everything. |
957 |
delete $reserve->{lastpickupdate}; |
958 |
return undef; |
959 |
} |
960 |
=head2 GetReservesControlBranch |
961 |
|
962 |
$branchcode = &GetReservesControlBranch($borrower, $item) |
963 |
|
964 |
Returns the branchcode to consider to check hold rules against |
965 |
|
966 |
=cut |
967 |
|
968 |
sub GetReservesControlBranch { |
969 |
my ( $borrower, $item ) = @_; |
970 |
my $controlbranch = C4::Context->preference('ReservesControlBranch'); |
971 |
my $hbr = C4::Context->preference('HomeOrHoldingBranch') || "homebranch"; |
972 |
my $branchcode = "*"; |
973 |
if ( $controlbranch eq "ItemHomeLibrary" ) { |
974 |
$branchcode = $item->{$hbr}; |
975 |
} elsif ( $controlbranch eq "PatronLibrary" ) { |
976 |
$branchcode = $borrower->{branchcode}; |
977 |
} |
978 |
return $branchcode; |
979 |
} |
980 |
|
877 |
=head2 CheckReserves |
981 |
=head2 CheckReserves |
878 |
|
982 |
|
879 |
($status, $reserve, $all_reserves) = &CheckReserves($itemnumber); |
983 |
($status, $reserve, $all_reserves) = &CheckReserves($itemnumber); |
Lines 1017-1051
sub CancelExpiredReserves {
Link Here
|
1017 |
} |
1121 |
} |
1018 |
|
1122 |
|
1019 |
# Cancel reserves that have been waiting too long |
1123 |
# Cancel reserves that have been waiting too long |
1020 |
if ( C4::Context->preference("ExpireReservesMaxPickUpDelay") ) { |
1124 |
if (C4::Context->preference("ExpireReservesMaxPickUpDelay")) { |
1021 |
my $max_pickup_delay = C4::Context->preference("ReservesMaxPickUpDelay"); |
|
|
1022 |
my $charge = C4::Context->preference("ExpireReservesMaxPickUpDelayCharge"); |
1023 |
my $cancel_on_holidays = C4::Context->preference('ExpireReservesOnHolidays'); |
1024 |
|
1125 |
|
1025 |
my $today = dt_from_string(); |
1126 |
my $today = dt_from_string(); |
|
|
1127 |
my $charge = C4::Context->preference("ExpireReservesMaxPickUpDelayCharge"); |
1026 |
|
1128 |
|
1027 |
my $query = "SELECT * FROM reserves WHERE TO_DAYS( NOW() ) - TO_DAYS( waitingdate ) > ? AND found = 'W' AND priority = 0"; |
1129 |
my $query = "SELECT * FROM reserves WHERE NOW() > lastpickupdate AND found = 'W' AND priority = 0"; |
1028 |
$sth = $dbh->prepare( $query ); |
1130 |
$sth = $dbh->prepare( $query ); |
1029 |
$sth->execute( $max_pickup_delay ); |
1131 |
$sth->execute(); |
1030 |
|
1132 |
|
1031 |
while ( my $res = $sth->fetchrow_hashref ) { |
1133 |
while ( my $res = $sth->fetchrow_hashref ) { |
1032 |
my $do_cancel = 1; |
|
|
1033 |
unless ( $cancel_on_holidays ) { |
1034 |
my $calendar = Koha::Calendar->new( branchcode => $res->{'branchcode'} ); |
1035 |
my $is_holiday = $calendar->is_holiday( $today ); |
1036 |
|
1134 |
|
1037 |
if ( $is_holiday ) { |
1135 |
if ( $charge ) { |
1038 |
$do_cancel = 0; |
1136 |
manualinvoice($res->{'borrowernumber'}, $res->{'itemnumber'}, 'Hold waiting too long', 'F', $charge); |
1039 |
} |
|
|
1040 |
} |
1137 |
} |
1041 |
|
1138 |
|
1042 |
if ( $do_cancel ) { |
1139 |
CancelReserve({ reserve_id => $res->{'reserve_id'} }); |
1043 |
if ( $charge ) { |
|
|
1044 |
manualinvoice($res->{'borrowernumber'}, $res->{'itemnumber'}, 'Hold waiting too long', 'F', $charge); |
1045 |
} |
1046 |
|
1047 |
CancelReserve({ reserve_id => $res->{'reserve_id'} }); |
1048 |
} |
1049 |
} |
1140 |
} |
1050 |
} |
1141 |
} |
1051 |
|
1142 |
|
Lines 1284-1292
sub ModReserveStatus {
Link Here
|
1284 |
my ($itemnumber, $newstatus) = @_; |
1375 |
my ($itemnumber, $newstatus) = @_; |
1285 |
my $dbh = C4::Context->dbh; |
1376 |
my $dbh = C4::Context->dbh; |
1286 |
|
1377 |
|
1287 |
my $query = "UPDATE reserves SET found = ?, waitingdate = NOW() WHERE itemnumber = ? AND found IS NULL AND priority = 0"; |
1378 |
my $now = dt_from_string; |
|
|
1379 |
my $reserve = $dbh->selectrow_hashref(q{ |
1380 |
SELECT * |
1381 |
FROM reserves |
1382 |
WHERE itemnumber = ? |
1383 |
AND found IS NULL |
1384 |
AND priority = 0 |
1385 |
}, {}, $itemnumber); |
1386 |
return unless $reserve; |
1387 |
|
1388 |
my $lastpickupdate = GetLastPickupDate( $reserve ); |
1389 |
my $query = q{ |
1390 |
UPDATE reserves |
1391 |
SET found = ?, |
1392 |
waitingdate = ?, |
1393 |
maxpickupdate = ? |
1394 |
WHERE itemnumber = ? |
1395 |
AND found IS NULL |
1396 |
AND priority = 0 |
1397 |
}; |
1288 |
my $sth_set = $dbh->prepare($query); |
1398 |
my $sth_set = $dbh->prepare($query); |
1289 |
$sth_set->execute( $newstatus, $itemnumber ); |
1399 |
$sth_set->execute( $newstatus, $now, $lastpickupdate, $itemnumber ); |
1290 |
|
1400 |
|
1291 |
if ( C4::Context->preference("ReturnToShelvingCart") && $newstatus ) { |
1401 |
if ( C4::Context->preference("ReturnToShelvingCart") && $newstatus ) { |
1292 |
CartToShelf( $itemnumber ); |
1402 |
CartToShelf( $itemnumber ); |
Lines 1331-1359
sub ModReserveAffect {
Link Here
|
1331 |
# If we affect a reserve that has to be transfered, don't set to Waiting |
1441 |
# If we affect a reserve that has to be transfered, don't set to Waiting |
1332 |
my $query; |
1442 |
my $query; |
1333 |
if ($transferToDo) { |
1443 |
if ($transferToDo) { |
1334 |
$query = " |
1444 |
$query = " |
1335 |
UPDATE reserves |
1445 |
UPDATE reserves |
1336 |
SET priority = 0, |
1446 |
SET priority = 0, |
1337 |
itemnumber = ?, |
1447 |
itemnumber = ?, |
1338 |
found = 'T' |
1448 |
found = 'T' |
1339 |
WHERE borrowernumber = ? |
1449 |
WHERE borrowernumber = ? |
1340 |
AND biblionumber = ? |
1450 |
AND biblionumber = ? |
1341 |
"; |
1451 |
"; |
|
|
1452 |
$sth = $dbh->prepare($query); |
1453 |
$sth->execute( $itemnumber, $borrowernumber,$biblionumber); |
1342 |
} |
1454 |
} |
1343 |
else { |
1455 |
else { |
1344 |
# affect the reserve to Waiting as well. |
1456 |
# affect the reserve to Waiting as well. |
|
|
1457 |
my $item = C4::Items::GetItem( $itemnumber ); |
1458 |
my $lastpickupdate = GetLastPickupDate( $request, $item ); |
1345 |
$query = " |
1459 |
$query = " |
1346 |
UPDATE reserves |
1460 |
UPDATE reserves |
1347 |
SET priority = 0, |
1461 |
SET priority = 0, |
1348 |
found = 'W', |
1462 |
found = 'W', |
1349 |
waitingdate = NOW(), |
1463 |
waitingdate = NOW(), |
|
|
1464 |
lastpickupdate = ?, |
1350 |
itemnumber = ? |
1465 |
itemnumber = ? |
1351 |
WHERE borrowernumber = ? |
1466 |
WHERE borrowernumber = ? |
1352 |
AND biblionumber = ? |
1467 |
AND biblionumber = ? |
1353 |
"; |
1468 |
"; |
|
|
1469 |
$sth = $dbh->prepare($query); |
1470 |
$sth->execute( $lastpickupdate, $itemnumber, $borrowernumber,$biblionumber); |
1354 |
} |
1471 |
} |
1355 |
$sth = $dbh->prepare($query); |
|
|
1356 |
$sth->execute( $itemnumber, $borrowernumber,$biblionumber); |
1357 |
_koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf ); |
1472 |
_koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf ); |
1358 |
_FixPriority( { biblionumber => $biblionumber } ); |
1473 |
_FixPriority( { biblionumber => $biblionumber } ); |
1359 |
if ( C4::Context->preference("ReturnToShelvingCart") ) { |
1474 |
if ( C4::Context->preference("ReturnToShelvingCart") ) { |
Lines 1429-1434
sub GetReserveInfo {
Link Here
|
1429 |
reserves.biblionumber, |
1544 |
reserves.biblionumber, |
1430 |
reserves.branchcode, |
1545 |
reserves.branchcode, |
1431 |
reserves.waitingdate, |
1546 |
reserves.waitingdate, |
|
|
1547 |
reserves.lastpickupdate, |
1432 |
notificationdate, |
1548 |
notificationdate, |
1433 |
reminderdate, |
1549 |
reminderdate, |
1434 |
priority, |
1550 |
priority, |
Lines 1840-1845
sub _Findgroupreserve {
Link Here
|
1840 |
reserves.borrowernumber AS borrowernumber, |
1956 |
reserves.borrowernumber AS borrowernumber, |
1841 |
reserves.reservedate AS reservedate, |
1957 |
reserves.reservedate AS reservedate, |
1842 |
reserves.branchcode AS branchcode, |
1958 |
reserves.branchcode AS branchcode, |
|
|
1959 |
reserves.lastpickupdate AS lastpickupdate, |
1843 |
reserves.cancellationdate AS cancellationdate, |
1960 |
reserves.cancellationdate AS cancellationdate, |
1844 |
reserves.found AS found, |
1961 |
reserves.found AS found, |
1845 |
reserves.reservenotes AS reservenotes, |
1962 |
reserves.reservenotes AS reservenotes, |
Lines 1872-1877
sub _Findgroupreserve {
Link Here
|
1872 |
reserves.borrowernumber AS borrowernumber, |
1989 |
reserves.borrowernumber AS borrowernumber, |
1873 |
reserves.reservedate AS reservedate, |
1990 |
reserves.reservedate AS reservedate, |
1874 |
reserves.branchcode AS branchcode, |
1991 |
reserves.branchcode AS branchcode, |
|
|
1992 |
reserves.lastpickupdate AS lastpickupdate, |
1875 |
reserves.cancellationdate AS cancellationdate, |
1993 |
reserves.cancellationdate AS cancellationdate, |
1876 |
reserves.found AS found, |
1994 |
reserves.found AS found, |
1877 |
reserves.reservenotes AS reservenotes, |
1995 |
reserves.reservenotes AS reservenotes, |
Lines 1904-1909
sub _Findgroupreserve {
Link Here
|
1904 |
reserves.reservedate AS reservedate, |
2022 |
reserves.reservedate AS reservedate, |
1905 |
reserves.waitingdate AS waitingdate, |
2023 |
reserves.waitingdate AS waitingdate, |
1906 |
reserves.branchcode AS branchcode, |
2024 |
reserves.branchcode AS branchcode, |
|
|
2025 |
reserves.lastpickupdate AS lastpickupdate, |
1907 |
reserves.cancellationdate AS cancellationdate, |
2026 |
reserves.cancellationdate AS cancellationdate, |
1908 |
reserves.found AS found, |
2027 |
reserves.found AS found, |
1909 |
reserves.reservenotes AS reservenotes, |
2028 |
reserves.reservenotes AS reservenotes, |
Lines 2117-2122
sub MoveReserve {
Link Here
|
2117 |
} |
2236 |
} |
2118 |
} |
2237 |
} |
2119 |
|
2238 |
|
|
|
2239 |
=head MoveWaitingdate |
2240 |
|
2241 |
#Move waitingdate two months and fifteen days forward. |
2242 |
my $dateDuration = DateTime::Duration->new( months => 2, days => 15 ); |
2243 |
$reserve = MoveWaitingdate( $reserve, $dateDuration); |
2244 |
|
2245 |
#Move waitingdate one year and eleven days backwards. |
2246 |
my $dateDuration = DateTime::Duration->new( years => -1, days => -11 ); |
2247 |
$reserve = MoveWaitingdate( $reserve, $dateDuration); |
2248 |
|
2249 |
Moves the waitingdate and updates the lastpickupdate to match. |
2250 |
If waitingdate is not defined, uses today. |
2251 |
Is intended to be used from automated tests, because under normal library |
2252 |
operations there should be NO REASON to move the waitingdate. |
2253 |
|
2254 |
@PARAM1 koha.reserves-row, with waitingdate set. |
2255 |
@PARAM2 DateTime::Duration, with the desired offset. |
2256 |
RETURNS koha.reserve-row, with keys waitingdate and lastpickupdate updated. |
2257 |
=cut |
2258 |
sub MoveWaitingdate { |
2259 |
my ($reserve, $dateDuration) = @_; |
2260 |
|
2261 |
my $dt = dt_from_string( $reserve->{waitingdate} ); |
2262 |
$dt->add_duration( $dateDuration ); |
2263 |
$reserve->{waitingdate} = $dt->ymd(); |
2264 |
|
2265 |
GetLastPickupDate( $reserve ); #Update the $reserve->{lastpickupdate} |
2266 |
|
2267 |
#UPDATE the DB part |
2268 |
my $dbh = C4::Context->dbh(); |
2269 |
my $sth = $dbh->prepare( "UPDATE reserves SET waitingdate=?, lastpickupdate=? WHERE reserve_id=?" ); |
2270 |
$sth->execute( $reserve->{waitingdate}, $reserve->{lastpickupdate}, $reserve->{reserve_id} ); |
2271 |
|
2272 |
return $reserve; |
2273 |
} |
2274 |
|
2120 |
=head2 MergeHolds |
2275 |
=head2 MergeHolds |
2121 |
|
2276 |
|
2122 |
MergeHolds($dbh,$to_biblio, $from_biblio); |
2277 |
MergeHolds($dbh,$to_biblio, $from_biblio); |
Lines 2213-2219
sub RevertWaitingStatus {
Link Here
|
2213 |
SET |
2368 |
SET |
2214 |
priority = 1, |
2369 |
priority = 1, |
2215 |
found = NULL, |
2370 |
found = NULL, |
2216 |
waitingdate = NULL |
2371 |
waitingdate = NULL, |
|
|
2372 |
lastpickupdate = NULL, |
2217 |
WHERE |
2373 |
WHERE |
2218 |
reserve_id = ? |
2374 |
reserve_id = ? |
2219 |
"; |
2375 |
"; |