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 |
"; |