View | Details | Raw Unified | Return to bug 8367
Collapse All | Expand All

(-)a/C4/Letters.pm (-15 lines)
Lines 602-622 sub _parseletter_sth { Link Here
602
sub _parseletter {
602
sub _parseletter {
603
    my ( $letter, $table, $values ) = @_;
603
    my ( $letter, $table, $values ) = @_;
604
604
605
    if ( $table eq 'reserves' && $values->{'waitingdate'} ) {
606
        my @waitingdate = split /-/, $values->{'waitingdate'};
607
608
        $values->{'expirationdate'} = '';
609
        if( C4::Context->preference('ExpireReservesMaxPickUpDelay') &&
610
        C4::Context->preference('ReservesMaxPickUpDelay') ) {
611
            my $dt = dt_from_string();
612
            $dt->add( days => C4::Context->preference('ReservesMaxPickUpDelay') );
613
            $values->{'expirationdate'} = output_pref({ dt => $dt, dateonly => 1 });
614
        }
615
616
        $values->{'waitingdate'} = output_pref({ dt => dt_from_string( $values->{'waitingdate'} ), dateonly => 1 });
617
618
    }
619
620
    if ($letter->{content} && $letter->{content} =~ /<<today>>/) {
605
    if ($letter->{content} && $letter->{content} =~ /<<today>>/) {
621
        my $todaysdate = output_pref( DateTime->now() );
606
        my $todaysdate = output_pref( DateTime->now() );
622
        $letter->{content} =~ s/<<today>>/$todaysdate/go;
607
        $letter->{content} =~ s/<<today>>/$todaysdate/go;
(-)a/C4/Reserves.pm (-47 / +188 lines)
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
@PARAM1 koha.reserves-row
895
@PARAM2 koha.items-row, If the reserve is not given, an item must be given to be
896
                        able to find a reservation
897
@PARAM3 koha.borrowers-row, OPTIONAL
898
RETURNS DateTime, depicting the last pickup date.
899
=cut
900
901
sub GetLastPickupDate {
902
    my ($reserve, $item, $borrower) = @_;
903
904
    ##Verify parameters
905
    if ( not defined $reserve and not defined $item ) {
906
        warn "C4::Reserves::GetMaxPickupDate(), is called without a reserve and a item";
907
        return;
908
    }
909
    if ( defined $reserve and not defined $item ) {
910
        $item = C4::Items::GetItem( $reserve->{itemnumber} );
911
    }
912
    unless ( defined $reserve ) {
913
        my $reserve = GetReservesFromItemnumber( $item->{itemnumber} );
914
    }
915
916
    my $date = $reserve->{waitingdate};
917
    unless ( $date ) { #It is possible that a reserve is just caught and it doesn't have a waitingdate yet.
918
        $date = DateTime->now( time_zone => C4::Context->tz() ); #So default to NOW()
919
    }
920
    else {
921
        $date = (ref $reserve->{waitingdate} eq 'DateTime') ? $reserve->{waitingdate}  :  dt_from_string($reserve->{waitingdate});
922
    }
923
    $borrower = C4::Members::GetMember( 'borrowernumber' => $reserve->{borrowernumber} ) unless $borrower;
924
925
    ##Get churning the LastPickupDate
926
    my $controlbranch = GetReservesControlBranch( $item, $borrower );
927
928
    my $issuingrule = C4::Circulation::GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $controlbranch );
929
930
    my $holdspickupwait = 0;
931
    if ( defined($issuingrule)
932
        and defined $issuingrule->{holdspickupwait} ) {
933
        $holdspickupwait = $issuingrule->{holdspickupwait}
934
    }
935
    $date->add( days => $holdspickupwait );
936
937
    my $calendar = Koha::Calendar->new( branchcode => $reserve->{'branchcode'} );
938
    my $is_holiday = $calendar->is_holiday( $date );
939
940
    while ( $is_holiday ) {
941
        $date->add( days => 1 );
942
        $is_holiday = $calendar->is_holiday( $date );
943
    }
944
945
    $reserve->{lastpickupdate} = $date->ymd();
946
    return $date;
947
}
948
=head2 GetReservesControlBranch
949
950
  $branchcode = &GetReservesControlBranch($borrower, $item)
951
952
Returns the branchcode to consider to check hold rules against
953
954
=cut
955
956
sub GetReservesControlBranch {
957
    my ( $borrower, $item ) = @_;
958
    my $controlbranch = C4::Context->preference('ReservesControlBranch');
959
    my $hbr           = C4::Context->preference('HomeOrHoldingBranch') || "homebranch";
960
    my $branchcode    = "*";
961
    if ( $controlbranch eq "ItemHomeLibrary" ) {
962
        $branchcode = $item->{$hbr};
963
    } elsif ( $controlbranch eq "PatronLibrary" ) {
964
        $branchcode = $borrower->{branchcode};
965
    }
966
    return $branchcode;
967
}
968
877
=head2 CheckReserves
969
=head2 CheckReserves
878
970
879
  ($status, $reserve, $all_reserves) = &CheckReserves($itemnumber);
971
  ($status, $reserve, $all_reserves) = &CheckReserves($itemnumber);
Lines 1017-1052 sub CancelExpiredReserves { Link Here
1017
    }
1109
    }
1018
  
1110
  
1019
    # Cancel reserves that have been waiting too long
1111
    # Cancel reserves that have been waiting too long
1020
    if ( C4::Context->preference("ExpireReservesMaxPickUpDelay") ) {
1112
    my $today = dt_from_string();
1021
        my $max_pickup_delay = C4::Context->preference("ReservesMaxPickUpDelay");
1113
    my $charge = C4::Context->preference("ExpireReservesMaxPickUpDelayCharge");
1022
        my $charge = C4::Context->preference("ExpireReservesMaxPickUpDelayCharge");
1023
        my $cancel_on_holidays = C4::Context->preference('ExpireReservesOnHolidays');
1024
1025
        my $today = dt_from_string();
1026
1027
        my $query = "SELECT * FROM reserves WHERE TO_DAYS( NOW() ) - TO_DAYS( waitingdate ) > ? AND found = 'W' AND priority = 0";
1028
        $sth = $dbh->prepare( $query );
1029
        $sth->execute( $max_pickup_delay );
1030
1114
1031
        while ( my $res = $sth->fetchrow_hashref ) {
1115
    my $query = "SELECT * FROM reserves WHERE NOW() > lastpickupdate AND found = 'W' AND priority = 0";
1032
            my $do_cancel = 1;
1116
    $sth = $dbh->prepare( $query );
1033
            unless ( $cancel_on_holidays ) {
1117
    $sth->execute();
1034
                my $calendar = Koha::Calendar->new( branchcode => $res->{'branchcode'} );
1035
                my $is_holiday = $calendar->is_holiday( $today );
1036
1037
                if ( $is_holiday ) {
1038
                    $do_cancel = 0;
1039
                }
1040
            }
1041
1118
1042
            if ( $do_cancel ) {
1119
    while ( my $res = $sth->fetchrow_hashref ) {
1043
                if ( $charge ) {
1044
                    manualinvoice($res->{'borrowernumber'}, $res->{'itemnumber'}, 'Hold waiting too long', 'F', $charge);
1045
                }
1046
1120
1047
                CancelReserve({ reserve_id => $res->{'reserve_id'} });
1121
        if ( $charge ) {
1048
            }
1122
            manualinvoice($res->{'borrowernumber'}, $res->{'itemnumber'}, 'Hold waiting too long', 'F', $charge);
1049
        }
1123
        }
1124
1125
        CancelReserve({ reserve_id => $res->{'reserve_id'} });
1050
    }
1126
    }
1051
1127
1052
}
1128
}
Lines 1284-1292 sub ModReserveStatus { Link Here
1284
    my ($itemnumber, $newstatus) = @_;
1360
    my ($itemnumber, $newstatus) = @_;
1285
    my $dbh = C4::Context->dbh;
1361
    my $dbh = C4::Context->dbh;
1286
1362
1287
    my $query = "UPDATE reserves SET found = ?, waitingdate = NOW() WHERE itemnumber = ? AND found IS NULL AND priority = 0";
1363
    my $now = dt_from_string;
1364
    my $reserve = $dbh->selectrow_hashref(q{
1365
        SELECT *
1366
        FROM reserves
1367
        WHERE itemnumber = ?
1368
            AND found IS NULL
1369
            AND priority = 0
1370
    }, {}, $itemnumber);
1371
    return unless $reserve;
1372
1373
    my $lastpickupdate = GetLastPickupDate( $reserve );
1374
    my $query = q{
1375
        UPDATE reserves
1376
        SET found = ?,
1377
            waitingdate = ?,
1378
            maxpickupdate = ?
1379
        WHERE itemnumber = ?
1380
            AND found IS NULL
1381
            AND priority = 0
1382
    };
1288
    my $sth_set = $dbh->prepare($query);
1383
    my $sth_set = $dbh->prepare($query);
1289
    $sth_set->execute( $newstatus, $itemnumber );
1384
    $sth_set->execute( $newstatus, $now, $lastpickupdate, $itemnumber );
1290
1385
1291
    if ( C4::Context->preference("ReturnToShelvingCart") && $newstatus ) {
1386
    if ( C4::Context->preference("ReturnToShelvingCart") && $newstatus ) {
1292
      CartToShelf( $itemnumber );
1387
      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
1426
    # If we affect a reserve that has to be transfered, don't set to Waiting
1332
    my $query;
1427
    my $query;
1333
    if ($transferToDo) {
1428
    if ($transferToDo) {
1334
    $query = "
1429
        $query = "
1335
        UPDATE reserves
1430
            UPDATE reserves
1336
        SET    priority = 0,
1431
            SET    priority = 0,
1337
               itemnumber = ?,
1432
                   itemnumber = ?,
1338
               found = 'T'
1433
                   found = 'T'
1339
        WHERE borrowernumber = ?
1434
            WHERE borrowernumber = ?
1340
          AND biblionumber = ?
1435
              AND biblionumber = ?
1341
    ";
1436
        ";
1437
        $sth = $dbh->prepare($query);
1438
        $sth->execute( $itemnumber, $borrowernumber,$biblionumber);
1342
    }
1439
    }
1343
    else {
1440
    else {
1344
    # affect the reserve to Waiting as well.
1441
        # affect the reserve to Waiting as well.
1442
        my $item = C4::Items::GetItem( $itemnumber );
1443
        my $lastpickupdate = GetLastPickupDate( $request, $item );
1345
        $query = "
1444
        $query = "
1346
            UPDATE reserves
1445
            UPDATE reserves
1347
            SET     priority = 0,
1446
            SET     priority = 0,
1348
                    found = 'W',
1447
                    found = 'W',
1349
                    waitingdate = NOW(),
1448
                    waitingdate = NOW(),
1449
                    lastpickupdate = ?,
1350
                    itemnumber = ?
1450
                    itemnumber = ?
1351
            WHERE borrowernumber = ?
1451
            WHERE borrowernumber = ?
1352
              AND biblionumber = ?
1452
              AND biblionumber = ?
1353
        ";
1453
        ";
1454
        $sth = $dbh->prepare($query);
1455
        $sth->execute( $lastpickupdate, $itemnumber, $borrowernumber,$biblionumber);
1354
    }
1456
    }
1355
    $sth = $dbh->prepare($query);
1356
    $sth->execute( $itemnumber, $borrowernumber,$biblionumber);
1357
    _koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf );
1457
    _koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf );
1358
    _FixPriority( { biblionumber => $biblionumber } );
1458
    _FixPriority( { biblionumber => $biblionumber } );
1359
    if ( C4::Context->preference("ReturnToShelvingCart") ) {
1459
    if ( C4::Context->preference("ReturnToShelvingCart") ) {
Lines 1429-1434 sub GetReserveInfo { Link Here
1429
                   reserves.biblionumber,
1529
                   reserves.biblionumber,
1430
                   reserves.branchcode,
1530
                   reserves.branchcode,
1431
                   reserves.waitingdate,
1531
                   reserves.waitingdate,
1532
                   reserves.lastpickupdate,
1432
                   notificationdate,
1533
                   notificationdate,
1433
                   reminderdate,
1534
                   reminderdate,
1434
                   priority,
1535
                   priority,
Lines 1840-1845 sub _Findgroupreserve { Link Here
1840
               reserves.borrowernumber      AS borrowernumber,
1941
               reserves.borrowernumber      AS borrowernumber,
1841
               reserves.reservedate         AS reservedate,
1942
               reserves.reservedate         AS reservedate,
1842
               reserves.branchcode          AS branchcode,
1943
               reserves.branchcode          AS branchcode,
1944
               reserves.lastpickupdate       AS maxpickupdate,
1843
               reserves.cancellationdate    AS cancellationdate,
1945
               reserves.cancellationdate    AS cancellationdate,
1844
               reserves.found               AS found,
1946
               reserves.found               AS found,
1845
               reserves.reservenotes        AS reservenotes,
1947
               reserves.reservenotes        AS reservenotes,
Lines 1872-1877 sub _Findgroupreserve { Link Here
1872
               reserves.borrowernumber      AS borrowernumber,
1974
               reserves.borrowernumber      AS borrowernumber,
1873
               reserves.reservedate         AS reservedate,
1975
               reserves.reservedate         AS reservedate,
1874
               reserves.branchcode          AS branchcode,
1976
               reserves.branchcode          AS branchcode,
1977
               reserves.lastpickupdate       AS maxpickupdate,
1875
               reserves.cancellationdate    AS cancellationdate,
1978
               reserves.cancellationdate    AS cancellationdate,
1876
               reserves.found               AS found,
1979
               reserves.found               AS found,
1877
               reserves.reservenotes        AS reservenotes,
1980
               reserves.reservenotes        AS reservenotes,
Lines 1904-1909 sub _Findgroupreserve { Link Here
1904
               reserves.reservedate                AS reservedate,
2007
               reserves.reservedate                AS reservedate,
1905
               reserves.waitingdate                AS waitingdate,
2008
               reserves.waitingdate                AS waitingdate,
1906
               reserves.branchcode                 AS branchcode,
2009
               reserves.branchcode                 AS branchcode,
2010
               reserves.lastpickupdate              AS maxpickupdate,
1907
               reserves.cancellationdate           AS cancellationdate,
2011
               reserves.cancellationdate           AS cancellationdate,
1908
               reserves.found                      AS found,
2012
               reserves.found                      AS found,
1909
               reserves.reservenotes               AS reservenotes,
2013
               reserves.reservenotes               AS reservenotes,
Lines 2117-2122 sub MoveReserve { Link Here
2117
    }
2221
    }
2118
}
2222
}
2119
2223
2224
=head MoveWaitingdate
2225
2226
  #Move waitingdate two months and fifteen days forward.
2227
  my $dateDuration = DateTime::Duration->new( months => 2, days => 15 );
2228
  $reserve = MoveWaitingdate( $reserve, $dateDuration);
2229
2230
  #Move waitingdate one year and eleven days backwards.
2231
  my $dateDuration = DateTime::Duration->new( years => -1, days => -11 );
2232
  $reserve = MoveWaitingdate( $reserve, $dateDuration);
2233
2234
Moves the waitingdate and updates the lastpickupdate to match.
2235
If waitingdate is not defined, uses today.
2236
Is intended to be used from automated tests, because under normal library
2237
operations there should be NO REASON to move the waitingdate.
2238
2239
@PARAM1 koha.reserves-row, with waitingdate set.
2240
@PARAM2 DateTime::Duration, with the desired offset.
2241
RETURNS koha.reserve-row, with keys waitingdate and lastpickupdate updated.
2242
=cut
2243
sub MoveWaitingdate {
2244
    my ($reserve, $dateDuration) = @_;
2245
2246
    my $dt = dt_from_string( $reserve->{waitingdate} );
2247
    $dt->add_duration( $dateDuration );
2248
    $reserve->{waitingdate} = $dt->ymd();
2249
2250
    GetLastPickupDate( $reserve ); #Update the $reserve->{lastpickupdate}
2251
2252
    #UPDATE the DB part
2253
    my $dbh = C4::Context->dbh();
2254
    my $sth = $dbh->prepare( "UPDATE reserves SET waitingdate=?, lastpickupdate=? WHERE reserve_id=?" );
2255
    $sth->execute( $reserve->{waitingdate}, $reserve->{lastpickupdate}, $reserve->{reserve_id} );
2256
2257
    return $reserve;
2258
}
2259
2120
=head2 MergeHolds
2260
=head2 MergeHolds
2121
2261
2122
  MergeHolds($dbh,$to_biblio, $from_biblio);
2262
  MergeHolds($dbh,$to_biblio, $from_biblio);
Lines 2213-2219 sub RevertWaitingStatus { Link Here
2213
    SET
2353
    SET
2214
      priority = 1,
2354
      priority = 1,
2215
      found = NULL,
2355
      found = NULL,
2216
      waitingdate = NULL
2356
      waitingdate = NULL,
2357
      lastpickupdate = NULL,
2217
    WHERE
2358
    WHERE
2218
      reserve_id = ?
2359
      reserve_id = ?
2219
    ";
2360
    ";
(-)a/Koha/Schema/Result/Reserve.pm (+7 lines)
Lines 139-144 __PACKAGE__->table("reserves"); Link Here
139
  datetime_undef_if_invalid: 1
139
  datetime_undef_if_invalid: 1
140
  is_nullable: 1
140
  is_nullable: 1
141
141
142
=head2 lastpickupdate
143
  date_type: 'date'
144
  datetime_undef_if_invalid: 1
145
  is_nullable: 1
146
142
=cut
147
=cut
143
148
144
__PACKAGE__->add_columns(
149
__PACKAGE__->add_columns(
Lines 199-204 __PACKAGE__->add_columns( Link Here
199
    datetime_undef_if_invalid => 1,
204
    datetime_undef_if_invalid => 1,
200
    is_nullable => 1,
205
    is_nullable => 1,
201
  },
206
  },
207
  "lastpickupdate",
208
  { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 },
202
);
209
);
203
210
204
=head1 PRIMARY KEY
211
=head1 PRIMARY KEY
(-)a/admin/smart-rules.pl (-4 / +5 lines)
Lines 101-108 elsif ($op eq 'delete-branch-item') { Link Here
101
# save the values entered
101
# save the values entered
102
elsif ($op eq 'add') {
102
elsif ($op eq 'add') {
103
    my $sth_search = $dbh->prepare('SELECT COUNT(*) AS total FROM issuingrules WHERE branchcode=? AND categorycode=? AND itemtype=?');
103
    my $sth_search = $dbh->prepare('SELECT COUNT(*) AS total FROM issuingrules WHERE branchcode=? AND categorycode=? AND itemtype=?');
104
    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(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
104
    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(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
105
    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=?");
105
    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=?");
106
    
106
    
107
    my $br = $branch; # branch
107
    my $br = $branch; # branch
108
    my $bor  = $input->param('categorycode'); # borrower category
108
    my $bor  = $input->param('categorycode'); # borrower category
Lines 120-125 elsif ($op eq 'add') { Link Here
120
    $norenewalbefore = undef if $norenewalbefore eq '0' or $norenewalbefore =~ /^\s*$/;
120
    $norenewalbefore = undef if $norenewalbefore eq '0' or $norenewalbefore =~ /^\s*$/;
121
    my $auto_renew = $input->param('auto_renew') eq 'yes' ? 1 : 0;
121
    my $auto_renew = $input->param('auto_renew') eq 'yes' ? 1 : 0;
122
    my $reservesallowed  = $input->param('reservesallowed');
122
    my $reservesallowed  = $input->param('reservesallowed');
123
    my $holdspickupwait = $input->param('holdspickupwait');
123
    $maxissueqty =~ s/\s//g;
124
    $maxissueqty =~ s/\s//g;
124
    $maxissueqty = undef if $maxissueqty !~ /^\d+/;
125
    $maxissueqty = undef if $maxissueqty !~ /^\d+/;
125
    my $issuelength  = $input->param('issuelength');
126
    my $issuelength  = $input->param('issuelength');
Lines 134-142 elsif ($op eq 'add') { Link Here
134
    $sth_search->execute($br,$bor,$cat);
135
    $sth_search->execute($br,$bor,$cat);
135
    my $res = $sth_search->fetchrow_hashref();
136
    my $res = $sth_search->fetchrow_hashref();
136
    if ($res->{total}) {
137
    if ($res->{total}) {
137
        $sth_update->execute($fine, $finedays, $maxsuspensiondays, $firstremind, $chargeperiod, $maxissueqty, $renewalsallowed, $renewalperiod, $norenewalbefore, $auto_renew, $reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount,$overduefinescap, $br,$bor,$cat);
138
        $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);
138
    } else {
139
    } else {
139
        $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed, $renewalperiod, $norenewalbefore, $auto_renew, $reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays, $maxsuspensiondays, $firstremind,$chargeperiod,$rentaldiscount,$overduefinescap);
140
        $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);
140
    }
141
    }
141
} 
142
} 
142
elsif ($op eq "set-branch-defaults") {
143
elsif ($op eq "set-branch-defaults") {
(-)a/circ/returns.pl (-1 / +1 lines)
Lines 1-4 Link Here
1
#!/usr/bin/perl
1
#!/usr/bin/perl -d
2
2
3
# Copyright 2000-2002 Katipo Communications
3
# Copyright 2000-2002 Katipo Communications
4
#           2006 SAN-OP
4
#           2006 SAN-OP
(-)a/circ/waitingreserves.pl (-31 / +25 lines)
Lines 27-43 use C4::Branch; # GetBranchName Link Here
27
use C4::Auth;
27
use C4::Auth;
28
use C4::Dates qw/format_date/;
28
use C4::Dates qw/format_date/;
29
use C4::Circulation;
29
use C4::Circulation;
30
use C4::Reserves;
30
use C4::Members;
31
use C4::Members;
31
use C4::Biblio;
32
use C4::Biblio;
32
use C4::Items;
33
use C4::Items;
33
34
34
use Date::Calc qw(
35
  Today
36
  Add_Delta_Days
37
  Date_to_Days
38
);
39
use C4::Reserves;
35
use C4::Reserves;
40
use C4::Koha;
36
use C4::Koha;
37
use Koha::DateUtils;
41
38
42
my $input = new CGI;
39
my $input = new CGI;
43
40
Lines 86-116 my ($reservcount, $overcount); Link Here
86
my @getreserves = $all_branches ? GetReservesForBranch() : GetReservesForBranch($default);
83
my @getreserves = $all_branches ? GetReservesForBranch() : GetReservesForBranch($default);
87
# get reserves for the branch we are logged into, or for all branches
84
# get reserves for the branch we are logged into, or for all branches
88
85
89
my $today = Date_to_Days(&Today);
86
my $today = dt_from_string;
90
foreach my $num (@getreserves) {
87
foreach my $num (@getreserves) {
91
    next unless ($num->{'waitingdate'} && $num->{'waitingdate'} ne '0000-00-00');
88
    next unless ($num->{'waitingdate'} && $num->{'waitingdate'} ne '0000-00-00');
92
89
93
    my $itemnumber = $num->{'itemnumber'};
90
    my $itemnumber = $num->{'itemnumber'};
94
    my $gettitle     = GetBiblioFromItemNumber( $itemnumber );
91
    my $gettitle     = GetBiblioFromItemNumber( $itemnumber );
95
    my $borrowernum = $num->{'borrowernumber'};
92
    my $borrowernumber = $num->{'borrowernumber'};
96
    my $holdingbranch = $gettitle->{'holdingbranch'};
93
    my $holdingbranch = $gettitle->{'holdingbranch'};
97
    my $homebranch = $gettitle->{'homebranch'};
94
    my $homebranch = $gettitle->{'homebranch'};
98
95
99
    my %getreserv = (
96
    my %getreserv = (
100
        itemnumber => $itemnumber,
97
        itemnumber => $itemnumber,
101
        borrowernum => $borrowernum,
98
        borrowernum => $borrowernumber,
102
    );
99
    );
103
100
104
    # fix up item type for display
101
    # fix up item type for display
105
    $gettitle->{'itemtype'} = C4::Context->preference('item-level_itypes') ? $gettitle->{'itype'} : $gettitle->{'itemtype'};
102
    $gettitle->{'itemtype'} = C4::Context->preference('item-level_itypes') ? $gettitle->{'itype'} : $gettitle->{'itemtype'};
106
    my $getborrower = GetMember(borrowernumber => $num->{'borrowernumber'});
103
    my $getborrower = GetMember(borrowernumber => $num->{'borrowernumber'});
107
    my $itemtypeinfo = getitemtypeinfo( $gettitle->{'itemtype'} );  # using the fixed up itype/itemtype
104
    my $itemtypeinfo = getitemtypeinfo( $gettitle->{'itemtype'} );  # using the fixed up itype/itemtype
108
    $getreserv{'waitingdate'} = $num->{'waitingdate'};
105
109
    my ( $waiting_year, $waiting_month, $waiting_day ) = split (/-/, $num->{'waitingdate'});
106
    if ( $num->{waitingdate} ) {
110
    ( $waiting_year, $waiting_month, $waiting_day ) =
107
        my $lastpickupdate = dt_from_string($num->{lastpickupdate});
111
      Add_Delta_Days( $waiting_year, $waiting_month, $waiting_day,
108
        $getreserv{waitingdate} = $num->{waitingdate};
112
        C4::Context->preference('ReservesMaxPickUpDelay'));
109
        $getreserv{lastpickupdate} = $num->{lastpickupdate};
113
    my $calcDate = Date_to_Days( $waiting_year, $waiting_month, $waiting_day );
110
        if ( DateTime->compare( $today, $lastpickupdate ) == 1 ) {
111
            if ($cancelall) {
112
                my $res = cancel( $itemnumber, $borrowernumber, $holdingbranch, $homebranch, !$transfer_when_cancel_all );
113
                push @cancel_result, $res if $res;
114
                next;
115
            } else {
116
                push @overloop,   \%getreserv;
117
                $overcount++;
118
            }
119
        }else{
120
            push @reservloop, \%getreserv;
121
            $reservcount++;
122
        }
123
    }
114
124
115
    $getreserv{'itemtype'}       = $itemtypeinfo->{'description'};
125
    $getreserv{'itemtype'}       = $itemtypeinfo->{'description'};
116
    $getreserv{'title'}          = $gettitle->{'title'};
126
    $getreserv{'title'}          = $gettitle->{'title'};
Lines 129-154 foreach my $num (@getreserves) { Link Here
129
    $getreserv{'borrowerfirstname'} = $getborrower->{'firstname'};
139
    $getreserv{'borrowerfirstname'} = $getborrower->{'firstname'};
130
    $getreserv{'borrowerphone'}     = $getborrower->{'phone'};
140
    $getreserv{'borrowerphone'}     = $getborrower->{'phone'};
131
141
132
    my $borEmail = GetFirstValidEmailAddress( $borrowernum );
142
    my $borEmail = GetFirstValidEmailAddress( $borrowernumber );
133
143
134
    if ( $borEmail ) {
144
    if ( $borEmail ) {
135
        $getreserv{'borrowermail'}  = $borEmail;
145
        $getreserv{'borrowermail'}  = $borEmail;
136
    }
146
    }
137
138
    if ($today > $calcDate) {
139
        if ($cancelall) {
140
            my $res = cancel( $itemnumber, $borrowernum, $holdingbranch, $homebranch, !$transfer_when_cancel_all );
141
            push @cancel_result, $res if $res;
142
            next;
143
        } else {
144
            push @overloop,   \%getreserv;
145
            $overcount++;
146
        }
147
    }else{
148
        push @reservloop, \%getreserv;
149
        $reservcount++;
150
    }
151
    
152
}
147
}
153
148
154
$template->param(cancel_result => \@cancel_result) if @cancel_result;
149
$template->param(cancel_result => \@cancel_result) if @cancel_result;
Lines 158-164 $template->param( Link Here
158
    overloop    => \@overloop,
153
    overloop    => \@overloop,
159
    overcount   => $overcount,
154
    overcount   => $overcount,
160
    show_date   => format_date(C4::Dates->today('iso')),
155
    show_date   => format_date(C4::Dates->today('iso')),
161
    ReservesMaxPickUpDelay => C4::Context->preference('ReservesMaxPickUpDelay')
162
);
156
);
163
157
164
if ($cancelall) {
158
if ($cancelall) {
(-)a/installer/data/mysql/kohastructure.sql (+3 lines)
Lines 1163-1168 CREATE TABLE `issuingrules` ( -- circulation and fine rules Link Here
1163
  `norenewalbefore` int(4) default NULL, -- no renewal allowed until X days or hours before due date. In the unit set in issuingrules.lengthunit
1163
  `norenewalbefore` int(4) default NULL, -- no renewal allowed until X days or hours before due date. In the unit set in issuingrules.lengthunit
1164
  `auto_renew` BOOLEAN default FALSE, -- automatic renewal
1164
  `auto_renew` BOOLEAN default FALSE, -- automatic renewal
1165
  `reservesallowed` smallint(6) NOT NULL default "0", -- how many holds are allowed
1165
  `reservesallowed` smallint(6) NOT NULL default "0", -- how many holds are allowed
1166
  `holdspickupwait` int(11)  default NULL, -- How many open library days a hold can wait in the pickup shelf until it becomes problematic
1166
  `branchcode` varchar(10) NOT NULL default '', -- the branch this rule is for (branches.branchcode)
1167
  `branchcode` varchar(10) NOT NULL default '', -- the branch this rule is for (branches.branchcode)
1167
  overduefinescap decimal(28,6) default NULL, -- the maximum amount of an overdue fine
1168
  overduefinescap decimal(28,6) default NULL, -- the maximum amount of an overdue fine
1168
  PRIMARY KEY  (`branchcode`,`categorycode`,`itemtype`),
1169
  PRIMARY KEY  (`branchcode`,`categorycode`,`itemtype`),
Lines 1634-1639 CREATE TABLE `old_reserves` ( -- this table holds all holds/reserves that have b Link Here
1634
  `lowestPriority` tinyint(1) NOT NULL, -- has this hold been pinned to the lowest priority in the holds queue (1 for yes, 0 for no)
1635
  `lowestPriority` tinyint(1) NOT NULL, -- has this hold been pinned to the lowest priority in the holds queue (1 for yes, 0 for no)
1635
  `suspend` BOOLEAN NOT NULL DEFAULT 0, -- in this hold suspended (1 for yes, 0 for no)
1636
  `suspend` BOOLEAN NOT NULL DEFAULT 0, -- in this hold suspended (1 for yes, 0 for no)
1636
  `suspend_until` DATETIME NULL DEFAULT NULL, -- the date this hold is suspended until (NULL for infinitely)
1637
  `suspend_until` DATETIME NULL DEFAULT NULL, -- the date this hold is suspended until (NULL for infinitely)
1638
  `lastpickupdate` date NULL DEFAULT NULL, -- the last day this hold is available for pickup, until it becomes problematic
1637
  PRIMARY KEY (`reserve_id`),
1639
  PRIMARY KEY (`reserve_id`),
1638
  KEY `old_reserves_borrowernumber` (`borrowernumber`),
1640
  KEY `old_reserves_borrowernumber` (`borrowernumber`),
1639
  KEY `old_reserves_biblionumber` (`biblionumber`),
1641
  KEY `old_reserves_biblionumber` (`biblionumber`),
Lines 1836-1841 CREATE TABLE `reserves` ( -- information related to holds/reserves in Koha Link Here
1836
  `lowestPriority` tinyint(1) NOT NULL,
1838
  `lowestPriority` tinyint(1) NOT NULL,
1837
  `suspend` BOOLEAN NOT NULL DEFAULT 0,
1839
  `suspend` BOOLEAN NOT NULL DEFAULT 0,
1838
  `suspend_until` DATETIME NULL DEFAULT NULL,
1840
  `suspend_until` DATETIME NULL DEFAULT NULL,
1841
  `lastpickupdate` date NULL DEFAULT NULL, -- the last day this hold is available for pickup, until it becomes problematic
1839
  PRIMARY KEY (`reserve_id`),
1842
  PRIMARY KEY (`reserve_id`),
1840
  KEY priorityfoundidx (priority,found),
1843
  KEY priorityfoundidx (priority,found),
1841
  KEY `borrowernumber` (`borrowernumber`),
1844
  KEY `borrowernumber` (`borrowernumber`),
(-)a/installer/data/mysql/sysprefs.sql (-2 / +1 lines)
Lines 116-122 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
116
('expandedSearchOption','0',NULL,'If ON, set advanced search to be expanded by default','YesNo'),
116
('expandedSearchOption','0',NULL,'If ON, set advanced search to be expanded by default','YesNo'),
117
('ExpireReservesMaxPickUpDelay','0','','Enabling this allows holds to expire automatically if they have not been picked by within the time period specified in ReservesMaxPickUpDelay','YesNo'),
117
('ExpireReservesMaxPickUpDelay','0','','Enabling this allows holds to expire automatically if they have not been picked by within the time period specified in ReservesMaxPickUpDelay','YesNo'),
118
('ExpireReservesMaxPickUpDelayCharge','0',NULL,'If ExpireReservesMaxPickUpDelay is enabled, and this field has a non-zero value, than a borrower whose waiting hold has expired will be charged this amount.','free'),
118
('ExpireReservesMaxPickUpDelayCharge','0',NULL,'If ExpireReservesMaxPickUpDelay is enabled, and this field has a non-zero value, than a borrower whose waiting hold has expired will be charged this amount.','free'),
119
('ExpireReservesOnHolidays', '1', NULL, 'If false, reserves at a library will not be canceled on days the library is not open.', 'YesNo'),
120
('ExtendedPatronAttributes','0',NULL,'Use extended patron IDs and attributes','YesNo'),
119
('ExtendedPatronAttributes','0',NULL,'Use extended patron IDs and attributes','YesNo'),
121
('FacetLabelTruncationLength','20',NULL,'Specify the facet max length in OPAC','Integer'),
120
('FacetLabelTruncationLength','20',NULL,'Specify the facet max length in OPAC','Integer'),
122
('FilterBeforeOverdueReport','0','','Do not run overdue report until filter selected','YesNo'),
121
('FilterBeforeOverdueReport','0','','Do not run overdue report until filter selected','YesNo'),
Lines 429-435 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
429
('UsageStatsID', '', 'This preference is part of Koha but it should not be deleted or updated manually.', '', 'Free'),
428
('UsageStatsID', '', 'This preference is part of Koha but it should not be deleted or updated manually.', '', 'Free'),
430
('UsageStatsLastUpdateTime', '', 'This preference is part of Koha but it should not be deleted or updated manually.', '', 'Free'),
429
('UsageStatsLastUpdateTime', '', 'This preference is part of Koha but it should not be deleted or updated manually.', '', 'Free'),
431
('UsageStatsLibraryName', '', 'The library name to be shown on Hea Koha community website', NULL, 'Free'),
430
('UsageStatsLibraryName', '', 'The library name to be shown on Hea Koha community website', NULL, 'Free'),
432
('UsageStatsLibraryType', 'public', 'public|university', 'The library type to be shown on the Hea Koha community website', NULL, 'Choice'),
431
('UsageStatsLibraryType', 'public', 'public|university', 'The library type to be shown on the Hea Koha community website', 'Choice'),
433
('UsageStatsLibraryUrl', '', 'The library URL to be shown on Hea Koha community website', NULL, 'Free'),
432
('UsageStatsLibraryUrl', '', 'The library URL to be shown on Hea Koha community website', NULL, 'Free'),
434
('UseAuthoritiesForTracings','1','0','Use authority record numbers for subject tracings instead of heading strings.','YesNo'),
433
('UseAuthoritiesForTracings','1','0','Use authority record numbers for subject tracings instead of heading strings.','YesNo'),
435
('UseBranchTransferLimits','0','','If ON, Koha will will use the rules defined in branch_transfer_limits to decide if an item transfer should be allowed.','YesNo'),
434
('UseBranchTransferLimits','0','','If ON, Koha will will use the rules defined in branch_transfer_limits to decide if an item transfer should be allowed.','YesNo'),
(-)a/installer/data/mysql/updatedatabase.pl (+32 lines)
Lines 37-42 use Getopt::Long; Link Here
37
use C4::Context;
37
use C4::Context;
38
use C4::Installer;
38
use C4::Installer;
39
use C4::Dates;
39
use C4::Dates;
40
use C4::Reserves;
41
use DateTime::Duration;
40
42
41
use MARC::Record;
43
use MARC::Record;
42
use MARC::File::XML ( BinaryEncoding => 'utf8' );
44
use MARC::File::XML ( BinaryEncoding => 'utf8' );
Lines 8838-8843 if ( CheckVersion($DBversion) ) { Link Here
8838
    SetVersion($DBversion);
8840
    SetVersion($DBversion);
8839
}
8841
}
8840
8842
8843
$DBversion = "3.17.00.XXX";
8844
if ( CheckVersion($DBversion) ) {
8845
    my $maxpickupdelay = C4::Context->preference('ReservesMaxPickUpDelay') || 0; #MaxPickupDelay
8846
    $dbh->do(q{ DELETE FROM systempreferences WHERE variable='ReservesMaxPickUpDelay'; });
8847
    $dbh->do(q{ DELETE FROM systempreferences WHERE variable='ExpireReservesOnHolidays'; });
8848
#        //DELETE FROM systempreferences WHERE variable='ExpireReservesMaxPickUpDelay'; #This syspref is not needed and would be better suited to be calculated from the holdspickupwait
8849
#        //ExpireReservesMaxPickUpDelayCharge #This could be added as a column to the issuing rules.
8850
    $dbh->do(q{ ALTER TABLE issuingrules ADD COLUMN holdspickupwait INT(11) NULL default NULL AFTER reservesallowed; });
8851
    $dbh->do(q{ ALTER TABLE reserves ADD COLUMN lastpickupdate DATE NULL default NULL AFTER suspend_until; });
8852
    $dbh->do(q{ ALTER TABLE old_reserves ADD COLUMN lastpickupdate DATE NULL default NULL AFTER suspend_until; });
8853
    
8854
    my $sth = $dbh->prepare(q{
8855
        UPDATE issuingrules SET holdspickupwait = ?
8856
    });
8857
    $sth->execute( $maxpickupdelay ) if $maxpickupdelay; #Don't want to accidentally nullify all!
8858
    
8859
    ##Populate the lastpickupdate-column from existing 'ReservesMaxPickUpDelay'
8860
    print "Populating the new lastpickupdate-column for all waiting holds. This might take a while.\n";
8861
    $sth = $dbh->prepare(q{ SELECT * FROM reserves WHERE found = 'W'; });
8862
    $sth->execute( );
8863
    my $dtdur = DateTime::Duration->new( days => 0 );
8864
    while ( my $res = $sth->fetchrow_hashref ) {
8865
        C4::Reserves::MoveWaitingdate( $res, $dtdur ); #We call MoveWaitingdate with a 0 duration to simply recalculate the lastpickupdate and store the new values to DB.
8866
    }
8867
8868
    print "Upgrade to $DBversion done (8367: Add colum issuingrules.holdspickupwait and reserves.lastpickupdate. Populates introduced columns from the expiring ReservesMaxPickUpDelay. Deletes the ReservesMaxPickUpDelay and ExpireReservesOnHolidays -sysprefs)\n";
8869
    SetVersion($DBversion);
8870
}
8871
8872
8841
=head1 FUNCTIONS
8873
=head1 FUNCTIONS
8842
8874
8843
=head2 TableExists($table)
8875
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/js/holds.js (+3 lines)
Lines 11-16 $(document).ready(function() { Link Here
11
                        "mDataProp": "reservedate_formatted"
11
                        "mDataProp": "reservedate_formatted"
12
                    },
12
                    },
13
                    {
13
                    {
14
                        "mDataProp": "lastpickupdate_formatted"
15
                    },
16
                    {
14
                        "mDataProp": function ( oObj ) {
17
                        "mDataProp": function ( oObj ) {
15
                            title = "<a href='/cgi-bin/koha/reserve/request.pl?biblionumber="
18
                            title = "<a href='/cgi-bin/koha/reserve/request.pl?biblionumber="
16
                                  + oObj.biblionumber
19
                                  + oObj.biblionumber
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (-12 / +1 lines)
Lines 427-442 Circulation: Link Here
427
                  PatronLibrary: "patron's home library"
427
                  PatronLibrary: "patron's home library"
428
            - to see if the patron can place a hold on the item.    
428
            - to see if the patron can place a hold on the item.    
429
        -
429
        -
430
            - Mark a hold as problematic if it has been waiting for more than
431
            - pref: ReservesMaxPickUpDelay
432
              class: integer
433
            - days.
434
        -
435
            - pref: ExpireReservesMaxPickUpDelay
430
            - pref: ExpireReservesMaxPickUpDelay
436
              choices:
431
              choices:
437
                  yes: Allow
432
                  yes: Allow
438
                  no: "Don't allow"
433
                  no: "Don't allow"
439
            - "holds to expire automatically if they have not been picked by within the time period specified in ReservesMaxPickUpDelay"
434
            - "holds to expire automatically if they have not been picked by within the time period specified in hold pickup delay defined in the issuing rules"
440
        -
435
        -
441
            - If using ExpireReservesMaxPickUpDelay, charge a borrower who allows his or her waiting hold to expire a fee of
436
            - If using ExpireReservesMaxPickUpDelay, charge a borrower who allows his or her waiting hold to expire a fee of
442
            - pref: ExpireReservesMaxPickUpDelayCharge
437
            - pref: ExpireReservesMaxPickUpDelayCharge
Lines 511-522 Circulation: Link Here
511
                  no: "Don't allow"
506
                  no: "Don't allow"
512
            - holds to be suspended from the OPAC.
507
            - holds to be suspended from the OPAC.
513
        -
508
        -
514
            - pref: ExpireReservesOnHolidays
515
              choices:
516
                  yes: Allow
517
                  no: "Don't allow"
518
            - expired holds to be canceled on days the library is closed.
519
        -
520
            - pref: decreaseLoanHighHolds
509
            - pref: decreaseLoanHighHolds
521
              choices:
510
              choices:
522
                  yes: Enable
511
                  yes: Enable
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (+4 lines)
Lines 117-122 $(document).ready(function() { Link Here
117
            <li>default (all libraries), all patron types, same item type</li>
117
            <li>default (all libraries), all patron types, same item type</li>
118
            <li>default (all libraries), all patron types, all item types</li>
118
            <li>default (all libraries), all patron types, all item types</li>
119
        </ul>
119
        </ul>
120
        <p>To get more information about how these settings affect Koha, hover your cursor over a column header.</p>
120
        <p>To modify a rule, create a new one with the same patron type and item type.</p>
121
        <p>To modify a rule, create a new one with the same patron type and item type.</p>
121
    </div>
122
    </div>
122
    <div>
123
    <div>
Lines 153-158 for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde Link Here
153
                <th>Max. suspension duration (day)</th>
154
                <th>Max. suspension duration (day)</th>
154
                <th>Renewals allowed (count)</th>
155
                <th>Renewals allowed (count)</th>
155
                <th>Renewal period</th>
156
                <th>Renewal period</th>
157
                <th>Holds wait for pickup (day)</th>
156
                <th>No renewal before</th>
158
                <th>No renewal before</th>
157
                <th>Automatic renewal</th>
159
                <th>Automatic renewal</th>
158
                <th>Holds allowed (count)</th>
160
                <th>Holds allowed (count)</th>
Lines 209-214 for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde Link Here
209
                            <td>[% rule.maxsuspensiondays %]</td>
211
                            <td>[% rule.maxsuspensiondays %]</td>
210
							<td>[% rule.renewalsallowed %]</td>
212
							<td>[% rule.renewalsallowed %]</td>
211
                            <td>[% rule.renewalperiod %]</td>
213
                            <td>[% rule.renewalperiod %]</td>
214
                            <td>[% rule.holdspickupwait %]</td>
212
                            <td>[% rule.norenewalbefore %]</td>
215
                            <td>[% rule.norenewalbefore %]</td>
213
                            <td>
216
                            <td>
214
                                [% IF ( rule.auto_renew ) %]
217
                                [% IF ( rule.auto_renew ) %]
Lines 267-272 for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde Link Here
267
                    <td><input type="text" name="maxsuspensiondays" id="maxsuspensiondays" size="3" /> </td>
270
                    <td><input type="text" name="maxsuspensiondays" id="maxsuspensiondays" size="3" /> </td>
268
                    <td><input type="text" name="renewalsallowed" id="renewalsallowed" size="2" /></td>
271
                    <td><input type="text" name="renewalsallowed" id="renewalsallowed" size="2" /></td>
269
                    <td><input type="text" name="renewalperiod" id="renewalperiod" size="3" /></td>
272
                    <td><input type="text" name="renewalperiod" id="renewalperiod" size="3" /></td>
273
                    <td><input type="text" name="holdspickupwait" id="holdspickupwait" size="2" /></td>
270
                    <td><input type="text" name="norenewalbefore" id="norenewalbefore" size="3" /></td>
274
                    <td><input type="text" name="norenewalbefore" id="norenewalbefore" size="3" /></td>
271
                    <td>
275
                    <td>
272
                        <select name="auto_renew" id="auto_renew">
276
                        <select name="auto_renew" id="auto_renew">
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt (+1 lines)
Lines 776-781 No patron matched <span class="ex">[% message %]</span> Link Here
776
            <thead>
776
            <thead>
777
                <tr>
777
                <tr>
778
                    <th>Hold date</th>
778
                    <th>Hold date</th>
779
                    <th>Last pickup date</th>
779
                    <th>Title</th>
780
                    <th>Title</th>
780
                    <th>Call number</th>
781
                    <th>Call number</th>
781
                    <th>Barcode</th>
782
                    <th>Barcode</th>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/waitingreserves.tt (-4 / +4 lines)
Lines 77-83 Link Here
77
            [% IF ( reserveloop ) %]
77
            [% IF ( reserveloop ) %]
78
               <table id="holdst">
78
               <table id="holdst">
79
               <thead><tr>
79
               <thead><tr>
80
                    <th class="title-string">Available since</th>
80
                    <th class="title-string">Available since-until</th>
81
                    <th class="anti-the">Title</th>
81
                    <th class="anti-the">Title</th>
82
                    <th>Patron</th>
82
                    <th>Patron</th>
83
                    <th>Location</th>
83
                    <th>Location</th>
Lines 87-93 Link Here
87
               </tr></thead>
87
               </tr></thead>
88
               <tbody>[% FOREACH reserveloo IN reserveloop %]
88
               <tbody>[% FOREACH reserveloo IN reserveloop %]
89
                <tr>
89
                <tr>
90
                    <td><span title="[% reserveloo.waitingdate %]">[% reserveloo.waitingdate | $KohaDates %]</span></td>
90
                    <td><span title="[% reserveloo.waitingdate %]">[% reserveloo.waitingdate | $KohaDates %] - [% reserveloo.lastpickupdate | $KohaDates %]</span></td>
91
                    <td>[% INCLUDE 'biblio-default-view.inc' biblionumber = reserveloo.biblionumber %]
91
                    <td>[% INCLUDE 'biblio-default-view.inc' biblionumber = reserveloo.biblionumber %]
92
                        [% reserveloo.title |html %] [% reserveloo.subtitle |html %]
92
                        [% reserveloo.title |html %] [% reserveloo.subtitle |html %]
93
                        </a>
93
                        </a>
Lines 137-143 Link Here
137
               <br/>
137
               <br/>
138
               <table id="holdso">
138
               <table id="holdso">
139
               <thead><tr>
139
               <thead><tr>
140
                    <th class="title-string">Available since</th>
140
                    <th class="title-string">Available since-until</th>
141
                    <th class="anti-the">Title</th>
141
                    <th class="anti-the">Title</th>
142
                    <th>Patron</th>
142
                    <th>Patron</th>
143
                    <th>Location</th>
143
                    <th>Location</th>
Lines 147-153 Link Here
147
               </tr></thead>
147
               </tr></thead>
148
               <tbody>[% FOREACH overloo IN overloop %]
148
               <tbody>[% FOREACH overloo IN overloop %]
149
                    <tr>
149
                    <tr>
150
                        <td><p><span title="[% overloo.waitingdate %]">[% overloo.waitingdate | $KohaDates %]</span></p></td>
150
                        <td><p><span title="[% overloo.waitingdate %]">[% overloo.waitingdate | $KohaDates %] - [% overloo.lastpickupdate | $KohaDates %]</span></p></td>
151
                        <td>[% INCLUDE 'biblio-default-view.inc' biblionumber = overloo.biblionumber %][% overloo.title |html %] [% overloo.subtitle |html %]
151
                        <td>[% INCLUDE 'biblio-default-view.inc' biblionumber = overloo.biblionumber %][% overloo.title |html %] [% overloo.subtitle |html %]
152
                        </a>
152
                        </a>
153
                            [% UNLESS ( item_level_itypes ) %][% IF ( overloo.itemtype ) %]&nbsp; (<b>[% overloo.itemtype %]</b>)[% END %][% END %]
153
                            [% UNLESS ( item_level_itypes ) %][% IF ( overloo.itemtype ) %]&nbsp; (<b>[% overloo.itemtype %]</b>)[% END %][% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/help/admin/smart-rules.tt (+1 lines)
Lines 57-62 Link Here
57
</li>
57
</li>
58
    <li>Next decide if the patron can renew this item type and if so, enter how many times they can renew it in the 'Renewals Allowed' box</li>
58
    <li>Next decide if the patron can renew this item type and if so, enter how many times they can renew it in the 'Renewals Allowed' box</li>
59
    <li>If you're allowing renewals you can control how long the renewal loan period will be (in the units you have chosen) in the 'Renewal period' box</li>
59
    <li>If you're allowing renewals you can control how long the renewal loan period will be (in the units you have chosen) in the 'Renewal period' box</li>
60
    <li><i>Holds wait for pickup (day)</i> - After a hold is caught and put waiting for pickup, the hold will wait for this many days until it becomes problematic. Set it to 0 or less to disable the expiration of waiting holds. This value respects the Calendar holidays, skipping the last pickup date to the next available open library day.</li>
60
    <li>If you're allowing renewals you can control how soon before the due date patrons can renew their materials with the 'No renewals before' box.
61
    <li>If you're allowing renewals you can control how soon before the due date patrons can renew their materials with the 'No renewals before' box.
61
    <ul><li>Items can be renewed at any time if this value is left blank. Otherwise items can only be renewed if the item is before the number in units (days/hours) entered in this box.</li></ul></li>
62
    <ul><li>Items can be renewed at any time if this value is left blank. Otherwise items can only be renewed if the item is before the number in units (days/hours) entered in this box.</li></ul></li>
62
    <li>If the patron can place holds on this item type, enter the total numbers of items (of this type) that can be put on hold in the 'Holds Allowed' field</li>
63
    <li>If the patron can place holds on this item type, enter the total numbers of items (of this type) that can be put on hold in the 'Holds Allowed' field</li>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/help/circ/waitingreserves.tt (-1 / +1 lines)
Lines 4-10 Link Here
4
4
5
<p>This report will show all of the holds that are waiting for patrons to pick them up.</p>
5
<p>This report will show all of the holds that are waiting for patrons to pick them up.</p>
6
6
7
<p>Items that have been on the hold shelf longer than you normally allow (based on the ReservesMaxPickUpDelay preference value) will appear on the 'Holds Over' tab, they will not automatically be cancelled unless you have set the cron job to do that for you, but you can cancel all holds using the button at the top of the list.</p>
7
<p>Items that have been on the hold shelf longer than you normally allow (based on the holds pickup delay defined in the issuing rules) will appear on the 'Holds Over' tab, they will not automatically be cancelled.</p>
8
8
9
<p><strong>See the full documentation for Holds Awaiting Pickup in the <a href="http://manual.koha-community.org/[% helpVersion %]/en/circreports.html#holdspickup">manual</a> (online).</strong></p>
9
<p><strong>See the full documentation for Holds Awaiting Pickup in the <a href="http://manual.koha-community.org/[% helpVersion %]/en/circreports.html#holdspickup">manual</a> (online).</strong></p>
10
10
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt (+1 lines)
Lines 522-527 function validate1(date) { Link Here
522
            <thead>
522
            <thead>
523
                <tr>
523
                <tr>
524
                    <th>Hold date</th>
524
                    <th>Hold date</th>
525
                    <th>Last pickup date</th>
525
                    <th>Title</th>
526
                    <th>Title</th>
526
                    <th>Call number</th>
527
                    <th>Call number</th>
527
                    <th>Barcode</th>
528
                    <th>Barcode</th>
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt (-1 / +1 lines)
Lines 560-566 Link Here
560
                                                [% IF ( RESERVE.wait ) %]
560
                                                [% IF ( RESERVE.wait ) %]
561
                                                    [% IF ( RESERVE.atdestination ) %]
561
                                                    [% IF ( RESERVE.atdestination ) %]
562
                                                        [% IF ( RESERVE.found ) %]
562
                                                        [% IF ( RESERVE.found ) %]
563
                                                            Item waiting at <b> [% RESERVE.wbrname %]</b>[% IF ( RESERVE.waitingdate ) %] since [% RESERVE.waitingdate | $KohaDates %][% END %]
563
                                                            Item waiting at <b> [% RESERVE.wbrname %]</b>[% IF ( RESERVE.waitingdate ) %] since [% RESERVE.waitingdate | $KohaDates %] until [% RESERVE.lastpickupdate | $KohaDates %][% END %]
564
                                                            <input type="hidden" name="pickup" value="[% RESERVE.wbrcd %]" />
564
                                                            <input type="hidden" name="pickup" value="[% RESERVE.wbrcd %]" />
565
                                                        [% ELSE %]
565
                                                        [% ELSE %]
566
                                                            Item waiting to be pulled from <b> [% RESERVE.wbrname %]</b>
566
                                                            Item waiting to be pulled from <b> [% RESERVE.wbrname %]</b>
(-)a/svc/holds (-1 / +6 lines)
Lines 47-53 my $branch = C4::Context->userenv->{'branch'}; Link Here
47
my $schema = Koha::Database->new()->schema();
47
my $schema = Koha::Database->new()->schema();
48
48
49
my @sort_columns =
49
my @sort_columns =
50
  qw/reservedate title itemcallnumber barcode expirationdate priority/;
50
  qw/reservedate lastpickupdate title itemcallnumber barcode expirationdate priority/;
51
51
52
my $borrowernumber    = $input->param('borrowernumber');
52
my $borrowernumber    = $input->param('borrowernumber');
53
my $offset            = $input->param('iDisplayStart');
53
my $offset            = $input->param('iDisplayStart');
Lines 81-86 while ( my $h = $holds_rs->next() ) { Link Here
81
        author         => $h->biblio()->author(),
81
        author         => $h->biblio()->author(),
82
        reserve_id     => $h->reserve_id(),
82
        reserve_id     => $h->reserve_id(),
83
        reservedate    => $h->reservedate(),
83
        reservedate    => $h->reservedate(),
84
        lastpickupdate => $h->lastpickupdate(),
84
        expirationdate => $h->expirationdate(),
85
        expirationdate => $h->expirationdate(),
85
        suspend        => $h->suspend(),
86
        suspend        => $h->suspend(),
86
        suspend_until  => $h->suspend_until(),
87
        suspend_until  => $h->suspend_until(),
Lines 97-102 while ( my $h = $holds_rs->next() ) { Link Here
97
            { dt => dt_from_string( $h->reservedate() ), dateonly => 1 }
98
            { dt => dt_from_string( $h->reservedate() ), dateonly => 1 }
98
          )
99
          )
99
        : q{},
100
        : q{},
101
        lastpickupdate_formatted => $h->lastpickupdate() ? output_pref(
102
            { dt => dt_from_string( $h->lastpickupdate() ), dateonly => 1 }
103
          )
104
        : q{},
100
        suspend_until_formatted => $h->suspend_until() ? output_pref(
105
        suspend_until_formatted => $h->suspend_until() ? output_pref(
101
            { dt => dt_from_string( $h->suspend_until() ), dateonly => 1 }
106
            { dt => dt_from_string( $h->suspend_until() ), dateonly => 1 }
102
          )
107
          )
(-)a/t/db_dependent/Holds.t (-38 / +186 lines)
Lines 6-17 use t::lib::Mocks; Link Here
6
use C4::Context;
6
use C4::Context;
7
use C4::Branch;
7
use C4::Branch;
8
8
9
use Test::More tests => 38;
9
use Test::More tests => 44;
10
use MARC::Record;
10
use MARC::Record;
11
use C4::Biblio;
11
use C4::Biblio;
12
use C4::Items;
12
use C4::Items;
13
use C4::Members;
13
use C4::Members;
14
use C4::Calendar;
14
use C4::Calendar;
15
use Koha::Calendar;
16
use DateTime;
17
use DateTime::Duration;
15
18
16
use Koha::DateUtils qw( dt_from_string output_pref );
19
use Koha::DateUtils qw( dt_from_string output_pref );
17
20
Lines 328-372 ok( Link Here
328
    "cannot request item if policy that matches on bib-level item type forbids it (bug 9532)"
331
    "cannot request item if policy that matches on bib-level item type forbids it (bug 9532)"
329
);
332
);
330
333
331
# Test CancelExpiredReserves
334
332
C4::Context->set_preference('ExpireReservesMaxPickUpDelay', 1);
335
##Setting duration variables
333
C4::Context->set_preference('ReservesMaxPickUpDelay', 1);
336
my $now = DateTime->now();
334
337
my $minus4days = DateTime::Duration->new(days => -4);
335
my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time);
338
my $minus1days = DateTime::Duration->new(days => -1);
336
$year += 1900;
339
my $plus1days = DateTime::Duration->new(days => 1);
337
$mon += 1;
340
my $plus4days = DateTime::Duration->new(days => 4);
338
$reserves = $dbh->selectall_arrayref('SELECT * FROM reserves', { Slice => {} });
341
##Setting some test prerequisites testing environment
339
$reserve = $reserves->[0];
342
setSimpleCircPolicy();
340
my $calendar = C4::Calendar->new(branchcode => $reserve->{branchcode});
343
setCalendars();
341
$calendar->insert_single_holiday(
344
#Running more tests
342
    day         => $mday,
345
testGetLastPickupDate();
343
    month       => $mon,
346
testMoveWaitingdate();
344
    year        => $year,
347
testCancelExpiredReserves();
345
    title       => 'Test',
348
346
    description => 'Test',
349
## Environment should be the following
347
);
350
## Holidays: days from today; -2,-3,-4
348
$reserve_id = $reserve->{reserve_id};
351
sub testCancelExpiredReserves {
349
$dbh->do("UPDATE reserves SET waitingdate = DATE_SUB( NOW(), INTERVAL 5 DAY ), found = 'W', priority = 0 WHERE reserve_id = ?", undef, $reserve_id );
352
    $dbh->do('UPDATE issuingrules SET holdspickupwait = 1'); #Make holds problematize after 1 day
350
C4::Context->set_preference('ExpireReservesOnHolidays', 0);
353
    
351
CancelExpiredReserves();
354
    $reserves = $dbh->selectall_arrayref('SELECT * FROM reserves WHERE found IS NULL', { Slice => {} });
352
my $count = $dbh->selectrow_array("SELECT COUNT(*) FROM reserves WHERE reserve_id = ?", undef, $reserve_id );
355
    $reserve = $reserves->[0];
353
is( $count, 1, "Waiting reserve beyond max pickup delay *not* canceled on holiday" );
356
    $reserve_id = $reserve->{reserve_id};
354
C4::Context->set_preference('ExpireReservesOnHolidays', 1);
357
    #Catch this hold and make it Waiting for pickup today.
355
CancelExpiredReserves();
358
    C4::Reserves::ModReserveAffect( $reserve->{itemnumber}, $reserve->{borrowernumber} );
356
$count = $dbh->selectrow_array("SELECT COUNT(*) FROM reserves WHERE reserve_id = ?", undef, $reserve_id );
359
    $reserve = C4::Reserves::GetReserve( $reserve_id ); #UPDATE DB changes to local scope.
357
is( $count, 0, "Waiting reserve beyond max pickup delay canceled on holiday" );
360
    
358
361
    CancelExpiredReserves();
359
# Test expirationdate
362
    my $count = $dbh->selectrow_array("SELECT COUNT(*) FROM reserves WHERE reserve_id = ?", undef, $reserve_id );
360
$reserve = $reserves->[1];
363
    is( $count, 1, "Waiting reserve with lastpickupdate for ".$reserve->{lastpickupdate}." not canceled" );
361
$reserve_id = $reserve->{reserve_id};
364
    
362
$dbh->do("UPDATE reserves SET expirationdate = DATE_SUB( NOW(), INTERVAL 1 DAY ) WHERE reserve_id = ?", undef, $reserve_id );
365
    C4::Reserves::MoveWaitingdate( $reserve, DateTime::Duration->new(days => -4) );
363
CancelExpiredReserves();
366
    CancelExpiredReserves();
364
$count = $dbh->selectrow_array("SELECT COUNT(*) FROM reserves WHERE reserve_id = ?", undef, $reserve_id );
367
    $count = $dbh->selectrow_array("SELECT COUNT(*) FROM reserves WHERE reserve_id = ?", undef, $reserve_id );
365
is( $count, 0, "Reserve with manual expiration date canceled correctly" );
368
    is( $count, 0, "Waiting reserve with lastpickupdate for ".$reserve->{lastpickupdate}." totally canceled" );
369
    
370
    # Test expirationdate
371
    $reserve = $reserves->[1];
372
    $reserve_id = $reserve->{reserve_id};
373
    $dbh->do("UPDATE reserves SET expirationdate = DATE_SUB( NOW(), INTERVAL 1 DAY ) WHERE reserve_id = ?", undef, $reserve_id );
374
    CancelExpiredReserves();
375
    $count = $dbh->selectrow_array("SELECT COUNT(*) FROM reserves WHERE reserve_id = ?", undef, $reserve_id );
376
    is( $count, 0, "Reserve with manual expiration date canceled correctly" );
377
}
378
379
## Environment should be the following
380
## Holidays: days from today; -2,-3,-4
381
sub testMoveWaitingdate {
382
    $dbh->do('UPDATE issuingrules SET holdspickupwait = 1'); #Make holds problematize after 1 day
383
    
384
    $reserves = $dbh->selectall_arrayref('SELECT * FROM reserves WHERE found IS NULL', { Slice => {} }); #Get reserves not waiting for pickup
385
    $reserve = $reserves->[0];
386
387
    C4::Reserves::ModReserveAffect( $reserve->{itemnumber}, $reserve->{borrowernumber} ); #Catch the reserve and put it to wait for pickup, now we get a waitingdate generated.
388
    
389
    C4::Reserves::MoveWaitingdate( $reserve, $minus1days );
390
    $reserve = C4::Reserves::GetReserve( $reserve_id ); #UPDATE DB changes to local scope. Actually MoveWaitingdate already updates changes to DB, but just making sure it does.
391
    is( ($reserve->{waitingdate} eq $now->clone()->add_duration($minus1days)->ymd() &&
392
         $reserve->{lastpickupdate} eq $now->ymd()),
393
         1, "MoveWaitingdate(): Moving to past");
394
    C4::Reserves::MoveWaitingdate( $reserve, $plus1days );
395
    
396
    C4::Reserves::MoveWaitingdate( $reserve, $plus4days );
397
    $reserve = C4::Reserves::GetReserve( $reserve_id );
398
    is( ($reserve->{waitingdate} eq $now->clone()->add_duration($plus4days)->ymd() &&
399
         $reserve->{lastpickupdate} eq $now->clone()->add_duration($plus4days)->add_duration($plus1days)->ymd()),
400
         1, "MoveWaitingdate(): Moving to future");
401
    C4::Reserves::MoveWaitingdate( $reserve, $minus4days );
402
}
403
404
## Environment should be the following
405
## Holidays: days from today; -2,-3,-4
406
sub testGetLastPickupDate {
407
    $dbh->do('UPDATE issuingrules SET holdspickupwait = 1'); #Make holds problematize after 1 day
408
    
409
    my $now = DateTime->now();
410
    my $minus4days = DateTime::Duration->new(days => -4);
411
    my $minus1days = DateTime::Duration->new(days => -1);
412
    my $plus1days = DateTime::Duration->new(days => 1);
413
    my $plus4days = DateTime::Duration->new(days => 4);
414
    
415
    $reserves = $dbh->selectall_arrayref('SELECT * FROM reserves', { Slice => {} }); #Get reserves not waiting for pickup
416
    $reserve = $reserves->[0];
417
418
    $reserve->{waitingdate} = $now->clone()->add_duration($minus4days)->ymd();
419
    my $lastpickupdate = C4::Reserves::GetLastPickupDate( $reserve )->ymd();
420
    $reserve = C4::Reserves::GetReserve( $reserve_id ); #UPDATE DB changes to local scope
421
    is( $lastpickupdate, $now->clone()->add_duration($minus1days)->ymd(),
422
         "GetLastPickupDate(): Calendar finds the next open day for lastpickupdate.");
423
    
424
    $reserve->{waitingdate} = $now->clone()->add_duration($minus1days)->ymd();
425
    $lastpickupdate = C4::Reserves::GetLastPickupDate( $reserve )->ymd();
426
    is( ($lastpickupdate eq $now->ymd()),
427
         1, "GetLastPickupDate(): Not using Calendar");
428
    
429
    $reserve->{waitingdate} = $now->clone()->add_duration($plus4days)->ymd();
430
    $lastpickupdate = C4::Reserves::GetLastPickupDate( $reserve )->ymd();
431
    is( ($lastpickupdate eq $now->clone()->add_duration($plus4days)->add_duration($plus1days)->ymd()),
432
         1, "GetLastPickupDate(): Moving to future");
433
    
434
    #This test catches moving lastpickupdate for each holiday, instead of just moving the last date to an open library day
435
    $dbh->do('UPDATE issuingrules SET holdspickupwait = 4'); #Make holds problematize after 4 days
436
    $reserve->{waitingdate} = $now->clone()->add_duration($minus4days)->ymd();
437
    $lastpickupdate = C4::Reserves::GetLastPickupDate( $reserve )->ymd();
438
    is( ($reserve->{lastpickupdate} eq $now->ymd()),
439
         1, "GetLastPickupDate(): Moving lastpickupdate over holidays, but not affected by them");
440
}
366
441
367
# Helper method to set up a Biblio.
442
# Helper method to set up a Biblio.
368
sub create_helper_biblio {
443
sub create_helper_biblio {
369
    my $itemtype = shift;
444
    my $itemtype = $_[0] ? $_[0] : 'BK';
370
    my $bib = MARC::Record->new();
445
    my $bib = MARC::Record->new();
371
    my $title = 'Silence in the library';
446
    my $title = 'Silence in the library';
372
    $bib->append_fields(
447
    $bib->append_fields(
Lines 376-378 sub create_helper_biblio { Link Here
376
    );
451
    );
377
    return ($bibnum, $title, $bibitemnum) = AddBiblio($bib, '');
452
    return ($bibnum, $title, $bibitemnum) = AddBiblio($bib, '');
378
}
453
}
379
- 
454
455
sub setSimpleCircPolicy {
456
    $dbh->do('DELETE FROM issuingrules');
457
    $dbh->do(
458
        q{INSERT INTO issuingrules (categorycode, branchcode, itemtype, reservesallowed,
459
                                    maxissueqty, issuelength, lengthunit,
460
                                    renewalsallowed, renewalperiod,
461
                                    norenewalbefore, auto_renew,
462
                                    fine, chargeperiod, holdspickupwait)
463
          VALUES (?, ?, ?, ?,
464
                  ?, ?, ?,
465
                  ?, ?,
466
                  ?, ?,
467
                  ?, ?, ?
468
                 )
469
        },
470
        {},
471
        '*', '*', '*', 25,
472
        20, 14, 'days',
473
        1, 7,
474
        '', 0,
475
        .10, 1,1
476
    );
477
}
478
479
###Set C4::Calendar and Koha::Calendar holidays for
480
# today -2 days
481
# today -3 days
482
# today -4 days
483
#
484
## Koha::Calendar for caching purposes (supposedly) doesn't work from the DB in this script
485
## So we must set the cache for Koha::calnder as well as the DB modifications for C4::Calendar.
486
## When making date comparisons with Koha::Calendar, using DateTime::Set, DateTime-objects
487
## need to match by the nanosecond and time_zone.
488
sub setCalendars {
489
    
490
    ##Set the C4::Calendar
491
    my $now = DateTime->now(time_zone => C4::Context->tz())->truncate(to => 'day');
492
    my $c4calendar = C4::Calendar->new(branchcode => $reserve->{branchcode});
493
    $now->add_duration( DateTime::Duration->new(days => -2) );
494
    $c4calendar->insert_single_holiday(
495
        day         => $now->day(),
496
        month       => $now->month(),
497
        year        => $now->year(),
498
        title       => 'Test',
499
        description => 'Test',
500
    );
501
    $now->add_duration( DateTime::Duration->new(days => -1) );
502
    $c4calendar->insert_single_holiday(
503
        day         => $now->day(),
504
        month       => $now->month(),
505
        year        => $now->year(),
506
        title       => 'Test',
507
        description => 'Test',
508
    );
509
    $now->add_duration( DateTime::Duration->new(days => -1) );
510
    $c4calendar->insert_single_holiday(
511
        day         => $now->day(),
512
        month       => $now->month(),
513
        year        => $now->year(),
514
        title       => 'Test',
515
        description => 'Test',
516
    );
517
    
518
    #Set the Koha::Calendar
519
    my $kohaCalendar = Koha::Calendar->new(branchcode => $reserve->{branchcode});
520
    $now = DateTime->now(time_zone => C4::Context->tz())->truncate(to => 'day');
521
    $now->add_duration( DateTime::Duration->new(days => -2) );
522
    $kohaCalendar->add_holiday( $now );
523
    $now->add_duration( DateTime::Duration->new(days => -1) );
524
    $kohaCalendar->add_holiday( $now );
525
    $now->add_duration( DateTime::Duration->new(days => -1) );
526
    $kohaCalendar->add_holiday( $now );
527
}

Return to bug 8367