From 6d97cc995d1bfa991d67cc20d026dd56d058d64b Mon Sep 17 00:00:00 2001 From: Olli-Antti Kivilahti Date: Fri, 24 Oct 2014 19:55:48 +0300 Subject: [PATCH] Bug 8367 - How long is a hold waiting for pickup at a more granular level This patch adds: - a new column in the issuing rules, including help topics. - a new column reserves.lastpickupdate (+old_reserves) It contains the waitingdate + the corresponding "holds pickup wait". Each time the waitingdate is modified, this value will be modified too. - a new field issuingrules.holdspickupwait - a new function C4::Reserves::MoveWaitingdate() to help in testing this feature. This patch removes the ReservesMaxPickUpDelay syspref. - Also removes a code section from C4::Letters::_parseLetter() which worked blatantly disrespectfully towards Koha Calendar. - TODO put the <> as a placeholder in C4::Letters. - TODO figure out how to rename existing letter placeholders <> with <> The update database script will update the issuingrules table with the correct value before removing it. You can now specify a pickup delay for an hold function of a patron category and/or a item type and/or a library. -TODO Refactoring unit tests is in progress. $$$$$$$$$$$$$ $ TEST PLAN $ $$$$$$$$$$$$$ ****** ****** *** *** *** TEST: BASIC WORKFLOW * ****** ****** 1. Check there is no regression with a normal reserve workflow. 2. Add one or more issuingrules. 3. Update the new column 'Holds pickup wait' in your issuing rules. 4. In 4 templates, you can see the 'Last pickup date' for an hold (circ/circulation.tt, circ/waitingreserves.tt, members/moremember.tt, opac-user.tt). 5. According to a library and an item type, the lastpickupdate value will be equal to the waiting date + the "holds pickup wait" defined. ** ** ** ** ** ** *** *** *** TEST: RESPECTING CALENDAR HOLIDAYS * ** ** ** ** ** ** 1) Note your ReservesMaxPickUpDelay setting. 2) Create and trap a hold 3) View waitingreserves.pl, note the last pickup date, and the pickup location 4) Cancel this hold 5) Edit the calendar for the given location, and make the pickup date a single, unrepeated, holiday. Then make the next day a weekly repeating holiday. Then make the next two days an annual holiday repeatable every year. 6) Repeat step 2 7) View waitingreserves.pl, the last pickup date for this new hold should now be increased by four days. ** ** ** ** ** ** *** *** *** TEST: LETTER lastpickupdate PLACEHOLDER AND REGRESSION * ** ** ** ** ** ** 1. Modify the HOLD-letter, add <> and <> somewhere. 2. Catch a hold for a borrower. 3. See the members/notices.pl for the message queued and verify that the lastpickupdate-placeholder is set in your desired datetime format and that it is not on a holiday. Verify that the waitingdate is today. --- C4/Letters.pm | 15 -- C4/Reserves.pm | 194 +++++++++++++++++--- Koha/Schema/Result/Reserve.pm | 7 + admin/smart-rules.pl | 9 +- circ/waitingreserves.pl | 56 +++--- installer/data/mysql/kohastructure.sql | 3 + installer/data/mysql/updatedatabase.pl | 31 ++++ koha-tmpl/intranet-tmpl/prog/en/js/holds.js | 3 + .../en/modules/admin/preferences/circulation.pref | 7 +- .../prog/en/modules/admin/smart-rules.tt | 4 + .../prog/en/modules/circ/circulation.tt | 1 + .../prog/en/modules/circ/waitingreserves.tt | 8 +- .../prog/en/modules/help/admin/smart-rules.tt | 1 + .../prog/en/modules/help/circ/waitingreserves.tt | 2 +- .../prog/en/modules/members/moremember.tt | 1 + .../opac-tmpl/bootstrap/en/modules/opac-user.tt | 2 +- svc/holds | 7 +- 17 files changed, 265 insertions(+), 86 deletions(-) diff --git a/C4/Letters.pm b/C4/Letters.pm index 912294e..01207af 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -602,21 +602,6 @@ sub _parseletter_sth { sub _parseletter { my ( $letter, $table, $values ) = @_; - if ( $table eq 'reserves' && $values->{'waitingdate'} ) { - my @waitingdate = split /-/, $values->{'waitingdate'}; - - $values->{'expirationdate'} = ''; - if( C4::Context->preference('ExpireReservesMaxPickUpDelay') && - C4::Context->preference('ReservesMaxPickUpDelay') ) { - my $dt = dt_from_string(); - $dt->add( days => C4::Context->preference('ReservesMaxPickUpDelay') ); - $values->{'expirationdate'} = output_pref({ dt => $dt, dateonly => 1 }); - } - - $values->{'waitingdate'} = output_pref({ dt => dt_from_string( $values->{'waitingdate'} ), dateonly => 1 }); - - } - if ($letter->{content} && $letter->{content} =~ /<>/) { my $todaysdate = output_pref( DateTime->now() ); $letter->{content} =~ s/<>/$todaysdate/go; diff --git a/C4/Reserves.pm b/C4/Reserves.pm index 7a075a4..3a2952d 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -175,6 +175,9 @@ sub AddReserve { $waitingdate = $resdate; } + my $item = C4::Items::GetItem( $checkitem ); + my $lastpickupdate = GetLastPickupDate( undef, $item ); + #eval { # updates take place here if ( $fee > 0 ) { @@ -194,16 +197,16 @@ sub AddReserve { my $query = qq/ INSERT INTO reserves (borrowernumber,biblionumber,reservedate,branchcode,constrainttype, - priority,reservenotes,itemnumber,found,waitingdate,expirationdate) + priority,reservenotes,itemnumber,found,waitingdate,expirationdate,lastpickupdate) VALUES (?,?,?,?,?, - ?,?,?,?,?,?) + ?,?,?,?,?,?,?) /; my $sth = $dbh->prepare($query); $sth->execute( $borrowernumber, $biblionumber, $resdate, $branch, $const, $priority, $notes, $checkitem, - $found, $waitingdate, $expdate + $found, $waitingdate, $expdate, $lastpickupdate ); # Send e-mail to librarian if syspref is active @@ -806,10 +809,10 @@ sub GetReservesToBranch { sub GetReservesForBranch { my ($frombranch) = @_; - my $dbh = C4::Context->dbh; - my $query = " - SELECT reserve_id,borrowernumber,reservedate,itemnumber,waitingdate + my $dbh = C4::Context->dbh; + my $query = " + SELECT reserve_id, borrowernumber, reservedate, itemnumber, waitingdate, lastpickupdate FROM reserves WHERE priority='0' AND found='W' @@ -874,6 +877,93 @@ sub GetReserveStatus { return ''; # empty string here will remove need for checking undef, or less log lines } +=head2 GetLastPickupDate + + my $lastpickupdate = GetLastPickupDate($reserve, $item); + my $lastpickupdate = GetLastPickupDate($reserve, $item, $borrower); + my $lastpickupdate = GetLastPickupDate(undef, $item); + +Gets the last pickup date from the issuingrules for the given reserves-row and sets the +$reserve->{lastpickupdate}.-value. +If the reserves-row is not passed, function tries to figure it out from the item-row. + +Calculating the last pickup date respects Calendar holidays and skips to the next open day. + +@PARAM1 koha.reserves-row +@PARAM2 koha.items-row, If the reserve is not given, an item must be given to be + able to find a reservation +@PARAM3 koha.borrowers-row, OPTIONAL +RETURNS DateTime, depicting the last pickup date. +=cut + +sub GetLastPickupDate { + my ($reserve, $item, $borrower) = @_; + + ##Verify parameters + if ( not defined $reserve and not defined $item ) { + warn "C4::Reserves::GetMaxPickupDate(), is called without a reserve and a item"; + return; + } + if ( defined $reserve and not defined $item ) { + $item = C4::Items::GetItem( $reserve->{itemnumber} ); + } + unless ( defined $reserve ) { + my $reserve = GetReservesFromItemnumber( $item->{itemnumber} ); + } + + my $date = $reserve->{waitingdate}; + unless ( $date ) { #It is possible that a reserve is just caught and it doesn't have a waitingdate yet. + $date = DateTime->now( time_zone => C4::Context->tz() ); #So default to NOW() + } + else { + $date = (ref $reserve->{waitingdate} eq 'DateTime') ? $reserve->{waitingdate} : dt_from_string($reserve->{waitingdate}); + } + $borrower = C4::Members::GetMember( 'borrowernumber' => $reserve->{borrowernumber} ) unless $borrower; + + ##Get churning the LastPickupDate + my $controlbranch = GetReservesControlBranch( $item, $borrower ); + + my $issuingrule = C4::Circulation::GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $controlbranch ); + + my $holdspickupwait = 0; + if ( defined($issuingrule) + and defined $issuingrule->{holdspickupwait} ) { + $holdspickupwait = $issuingrule->{holdspickupwait} + } + $date->add( days => $holdspickupwait ); + + my $calendar = Koha::Calendar->new( branchcode => $reserve->{'branchcode'} ); + my $is_holiday = $calendar->is_holiday( $date ); + + while ( $is_holiday ) { + $date->add( days => 1 ); + $is_holiday = $calendar->is_holiday( $date ); + } + + $reserve->{lastpickupdate} = $date->ymd(); + return $date; +} +=head2 GetReservesControlBranch + + $branchcode = &GetReservesControlBranch($borrower, $item) + +Returns the branchcode to consider to check hold rules against + +=cut + +sub GetReservesControlBranch { + my ( $borrower, $item ) = @_; + my $controlbranch = C4::Context->preference('ReservesControlBranch'); + my $hbr = C4::Context->preference('HomeOrHoldingBranch') || "homebranch"; + my $branchcode = "*"; + if ( $controlbranch eq "ItemHomeLibrary" ) { + $branchcode = $item->{$hbr}; + } elsif ( $controlbranch eq "PatronLibrary" ) { + $branchcode = $borrower->{branchcode}; + } + return $branchcode; +} + =head2 CheckReserves ($status, $reserve, $all_reserves) = &CheckReserves($itemnumber); @@ -1018,15 +1108,14 @@ sub CancelExpiredReserves { # Cancel reserves that have been waiting too long if ( C4::Context->preference("ExpireReservesMaxPickUpDelay") ) { - my $max_pickup_delay = C4::Context->preference("ReservesMaxPickUpDelay"); my $charge = C4::Context->preference("ExpireReservesMaxPickUpDelayCharge"); my $cancel_on_holidays = C4::Context->preference('ExpireReservesOnHolidays'); my $today = dt_from_string(); - my $query = "SELECT * FROM reserves WHERE TO_DAYS( NOW() ) - TO_DAYS( waitingdate ) > ? AND found = 'W' AND priority = 0"; + my $query = "SELECT * FROM reserves WHERE NOW() > lastpickupdate AND found = 'W' AND priority = 0"; $sth = $dbh->prepare( $query ); - $sth->execute( $max_pickup_delay ); + $sth->execute(); while ( my $res = $sth->fetchrow_hashref ) { my $do_cancel = 1; @@ -1284,9 +1373,28 @@ sub ModReserveStatus { my ($itemnumber, $newstatus) = @_; my $dbh = C4::Context->dbh; - my $query = "UPDATE reserves SET found = ?, waitingdate = NOW() WHERE itemnumber = ? AND found IS NULL AND priority = 0"; + my $now = dt_from_string; + my $reserve = $dbh->selectrow_hashref(q{ + SELECT * + FROM reserves + WHERE itemnumber = ? + AND found IS NULL + AND priority = 0 + }, {}, $itemnumber); + return unless $reserve; + + my $lastpickupdate = GetLastPickupDate( $reserve ); + my $query = q{ + UPDATE reserves + SET found = ?, + waitingdate = ?, + maxpickupdate = ? + WHERE itemnumber = ? + AND found IS NULL + AND priority = 0 + }; my $sth_set = $dbh->prepare($query); - $sth_set->execute( $newstatus, $itemnumber ); + $sth_set->execute( $newstatus, $now, $lastpickupdate, $itemnumber ); if ( C4::Context->preference("ReturnToShelvingCart") && $newstatus ) { CartToShelf( $itemnumber ); @@ -1331,29 +1439,34 @@ sub ModReserveAffect { # If we affect a reserve that has to be transfered, don't set to Waiting my $query; if ($transferToDo) { - $query = " - UPDATE reserves - SET priority = 0, - itemnumber = ?, - found = 'T' - WHERE borrowernumber = ? - AND biblionumber = ? - "; + $query = " + UPDATE reserves + SET priority = 0, + itemnumber = ?, + found = 'T' + WHERE borrowernumber = ? + AND biblionumber = ? + "; + $sth = $dbh->prepare($query); + $sth->execute( $itemnumber, $borrowernumber,$biblionumber); } else { - # affect the reserve to Waiting as well. + # affect the reserve to Waiting as well. + my $item = C4::Items::GetItem( $itemnumber ); + my $lastpickupdate = GetLastPickupDate( $request, $item ); $query = " UPDATE reserves SET priority = 0, found = 'W', waitingdate = NOW(), + lastpickupdate = ?, itemnumber = ? WHERE borrowernumber = ? AND biblionumber = ? "; + $sth = $dbh->prepare($query); + $sth->execute( $lastpickupdate, $itemnumber, $borrowernumber,$biblionumber); } - $sth = $dbh->prepare($query); - $sth->execute( $itemnumber, $borrowernumber,$biblionumber); _koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf ); _FixPriority( { biblionumber => $biblionumber } ); if ( C4::Context->preference("ReturnToShelvingCart") ) { @@ -1429,6 +1542,7 @@ sub GetReserveInfo { reserves.biblionumber, reserves.branchcode, reserves.waitingdate, + reserves.lastpickupdate, notificationdate, reminderdate, priority, @@ -1840,6 +1954,7 @@ sub _Findgroupreserve { reserves.borrowernumber AS borrowernumber, reserves.reservedate AS reservedate, reserves.branchcode AS branchcode, + reserves.lastpickupdate AS maxpickupdate, reserves.cancellationdate AS cancellationdate, reserves.found AS found, reserves.reservenotes AS reservenotes, @@ -1872,6 +1987,7 @@ sub _Findgroupreserve { reserves.borrowernumber AS borrowernumber, reserves.reservedate AS reservedate, reserves.branchcode AS branchcode, + reserves.lastpickupdate AS maxpickupdate, reserves.cancellationdate AS cancellationdate, reserves.found AS found, reserves.reservenotes AS reservenotes, @@ -1904,6 +2020,7 @@ sub _Findgroupreserve { reserves.reservedate AS reservedate, reserves.waitingdate AS waitingdate, reserves.branchcode AS branchcode, + reserves.lastpickupdate AS maxpickupdate, reserves.cancellationdate AS cancellationdate, reserves.found AS found, reserves.reservenotes AS reservenotes, @@ -2117,6 +2234,36 @@ sub MoveReserve { } } +=head MoveWaitingdate + + #Move waitingdate two months and fifteen days forward. + my $dateDuration = DateTime::Duration->new( months => 2, days => 15 ); + $reserve = MoveWaitingdate( $reserve, $dateDuration); + + #Move waitingdate one year and eleven days backwards. + my $dateDuration = DateTime::Duration->new( years => -1, days => -11 ); + $reserve = MoveWaitingdate( $reserve, $dateDuration); + +Moves the waitingdate and updates the lastpickupdate to match. +Is intended to be used from automated tests, because under normal library +operations there should be NO REASON to move the waitingdate. + +@PARAM1 koha.reserves-row, with waitingdate set. +@PARAM2 DateTime::Duration, with the desired offset. +RETURNS koha.reserve-row, with keys waitingdate and lastpickupdate updated. +=cut +sub MoveWaitingdate { + my ($reserve, $dateDuration) = @_; + + my $dt = dt_from_string( $reserve->{waitingdate} ); + $dt->add_duration( $dateDuration ); + $reserve->{waitingdate} = $dateDuration->ymd(); + + GetLastPickupDate( $reserve ); #Update the $reserve->{lastpickupdate} + + return $reserve; +} + =head2 MergeHolds MergeHolds($dbh,$to_biblio, $from_biblio); @@ -2213,7 +2360,8 @@ sub RevertWaitingStatus { SET priority = 1, found = NULL, - waitingdate = NULL + waitingdate = NULL, + lastpickupdate = NULL, WHERE reserve_id = ? "; diff --git a/Koha/Schema/Result/Reserve.pm b/Koha/Schema/Result/Reserve.pm index 16f951b..894febe 100644 --- a/Koha/Schema/Result/Reserve.pm +++ b/Koha/Schema/Result/Reserve.pm @@ -139,6 +139,11 @@ __PACKAGE__->table("reserves"); datetime_undef_if_invalid: 1 is_nullable: 1 +=head2 lastpickupdate + date_type: 'date' + datetime_undef_if_invalid: 1 + is_nullable: 1 + =cut __PACKAGE__->add_columns( @@ -199,6 +204,8 @@ __PACKAGE__->add_columns( datetime_undef_if_invalid => 1, is_nullable => 1, }, + "lastpickupdate", + { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 }, ); =head1 PRIMARY KEY diff --git a/admin/smart-rules.pl b/admin/smart-rules.pl index eb3e875..a0d8dc0 100755 --- a/admin/smart-rules.pl +++ b/admin/smart-rules.pl @@ -101,8 +101,8 @@ elsif ($op eq 'delete-branch-item') { # save the values entered elsif ($op eq 'add') { my $sth_search = $dbh->prepare('SELECT COUNT(*) AS total FROM issuingrules WHERE branchcode=? AND categorycode=? AND itemtype=?'); - my $sth_insert = $dbh->prepare('INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, renewalperiod, norenewalbefore, auto_renew, reservesallowed, issuelength, lengthunit, hardduedate, hardduedatecompare, fine, finedays, maxsuspensiondays, firstremind, chargeperiod,rentaldiscount, overduefinescap) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'); - my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, maxsuspensiondays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, renewalperiod=?, norenewalbefore=?, auto_renew=?, reservesallowed=?, issuelength=?, lengthunit = ?, hardduedate=?, hardduedatecompare=?, rentaldiscount=?, overduefinescap=? WHERE branchcode=? AND categorycode=? AND itemtype=?"); + my $sth_insert = $dbh->prepare('INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, renewalperiod, norenewalbefore, auto_renew, reservesallowed, holdspickupwait, issuelength, lengthunit, hardduedate, hardduedatecompare, fine, finedays, maxsuspensiondays, firstremind, chargeperiod,rentaldiscount, overduefinescap) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'); + my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, maxsuspensiondays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, renewalperiod=?, norenewalbefore=?, auto_renew=?, reservesallowed=?, holdspickupwait=?, issuelength=?, lengthunit = ?, hardduedate=?, hardduedatecompare=?, rentaldiscount=?, overduefinescap=? WHERE branchcode=? AND categorycode=? AND itemtype=?"); my $br = $branch; # branch my $bor = $input->param('categorycode'); # borrower category @@ -120,6 +120,7 @@ elsif ($op eq 'add') { $norenewalbefore = undef if $norenewalbefore eq '0' or $norenewalbefore =~ /^\s*$/; my $auto_renew = $input->param('auto_renew') eq 'yes' ? 1 : 0; my $reservesallowed = $input->param('reservesallowed'); + my $holdspickupwait = $input->param('holdspickupwait'); $maxissueqty =~ s/\s//g; $maxissueqty = undef if $maxissueqty !~ /^\d+/; my $issuelength = $input->param('issuelength'); @@ -134,9 +135,9 @@ elsif ($op eq 'add') { $sth_search->execute($br,$bor,$cat); my $res = $sth_search->fetchrow_hashref(); if ($res->{total}) { - $sth_update->execute($fine, $finedays, $maxsuspensiondays, $firstremind, $chargeperiod, $maxissueqty, $renewalsallowed, $renewalperiod, $norenewalbefore, $auto_renew, $reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount,$overduefinescap, $br,$bor,$cat); + $sth_update->execute($fine, $finedays, $maxsuspensiondays, $firstremind, $chargeperiod, $maxissueqty, $renewalsallowed, $renewalperiod, $norenewalbefore, $auto_renew, $reservesallowed, $holdspickupwait, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount,$overduefinescap, $br,$bor,$cat); } else { - $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed, $renewalperiod, $norenewalbefore, $auto_renew, $reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays, $maxsuspensiondays, $firstremind,$chargeperiod,$rentaldiscount,$overduefinescap); + $sth_insert->execute($br,$bor,$cat, $maxissueqty, $renewalsallowed, $renewalperiod, $norenewalbefore, $auto_renew, $reservesallowed, $holdspickupwait, $issuelength, $lengthunit, $hardduedate, $hardduedatecompare, $fine, $finedays, $maxsuspensiondays, $firstremind, $chargeperiod, $rentaldiscount, $overduefinescap); } } elsif ($op eq "set-branch-defaults") { diff --git a/circ/waitingreserves.pl b/circ/waitingreserves.pl index 07190a1..0a6d3b6 100755 --- a/circ/waitingreserves.pl +++ b/circ/waitingreserves.pl @@ -27,17 +27,14 @@ use C4::Branch; # GetBranchName use C4::Auth; use C4::Dates qw/format_date/; use C4::Circulation; +use C4::Reserves; use C4::Members; use C4::Biblio; use C4::Items; -use Date::Calc qw( - Today - Add_Delta_Days - Date_to_Days -); use C4::Reserves; use C4::Koha; +use Koha::DateUtils; my $input = new CGI; @@ -86,31 +83,44 @@ my ($reservcount, $overcount); my @getreserves = $all_branches ? GetReservesForBranch() : GetReservesForBranch($default); # get reserves for the branch we are logged into, or for all branches -my $today = Date_to_Days(&Today); +my $today = dt_from_string; foreach my $num (@getreserves) { next unless ($num->{'waitingdate'} && $num->{'waitingdate'} ne '0000-00-00'); my $itemnumber = $num->{'itemnumber'}; my $gettitle = GetBiblioFromItemNumber( $itemnumber ); - my $borrowernum = $num->{'borrowernumber'}; + my $borrowernumber = $num->{'borrowernumber'}; my $holdingbranch = $gettitle->{'holdingbranch'}; my $homebranch = $gettitle->{'homebranch'}; my %getreserv = ( itemnumber => $itemnumber, - borrowernum => $borrowernum, + borrowernum => $borrowernumber, ); # fix up item type for display $gettitle->{'itemtype'} = C4::Context->preference('item-level_itypes') ? $gettitle->{'itype'} : $gettitle->{'itemtype'}; my $getborrower = GetMember(borrowernumber => $num->{'borrowernumber'}); my $itemtypeinfo = getitemtypeinfo( $gettitle->{'itemtype'} ); # using the fixed up itype/itemtype - $getreserv{'waitingdate'} = $num->{'waitingdate'}; - my ( $waiting_year, $waiting_month, $waiting_day ) = split (/-/, $num->{'waitingdate'}); - ( $waiting_year, $waiting_month, $waiting_day ) = - Add_Delta_Days( $waiting_year, $waiting_month, $waiting_day, - C4::Context->preference('ReservesMaxPickUpDelay')); - my $calcDate = Date_to_Days( $waiting_year, $waiting_month, $waiting_day ); + + if ( $num->{waitingdate} ) { + my $lastpickupdate = dt_from_string($num->{lastpickupdate}); + $getreserv{waitingdate} = $num->{waitingdate}; + $getreserv{lastpickupdate} = $num->{lastpickupdate}; + if ( DateTime->compare( $today, $lastpickupdate ) == 1 ) { + if ($cancelall) { + my $res = cancel( $itemnumber, $borrowernumber, $holdingbranch, $homebranch, !$transfer_when_cancel_all ); + push @cancel_result, $res if $res; + next; + } else { + push @overloop, \%getreserv; + $overcount++; + } + }else{ + push @reservloop, \%getreserv; + $reservcount++; + } + } $getreserv{'itemtype'} = $itemtypeinfo->{'description'}; $getreserv{'title'} = $gettitle->{'title'}; @@ -129,26 +139,11 @@ foreach my $num (@getreserves) { $getreserv{'borrowerfirstname'} = $getborrower->{'firstname'}; $getreserv{'borrowerphone'} = $getborrower->{'phone'}; - my $borEmail = GetFirstValidEmailAddress( $borrowernum ); + my $borEmail = GetFirstValidEmailAddress( $borrowernumber ); if ( $borEmail ) { $getreserv{'borrowermail'} = $borEmail; } - - if ($today > $calcDate) { - if ($cancelall) { - my $res = cancel( $itemnumber, $borrowernum, $holdingbranch, $homebranch, !$transfer_when_cancel_all ); - push @cancel_result, $res if $res; - next; - } else { - push @overloop, \%getreserv; - $overcount++; - } - }else{ - push @reservloop, \%getreserv; - $reservcount++; - } - } $template->param(cancel_result => \@cancel_result) if @cancel_result; @@ -158,7 +153,6 @@ $template->param( overloop => \@overloop, overcount => $overcount, show_date => format_date(C4::Dates->today('iso')), - ReservesMaxPickUpDelay => C4::Context->preference('ReservesMaxPickUpDelay') ); if ($cancelall) { diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index e33c168..2f0c24b 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -1163,6 +1163,7 @@ CREATE TABLE `issuingrules` ( -- circulation and fine rules `norenewalbefore` int(4) default NULL, -- no renewal allowed until X days or hours before due date. In the unit set in issuingrules.lengthunit `auto_renew` BOOLEAN default FALSE, -- automatic renewal `reservesallowed` smallint(6) NOT NULL default "0", -- how many holds are allowed + `holdspickupwait` int(11) default NULL, -- How many open library days a hold can wait in the pickup shelf until it becomes problematic `branchcode` varchar(10) NOT NULL default '', -- the branch this rule is for (branches.branchcode) overduefinescap decimal(28,6) default NULL, -- the maximum amount of an overdue fine PRIMARY KEY (`branchcode`,`categorycode`,`itemtype`), @@ -1634,6 +1635,7 @@ CREATE TABLE `old_reserves` ( -- this table holds all holds/reserves that have b `lowestPriority` tinyint(1) NOT NULL, -- has this hold been pinned to the lowest priority in the holds queue (1 for yes, 0 for no) `suspend` BOOLEAN NOT NULL DEFAULT 0, -- in this hold suspended (1 for yes, 0 for no) `suspend_until` DATETIME NULL DEFAULT NULL, -- the date this hold is suspended until (NULL for infinitely) + `lastpickupdate` date NULL DEFAULT NULL, -- the last day this hold is available for pickup, until it becomes problematic PRIMARY KEY (`reserve_id`), KEY `old_reserves_borrowernumber` (`borrowernumber`), KEY `old_reserves_biblionumber` (`biblionumber`), @@ -1836,6 +1838,7 @@ CREATE TABLE `reserves` ( -- information related to holds/reserves in Koha `lowestPriority` tinyint(1) NOT NULL, `suspend` BOOLEAN NOT NULL DEFAULT 0, `suspend_until` DATETIME NULL DEFAULT NULL, + `lastpickupdate` date NULL DEFAULT NULL, -- the last day this hold is available for pickup, until it becomes problematic PRIMARY KEY (`reserve_id`), KEY priorityfoundidx (priority,found), KEY `borrowernumber` (`borrowernumber`), diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index e34d214..d916de7 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -8838,6 +8838,37 @@ if ( CheckVersion($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.17.00.XXX"; +if ( CheckVersion($DBversion) ) { + my $maxpickupdelay = C4::Context->preference('ReservesMaxPickUpDelay') || 0; #MaxPickupDelay + #$dbh->do(q{ + # DELETE FROM systempreferences WHERE variable='ReservesMaxPickUpDelay'; + # //DELETE FROM systempreferences WHERE variable='ExpireReservesMaxPickUpDelay'; #This syspref is not needed and would be better suited to be calculated from the holdspickupwait + # //ExpireReservesMaxPickUpDelayCharge #This could be added as a column to the issuing rules. + #}); + $dbh->do(qq{ + ALTER TABLE issuingrules ADD COLUMN holdspickupwait INT(11) NULL default NULL AFTER reservesallowed; + }); + my $sth = $dbh->prepare(q{ + UPDATE issuingrules SET holdspickupwait = ? + }); + $sth->execute( $maxpickupdelay ); + $dbh->do(q{ + ALTER TABLE reserves ADD COLUMN lastpickupdate DATE NULL default NULL AFTER suspend_until; + }); + #$sth = $dbh->prepare(q{ #THIS NOT WORKY WORKY BECAUSE OF HOLIDAYS + # UPDATE reserves SET lastpickupdate = ADDDATE(waitingdate, INTERVAL ? DAY); + #}); + #$sth->execute( $maxpickupdelay ); + #TODO Make a function to migrate this value from. + $dbh->do(q{ + ALTER TABLE old_reserves ADD COLUMN lastpickupdate DATE NULL default NULL AFTER suspend_until; + }); + print "Upgrade to $DBversion done (8367: Add colum issuingrules.holdspickupwait and reserves.lastpickupdate. Delete the ReservesMaxPickUpDelay syspref)\n"; + SetVersion($DBversion); +} + + =head1 FUNCTIONS =head2 TableExists($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/js/holds.js b/koha-tmpl/intranet-tmpl/prog/en/js/holds.js index 73807ea..1d325c0 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/js/holds.js +++ b/koha-tmpl/intranet-tmpl/prog/en/js/holds.js @@ -11,6 +11,9 @@ $(document).ready(function() { "mDataProp": "reservedate_formatted" }, { + "mDataProp": "lastpickupdate_formatted" + }, + { "mDataProp": function ( oObj ) { title = "default (all libraries), all patron types, same item type
  • default (all libraries), all patron types, all item types
  • +

    To get more information about how these settings affect Koha, hover your cursor over a column header.

    To modify a rule, create a new one with the same patron type and item type.

    @@ -153,6 +154,7 @@ for="tobranch">Clone these rules to: Clone these rules to: Clone these rules to: + [% ELSE %] Item waiting to be pulled from [% RESERVE.wbrname %] diff --git a/svc/holds b/svc/holds index 3ff704f..d135299 100755 --- a/svc/holds +++ b/svc/holds @@ -47,7 +47,7 @@ my $branch = C4::Context->userenv->{'branch'}; my $schema = Koha::Database->new()->schema(); my @sort_columns = - qw/reservedate title itemcallnumber barcode expirationdate priority/; + qw/reservedate lastpickupdate title itemcallnumber barcode expirationdate priority/; my $borrowernumber = $input->param('borrowernumber'); my $offset = $input->param('iDisplayStart'); @@ -81,6 +81,7 @@ while ( my $h = $holds_rs->next() ) { author => $h->biblio()->author(), reserve_id => $h->reserve_id(), reservedate => $h->reservedate(), + lastpickupdate => $h->lastpickupdate(), expirationdate => $h->expirationdate(), suspend => $h->suspend(), suspend_until => $h->suspend_until(), @@ -97,6 +98,10 @@ while ( my $h = $holds_rs->next() ) { { dt => dt_from_string( $h->reservedate() ), dateonly => 1 } ) : q{}, + lastpickupdate_formatted => $h->lastpickupdate() ? output_pref( + { dt => dt_from_string( $h->lastpickupdate() ), dateonly => 1 } + ) + : q{}, suspend_until_formatted => $h->suspend_until() ? output_pref( { dt => dt_from_string( $h->suspend_until() ), dateonly => 1 } ) -- 1.7.9.5