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

(-)a/C4/Circulation.pm (-21 / +24 lines)
Lines 1097-1103 sub CanBookBeIssued { Link Here
1097
        # See if the item is on reserve.
1097
        # See if the item is on reserve.
1098
        my ( $restype, $res ) = C4::Reserves::CheckReserves( $item_object->itemnumber );
1098
        my ( $restype, $res ) = C4::Reserves::CheckReserves( $item_object->itemnumber );
1099
        if ($restype) {
1099
        if ($restype) {
1100
            my $resbor = $res->{'borrowernumber'};
1100
            my $resbor = $res->{patron_id};
1101
            if ( $resbor ne $patron->borrowernumber ) {
1101
            if ( $resbor ne $patron->borrowernumber ) {
1102
                my $patron = Koha::Patrons->find( $resbor );
1102
                my $patron = Koha::Patrons->find( $resbor );
1103
                if ( $restype eq "Waiting" )
1103
                if ( $restype eq "Waiting" )
Lines 1109-1117 sub CanBookBeIssued { Link Here
1109
                    $needsconfirmation{'ressurname'} = $patron->surname;
1109
                    $needsconfirmation{'ressurname'} = $patron->surname;
1110
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1110
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1111
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1111
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1112
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1112
                    $needsconfirmation{'resbranchcode'} = $res->{pickup_library_id};
1113
                    $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'};
1113
                    $needsconfirmation{'reswaitingdate'} = $res->{waiting_date};
1114
                    $needsconfirmation{'reserve_id'} = $res->{reserve_id};
1114
                    $needsconfirmation{'reserve_id'} = $res->{id};
1115
                }
1115
                }
1116
                elsif ( $restype eq "Reserved" ) {
1116
                elsif ( $restype eq "Reserved" ) {
1117
                    # The item is on reserve for someone else.
1117
                    # The item is on reserve for someone else.
Lines 1121-1128 sub CanBookBeIssued { Link Here
1121
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1121
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1122
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1122
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1123
                    $needsconfirmation{'resbranchcode'} = $patron->branchcode;
1123
                    $needsconfirmation{'resbranchcode'} = $patron->branchcode;
1124
                    $needsconfirmation{'resreservedate'} = $res->{reservedate};
1124
                    $needsconfirmation{'resreservedate'} = $res->{created_date};
1125
                    $needsconfirmation{'reserve_id'} = $res->{reserve_id};
1125
                    $needsconfirmation{'reserve_id'} = $res->{id};
1126
                }
1126
                }
1127
                elsif ( $restype eq "Transferred" ) {
1127
                elsif ( $restype eq "Transferred" ) {
1128
                    # The item is determined hold being transferred for someone else.
1128
                    # The item is determined hold being transferred for someone else.
Lines 1132-1139 sub CanBookBeIssued { Link Here
1132
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1132
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1133
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1133
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1134
                    $needsconfirmation{'resbranchcode'} = $patron->branchcode;
1134
                    $needsconfirmation{'resbranchcode'} = $patron->branchcode;
1135
                    $needsconfirmation{'resreservedate'} = $res->{reservedate};
1135
                    $needsconfirmation{'resreservedate'} = $res->{created_date};
1136
                    $needsconfirmation{'reserve_id'} = $res->{reserve_id};
1136
                    $needsconfirmation{'reserve_id'} = $res->{id};
1137
                }
1137
                }
1138
                elsif ( $restype eq "Processing" ) {
1138
                elsif ( $restype eq "Processing" ) {
1139
                    # The item is determined hold being processed for someone else.
1139
                    # The item is determined hold being processed for someone else.
Lines 1143-1150 sub CanBookBeIssued { Link Here
1143
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1143
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1144
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1144
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1145
                    $needsconfirmation{'resbranchcode'} = $patron->branchcode;
1145
                    $needsconfirmation{'resbranchcode'} = $patron->branchcode;
1146
                    $needsconfirmation{'resreservedate'} = $res->{reservedate};
1146
                    $needsconfirmation{'resreservedate'} = $res->{created_date};
1147
                    $needsconfirmation{'reserve_id'} = $res->{reserve_id};
1147
                    $needsconfirmation{'reserve_id'} = $res->{id};
1148
                }
1148
                }
1149
            }
1149
            }
1150
        }
1150
        }
Lines 1287-1293 sub checkHighHolds { Link Here
1287
        due_date    => undef,
1287
        due_date    => undef,
1288
    };
1288
    };
1289
1289
1290
    my $holds = Koha::Holds->search( { biblionumber => $item->{'biblionumber'} } );
1290
    my $holds = Koha::Holds->search( { biblio_id => $item->{'biblionumber'} } );
1291
1291
1292
    if ( $holds->count() ) {
1292
    if ( $holds->count() ) {
1293
        $return_data->{outstanding} = $holds->count();
1293
        $return_data->{outstanding} = $holds->count();
Lines 1508-1517 sub AddIssue { Link Here
1508
                    }
1508
                    }
1509
                )->store;
1509
                )->store;
1510
                if ( $transfer->reason && $transfer->reason eq 'Reserve' ) {
1510
                if ( $transfer->reason && $transfer->reason eq 'Reserve' ) {
1511
                    my $hold = $item_object->holds->search( { found => 'T' } )->next;
1511
                    my $hold = $item_object->holds->search( { status => 'in_transit' } )->next;
1512
                    if ( $hold ) { # Is this really needed?
1512
                    if ( $hold ) { # Is this really needed?
1513
                        $hold->set( { found => undef } )->store;
1513
                        $hold->set( { status => 'placed' } )->store;
1514
                        C4::Reserves::ModReserveMinusPriority($item_object->itemnumber, $hold->reserve_id);
1514
                        C4::Reserves::ModReserveMinusPriority($item_object->itemnumber, $hold->id);
1515
                    }
1515
                    }
1516
                }
1516
                }
1517
            }
1517
            }
Lines 2218-2224 sub AddReturn { Link Here
2218
    my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2218
    my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2219
    ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->itemnumber, undef, $lookahead ) unless ( $item->withdrawn );
2219
    ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->itemnumber, undef, $lookahead ) unless ( $item->withdrawn );
2220
    # if a hold is found and is waiting at another branch, change the priority back to 1 and trigger the hold (this will trigger a transfer and update the hold status properly)
2220
    # if a hold is found and is waiting at another branch, change the priority back to 1 and trigger the hold (this will trigger a transfer and update the hold status properly)
2221
    if ( $resfound and $resfound eq "Waiting" and $branch ne $resrec->{branchcode} ) {
2221
    if ( $resfound and $resfound eq "Waiting" and $branch ne $resrec->{pickup_library_id} ) {
2222
        my $hold = C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
2222
        my $hold = C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
2223
        $resfound = 'Reserved';
2223
        $resfound = 'Reserved';
2224
        $resrec = $hold->unblessed;
2224
        $resrec = $hold->unblessed;
Lines 2864-2874 sub CanBookBeRenewed { Link Here
2864
    }
2864
    }
2865
2865
2866
    my ( $resfound, $resrec, $possible_reserves ) = C4::Reserves::CheckReserves($itemnumber);
2866
    my ( $resfound, $resrec, $possible_reserves ) = C4::Reserves::CheckReserves($itemnumber);
2867
    use Data::Printer colored => 1;
2868
    p( $resfound );
2869
    p( $resrec );
2870
    p( $possible_reserves );
2867
2871
2868
    # If next hold is non priority, then check if any hold with priority (non_priority = 0) exists for the same biblionumber.
2872
    # If next hold is non priority, then check if any hold with priority (non_priority = 0) exists for the same biblionumber.
2869
    if ( $resfound && $resrec->{non_priority} ) {
2873
    if ( $resfound && $resrec->{non_priority} ) {
2870
        $resfound = Koha::Holds->search(
2874
        $resfound = Koha::Holds->search(
2871
            { biblionumber => $resrec->{biblionumber}, non_priority => 0 } )
2875
            { biblio_id => $resrec->{biblio_id}, non_priority => 0, completed => 0 } )
2872
          ->count > 0;
2876
          ->count > 0;
2873
    }
2877
    }
2874
2878
Lines 2879-2885 sub CanBookBeRenewed { Link Here
2879
    if ( $resfound
2883
    if ( $resfound
2880
        && C4::Context->preference('AllowRenewalIfOtherItemsAvailable') )
2884
        && C4::Context->preference('AllowRenewalIfOtherItemsAvailable') )
2881
    {
2885
    {
2882
        my $item_holds = Koha::Holds->search( { itemnumber => $itemnumber, found => undef } )->count();
2886
        my $item_holds = Koha::Holds->search( { item_id => $itemnumber, status => 'placed' } )->count();
2883
        if ($item_holds) {
2887
        if ($item_holds) {
2884
            # There is an item level hold on this item, no other item can fill the hold
2888
            # There is an item level hold on this item, no other item can fill the hold
2885
            $resfound = 1;
2889
            $resfound = 1;
Lines 2888-2901 sub CanBookBeRenewed { Link Here
2888
2892
2889
            # Get all other items that could possibly fill reserves
2893
            # Get all other items that could possibly fill reserves
2890
            my $items = Koha::Items->search({
2894
            my $items = Koha::Items->search({
2891
                biblionumber => $resrec->{biblionumber},
2895
                biblionumber => $resrec->{biblio_id},
2892
                onloan       => undef,
2896
                onloan       => undef,
2893
                notforloan   => 0,
2897
                notforloan   => 0,
2894
                -not         => { itemnumber => $itemnumber }
2898
                -not         => { itemnumber => $itemnumber }
2895
            });
2899
            });
2896
2900
2897
            # Get all other reserves that could have been filled by this item
2901
            # Get all other reserves that could have been filled by this item
2898
            my @borrowernumbers = map { $_->{borrowernumber} } @$possible_reserves;
2902
            my @borrowernumbers = map { $_->{patron_id} } @$possible_reserves;
2899
            my $patrons = Koha::Patrons->search({
2903
            my $patrons = Koha::Patrons->search({
2900
                borrowernumber => { -in => \@borrowernumbers }
2904
                borrowernumber => { -in => \@borrowernumbers }
2901
            });
2905
            });
Lines 2930-2936 sub CanBookBeRenewed { Link Here
2930
    }
2934
    }
2931
2935
2932
    return ( 0, "auto_renew" ) if $auto_renew eq "ok" && !$override_limit; # 0 if auto-renewal should not succeed
2936
    return ( 0, "auto_renew" ) if $auto_renew eq "ok" && !$override_limit; # 0 if auto-renewal should not succeed
2933
2934
    return ( 1, undef );
2937
    return ( 1, undef );
2935
}
2938
}
2936
2939
Lines 3371-3377 sub GetIssuingCharges { Link Here
3371
    $sth->execute($itemnumber);
3374
    $sth->execute($itemnumber);
3372
    if ( my $item_data = $sth->fetchrow_hashref ) {
3375
    if ( my $item_data = $sth->fetchrow_hashref ) {
3373
        $item_type = $item_data->{itemtype};
3376
        $item_type = $item_data->{itemtype};
3374
        $charge    = $item_data->{rentalcharge};
3377
        $charge    = $item_data->{rentalcharge} // 0;
3375
        # FIXME This should follow CircControl
3378
        # FIXME This should follow CircControl
3376
        my $branch = C4::Context::mybranch();
3379
        my $branch = C4::Context::mybranch();
3377
        my $patron = Koha::Patrons->find( $borrowernumber );
3380
        my $patron = Koha::Patrons->find( $borrowernumber );
(-)a/C4/Items.pm (-2 / +3 lines)
Lines 602-609 sub GetItemsForInventory { Link Here
602
    }
602
    }
603
603
604
    if ( $ignore_waiting_holds ) {
604
    if ( $ignore_waiting_holds ) {
605
        $query .= "LEFT JOIN reserves ON items.itemnumber = reserves.itemnumber ";
605
        $query .= "LEFT JOIN holds ON items.itemnumber = holds.item_id ";
606
        push( @where_strings, q{(reserves.found != 'W' OR reserves.found IS NULL)} );
606
        # holds.status IS NULL <- means the join doesn't match any hold to the item
607
        push( @where_strings, q{(holds.status != 'waiting' OR holds.status IS NULL)} );
607
    }
608
    }
608
609
609
    if ( @$itemtypes ) {
610
    if ( @$itemtypes ) {
(-)a/C4/Letters.pm (-5 / +5 lines)
Lines 786-792 sub _parseletter_sth { Link Here
786
    ($table eq 'items'        )    ? "SELECT * FROM $table WHERE     itemnumber = ?"                                  :
786
    ($table eq 'items'        )    ? "SELECT * FROM $table WHERE     itemnumber = ?"                                  :
787
    ($table eq 'issues'       )    ? "SELECT * FROM $table WHERE     itemnumber = ?"                                  :
787
    ($table eq 'issues'       )    ? "SELECT * FROM $table WHERE     itemnumber = ?"                                  :
788
    ($table eq 'old_issues'   )    ? "SELECT * FROM $table WHERE     itemnumber = ? ORDER BY timestamp DESC LIMIT 1"  :
788
    ($table eq 'old_issues'   )    ? "SELECT * FROM $table WHERE     itemnumber = ? ORDER BY timestamp DESC LIMIT 1"  :
789
    ($table eq 'reserves'     )    ? "SELECT * FROM $table WHERE borrowernumber = ? and biblionumber = ?"             :
789
    ($table eq 'holds'        )    ? "SELECT * FROM $table WHERE      patron_id = ? AND biblio_id = ?"                :
790
    ($table eq 'borrowers'    )    ? "SELECT * FROM $table WHERE borrowernumber = ?"                                  :
790
    ($table eq 'borrowers'    )    ? "SELECT * FROM $table WHERE borrowernumber = ?"                                  :
791
    ($table eq 'branches'     )    ? "SELECT * FROM $table WHERE     branchcode = ?"                                  :
791
    ($table eq 'branches'     )    ? "SELECT * FROM $table WHERE     branchcode = ?"                                  :
792
    ($table eq 'suggestions'  )    ? "SELECT * FROM $table WHERE   suggestionid = ?"                                  :
792
    ($table eq 'suggestions'  )    ? "SELECT * FROM $table WHERE   suggestionid = ?"                                  :
Lines 834-841 sub _parseletter { Link Here
834
        $values->{'dateexpiry'} = output_pref({ dt => dt_from_string( $values->{'dateexpiry'} ), dateonly => 1 });
834
        $values->{'dateexpiry'} = output_pref({ dt => dt_from_string( $values->{'dateexpiry'} ), dateonly => 1 });
835
    }
835
    }
836
836
837
    if ( $table eq 'reserves' && $values->{'waitingdate'} ) {
837
    if ( $table eq 'holds' && $values->{waiting_date} ) {
838
        $values->{'waitingdate'} = output_pref({ dt => dt_from_string( $values->{'waitingdate'} ), dateonly => 1 });
838
        $values->{waiting_date} = output_pref({ dt => dt_from_string( $values->{waiting_date} ), dateonly => 1 });
839
    }
839
    }
840
840
841
    if ($letter->{content} && $letter->{content} =~ /<<today>>/) {
841
    if ($letter->{content} && $letter->{content} =~ /<<today>>/) {
Lines 1665-1675 sub _get_tt_params { Link Here
1665
            plural   => 'orders',
1665
            plural   => 'orders',
1666
            pk       => 'ordernumber',
1666
            pk       => 'ordernumber',
1667
        },
1667
        },
1668
        reserves => {
1668
        holds => {
1669
            module   => 'Koha::Holds',
1669
            module   => 'Koha::Holds',
1670
            singular => 'hold',
1670
            singular => 'hold',
1671
            plural   => 'holds',
1671
            plural   => 'holds',
1672
            pk       => 'reserve_id',
1672
            pk       => 'id',
1673
        },
1673
        },
1674
        serial => {
1674
        serial => {
1675
            module   => 'Koha::Serials',
1675
            module   => 'Koha::Serials',
(-)a/C4/Members.pm (-1 / +1 lines)
Lines 227-233 sub patronflags { Link Here
227
        $flags{'ODUES'} = \%flaginfo;
227
        $flags{'ODUES'} = \%flaginfo;
228
    }
228
    }
229
229
230
    my $waiting_holds = $patron->holds->search({ found => 'W' });
230
    my $waiting_holds = $patron->holds->search({ status => 'waiting' });
231
    my $nowaiting = $waiting_holds->count;
231
    my $nowaiting = $waiting_holds->count;
232
    if ( $nowaiting > 0 ) {
232
    if ( $nowaiting > 0 ) {
233
        my %flaginfo;
233
        my %flaginfo;
(-)a/C4/Reserves.pm (-269 / +258 lines)
Lines 37-48 use Koha::Calendar; Link Here
37
use Koha::CirculationRules;
37
use Koha::CirculationRules;
38
use Koha::Database;
38
use Koha::Database;
39
use Koha::DateUtils qw( dt_from_string output_pref );
39
use Koha::DateUtils qw( dt_from_string output_pref );
40
use Koha::Hold;
41
use Koha::Holds;
40
use Koha::Holds;
42
use Koha::ItemTypes;
41
use Koha::ItemTypes;
43
use Koha::Items;
42
use Koha::Items;
44
use Koha::Libraries;
43
use Koha::Libraries;
45
use Koha::Old::Hold;
46
use Koha::Patrons;
44
use Koha::Patrons;
47
use Koha::Plugins;
45
use Koha::Plugins;
48
46
Lines 190-196 sub AddReserve { Link Here
190
    my $notes          = $params->{notes};
188
    my $notes          = $params->{notes};
191
    my $title          = $params->{title};
189
    my $title          = $params->{title};
192
    my $checkitem      = $params->{itemnumber};
190
    my $checkitem      = $params->{itemnumber};
193
    my $found          = $params->{found};
191
    my $found          = $params->{found} // 'placed';
194
    my $itemtype       = $params->{itemtype};
192
    my $itemtype       = $params->{itemtype};
195
    my $non_priority   = $params->{non_priority};
193
    my $non_priority   = $params->{non_priority};
196
194
Lines 221-227 sub AddReserve { Link Here
221
            && !$item->current_holds->count )
219
            && !$item->current_holds->count )
222
        {
220
        {
223
            $priority = 0;
221
            $priority = 0;
224
            $found = 'W';
222
            $found = 'waiting';
225
        }
223
        }
226
    }
224
    }
227
225
Lines 234-240 sub AddReserve { Link Here
234
    my $waitingdate;
232
    my $waitingdate;
235
233
236
    # If the reserv had the waiting status, we had the value of the resdate
234
    # If the reserv had the waiting status, we had the value of the resdate
237
    if ( $found && $found eq 'W' ) {
235
    if ( $found and $found eq 'waiting' ) {
238
        $waitingdate = $resdate;
236
        $waitingdate = $resdate;
239
    }
237
    }
240
238
Lines 244-265 sub AddReserve { Link Here
244
    # updates take place here
242
    # updates take place here
245
    my $hold = Koha::Hold->new(
243
    my $hold = Koha::Hold->new(
246
        {
244
        {
247
            borrowernumber => $borrowernumber,
245
            patron_id      => $borrowernumber,
248
            biblionumber   => $biblionumber,
246
            biblio_id      => $biblionumber,
249
            reservedate    => $resdate,
247
            created_date   => $resdate,
250
            branchcode     => $branch,
248
            pickup_library_id => $branch,
251
            priority       => $priority,
249
            priority       => $priority,
252
            reservenotes   => $notes,
250
            notes          => $notes,
253
            itemnumber     => $checkitem,
251
            item_id        => $checkitem,
254
            found          => $found,
252
            waiting_date   => $waitingdate,
255
            waitingdate    => $waitingdate,
253
            expiration_date => $expdate,
256
            expirationdate => $expdate,
254
            item_type      => $itemtype,
257
            itemtype       => $itemtype,
255
            item_level     => $checkitem ? 1 : 0,
258
            item_level_hold => $checkitem ? 1 : 0,
259
            non_priority   => $non_priority ? 1 : 0,
256
            non_priority   => $non_priority ? 1 : 0,
260
        }
257
        }
261
    )->store();
258
    )->store();
262
    $hold->set_waiting() if $found && $found eq 'W';
259
    $hold->set_waiting() if $found eq 'waiting';
263
260
264
    logaction( 'HOLDS', 'CREATE', $hold->id, Dumper($hold->unblessed) )
261
    logaction( 'HOLDS', 'CREATE', $hold->id, Dumper($hold->unblessed) )
265
        if C4::Context->preference('HoldsLog');
262
        if C4::Context->preference('HoldsLog');
Lines 398-404 sub CanItemBeReserved { Link Here
398
395
399
    # Check that the patron doesn't have an item level hold on this item already
396
    # Check that the patron doesn't have an item level hold on this item already
400
    return { status =>'itemAlreadyOnHold' }
397
    return { status =>'itemAlreadyOnHold' }
401
      if ( !$params->{ignore_hold_counts} && Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count() );
398
      if ( !$params->{ignore_hold_counts} && Koha::Holds->search( { patron_id => $borrowernumber, item_id => $itemnumber, completed => 0 } )->count() );
402
399
403
    # Check that patron have not checked out this biblio (if AllowHoldsOnPatronsPossessions set)
400
    # Check that patron have not checked out this biblio (if AllowHoldsOnPatronsPossessions set)
404
    if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions')
401
    if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions')
Lines 410-424 sub CanItemBeReserved { Link Here
410
407
411
    my $querycount = q{
408
    my $querycount = q{
412
        SELECT count(*) AS count
409
        SELECT count(*) AS count
413
          FROM reserves
410
          FROM holds
414
     LEFT JOIN items USING (itemnumber)
411
     LEFT JOIN items ON (holds.item_id=items.itemnumber)
415
     LEFT JOIN biblioitems ON (reserves.biblionumber=biblioitems.biblionumber)
412
     LEFT JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
416
     LEFT JOIN borrowers USING (borrowernumber)
413
     LEFT JOIN borrowers ON (holds.patron_id=borrowers.borrowernumber)
417
         WHERE borrowernumber = ?
414
         WHERE completed = 0 and borrowernumber = ?
418
    };
415
    };
419
416
420
    my $branchcode  = "";
417
    my $branchcode  = "";
421
    my $branchfield = "reserves.branchcode";
418
    my $branchfield = "holds.pickup_library_id";
422
419
423
    if ( $controlbranch eq "ItemHomeLibrary" ) {
420
    if ( $controlbranch eq "ItemHomeLibrary" ) {
424
        $branchfield = "items.homebranch";
421
        $branchfield = "items.homebranch";
Lines 455-464 sub CanItemBeReserved { Link Here
455
    my $holds_per_day    = $rights->{holds_per_day};
452
    my $holds_per_day    = $rights->{holds_per_day};
456
453
457
    my $search_params = {
454
    my $search_params = {
458
        borrowernumber => $borrowernumber,
455
        patron_id => $borrowernumber,
459
        biblionumber   => $item->biblionumber,
456
        biblio_id => $item->biblionumber,
457
        completed => 0,
460
    };
458
    };
461
    $search_params->{found} = undef if $params->{ignore_found_holds};
459
    $search_params->{status} = 'placed' if $params->{ignore_found_holds};
462
460
463
    my $holds = Koha::Holds->search($search_params);
461
    my $holds = Koha::Holds->search($search_params);
464
    if (   defined $holds_per_record && $holds_per_record ne '' ){
462
    if (   defined $holds_per_record && $holds_per_record ne '' ){
Lines 471-478 sub CanItemBeReserved { Link Here
471
    }
469
    }
472
470
473
    my $today_holds = Koha::Holds->search({
471
    my $today_holds = Koha::Holds->search({
474
        borrowernumber => $borrowernumber,
472
        patron_id    => $borrowernumber,
475
        reservedate    => dt_from_string->date
473
        created_date => dt_from_string->date,
474
        completed    => 0
476
    });
475
    });
477
476
478
    if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne ''
477
    if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne ''
Lines 528-534 sub CanItemBeReserved { Link Here
528
    if (!$params->{ignore_hold_counts} && $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
527
    if (!$params->{ignore_hold_counts} && $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
529
        my $total_holds_count = Koha::Holds->search(
528
        my $total_holds_count = Koha::Holds->search(
530
            {
529
            {
531
                borrowernumber => $borrower->{borrowernumber}
530
                patron_id => $borrower->{borrowernumber},
531
                completed => 0
532
            }
532
            }
533
        )->count();
533
        )->count();
534
534
Lines 606-615 sub CanReserveBeCanceledFromOpac { Link Here
606
    my ($reserve_id, $borrowernumber) = @_;
606
    my ($reserve_id, $borrowernumber) = @_;
607
607
608
    return unless $reserve_id and $borrowernumber;
608
    return unless $reserve_id and $borrowernumber;
609
    my $reserve = Koha::Holds->find($reserve_id) or return;
609
    my $hold = Koha::Holds->find($reserve_id);
610
    return unless $hold;
610
611
611
    return 0 unless $reserve->borrowernumber == $borrowernumber;
612
    return 0 unless $hold->patron_id == $borrowernumber;
612
    return $reserve->is_cancelable_from_opac;
613
    return $hold->is_cancelable_from_opac;
613
}
614
}
614
615
615
=head2 GetOtherReserves
616
=head2 GetOtherReserves
Lines 627-645 sub GetOtherReserves { Link Here
627
    my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber);
628
    my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber);
628
    if ($checkreserves) {
629
    if ($checkreserves) {
629
        my $item = Koha::Items->find($itemnumber);
630
        my $item = Koha::Items->find($itemnumber);
630
        if ( $item->holdingbranch ne $checkreserves->{'branchcode'} ) {
631
        if ( $item->holdingbranch ne $checkreserves->{pickup_library_id} ) {
631
            $messages->{'transfert'} = $checkreserves->{'branchcode'};
632
            $messages->{'transfert'} = $checkreserves->{pickup_library_id};
632
            #minus priorities of others reservs
633
            #minus priorities of others reservs
633
            ModReserveMinusPriority(
634
            ModReserveMinusPriority(
634
                $itemnumber,
635
                $itemnumber,
635
                $checkreserves->{'reserve_id'},
636
                $checkreserves->{id},
636
            );
637
            );
637
638
638
            #launch the subroutine dotransfer
639
            #launch the subroutine dotransfer
639
            C4::Items::ModItemTransfer(
640
            C4::Items::ModItemTransfer(
640
                $itemnumber,
641
                $itemnumber,
641
                $item->holdingbranch,
642
                $item->holdingbranch,
642
                $checkreserves->{'branchcode'},
643
                $checkreserves->{pickup_library_id},
643
                'Reserve'
644
                'Reserve'
644
              ),
645
              ),
645
              ;
646
              ;
Lines 650-658 sub GetOtherReserves { Link Here
650
            $messages->{'waiting'} = 1;
651
            $messages->{'waiting'} = 1;
651
            ModReserveMinusPriority(
652
            ModReserveMinusPriority(
652
                $itemnumber,
653
                $itemnumber,
653
                $checkreserves->{'reserve_id'},
654
                $checkreserves->{id},
654
            );
655
            );
655
            ModReserveStatus($itemnumber,'W');
656
            ModReserveStatus($itemnumber,'waiting');
656
        }
657
        }
657
658
658
        $nextreservinfo = $checkreserves;
659
        $nextreservinfo = $checkreserves;
Lines 743-767 If several reserves exist, the reserve with the lower priority is given. Link Here
743
## multiple reserves for that bib can have the itemnumber set
744
## multiple reserves for that bib can have the itemnumber set
744
## the sub is only used once in the codebase.
745
## the sub is only used once in the codebase.
745
sub GetReserveStatus {
746
sub GetReserveStatus {
746
    my ($itemnumber) = @_;
747
    my ($item_id) = @_;
747
748
748
    my $dbh = C4::Context->dbh;
749
    my $holds_rs = Koha::Holds->search({ item_id => $item_id, completed => 0 }, { order_by => 'priority' });
749
750
750
    my ($sth, $found, $priority);
751
    if ( $holds_rs->count > 0 ) {
751
    if ( $itemnumber ) {
752
        # They are sorted by priority, pick the first one
752
        $sth = $dbh->prepare("SELECT found, priority FROM reserves WHERE itemnumber = ? order by priority LIMIT 1");
753
        my $hold = $holds_rs->next;
753
        $sth->execute($itemnumber);
754
        ($found, $priority) = $sth->fetchrow_array;
755
    }
756
754
757
    if(defined $found) {
755
        return 'Waiting'    if $hold->is_waiting and $hold->priority == 0;
758
        return 'Waiting'  if $found eq 'W' and $priority == 0;
756
        return 'Processing' if $hold->is_in_processing;
759
        return 'Processing'  if $found eq 'P';
757
        return 'Finished'   if $hold->status eq 'fulfilled';
760
        return 'Finished' if $found eq 'F';
758
        return 'Reserved'   if $hold->priority > 0;
761
    }
759
    }
762
760
763
    return 'Reserved' if defined $priority && $priority > 0;
764
765
    return ''; # empty string here will remove need for checking undef, or less log lines
761
    return ''; # empty string here will remove need for checking undef, or less log lines
766
}
762
}
767
763
Lines 800-806 sub CheckReserves { Link Here
800
    my $sth;
796
    my $sth;
801
    my $select;
797
    my $select;
802
    if (C4::Context->preference('item-level_itypes')){
798
    if (C4::Context->preference('item-level_itypes')){
803
	$select = "
799
    $select = "
804
           SELECT items.biblionumber,
800
           SELECT items.biblionumber,
805
           items.biblioitemnumber,
801
           items.biblioitemnumber,
806
           itemtypes.notforloan,
802
           itemtypes.notforloan,
Lines 815-821 sub CheckReserves { Link Here
815
        ";
811
        ";
816
    }
812
    }
817
    else {
813
    else {
818
	$select = "
814
    $select = "
819
           SELECT items.biblionumber,
815
           SELECT items.biblionumber,
820
           items.biblioitemnumber,
816
           items.biblioitemnumber,
821
           itemtypes.notforloan,
817
           itemtypes.notforloan,
Lines 868-878 sub CheckReserves { Link Here
868
864
869
        my $priority = 10000000;
865
        my $priority = 10000000;
870
        foreach my $res (@reserves) {
866
        foreach my $res (@reserves) {
871
            if ($res->{'found'} && $res->{'found'} eq 'W') {
867
            if ($res->{status} eq 'waiting') {
872
                return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
868
                return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
873
            } elsif ($res->{'found'} && $res->{'found'} eq 'P') {
869
            } elsif ($res->{status} eq 'processing') {
874
                return ( "Processing", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
870
                return ( "Processing", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
875
            } elsif ($res->{'found'} && $res->{'found'} eq 'T') {
871
            } elsif ($res->{status} eq 'in_transit') {
876
                return ( "Transferred", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
872
                return ( "Transferred", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
877
            } else {
873
            } else {
878
                my $patron;
874
                my $patron;
Lines 880-886 sub CheckReserves { Link Here
880
                my $local_hold_match;
876
                my $local_hold_match;
881
877
882
                if ($LocalHoldsPriority) {
878
                if ($LocalHoldsPriority) {
883
                    $patron = Koha::Patrons->find( $res->{borrowernumber} );
879
                    $patron = Koha::Patrons->find( $res->{patron_id} );
884
                    $item = Koha::Items->find($itemnumber);
880
                    $item = Koha::Items->find($itemnumber);
885
881
886
                    unless ($item->exclude_from_local_holds_priority || $patron->category->exclude_from_local_holds_priority) {
882
                    unless ($item->exclude_from_local_holds_priority || $patron->category->exclude_from_local_holds_priority) {
Lines 888-894 sub CheckReserves { Link Here
888
                            $item->$LocalHoldsPriorityItemControl;
884
                            $item->$LocalHoldsPriorityItemControl;
889
                        my $local_holds_priority_patron_branchcode =
885
                        my $local_holds_priority_patron_branchcode =
890
                            ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
886
                            ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
891
                            ? $res->{branchcode}
887
                            ? $res->{pickup_library_id}
892
                            : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )
888
                            : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )
893
                            ? $patron->branchcode
889
                            ? $patron->branchcode
894
                            : undef;
890
                            : undef;
Lines 899-908 sub CheckReserves { Link Here
899
                }
895
                }
900
896
901
                # See if this item is more important than what we've got so far
897
                # See if this item is more important than what we've got so far
902
                if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
898
                if ( ( $res->{priority} && $res->{priority} < $priority ) || $local_hold_match ) {
903
                    $item ||= Koha::Items->find($itemnumber);
899
                    $item ||= Koha::Items->find($itemnumber);
904
                    next if $res->{itemtype} && $res->{itemtype} ne $item->effective_itemtype;
900
                    next if $res->{item_type} && $res->{item_type} ne $item->effective_itemtype;
905
                    $patron ||= Koha::Patrons->find( $res->{borrowernumber} );
901
                    $patron ||= Koha::Patrons->find( $res->{patron_id} );
906
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
902
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
907
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
903
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
908
                    next if ($branchitemrule->{'holdallowed'} eq 'not_allowed');
904
                    next if ($branchitemrule->{'holdallowed'} eq 'not_allowed');
Lines 910-919 sub CheckReserves { Link Here
910
                    my $library = Koha::Libraries->find({branchcode=>$item->homebranch});
906
                    my $library = Koha::Libraries->find({branchcode=>$item->homebranch});
911
                    next if (($branchitemrule->{'holdallowed'} eq 'from_local_hold_group') && (!$library->validate_hold_sibling({branchcode => $patron->branchcode}) ));
907
                    next if (($branchitemrule->{'holdallowed'} eq 'from_local_hold_group') && (!$library->validate_hold_sibling({branchcode => $patron->branchcode}) ));
912
                    my $hold_fulfillment_policy = $branchitemrule->{hold_fulfillment_policy};
908
                    my $hold_fulfillment_policy = $branchitemrule->{hold_fulfillment_policy};
913
                    next if ( ($hold_fulfillment_policy eq 'holdgroup') && (!$library->validate_hold_sibling({branchcode => $res->{branchcode}})) );
909
                    next if ( ($hold_fulfillment_policy eq 'holdgroup') && (!$library->validate_hold_sibling({branchcode => $res->{pickup_library_id}})) );
914
                    next if ( ($hold_fulfillment_policy eq 'homebranch') && ($res->{branchcode} ne $item->$hold_fulfillment_policy) );
910
                    next if ( ($hold_fulfillment_policy eq 'homebranch') && ($res->{pickup_library_id} ne $item->$hold_fulfillment_policy) );
915
                    next if ( ($hold_fulfillment_policy eq 'holdingbranch') && ($res->{branchcode} ne $item->$hold_fulfillment_policy) );
911
                    next if ( ($hold_fulfillment_policy eq 'holdingbranch') && ($res->{pickup_library_id} ne $item->$hold_fulfillment_policy) );
916
                    next unless $item->can_be_transferred( { to => Koha::Libraries->find( $res->{branchcode} ) } );
912
                    next unless $item->can_be_transferred( { to => Koha::Libraries->find( $res->{pickup_library_id} ) } );
917
                    $priority = $res->{'priority'};
913
                    $priority = $res->{'priority'};
918
                    $highest  = $res;
914
                    $highest  = $res;
919
                    last if $local_hold_match;
915
                    last if $local_hold_match;
Lines 947-966 sub CancelExpiredReserves { Link Here
947
    my $expireWaiting = C4::Context->preference('ExpireReservesMaxPickUpDelay');
943
    my $expireWaiting = C4::Context->preference('ExpireReservesMaxPickUpDelay');
948
944
949
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
945
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
950
    my $params = { expirationdate => { '<', $dtf->format_date($today) } };
946
    my $params = { expiration_date => { '<', $dtf->format_date($today) } };
951
    $params->{found} = [ { '!=', 'W' }, undef ]  unless $expireWaiting;
947
    $params->{status} = [ { '!=', 'waiting' }, undef ]  unless $expireWaiting;
952
948
953
    # FIXME To move to Koha::Holds->search_expired (?)
949
    # FIXME To move to Koha::Holds->search_expired (?)
954
    my $holds = Koha::Holds->search( $params );
950
    my $holds = Koha::Holds->search( $params );
955
951
956
    while ( my $hold = $holds->next ) {
952
    while ( my $hold = $holds->next ) {
957
        my $calendar = Koha::Calendar->new( branchcode => $hold->branchcode );
953
        my $calendar = Koha::Calendar->new( branchcode => $hold->pickup_library_id );
958
954
959
        next if !$cancel_on_holidays && $calendar->is_holiday( $today );
955
        next if !$cancel_on_holidays && $calendar->is_holiday( $today );
960
956
961
        my $cancel_params = {};
957
        my $cancel_params = {};
962
        $cancel_params->{cancellation_reason} = $cancellation_reason if defined($cancellation_reason);
958
        $cancel_params->{cancellation_reason} = $cancellation_reason if defined($cancellation_reason);
963
        if ( defined($hold->found) && $hold->found eq 'W' ) {
959
        if ( $hold->is_waiting ) {
964
            $cancel_params->{charge_cancel_fee} = 1;
960
            $cancel_params->{charge_cancel_fee} = 1;
965
        }
961
        }
966
        $hold->cancel( $cancel_params );
962
        $hold->cancel( $cancel_params );
Lines 971-984 sub CancelExpiredReserves { Link Here
971
967
972
  AutoUnsuspendReserves();
968
  AutoUnsuspendReserves();
973
969
974
Unsuspends all suspended reserves with a suspend_until date from before today.
970
Unsuspends all suspended reserves with a suspended_until date from before today.
975
971
976
=cut
972
=cut
977
973
978
sub AutoUnsuspendReserves {
974
sub AutoUnsuspendReserves {
979
    my $today = dt_from_string();
975
    my $today = dt_from_string();
980
976
981
    my @holds = Koha::Holds->search( { suspend_until => { '<=' => $today->ymd() } } );
977
    my @holds = Koha::Holds->search( { suspended_until_date => { '<=' => $today->ymd() } } );
982
978
983
    map { $_->resume() } @holds;
979
    map { $_->resume() } @holds;
984
}
980
}
Lines 1038-1047 sub ModReserve { Link Here
1038
1034
1039
    my $hold;
1035
    my $hold;
1040
    unless ( $reserve_id ) {
1036
    unless ( $reserve_id ) {
1041
        my $holds = Koha::Holds->search({ biblionumber => $biblionumber, borrowernumber => $borrowernumber, itemnumber => $itemnumber });
1037
        my $holds = Koha::Holds->search({ biblio_id => $biblionumber, patron_id => $borrowernumber, item_id => $itemnumber });
1042
        return unless $holds->count; # FIXME Should raise an exception
1038
        return unless $holds->count; # FIXME Should raise an exception
1043
        $hold = $holds->next;
1039
        $hold = $holds->next;
1044
        $reserve_id = $hold->reserve_id;
1040
        $reserve_id = $hold->id;
1045
    }
1041
    }
1046
1042
1047
    $hold ||= Koha::Holds->find($reserve_id);
1043
    $hold ||= Koha::Holds->find($reserve_id);
Lines 1050-1070 sub ModReserve { Link Here
1050
        $hold->cancel({ cancellation_reason => $cancellation_reason });
1046
        $hold->cancel({ cancellation_reason => $cancellation_reason });
1051
    }
1047
    }
1052
    elsif ($rank =~ /^\d+/ and $rank > 0) {
1048
    elsif ($rank =~ /^\d+/ and $rank > 0) {
1053
        logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
1049
        logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->unblessed) )
1054
            if C4::Context->preference('HoldsLog');
1050
            if C4::Context->preference('HoldsLog');
1055
1051
1056
        my $properties = {
1052
        my $properties = {
1057
            priority    => $rank,
1053
            priority     => $rank,
1058
            branchcode  => $branchcode,
1054
            pickup_library_id => $branchcode,
1059
            itemnumber  => $itemnumber,
1055
            item_id      => $itemnumber,
1060
            found       => undef,
1056
            status       => 'placed',
1061
            waitingdate => undef
1057
            waiting_date => undef
1062
        };
1058
        };
1063
        if (exists $params->{reservedate}) {
1059
        if (exists $params->{reservedate}) {
1064
            $properties->{reservedate} = $params->{reservedate} || undef;
1060
            $properties->{created_date} = $params->{reservedate} || undef;
1065
        }
1061
        }
1066
        if (exists $params->{expirationdate}) {
1062
        if (exists $params->{expirationdate}) {
1067
            $properties->{expirationdate} = $params->{expirationdate} || undef;
1063
            $properties->{expiration_date} = $params->{expirationdate} || undef;
1068
        }
1064
        }
1069
1065
1070
        $hold->set($properties)->store();
1066
        $hold->set($properties)->store();
Lines 1076-1082 sub ModReserve { Link Here
1076
            } else {
1072
            } else {
1077
                # If the hold is suspended leave the hold suspended, but convert it to an indefinite hold.
1073
                # If the hold is suspended leave the hold suspended, but convert it to an indefinite hold.
1078
                # If the hold is not suspended, this does nothing.
1074
                # If the hold is not suspended, this does nothing.
1079
                $hold->set( { suspend_until => undef } )->store();
1075
                $hold->set( { suspended_until_date => undef } )->store();
1080
            }
1076
            }
1081
        }
1077
        }
1082
1078
Lines 1098-1134 whose keys are fields from the reserves table in the Koha database. Link Here
1098
1094
1099
sub ModReserveFill {
1095
sub ModReserveFill {
1100
    my ($res) = @_;
1096
    my ($res) = @_;
1101
    my $reserve_id = $res->{'reserve_id'};
1097
    my $reserve_id = $res->{'id'};
1102
1098
1103
    my $hold = Koha::Holds->find($reserve_id);
1099
    my $hold = Koha::Holds->find($reserve_id);
1104
    # get the priority on this record....
1100
    # get the priority on this record....
1105
    my $priority = $hold->priority;
1101
    my $priority = $hold->priority;
1106
1102
1107
    # update the hold statuses, no need to store it though, we will be deleting it anyway
1103
    # update the hold statuses, no need to store it though, we will be deleting it anyway
1104
    # FIXME: Add Koha::Hold->set_filled and add the correct log
1108
    $hold->set(
1105
    $hold->set(
1109
        {
1106
        {
1110
            found    => 'F',
1107
            status    => 'fulfilled',
1111
            priority => 0,
1108
            priority  => 0,
1109
            completed => 1,
1110
            completed_date => \'NOW()'
1112
        }
1111
        }
1113
    );
1112
    );
1114
1113
1115
    logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
1114
    logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->unblessed) )
1116
        if C4::Context->preference('HoldsLog');
1115
        if C4::Context->preference('HoldsLog');
1117
1116
1118
    # FIXME Must call Koha::Hold->cancel ? => No, should call ->filled and add the correct log
1117
    $hold->store();
1119
    Koha::Old::Hold->new( $hold->unblessed() )->store();
1120
1121
    $hold->delete();
1122
1118
1123
    if ( C4::Context->preference('HoldFeeMode') eq 'any_time_is_collected' ) {
1119
    if ( C4::Context->preference('HoldFeeMode') eq 'any_time_is_collected' ) {
1124
        my $reserve_fee = GetReserveFee( $hold->borrowernumber, $hold->biblionumber );
1120
        my $reserve_fee = GetReserveFee( $hold->patron_id, $hold->biblio_id );
1125
        ChargeReserveFee( $hold->borrowernumber, $reserve_fee, $hold->biblio->title );
1121
        ChargeReserveFee( $hold->patron_id, $reserve_fee, $hold->biblio->title );
1126
    }
1122
    }
1127
1123
1128
    # now fix the priority on the others (if the priority wasn't
1124
    # now fix the priority on the others (if the priority wasn't
1129
    # already sorted!)....
1125
    # already sorted!)....
1130
    unless ( $priority == 0 ) {
1126
    unless ( $priority == 0 ) {
1131
        _FixPriority( { reserve_id => $reserve_id, biblionumber => $hold->biblionumber } );
1127
        _FixPriority( { reserve_id => $reserve_id, biblionumber => $hold->biblio_id } );
1132
    }
1128
    }
1133
}
1129
}
1134
1130
Lines 1150-1156 sub ModReserveStatus { Link Here
1150
    my ($itemnumber, $newstatus) = @_;
1146
    my ($itemnumber, $newstatus) = @_;
1151
    my $dbh = C4::Context->dbh;
1147
    my $dbh = C4::Context->dbh;
1152
1148
1153
    my $query = "UPDATE reserves SET found = ?, waitingdate = NOW() WHERE itemnumber = ? AND found IS NULL AND priority = 0";
1149
    my $query = "UPDATE holds SET status = ?, waiting_date = NOW() WHERE item_id = ? AND status='placed' AND priority = 0";
1154
    my $sth_set = $dbh->prepare($query);
1150
    my $sth_set = $dbh->prepare($query);
1155
    $sth_set->execute( $newstatus, $itemnumber );
1151
    $sth_set->execute( $newstatus, $itemnumber );
1156
1152
Lines 1196-1210 sub ModReserveAffect { Link Here
1196
    # Find hold by id if we have it
1192
    # Find hold by id if we have it
1197
    $hold = Koha::Holds->find( $reserve_id ) if $reserve_id;
1193
    $hold = Koha::Holds->find( $reserve_id ) if $reserve_id;
1198
    # Find item level hold for this item if there is one
1194
    # Find item level hold for this item if there is one
1199
    $hold ||= Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->next();
1195
    $hold ||= Koha::Holds->search( { patron_id => $borrowernumber, item_id => $itemnumber } )->next();
1200
    # Find record level hold if there is no item level hold
1196
    # Find record level hold if there is no item level hold
1201
    $hold ||= Koha::Holds->search( { borrowernumber => $borrowernumber, biblionumber => $biblionumber } )->next();
1197
    $hold ||= Koha::Holds->search( { patron_id => $borrowernumber, biblio_id => $biblionumber } )->next();
1202
1198
1203
    return unless $hold;
1199
    return unless $hold;
1204
1200
1205
    my $already_on_shelf = $hold->found && $hold->found eq 'W';
1201
    my $already_on_shelf = $hold->status eq 'waiting';
1206
1202
1207
    $hold->itemnumber($itemnumber);
1203
    $hold->item_id($itemnumber);
1208
1204
1209
    if ($transferToDo) {
1205
    if ($transferToDo) {
1210
        $hold->set_transfer();
1206
        $hold->set_transfer();
Lines 1214-1220 sub ModReserveAffect { Link Here
1214
        $hold->set_processing();
1210
        $hold->set_processing();
1215
    } else {
1211
    } else {
1216
        $hold->set_waiting($desk_id);
1212
        $hold->set_waiting($desk_id);
1217
        _koha_notify_reserve( $hold->reserve_id ) unless $already_on_shelf;
1213
        _koha_notify_reserve( $hold->id ) unless $already_on_shelf;
1218
        # Complete transfer if one exists
1214
        # Complete transfer if one exists
1219
        my $transfer = $hold->item->get_transfer;
1215
        my $transfer = $hold->item->get_transfer;
1220
        $transfer->receive if $transfer;
1216
        $transfer->receive if $transfer;
Lines 1238-1246 sub ModReserveAffect { Link Here
1238
            AND q.holdingbranch = t.source_branchcode
1234
            AND q.holdingbranch = t.source_branchcode
1239
        WHERE t.reserve_id = ?
1235
        WHERE t.reserve_id = ?
1240
    });
1236
    });
1241
    $std->execute($hold->reserve_id);
1237
    $std->execute($hold->id);
1242
1238
1243
    logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->get_from_storage->unblessed) )
1239
    logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->get_from_storage->unblessed) )
1244
        if C4::Context->preference('HoldsLog');
1240
        if C4::Context->preference('HoldsLog');
1245
1241
1246
    return;
1242
    return;
Lines 1257-1271 function to cancel reserv,check other reserves, and transfer document if it's ne Link Here
1257
sub ModReserveCancelAll {
1253
sub ModReserveCancelAll {
1258
    my $messages;
1254
    my $messages;
1259
    my $nextreservinfo;
1255
    my $nextreservinfo;
1260
    my ( $itemnumber, $borrowernumber, $cancellation_reason ) = @_;
1256
    my ( $item_id, $patron_id, $cancellation_reason ) = @_;
1261
1257
1262
    #step 1 : cancel the reservation
1258
    #step 1 : cancel the reservation
1263
    my $holds = Koha::Holds->search({ itemnumber => $itemnumber, borrowernumber => $borrowernumber });
1259
    my $holds = Koha::Holds->search({ item_id => $item_id, patron_id => $patron_id });
1264
    return unless $holds->count;
1260
    return unless $holds->count;
1265
    $holds->next->cancel({ cancellation_reason => $cancellation_reason });
1261
    $holds->next->cancel({ cancellation_reason => $cancellation_reason });
1266
1262
1267
    #step 2 launch the subroutine of the others reserves
1263
    #step 2 launch the subroutine of the others reserves
1268
    ( $messages, $nextreservinfo ) = GetOtherReserves($itemnumber);
1264
    ( $messages, $nextreservinfo ) = GetOtherReserves($item_id);
1269
1265
1270
    return ( $messages, $nextreservinfo->{borrowernumber} );
1266
    return ( $messages, $nextreservinfo->{borrowernumber} );
1271
}
1267
}
Lines 1279-1295 Reduce the values of queued list Link Here
1279
=cut
1275
=cut
1280
1276
1281
sub ModReserveMinusPriority {
1277
sub ModReserveMinusPriority {
1282
    my ( $itemnumber, $reserve_id ) = @_;
1278
    my ( $item_id, $reserve_id ) = @_;
1283
1279
1284
    #first step update the value of the first person on reserv
1280
    #first step update the value of the first person on reserv
1285
    my $dbh   = C4::Context->dbh;
1281
    my $dbh   = C4::Context->dbh;
1286
    my $query = "
1282
    my $query = "
1287
        UPDATE reserves
1283
        UPDATE holds
1288
        SET    priority = 0 , itemnumber = ?
1284
        SET    priority = 0 , item_id = ?
1289
        WHERE  reserve_id = ?
1285
        WHERE  id = ?
1290
    ";
1286
    ";
1291
    my $sth_upd = $dbh->prepare($query);
1287
    my $sth_upd = $dbh->prepare($query);
1292
    $sth_upd->execute( $itemnumber, $reserve_id );
1288
    $sth_upd->execute( $item_id, $reserve_id );
1293
    # second step update all others reserves
1289
    # second step update all others reserves
1294
    _FixPriority({ reserve_id => $reserve_id, rank => '0' });
1290
    _FixPriority({ reserve_id => $reserve_id, rank => '0' });
1295
}
1291
}
Lines 1433-1440 sub AlterPriority { Link Here
1433
    my $hold = Koha::Holds->find( $reserve_id );
1429
    my $hold = Koha::Holds->find( $reserve_id );
1434
    return unless $hold;
1430
    return unless $hold;
1435
1431
1436
    if ( $hold->cancellationdate ) {
1432
    if ( $hold->completed_date and $hold->status eq 'cancelled' ) {
1437
        warn "I cannot alter the priority for reserve_id $reserve_id, the reserve has been cancelled (" . $hold->cancellationdate . ')';
1433
        warn "I cannot alter the priority for reserve_id $reserve_id, the reserve has been cancelled (" . $hold->completed_date . ')';
1438
        return;
1434
        return;
1439
    }
1435
    }
1440
1436
Lines 1466-1472 sub ToggleLowestPriority { Link Here
1466
1462
1467
    my $dbh = C4::Context->dbh;
1463
    my $dbh = C4::Context->dbh;
1468
1464
1469
    my $sth = $dbh->prepare( "UPDATE reserves SET lowestPriority = NOT lowestPriority WHERE reserve_id = ?");
1465
    my $sth = $dbh->prepare( "UPDATE holds SET lowest_priority = NOT lowest_priority WHERE id = ?");
1470
    $sth->execute( $reserve_id );
1466
    $sth->execute( $reserve_id );
1471
1467
1472
    _FixPriority({ reserve_id => $reserve_id, rank => '999999' });
1468
    _FixPriority({ reserve_id => $reserve_id, rank => '999999' });
Lines 1526-1534 sub SuspendAll { Link Here
1526
    return unless ( $borrowernumber || $biblionumber );
1522
    return unless ( $borrowernumber || $biblionumber );
1527
1523
1528
    my $params;
1524
    my $params;
1529
    $params->{found}          = undef;
1525
    $params->{status} = 'placed';
1530
    $params->{borrowernumber} = $borrowernumber if $borrowernumber;
1526
    $params->{patron_id} = $borrowernumber if $borrowernumber;
1531
    $params->{biblionumber}   = $biblionumber if $biblionumber;
1527
    $params->{biblio_id} = $biblionumber if $biblionumber;
1532
1528
1533
    my @holds = Koha::Holds->search($params);
1529
    my @holds = Koha::Holds->search($params);
1534
1530
Lines 1588-1602 sub _FixPriority { Link Here
1588
    my $hold;
1584
    my $hold;
1589
    if ( $reserve_id ) {
1585
    if ( $reserve_id ) {
1590
        $hold = Koha::Holds->find( $reserve_id );
1586
        $hold = Koha::Holds->find( $reserve_id );
1591
        if (!defined $hold){
1592
            # may have already been checked out and hold fulfilled
1593
            $hold = Koha::Old::Holds->find( $reserve_id );
1594
        }
1595
        return unless $hold;
1587
        return unless $hold;
1596
    }
1588
    }
1597
1589
1598
    unless ( $biblionumber ) { # FIXME This is a very weird API
1590
    unless ( $biblionumber ) { # FIXME This is a very weird API
1599
        $biblionumber = $hold->biblionumber;
1591
        $biblionumber = $hold->biblio_id;
1600
    }
1592
    }
1601
1593
1602
    if ( $rank eq "del" ) { # FIXME will crash if called without $hold
1594
    if ( $rank eq "del" ) { # FIXME will crash if called without $hold
Lines 1606-1615 sub _FixPriority { Link Here
1606
1598
1607
        # make sure priority for waiting or in-transit items is 0
1599
        # make sure priority for waiting or in-transit items is 0
1608
        my $query = "
1600
        my $query = "
1609
            UPDATE reserves
1601
            UPDATE holds
1610
            SET    priority = 0
1602
            SET    priority = 0
1611
            WHERE reserve_id = ?
1603
            WHERE  id = ?
1612
            AND found IN ('W', 'T', 'P')
1604
            AND status IN ('waiting', 'in_transit', 'processing')
1613
        ";
1605
        ";
1614
        my $sth = $dbh->prepare($query);
1606
        my $sth = $dbh->prepare($query);
1615
        $sth->execute( $reserve_id );
1607
        $sth->execute( $reserve_id );
Lines 1618-1627 sub _FixPriority { Link Here
1618
1610
1619
    # get whats left
1611
    # get whats left
1620
    my $query = "
1612
    my $query = "
1621
        SELECT reserve_id, borrowernumber, reservedate
1613
        SELECT id
1622
        FROM   reserves
1614
        FROM   holds
1623
        WHERE  biblionumber   = ?
1615
        WHERE  biblio_id   = ?
1624
          AND  ((found <> 'W' AND found <> 'T' AND found <> 'P') OR found IS NULL)
1616
          AND  completed = 0
1617
          AND  status = 'placed'
1625
        ORDER BY priority ASC
1618
        ORDER BY priority ASC
1626
    ";
1619
    ";
1627
    my $sth = $dbh->prepare($query);
1620
    my $sth = $dbh->prepare($query);
Lines 1635-1641 sub _FixPriority { Link Here
1635
    my $i;
1628
    my $i;
1636
    my $key = -1;    # to allow for 0 to be a valid result
1629
    my $key = -1;    # to allow for 0 to be a valid result
1637
    for ( $i = 0 ; $i < @priority ; $i++ ) {
1630
    for ( $i = 0 ; $i < @priority ; $i++ ) {
1638
        if ( $reserve_id && $reserve_id == $priority[$i]->{'reserve_id'} ) {
1631
        if ( $reserve_id && $reserve_id == $priority[$i]->{'id'} ) {
1639
            $key = $i;    # save the index
1632
            $key = $i;    # save the index
1640
            last;
1633
            last;
1641
        }
1634
        }
Lines 1651-1675 sub _FixPriority { Link Here
1651
1644
1652
    # now fix the priority on those that are left....
1645
    # now fix the priority on those that are left....
1653
    $query = "
1646
    $query = "
1654
        UPDATE reserves
1647
        UPDATE holds
1655
        SET    priority = ?
1648
        SET    priority = ?
1656
        WHERE  reserve_id = ?
1649
        WHERE  id = ?
1657
    ";
1650
    ";
1658
    $sth = $dbh->prepare($query);
1651
    $sth = $dbh->prepare($query);
1659
    for ( my $j = 0 ; $j < @priority ; $j++ ) {
1652
    for ( my $j = 0 ; $j < @priority ; $j++ ) {
1660
        $sth->execute(
1653
        $sth->execute(
1661
            $j + 1,
1654
            $j + 1,
1662
            $priority[$j]->{'reserve_id'}
1655
            $priority[$j]->{'id'}
1663
        );
1656
        );
1664
    }
1657
    }
1665
1658
1666
    $sth = $dbh->prepare( "SELECT reserve_id FROM reserves WHERE lowestPriority = 1 ORDER BY priority" );
1659
    $sth = $dbh->prepare( "SELECT id FROM holds WHERE lowest_priority = 1 ORDER BY priority" );
1667
    $sth->execute();
1660
    $sth->execute();
1668
1661
1669
    unless ( $ignoreSetLowestRank ) {
1662
    unless ( $ignoreSetLowestRank ) {
1670
      while ( my $res = $sth->fetchrow_hashref() ) {
1663
      while ( my $res = $sth->fetchrow_hashref() ) {
1671
        _FixPriority({
1664
        _FixPriority({
1672
            reserve_id => $res->{'reserve_id'},
1665
            reserve_id => $res->{'id'},
1673
            rank => '999999',
1666
            rank => '999999',
1674
            ignoreSetLowestRank => 1
1667
            ignoreSetLowestRank => 1
1675
        });
1668
        });
Lines 1706-1734 sub _Findgroupreserve { Link Here
1706
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1699
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1707
    # check for exact targeted match
1700
    # check for exact targeted match
1708
    my $item_level_target_query = qq{
1701
    my $item_level_target_query = qq{
1709
        SELECT reserves.biblionumber        AS biblionumber,
1702
        SELECT holds.biblio_id         AS biblio_id,
1710
               reserves.borrowernumber      AS borrowernumber,
1703
               holds.patron_id         AS patron_id,
1711
               reserves.reservedate         AS reservedate,
1704
               holds.created_date      AS created_date,
1712
               reserves.branchcode          AS branchcode,
1705
               holds.pickup_library_id AS pickup_library_id,
1713
               reserves.cancellationdate    AS cancellationdate,
1706
               holds.completed_date   AS completed_date,
1714
               reserves.found               AS found,
1707
               holds.status            AS status,
1715
               reserves.reservenotes        AS reservenotes,
1708
               holds.notes             AS notes,
1716
               reserves.priority            AS priority,
1709
               holds.priority          AS priority,
1717
               reserves.timestamp           AS timestamp,
1710
               holds.timestamp         AS timestamp,
1718
               biblioitems.biblioitemnumber AS biblioitemnumber,
1711
               biblioitems.biblioitemnumber AS biblioitemnumber,
1719
               reserves.itemnumber          AS itemnumber,
1712
               holds.item_id           AS item_id,
1720
               reserves.reserve_id          AS reserve_id,
1713
               holds.id                AS id,
1721
               reserves.itemtype            AS itemtype,
1714
               holds.item_type         AS item_type,
1722
               reserves.non_priority        AS non_priority
1715
               holds.non_priority      AS non_priority
1723
        FROM reserves
1716
        FROM holds
1724
        JOIN biblioitems USING (biblionumber)
1717
        JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
1725
        JOIN hold_fill_targets USING (reserve_id)
1718
        JOIN hold_fill_targets ON (holds.id=hold_fill_targets.reserve_id)
1726
        WHERE found IS NULL
1719
        WHERE status='placed'
1727
        AND priority > 0
1720
        AND priority > 0
1728
        AND item_level_request = 1
1721
        AND completed = 0
1729
        AND hold_fill_targets.itemnumber = ?
1722
        AND item_level = 1
1730
        AND reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1723
        AND item_id = ?
1731
        AND suspend = 0
1724
        AND created_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1725
        AND suspended = 0
1732
        ORDER BY priority
1726
        ORDER BY priority
1733
    };
1727
    };
1734
    my $sth = $dbh->prepare($item_level_target_query);
1728
    my $sth = $dbh->prepare($item_level_target_query);
Lines 1736-1770 sub _Findgroupreserve { Link Here
1736
    my @results;
1730
    my @results;
1737
    if ( my $data = $sth->fetchrow_hashref ) {
1731
    if ( my $data = $sth->fetchrow_hashref ) {
1738
        push( @results, $data )
1732
        push( @results, $data )
1739
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1733
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1740
    }
1734
    }
1741
    return @results if @results;
1735
    return @results if @results;
1742
1736
1743
    # check for title-level targeted match
1737
    # check for title-level targeted match
1744
    my $title_level_target_query = qq{
1738
    my $title_level_target_query = qq{
1745
        SELECT reserves.biblionumber        AS biblionumber,
1739
        SELECT holds.biblio_id         AS biblio_id,
1746
               reserves.borrowernumber      AS borrowernumber,
1740
               holds.patron_id         AS patron_id,
1747
               reserves.reservedate         AS reservedate,
1741
               holds.created_date      AS created_date,
1748
               reserves.branchcode          AS branchcode,
1742
               holds.pickup_library_id AS pickup_library_id,
1749
               reserves.cancellationdate    AS cancellationdate,
1743
               holds.completed_date   AS completed_date,
1750
               reserves.found               AS found,
1744
               holds.status            AS status,
1751
               reserves.reservenotes        AS reservenotes,
1745
               holds.notes             AS notes,
1752
               reserves.priority            AS priority,
1746
               holds.priority          AS priority,
1753
               reserves.timestamp           AS timestamp,
1747
               holds.timestamp         AS timestamp,
1754
               biblioitems.biblioitemnumber AS biblioitemnumber,
1748
               biblioitems.biblioitemnumber AS biblioitemnumber,
1755
               reserves.itemnumber          AS itemnumber,
1749
               holds.item_id           AS item_id,
1756
               reserves.reserve_id          AS reserve_id,
1750
               holds.id                AS id,
1757
               reserves.itemtype            AS itemtype,
1751
               holds.item_type         AS item_type,
1758
               reserves.non_priority        AS non_priority
1752
               holds.non_priority      AS non_priority
1759
        FROM reserves
1753
        FROM holds
1760
        JOIN biblioitems USING (biblionumber)
1754
        JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
1761
        JOIN hold_fill_targets USING (reserve_id)
1755
        JOIN hold_fill_targets ON (holds.id=hold_fill_targets.reserve_id)
1762
        WHERE found IS NULL
1756
        WHERE status='placed'
1763
        AND priority > 0
1757
        AND priority > 0
1764
        AND item_level_request = 0
1758
        AND completed = 0
1759
        AND item_level = 0
1765
        AND hold_fill_targets.itemnumber = ?
1760
        AND hold_fill_targets.itemnumber = ?
1766
        AND reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1761
        AND created_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1767
        AND suspend = 0
1762
        AND suspended = 0
1768
        ORDER BY priority
1763
        ORDER BY priority
1769
    };
1764
    };
1770
    $sth = $dbh->prepare($title_level_target_query);
1765
    $sth = $dbh->prepare($title_level_target_query);
Lines 1772-1801 sub _Findgroupreserve { Link Here
1772
    @results = ();
1767
    @results = ();
1773
    if ( my $data = $sth->fetchrow_hashref ) {
1768
    if ( my $data = $sth->fetchrow_hashref ) {
1774
        push( @results, $data )
1769
        push( @results, $data )
1775
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1770
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1776
    }
1771
    }
1777
    return @results if @results;
1772
    return @results if @results;
1778
1773
1779
    my $query = qq{
1774
    my $query = qq{
1780
        SELECT reserves.biblionumber               AS biblionumber,
1775
        SELECT holds.biblio_id                  AS biblio_id,
1781
               reserves.borrowernumber             AS borrowernumber,
1776
               holds.patron_id                  AS patron_id,
1782
               reserves.reservedate                AS reservedate,
1777
               holds.created_date               AS created_date,
1783
               reserves.waitingdate                AS waitingdate,
1778
               holds.waiting_date               AS waiting_date,
1784
               reserves.branchcode                 AS branchcode,
1779
               holds.pickup_library_id          AS pickup_library_id,
1785
               reserves.cancellationdate           AS cancellationdate,
1780
               holds.completed_date             AS completed_date,
1786
               reserves.found                      AS found,
1781
               holds.status                     AS status,
1787
               reserves.reservenotes               AS reservenotes,
1782
               holds.notes                      AS notes,
1788
               reserves.priority                   AS priority,
1783
               holds.priority                   AS priority,
1789
               reserves.timestamp                  AS timestamp,
1784
               holds.timestamp                  AS timestamp,
1790
               reserves.itemnumber                 AS itemnumber,
1785
               holds.item_id                    AS item_id,
1791
               reserves.reserve_id                 AS reserve_id,
1786
               holds.id                         AS id,
1792
               reserves.itemtype                   AS itemtype,
1787
               holds.item_type                  AS item_type,
1793
               reserves.non_priority        AS non_priority
1788
               holds.non_priority               AS non_priority
1794
        FROM reserves
1789
        FROM holds
1795
        WHERE reserves.biblionumber = ?
1790
        WHERE holds.biblio_id = ?
1796
          AND (reserves.itemnumber IS NULL OR reserves.itemnumber = ?)
1791
          AND (holds.item_id IS NULL OR holds.item_id = ?)
1797
          AND reserves.reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1792
          AND holds.created_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1798
          AND suspend = 0
1793
          AND suspended = 0
1794
          AND completed = 0
1799
          ORDER BY priority
1795
          ORDER BY priority
1800
    };
1796
    };
1801
    $sth = $dbh->prepare($query);
1797
    $sth = $dbh->prepare($query);
Lines 1803-1809 sub _Findgroupreserve { Link Here
1803
    @results = ();
1799
    @results = ();
1804
    while ( my $data = $sth->fetchrow_hashref ) {
1800
    while ( my $data = $sth->fetchrow_hashref ) {
1805
        push( @results, $data )
1801
        push( @results, $data )
1806
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1802
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1807
    }
1803
    }
1808
    return @results;
1804
    return @results;
1809
}
1805
}
Lines 1839-1845 The following tables are availalbe witin the notice: Link Here
1839
sub _koha_notify_reserve {
1835
sub _koha_notify_reserve {
1840
    my $reserve_id = shift;
1836
    my $reserve_id = shift;
1841
    my $hold = Koha::Holds->find($reserve_id);
1837
    my $hold = Koha::Holds->find($reserve_id);
1842
    my $borrowernumber = $hold->borrowernumber;
1838
    my $borrowernumber = $hold->patron_id;
1843
1839
1844
    my $patron = Koha::Patrons->find( $borrowernumber );
1840
    my $patron = Koha::Patrons->find( $borrowernumber );
1845
1841
Lines 1851-1871 sub _koha_notify_reserve { Link Here
1851
            message_name => 'Hold_Filled'
1847
            message_name => 'Hold_Filled'
1852
    } );
1848
    } );
1853
1849
1854
    my $library = Koha::Libraries->find( $hold->branchcode );
1850
    my $library = Koha::Libraries->find( $hold->pickup_library_id );
1855
    my $admin_email_address = $library->from_email_address;
1851
    my $admin_email_address = $library->from_email_address;
1856
    $library = $library->unblessed;
1852
    $library = $library->unblessed;
1857
1853
1858
    my %letter_params = (
1854
    my %letter_params = (
1859
        module => 'reserves',
1855
        module => 'reserves',
1860
        branchcode => $hold->branchcode,
1856
        branchcode => $hold->pickup_library_id,
1861
        lang => $patron->lang,
1857
        lang => $patron->lang,
1862
        tables => {
1858
        tables => {
1863
            'branches'       => $library,
1859
            'branches'       => $library,
1864
            'borrowers'      => $patron->unblessed,
1860
            'borrowers'      => $patron->unblessed,
1865
            'biblio'         => $hold->biblionumber,
1861
            'biblio'         => $hold->biblio_id,
1866
            'biblioitems'    => $hold->biblionumber,
1862
            'biblioitems'    => $hold->biblio_id,
1867
            'reserves'       => $hold->unblessed,
1863
            'holds'          => $hold->unblessed,
1868
            'items'          => $hold->itemnumber,
1864
            'items'          => $hold->item_id,
1869
        },
1865
        },
1870
    );
1866
    );
1871
1867
Lines 1929-1935 sub _ShiftPriorityByDateAndPriority { Link Here
1929
    my ( $biblio, $resdate, $new_priority ) = @_;
1925
    my ( $biblio, $resdate, $new_priority ) = @_;
1930
1926
1931
    my $dbh = C4::Context->dbh;
1927
    my $dbh = C4::Context->dbh;
1932
    my $query = "SELECT priority FROM reserves WHERE biblionumber = ? AND ( reservedate > ? OR priority > ? ) ORDER BY priority ASC LIMIT 1";
1928
    my $query = "SELECT priority FROM holds WHERE biblio_id = ? AND ( created_date > ? OR priority > ? ) AND completed = 0 ORDER BY priority ASC LIMIT 1";
1933
    my $sth = $dbh->prepare( $query );
1929
    my $sth = $dbh->prepare( $query );
1934
    $sth->execute( $biblio, $resdate, $new_priority );
1930
    $sth->execute( $biblio, $resdate, $new_priority );
1935
    my $min_priority = $sth->fetchrow;
1931
    my $min_priority = $sth->fetchrow;
Lines 1937-1956 sub _ShiftPriorityByDateAndPriority { Link Here
1937
    $new_priority = $min_priority if ( $min_priority );
1933
    $new_priority = $min_priority if ( $min_priority );
1938
1934
1939
    # Shift the priority up by one; works in conjunction with the next SQL statement
1935
    # Shift the priority up by one; works in conjunction with the next SQL statement
1940
    $query = "UPDATE reserves
1936
    $query = "UPDATE holds
1941
              SET priority = priority+1
1937
              SET priority = priority+1
1942
              WHERE biblionumber = ?
1938
              WHERE biblio_id = ?
1943
              AND borrowernumber = ?
1939
              AND patron_id = ?
1944
              AND reservedate = ?
1940
              AND created_date = ?
1945
              AND found IS NULL";
1941
              AND status = 'placed'";
1946
    my $sth_update = $dbh->prepare( $query );
1942
    my $sth_update = $dbh->prepare( $query );
1947
1943
1948
    # Select all reserves for the biblio with priority greater than $new_priority, and order greatest to least
1944
    # Select all reserves for the biblio with priority greater than $new_priority, and order greatest to least
1949
    $query = "SELECT borrowernumber, reservedate FROM reserves WHERE priority >= ? AND biblionumber = ? ORDER BY priority DESC";
1945
    $query = "SELECT patron_id, created_date FROM holds WHERE priority >= ? AND biblio_id = ? ORDER BY priority DESC";
1950
    $sth = $dbh->prepare( $query );
1946
    $sth = $dbh->prepare( $query );
1951
    $sth->execute( $new_priority, $biblio );
1947
    $sth->execute( $new_priority, $biblio );
1952
    while ( my $row = $sth->fetchrow_hashref ) {
1948
    while ( my $row = $sth->fetchrow_hashref ) {
1953
	$sth_update->execute( $biblio, $row->{borrowernumber}, $row->{reservedate} );
1949
    $sth_update->execute( $biblio, $row->{patron_id}, $row->{created_date} );
1954
    }
1950
    }
1955
1951
1956
    return $new_priority;  # so the caller knows what priority they wind up receiving
1952
    return $new_priority;  # so the caller knows what priority they wind up receiving
Lines 1974-1982 sub MoveReserve { Link Here
1974
    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
1970
    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
1975
    return unless $res;
1971
    return unless $res;
1976
1972
1977
    my $biblionumber     =  $res->{biblionumber};
1973
    my $biblionumber = $res->{biblio_id};
1978
1974
1979
    if ($res->{borrowernumber} == $borrowernumber) {
1975
    if ($res->{patron_id} == $borrowernumber) {
1980
        ModReserveFill($res);
1976
        ModReserveFill($res);
1981
    }
1977
    }
1982
    else {
1978
    else {
Lines 1985-1992 sub MoveReserve { Link Here
1985
        # Find this item in the reserves
1981
        # Find this item in the reserves
1986
1982
1987
        my $borr_res  = Koha::Holds->search({
1983
        my $borr_res  = Koha::Holds->search({
1988
            borrowernumber => $borrowernumber,
1984
            patron_id => $borrowernumber,
1989
            biblionumber   => $biblionumber,
1985
            biblio_id => $biblionumber,
1990
        },{
1986
        },{
1991
            order_by       => 'priority'
1987
            order_by       => 'priority'
1992
        })->next();
1988
        })->next();
Lines 2000-2006 sub MoveReserve { Link Here
2000
            RevertWaitingStatus({ itemnumber => $itemnumber });
1996
            RevertWaitingStatus({ itemnumber => $itemnumber });
2001
        }
1997
        }
2002
        elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item
1998
        elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item
2003
            my $hold = Koha::Holds->find( $res->{reserve_id} );
1999
            my $hold = Koha::Holds->find( $res->{id} );
2004
            $hold->cancel;
2000
            $hold->cancel;
2005
        }
2001
        }
2006
    }
2002
    }
Lines 2017-2049 This shifts the holds from C<$from_biblio> to C<$to_biblio> and reorders them by Link Here
2017
sub MergeHolds {
2013
sub MergeHolds {
2018
    my ( $dbh, $to_biblio, $from_biblio ) = @_;
2014
    my ( $dbh, $to_biblio, $from_biblio ) = @_;
2019
    my $sth = $dbh->prepare(
2015
    my $sth = $dbh->prepare(
2020
        "SELECT count(*) as reserve_count FROM reserves WHERE biblionumber = ?"
2016
        "SELECT count(*) as reserve_count FROM holds WHERE biblio_id = ? AND completed = 0"
2021
    );
2017
    );
2022
    $sth->execute($from_biblio);
2018
    $sth->execute($from_biblio);
2023
    if ( my $data = $sth->fetchrow_hashref() ) {
2019
    if ( my $data = $sth->fetchrow_hashref() ) {
2024
2020
2025
        # holds exist on old record, if not we don't need to do anything
2021
        # holds exist on old record, if not we don't need to do anything
2026
        $sth = $dbh->prepare(
2022
        $sth = $dbh->prepare(
2027
            "UPDATE reserves SET biblionumber = ? WHERE biblionumber = ?");
2023
            "UPDATE holds SET biblio_id = ? WHERE biblio_id = ?");
2028
        $sth->execute( $to_biblio, $from_biblio );
2024
        $sth->execute( $to_biblio, $from_biblio );
2029
2025
2030
        # Reorder by date
2026
        # Reorder by date
2031
        # don't reorder those already waiting
2027
        # don't reorder those already waiting
2032
2028
2033
        $sth = $dbh->prepare(
2029
        $sth = $dbh->prepare(
2034
"SELECT * FROM reserves WHERE biblionumber = ? AND (found NOT IN ('W', 'T', 'P') OR found is NULL) ORDER BY reservedate ASC"
2030
            "SELECT id FROM holds WHERE biblio_id = ? AND status = 'placed' AND completed = 0 ORDER BY created_date ASC"
2035
        );
2031
        );
2036
        my $upd_sth = $dbh->prepare(
2032
        my $upd_sth = $dbh->prepare(
2037
"UPDATE reserves SET priority = ? WHERE biblionumber = ? AND borrowernumber = ?
2033
            "UPDATE holds SET priority = ? WHERE id = ? "
2038
        AND reservedate = ? AND (itemnumber = ? or itemnumber is NULL) "
2039
        );
2034
        );
2040
        $sth->execute( $to_biblio );
2035
        $sth->execute( $to_biblio );
2041
        my $priority = 1;
2036
        my $priority = 1;
2042
        while ( my $reserve = $sth->fetchrow_hashref() ) {
2037
        while ( my $reserve = $sth->fetchrow_hashref() ) {
2043
            $upd_sth->execute(
2038
            $upd_sth->execute(
2044
                $priority,                    $to_biblio,
2039
                $priority,
2045
                $reserve->{'borrowernumber'}, $reserve->{'reservedate'},
2040
                $reserve->{'id'}
2046
                $reserve->{'itemnumber'}
2047
            );
2041
            );
2048
            $priority++;
2042
            $priority++;
2049
        }
2043
        }
Lines 2066-2101 sub MergeHolds { Link Here
2066
2060
2067
sub RevertWaitingStatus {
2061
sub RevertWaitingStatus {
2068
    my ( $params ) = @_;
2062
    my ( $params ) = @_;
2069
    my $itemnumber = $params->{'itemnumber'};
2063
    my $item_id = $params->{'itemnumber'};
2070
2064
2071
    return unless ( $itemnumber );
2065
    return unless ( $item_id );
2072
2073
    my $dbh = C4::Context->dbh;
2074
2066
2075
    ## Get the waiting reserve we want to revert
2067
    ## Get the waiting reserve we want to revert
2076
    my $hold = Koha::Holds->search(
2068
    my $hold = Koha::Holds->search(
2077
        {
2069
        {
2078
            itemnumber => $itemnumber,
2070
            item_id => $item_id,
2079
            found => { not => undef },
2071
            status => 'waiting',
2080
        }
2072
        }
2081
    )->next;
2073
    )->next;
2082
2074
2083
    ## Increment the priority of all other non-waiting
2075
    ## Increment the priority of all other non-waiting
2084
    ## reserves for this bib record
2076
    ## reserves for this bib record
2085
    my $holds = Koha::Holds->search({ biblionumber => $hold->biblionumber, priority => { '>' => 0 } })
2077
    my $holds = Koha::Holds->search({ biblio_id => $hold->biblio_id, priority => { '>' => 0 } })
2086
                           ->update({ priority => \'priority + 1' }, { no_triggers => 1 });
2078
                           ->update({ priority => \'priority + 1' }, { no_triggers => 1 });
2087
2079
2088
    ## Fix up the currently waiting reserve
2080
    ## Fix up the currently waiting reserve
2089
    $hold->set(
2081
    $hold->set(
2090
        {
2082
        {
2091
            priority    => 1,
2083
            priority     => 1,
2092
            found       => undef,
2084
            status       => 'placed',
2093
            waitingdate => undef,
2085
            waiting_date => undef,
2094
            itemnumber  => $hold->item_level_hold ? $hold->itemnumber : undef,
2086
            item_id      => $hold->item_level ? $hold->item_id : undef,
2095
        }
2087
        }
2096
    )->store();
2088
    )->store();
2097
2089
2098
    _FixPriority( { biblionumber => $hold->biblionumber } );
2090
    _FixPriority( { biblionumber => $hold->biblio_id } );
2099
2091
2100
    return $hold;
2092
    return $hold;
2101
}
2093
}
Lines 2128-2154 available within the slip: Link Here
2128
2120
2129
sub ReserveSlip {
2121
sub ReserveSlip {
2130
    my ($args) = @_;
2122
    my ($args) = @_;
2131
    my $branchcode     = $args->{branchcode};
2123
    my $branchcode = $args->{branchcode};
2132
    my $reserve_id = $args->{reserve_id};
2124
    my $reserve_id = $args->{reserve_id};
2133
2125
2134
    my $hold = Koha::Holds->find($reserve_id);
2126
    my $hold = Koha::Holds->find($reserve_id);
2135
    return unless $hold;
2127
    return unless $hold;
2136
2128
2137
    my $patron = $hold->borrower;
2129
    my $patron = $hold->patron;
2138
    my $reserve = $hold->unblessed;
2139
2130
2140
    return  C4::Letters::GetPreparedLetter (
2131
    return C4::Letters::GetPreparedLetter(
2141
        module => 'circulation',
2132
        module      => 'circulation',
2142
        letter_code => 'HOLD_SLIP',
2133
        letter_code => 'HOLD_SLIP',
2143
        branchcode => $branchcode,
2134
        branchcode  => $branchcode,
2144
        lang => $patron->lang,
2135
        lang        => $patron->lang,
2145
        tables => {
2136
        tables      => {
2146
            'reserves'    => $reserve,
2137
            'holds'       => $hold->unblessed,
2147
            'branches'    => $reserve->{branchcode},
2138
            'branches'    => $hold->pickup_library_id,
2148
            'borrowers'   => $reserve->{borrowernumber},
2139
            'borrowers'   => $hold->patron_id,
2149
            'biblio'      => $reserve->{biblionumber},
2140
            'biblio'      => $hold->biblio_id,
2150
            'biblioitems' => $reserve->{biblionumber},
2141
            'biblioitems' => $hold->biblio_id,
2151
            'items'       => $reserve->{itemnumber},
2142
            'items'       => $hold->item_id,
2152
        },
2143
        },
2153
    );
2144
    );
2154
}
2145
}
Lines 2202-2218 sub CalculatePriority { Link Here
2202
    my ( $biblionumber, $resdate ) = @_;
2193
    my ( $biblionumber, $resdate ) = @_;
2203
2194
2204
    my $sql = q{
2195
    my $sql = q{
2205
        SELECT COUNT(*) FROM reserves
2196
        SELECT COUNT(*) FROM holds
2206
        WHERE biblionumber = ?
2197
        WHERE biblio_id = ?
2207
        AND   priority > 0
2198
        AND   priority > 0
2208
        AND   (found IS NULL OR found = '')
2199
        AND   status='placed'
2209
    };
2200
    };
2210
    #skip found==W or found==T or found==P (waiting, transit or processing holds)
2201
    #skip status==waiting or status==in_transit or status==processing
2211
    if( $resdate ) {
2202
    if( $resdate ) {
2212
        $sql.= ' AND ( reservedate <= ? )';
2203
        $sql.= ' AND ( created_date <= ? )';
2213
    }
2204
    }
2214
    else {
2205
    else {
2215
        $sql.= ' AND ( reservedate < NOW() )';
2206
        $sql.= ' AND ( created_date < NOW() )';
2216
    }
2207
    }
2217
    my $dbh = C4::Context->dbh();
2208
    my $dbh = C4::Context->dbh();
2218
    my @row = $dbh->selectrow_array(
2209
    my @row = $dbh->selectrow_array(
Lines 2226-2251 sub CalculatePriority { Link Here
2226
2217
2227
=head2 IsItemOnHoldAndFound
2218
=head2 IsItemOnHoldAndFound
2228
2219
2229
    my $bool = IsItemFoundHold( $itemnumber );
2220
    my $bool = IsItemFoundHold( $item_id );
2230
2221
2231
    Returns true if the item is currently on hold
2222
    Returns true if the item is currently on hold
2232
    and that hold has a non-null found status ( W, T, etc. )
2223
    and that hold has a status of in_transit, processing
2224
    or waiting.
2233
2225
2234
=cut
2226
=cut
2235
2227
2236
sub IsItemOnHoldAndFound {
2228
sub IsItemOnHoldAndFound {
2237
    my ($itemnumber) = @_;
2229
    my ($item_id) = @_;
2238
2239
    my $rs = Koha::Database->new()->schema()->resultset('Reserve');
2240
2230
2241
    my $found = $rs->count(
2231
    return Koha::Holds->search(
2242
        {
2232
        {
2243
            itemnumber => $itemnumber,
2233
            item_id   => $item_id,
2244
            found      => { '!=' => undef }
2234
            status    => [ 'in_transit', 'processing', 'waiting' ],
2235
            completed => 0
2245
        }
2236
        }
2246
    );
2237
    )->count;
2247
2248
    return $found;
2249
}
2238
}
2250
2239
2251
=head2 GetMaxPatronHoldsForRecord
2240
=head2 GetMaxPatronHoldsForRecord
(-)a/C4/SIP/ILS/Item.pm (-2 / +13 lines)
Lines 105-111 sub new { Link Here
105
        $self->{borrowernumber} = $patron->borrowernumber;
105
        $self->{borrowernumber} = $patron->borrowernumber;
106
    }
106
    }
107
    my $biblio = Koha::Biblios->find( $self->{biblionumber} );
107
    my $biblio = Koha::Biblios->find( $self->{biblionumber} );
108
    my $holds = $biblio->current_holds->unblessed;
108
109
    # Holds
110
    my $view_query = q{
111
    SELECT *
112
    FROM
113
        reserves
114
    WHERE
115
        biblionumber = ?
116
    };
117
118
    my $holds = C4::Context->dbh->selectall_arrayref( $view_query, { 'Slice' => {} }, $biblio->biblionumber );
119
109
    $self->{hold_queue} = $holds;
120
    $self->{hold_queue} = $holds;
110
    $self->{hold_attached} = [( grep { defined $_->{found}  and ( $_->{found} eq 'W' or $_->{found} eq 'P' or $_->{found} eq 'T' ) } @{$self->{hold_queue}} )];
121
    $self->{hold_attached} = [( grep { defined $_->{found}  and ( $_->{found} eq 'W' or $_->{found} eq 'P' or $_->{found} eq 'T' ) } @{$self->{hold_queue}} )];
111
    $self->{pending_queue} = [( grep {(! defined $_->{found}) or ( $_->{found} ne 'W' and $_->{found} ne 'P' and $_->{found} ne 'T' ) } @{$self->{hold_queue}} )];
122
    $self->{pending_queue} = [( grep {(! defined $_->{found}) or ( $_->{found} ne 'W' and $_->{found} ne 'P' and $_->{found} ne 'T' ) } @{$self->{hold_queue}} )];
Lines 353-359 sub recall_date { Link Here
353
sub hold_pickup_date {
364
sub hold_pickup_date {
354
    my $self = shift;
365
    my $self = shift;
355
366
356
    my $hold = Koha::Holds->find({ itemnumber => $self->{itemnumber}, found => 'W' });
367
    my $hold = Koha::Holds->find({ item_id => $self->{itemnumber}, status => 'waiting' });
357
    if ( $hold ) {
368
    if ( $hold ) {
358
        return $hold->expirationdate || 0;
369
        return $hold->expirationdate || 0;
359
    }
370
    }
(-)a/C4/SIP/ILS/Patron.pm (-2 / +2 lines)
Lines 520-530 sub _get_outstanding_holds { Link Here
520
    my $borrowernumber = shift;
520
    my $borrowernumber = shift;
521
521
522
    my $patron = Koha::Patrons->find( $borrowernumber );
522
    my $patron = Koha::Patrons->find( $borrowernumber );
523
    my $holds = $patron->holds->search( { -or => [ { found => undef }, { found => { '!=' => 'W' } } ] } );
523
    my $holds = $patron->holds->search( { completed => 0, status => {'!=' => 'waiting'} } );
524
    my @holds;
524
    my @holds;
525
    while ( my $hold = $holds->next ) {
525
    while ( my $hold = $holds->next ) {
526
        my $item;
526
        my $item;
527
        if ($hold->itemnumber) {
527
        if ($hold->item_id) {
528
            $item = $hold->item;
528
            $item = $hold->item;
529
        }
529
        }
530
        else {
530
        else {
(-)a/C4/SIP/ILS/Transaction/Hold.pm (-1 / +1 lines)
Lines 86-92 sub drop_hold { Link Here
86
    }
86
    }
87
87
88
    my $item = Koha::Items->find({ barcode => $self->{item}->id });
88
    my $item = Koha::Items->find({ barcode => $self->{item}->id });
89
    my $holds = $item->holds->search({ borrowernumber => $patron->borrowernumber });
89
    my $holds = $item->holds->search({ patron_id => $patron->borrowernumber });
90
90
91
    return $self unless $holds->count;
91
    return $self unless $holds->count;
92
92
(-)a/C4/XSLT.pm (-1 / +1 lines)
Lines 315-321 sub buildKohaItemsNamespace { Link Here
315
        $items_rs = Koha::Items->new;
315
        $items_rs = Koha::Items->new;
316
    }
316
    }
317
317
318
    my $items = $items_rs->search( $query, { prefetch => [ 'branchtransfers', 'reserves' ] } );
318
    my $items = $items_rs->search( $query, { prefetch => [ 'branchtransfers', 'holds' ] } );
319
319
320
    my $shelflocations =
320
    my $shelflocations =
321
      { map { $_->{authorised_value} => $_->{opac_description} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => "", kohafield => 'items.location' } ) };
321
      { map { $_->{authorised_value} => $_->{opac_description} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => "", kohafield => 'items.location' } ) };
(-)a/Koha/Acquisition/Order.pm (-1 / +1 lines)
Lines 298-304 sub current_item_level_holds { Link Here
298
298
299
    return $biblio->current_holds->search(
299
    return $biblio->current_holds->search(
300
        {
300
        {
301
            itemnumber => {
301
            item_id => {
302
                -in => \@item_numbers
302
                -in => \@item_numbers
303
            }
303
            }
304
        }
304
        }
(-)a/Koha/Biblio.pm (-4 / +5 lines)
Lines 444-450 return the current holds placed on this record Link Here
444
sub holds {
444
sub holds {
445
    my ( $self, $params, $attributes ) = @_;
445
    my ( $self, $params, $attributes ) = @_;
446
    $attributes->{order_by} = 'priority' unless exists $attributes->{order_by};
446
    $attributes->{order_by} = 'priority' unless exists $attributes->{order_by};
447
    my $hold_rs = $self->_result->reserves->search( $params, $attributes );
447
    $params->{completed} = 0 unless exists $params->{completed};
448
    my $hold_rs = $self->_result->holds->search( $params, $attributes );
448
    return Koha::Holds->_new_from_dbic($hold_rs);
449
    return Koha::Holds->_new_from_dbic($hold_rs);
449
}
450
}
450
451
Lines 461-467 sub current_holds { Link Here
461
    my ($self) = @_;
462
    my ($self) = @_;
462
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
463
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
463
    return $self->holds(
464
    return $self->holds(
464
        { reservedate => { '<=' => $dtf->format_date(dt_from_string) } } );
465
        { completed => 0, created_date => { '<=' => $dtf->format_date(dt_from_string) } } );
465
}
466
}
466
467
467
=head3 biblioitem
468
=head3 biblioitem
Lines 522-529 Tells if this bibliographic record has items waiting or in transit. Link Here
522
sub has_items_waiting_or_intransit {
523
sub has_items_waiting_or_intransit {
523
    my ( $self ) = @_;
524
    my ( $self ) = @_;
524
525
525
    if ( Koha::Holds->search({ biblionumber => $self->id,
526
    if ( Koha::Holds->search({ biblio_id => $self->id,
526
                               found => ['W', 'T'] })->count ) {
527
                               status => ['waiting', 'in_transit'] })->count ) {
527
        return 1;
528
        return 1;
528
    }
529
    }
529
530
(-)a/Koha/Hold.pm (-14 / +17 lines)
Lines 368-374 sub is_in_processing { Link Here
368
368
369
Returns true if hold is a cancelable hold
369
Returns true if hold is a cancelable hold
370
370
371
Holds may be only canceled if they are not found.
371
Holds may be only canceled if they are not found or completed.
372
372
373
This is used from the OPAC.
373
This is used from the OPAC.
374
374
Lines 377-384 This is used from the OPAC. Link Here
377
sub is_cancelable_from_opac {
377
sub is_cancelable_from_opac {
378
    my ($self) = @_;
378
    my ($self) = @_;
379
379
380
    return 1 unless $self->is_found();
380
    if ( $self->completed or $self->is_found ) {
381
    return 0; # if ->is_in_transit or if ->is_waiting or ->is_in_processing
381
        return 0;
382
    }
383
384
    return 1;
382
}
385
}
383
386
384
=head3 is_at_destination
387
=head3 is_at_destination
Lines 590-600 sub store { Link Here
590
    if ( !$self->in_storage ) {
593
    if ( !$self->in_storage ) {
591
        if (
594
        if (
592
            C4::Context->preference('DefaultHoldExpirationdate')
595
            C4::Context->preference('DefaultHoldExpirationdate')
593
            and ( not defined $self->expirationdate
596
            and ( not defined $self->expiration_date
594
                or $self->expirationdate eq '' )
597
                or $self->expiration_date eq '' )
595
          )
598
          )
596
        {
599
        {
597
            $self->_set_default_expirationdate;
600
            $self->_set_default_expiration_date;
598
        }
601
        }
599
    }
602
    }
600
    else {
603
    else {
Lines 602-616 sub store { Link Here
602
        my %updated_columns = $self->_result->get_dirty_columns;
605
        my %updated_columns = $self->_result->get_dirty_columns;
603
        return $self->SUPER::store unless %updated_columns;
606
        return $self->SUPER::store unless %updated_columns;
604
607
605
        if ( exists $updated_columns{reservedate} ) {
608
        if ( exists $updated_columns{created_date} ) {
606
            if (
609
            if (
607
                C4::Context->preference('DefaultHoldExpirationdate')
610
                C4::Context->preference('DefaultHoldExpirationdate')
608
                and ( not exists $updated_columns{expirationdate}
611
                and ( not exists $updated_columns{expiration_date}
609
                    or exists $updated_columns{expirationdate}
612
                    or exists $updated_columns{expiration_date}
610
                    and $updated_columns{expirationdate} eq '' )
613
                    and $updated_columns{expiration_date} eq '' )
611
              )
614
              )
612
            {
615
            {
613
                $self->_set_default_expirationdate;
616
                $self->_set_default_expiration_date;
614
            }
617
            }
615
        }
618
        }
616
    }
619
    }
Lines 618-632 sub store { Link Here
618
    $self = $self->SUPER::store;
621
    $self = $self->SUPER::store;
619
}
622
}
620
623
621
sub _set_default_expirationdate {
624
sub _set_default_expiration_date {
622
    my $self = shift;
625
    my $self = shift;
623
626
624
    my $period = C4::Context->preference('DefaultHoldExpirationdatePeriod') || 0;
627
    my $period = C4::Context->preference('DefaultHoldExpirationdatePeriod') || 0;
625
    my $timeunit =
628
    my $timeunit =
626
      C4::Context->preference('DefaultHoldExpirationdateUnitOfTime') || 'days';
629
      C4::Context->preference('DefaultHoldExpirationdateUnitOfTime') || 'days';
627
630
628
    $self->expirationdate(
631
    $self->expiration_date(
629
        dt_from_string( $self->reservedate )->add( $timeunit => $period ) );
632
        dt_from_string( $self->created_date )->add( $timeunit => $period ) );
630
}
633
}
631
634
632
=head3 to_api_mapping
635
=head3 to_api_mapping
(-)a/Koha/Holds.pm (-4 / +27 lines)
Lines 36-41 Koha::Holds - Koha Hold object set class Link Here
36
36
37
=cut
37
=cut
38
38
39
40
=head3 filter_by_current
41
42
    my $holds_rs = Koha::Holds->filter_by_current( ... );
43
44
Filter the resultset by current (i.e. completed = 0).
45
46
=cut
47
48
sub filter_by_current {
49
    my ( $self ) = @_;
50
51
    return $self->search(
52
        {
53
            completed => 0
54
        }
55
    );
56
}
57
58
39
=head3 waiting
59
=head3 waiting
40
60
41
returns a set of holds that are waiting from an existing set
61
returns a set of holds that are waiting from an existing set
Lines 121-127 Items that are not: Link Here
121
sub get_items_that_can_fill {
141
sub get_items_that_can_fill {
122
    my ( $self ) = @_;
142
    my ( $self ) = @_;
123
143
124
    my @biblionumbers = $self->get_column('biblionumber');
144
    my @biblionumbers = $self->get_column('biblio_id');
125
145
126
    my @branchtransfers = map { $_->itemnumber }
146
    my @branchtransfers = map { $_->itemnumber }
127
      Koha::Item::Transfers->search(
147
      Koha::Item::Transfers->search(
Lines 131-141 sub get_items_that_can_fill { Link Here
131
              collapse => 1,
151
              collapse => 1,
132
          }
152
          }
133
      );
153
      );
134
    my @waiting_holds = map { $_->itemnumber }
154
    my @waiting_holds = map { $_->item_id }
135
      Koha::Holds->search(
155
      Koha::Holds->search(
136
          { 'found' => 'W' },
137
          {
156
          {
138
              columns => ['itemnumber'],
157
              status    => 'waiting',
158
              completed => 0
159
          },
160
          {
161
              columns => ['item_id'],
139
              collapse => 1,
162
              collapse => 1,
140
          }
163
          }
141
      );
164
      );
(-)a/Koha/Item.pm (-9 / +11 lines)
Lines 281-287 sub safe_to_delete { Link Here
281
281
282
    # check it doesn't have a waiting reserve
282
    # check it doesn't have a waiting reserve
283
    return "book_reserved"
283
    return "book_reserved"
284
      if $self->holds->search( { found => [ 'W', 'T' ] } )->count;
284
      if $self->holds->search( { status => [ 'waiting', 'in_transit' ], completed => 0 } )->count;
285
285
286
    return "linked_analytics"
286
    return "linked_analytics"
287
      if C4::Items::GetAnalyticsCount( $self->itemnumber ) > 0;
287
      if C4::Items::GetAnalyticsCount( $self->itemnumber ) > 0;
Lines 290-296 sub safe_to_delete { Link Here
290
      if $self->biblio->items->count == 1
290
      if $self->biblio->items->count == 1
291
      && $self->biblio->holds->search(
291
      && $self->biblio->holds->search(
292
          {
292
          {
293
              itemnumber => undef,
293
              item_id => undef,
294
          }
294
          }
295
        )->count;
295
        )->count;
296
296
Lines 397-403 sub checkout { Link Here
397
397
398
my $holds = $item->holds();
398
my $holds = $item->holds();
399
my $holds = $item->holds($params);
399
my $holds = $item->holds($params);
400
my $holds = $item->holds({ found => 'W'});
400
my $holds = $item->holds({ status => 'waiting'});
401
401
402
Return holds attached to an item, optionally accept a hashref of params to pass to search
402
Return holds attached to an item, optionally accept a hashref of params to pass to search
403
403
Lines 405-411 Return holds attached to an item, optionally accept a hashref of params to pass Link Here
405
405
406
sub holds {
406
sub holds {
407
    my ( $self,$params ) = @_;
407
    my ( $self,$params ) = @_;
408
    my $holds_rs = $self->_result->reserves->search($params);
408
    $params->{completed} = 0 unless exists $params->{completed};
409
    my $holds_rs = $self->_result->holds->search($params);
409
    return Koha::Holds->_new_from_dbic( $holds_rs );
410
    return Koha::Holds->_new_from_dbic( $holds_rs );
410
}
411
}
411
412
Lines 789-802 sub current_holds { Link Here
789
    my $attributes = { order_by => 'priority' };
790
    my $attributes = { order_by => 'priority' };
790
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
791
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
791
    my $params = {
792
    my $params = {
792
        itemnumber => $self->itemnumber,
793
        item_id => $self->itemnumber,
793
        suspend => 0,
794
        suspended => 0,
794
        -or => [
795
        -or => [
795
            reservedate => { '<=' => $dtf->format_date(dt_from_string) },
796
            created_date => { '<=' => $dtf->format_date(dt_from_string) },
796
            waitingdate => { '!=' => undef },
797
            waiting_date => { '!=' => undef },
797
        ],
798
        ],
799
        completed => 0
798
    };
800
    };
799
    my $hold_rs = $self->_result->reserves->search( $params, $attributes );
801
    my $hold_rs = $self->_result->holds->search( $params, $attributes );
800
    return Koha::Holds->_new_from_dbic($hold_rs);
802
    return Koha::Holds->_new_from_dbic($hold_rs);
801
}
803
}
802
804
(-)a/Koha/Patron.pm (-6 / +6 lines)
Lines 71-79 our $RESULTSET_PATRON_ID_MAPPING = { Link Here
71
    Message              => 'borrowernumber',
71
    Message              => 'borrowernumber',
72
    MessageQueue         => 'borrowernumber',
72
    MessageQueue         => 'borrowernumber',
73
    OldIssue             => 'borrowernumber',
73
    OldIssue             => 'borrowernumber',
74
    OldReserve           => 'borrowernumber',
75
    Rating               => 'borrowernumber',
74
    Rating               => 'borrowernumber',
76
    Reserve              => 'borrowernumber',
75
    Hold                 => 'patron_id',
77
    Review               => 'borrowernumber',
76
    Review               => 'borrowernumber',
78
    SearchHistory        => 'userid',
77
    SearchHistory        => 'userid',
79
    Statistic            => 'borrowernumber',
78
    Statistic            => 'borrowernumber',
Lines 1205-1212 Return all the holds placed by this patron Link Here
1205
=cut
1204
=cut
1206
1205
1207
sub holds {
1206
sub holds {
1208
    my ($self) = @_;
1207
    my ($self, $params) = @_;
1209
    my $holds_rs = $self->_result->reserves->search( {}, { order_by => 'reservedate' } );
1208
    $params->{completed} = 0 unless exists $params->{completed};
1209
    my $holds_rs = $self->_result->holds->search( $params, { order_by => 'created_date' } );
1210
    return Koha::Holds->_new_from_dbic($holds_rs);
1210
    return Koha::Holds->_new_from_dbic($holds_rs);
1211
}
1211
}
1212
1212
Lines 1220-1227 Return all the historical holds for this patron Link Here
1220
1220
1221
sub old_holds {
1221
sub old_holds {
1222
    my ($self) = @_;
1222
    my ($self) = @_;
1223
    my $old_holds_rs = $self->_result->old_reserves->search( {}, { order_by => 'reservedate' } );
1223
    my $old_holds_rs = $self->_result->holds->search( { completed => 1 }, { order_by => 'created_date' } );
1224
    return Koha::Old::Holds->_new_from_dbic($old_holds_rs);
1224
    return Koha::Holds->_new_from_dbic($old_holds_rs);
1225
}
1225
}
1226
1226
1227
=head3 return_claims
1227
=head3 return_claims
(-)a/Koha/REST/V1/Auth.pm (-11 / +9 lines)
Lines 318-327 sub validate_query_parameters { Link Here
318
Allows access to object for its owner.
318
Allows access to object for its owner.
319
319
320
There are endpoints that should allow access for the object owner even if they
320
There are endpoints that should allow access for the object owner even if they
321
do not have the required permission, e.g. access an own reserve. This can be
321
do not have the required permission, e.g. access an own hold. This can be
322
achieved by defining the operation as follows:
322
achieved by defining the operation as follows:
323
323
324
"/holds/{reserve_id}": {
324
"/holds/{hold_id}": {
325
    "get": {
325
    "get": {
326
        ...,
326
        ...,
327
        "x-koha-authorization": {
327
        "x-koha-authorization": {
Lines 385-391 sub check_object_ownership { Link Here
385
        borrowernumber  => \&_object_ownership_by_patron_id,
385
        borrowernumber  => \&_object_ownership_by_patron_id,
386
        patron_id       => \&_object_ownership_by_patron_id,
386
        patron_id       => \&_object_ownership_by_patron_id,
387
        checkout_id     => \&_object_ownership_by_checkout_id,
387
        checkout_id     => \&_object_ownership_by_checkout_id,
388
        reserve_id      => \&_object_ownership_by_reserve_id,
388
        hold_id      => \&_object_ownership_by_hold_id,
389
    };
389
    };
390
390
391
    foreach my $param ( keys %{ $parameters } ) {
391
    foreach my $param ( keys %{ $parameters } ) {
Lines 449-468 sub _object_ownership_by_checkout_id { Link Here
449
            && $user->borrowernumber == $issue->borrowernumber;
449
            && $user->borrowernumber == $issue->borrowernumber;
450
}
450
}
451
451
452
=head3 _object_ownership_by_reserve_id
452
=head3 _object_ownership_by_hold_id
453
453
454
Finds a Koha::Hold-object by C<$reserve_id> and checks if it
454
Finds a Koha::Hold-object by C<$hold_id> and checks if it
455
belongs to C<$user>.
455
belongs to C<$user>.
456
456
457
TODO: Also compare against old_reserves
458
459
=cut
457
=cut
460
458
461
sub _object_ownership_by_reserve_id {
459
sub _object_ownership_by_hold_id {
462
    my ($c, $user, $reserve_id) = @_;
460
    my ($c, $user, $hold_id) = @_;
463
461
464
    my $reserve = Koha::Holds->find($reserve_id);
462
    my $hold = Koha::Holds->find($hold_id);
465
    return $reserve && $user->borrowernumber == $reserve->borrowernumber;
463
    return $hold && $user->borrowernumber == $hold->borrowernumber;
466
}
464
}
467
465
468
=head3 _basic_auth
466
=head3 _basic_auth
(-)a/Koha/REST/V1/Holds.pm (-15 / +15 lines)
Lines 45-51 sub list { Link Here
45
    my $c = shift->openapi->valid_input or return;
45
    my $c = shift->openapi->valid_input or return;
46
46
47
    return try {
47
    return try {
48
        my $holds_set = Koha::Holds->new;
48
        my $holds_set = Koha::Holds->search({completed=>0});
49
        my $holds     = $c->objects->search( $holds_set );
49
        my $holds     = $c->objects->search( $holds_set );
50
        return $c->render( status => 200, openapi => $holds );
50
        return $c->render( status => 200, openapi => $holds );
51
    }
51
    }
Lines 76-88 sub add { Link Here
76
        my $item_type         = $body->{item_type};
76
        my $item_type         = $body->{item_type};
77
        my $expiration_date   = $body->{expiration_date};
77
        my $expiration_date   = $body->{expiration_date};
78
        my $notes             = $body->{notes};
78
        my $notes             = $body->{notes};
79
        my $hold_date         = $body->{hold_date};
79
        my $created_date      = $body->{created_date};
80
        my $non_priority      = $body->{non_priority};
80
        my $non_priority      = $body->{non_priority};
81
81
82
        my $overrides = $c->stash('koha.overrides');
82
        my $overrides = $c->stash('koha.overrides');
83
        my $can_override = $overrides->{any} && C4::Context->preference('AllowHoldPolicyOverride');
83
        my $can_override = $overrides->{any} && C4::Context->preference('AllowHoldPolicyOverride');
84
84
85
        if(!C4::Context->preference( 'AllowHoldDateInFuture' ) && $hold_date) {
85
        if(!C4::Context->preference( 'AllowHoldDateInFuture' ) && $created_date) {
86
            return $c->render(
86
            return $c->render(
87
                status  => 400,
87
                status  => 400,
88
                openapi => { error => "Hold date in future not allowed" }
88
                openapi => { error => "Hold date in future not allowed" }
Lines 194-200 sub add { Link Here
194
                borrowernumber   => $patron_id,
194
                borrowernumber   => $patron_id,
195
                biblionumber     => $biblio_id,
195
                biblionumber     => $biblio_id,
196
                priority         => $priority,
196
                priority         => $priority,
197
                reservation_date => $hold_date,
197
                reservation_date => $created_date,
198
                expiration_date  => $expiration_date,
198
                expiration_date  => $expiration_date,
199
                notes            => $notes,
199
                notes            => $notes,
200
                title            => $biblio->title,
200
                title            => $biblio->title,
Lines 248-254 sub edit { Link Here
248
248
249
    return try {
249
    return try {
250
        my $hold_id = $c->validation->param('hold_id');
250
        my $hold_id = $c->validation->param('hold_id');
251
        my $hold = Koha::Holds->find( $hold_id );
251
        my $hold    = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
252
252
253
        unless ($hold) {
253
        unless ($hold) {
254
            return $c->render(
254
            return $c->render(
Lines 277-293 sub edit { Link Here
277
            );
277
            );
278
        }
278
        }
279
279
280
        $pickup_library_id //= $hold->branchcode;
280
        $pickup_library_id //= $hold->pickup_library_id;
281
        my $priority         = $body->{priority} // $hold->priority;
281
        my $priority         = $body->{priority} // $hold->priority;
282
        # suspended_until can also be set to undef
282
        # suspended_until can also be set to undef
283
        my $suspended_until   = exists $body->{suspended_until} ? $body->{suspended_until} : $hold->suspend_until;
283
        my $suspended_until   = exists $body->{suspended_until_date} ? $body->{suspended_until_date} : $hold->suspended_until_date;
284
284
285
        my $params = {
285
        my $params = {
286
            reserve_id    => $hold_id,
286
            reserve_id    => $hold_id,
287
            branchcode    => $pickup_library_id,
287
            branchcode    => $pickup_library_id,
288
            rank          => $priority,
288
            rank          => $priority,
289
            suspend_until => $suspended_until ? output_pref(dt_from_string($suspended_until, 'rfc3339')) : '',
289
            suspend_until => $suspended_until ? output_pref(dt_from_string($suspended_until, 'rfc3339')) : '',
290
            itemnumber    => $hold->itemnumber
290
            itemnumber    => $hold->item_id
291
        };
291
        };
292
292
293
        C4::Reserves::ModReserve($params);
293
        C4::Reserves::ModReserve($params);
Lines 313-319 sub delete { Link Here
313
    my $c = shift->openapi->valid_input or return;
313
    my $c = shift->openapi->valid_input or return;
314
314
315
    my $hold_id = $c->validation->param('hold_id');
315
    my $hold_id = $c->validation->param('hold_id');
316
    my $hold    = Koha::Holds->find($hold_id);
316
    my $hold    = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
317
317
318
    unless ($hold) {
318
    unless ($hold) {
319
        return $c->render( status => 404, openapi => { error => "Hold not found." } );
319
        return $c->render( status => 404, openapi => { error => "Hold not found." } );
Lines 342-348 sub suspend { Link Here
342
    my $c = shift->openapi->valid_input or return;
342
    my $c = shift->openapi->valid_input or return;
343
343
344
    my $hold_id  = $c->validation->param('hold_id');
344
    my $hold_id  = $c->validation->param('hold_id');
345
    my $hold     = Koha::Holds->find($hold_id);
345
    my $hold     = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
346
    my $body     = $c->req->json;
346
    my $body     = $c->req->json;
347
    my $end_date = ($body) ? $body->{end_date} : undef;
347
    my $end_date = ($body) ? $body->{end_date} : undef;
348
348
Lines 356-364 sub suspend { Link Here
356
        $hold->discard_changes;
356
        $hold->discard_changes;
357
        $c->res->headers->location( $c->req->url->to_string );
357
        $c->res->headers->location( $c->req->url->to_string );
358
        my $suspend_end_date;
358
        my $suspend_end_date;
359
        if ($hold->suspend_until) {
359
        if ($hold->suspended_until_date) {
360
            $suspend_end_date = output_pref({
360
            $suspend_end_date = output_pref({
361
                dt         => dt_from_string( $hold->suspend_until ),
361
                dt         => dt_from_string( $hold->suspended_until_date ),
362
                dateformat => 'rfc3339',
362
                dateformat => 'rfc3339',
363
                dateonly   => 1
363
                dateonly   => 1
364
                }
364
                }
Lines 390-396 sub resume { Link Here
390
    my $c = shift->openapi->valid_input or return;
390
    my $c = shift->openapi->valid_input or return;
391
391
392
    my $hold_id = $c->validation->param('hold_id');
392
    my $hold_id = $c->validation->param('hold_id');
393
    my $hold    = Koha::Holds->find($hold_id);
393
    my $hold    = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
394
    my $body    = $c->req->json;
394
    my $body    = $c->req->json;
395
395
396
    unless ($hold) {
396
    unless ($hold) {
Lines 416-422 sub update_priority { Link Here
416
    my $c = shift->openapi->valid_input or return;
416
    my $c = shift->openapi->valid_input or return;
417
417
418
    my $hold_id = $c->validation->param('hold_id');
418
    my $hold_id = $c->validation->param('hold_id');
419
    my $hold = Koha::Holds->find($hold_id);
419
    my $hold = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
420
420
421
    unless ($hold) {
421
    unless ($hold) {
422
        return $c->render(
422
        return $c->render(
Lines 464-470 sub pickup_locations { Link Here
464
    return try {
464
    return try {
465
        my $ps_set;
465
        my $ps_set;
466
466
467
        if ( $hold->itemnumber ) {
467
        if ( $hold->item_id ) {
468
            $ps_set = $hold->item->pickup_locations( { patron => $hold->patron } );
468
            $ps_set = $hold->item->pickup_locations( { patron => $hold->patron } );
469
        }
469
        }
470
        else {
470
        else {
(-)a/Koha/Template/Plugin/Biblio.pm (-4 / +7 lines)
Lines 29-39 use Koha::ArticleRequests; Link Here
29
use Koha::ArticleRequest::Status;
29
use Koha::ArticleRequest::Status;
30
30
31
sub HoldsCount {
31
sub HoldsCount {
32
    my ( $self, $biblionumber ) = @_;
32
    my ( $self, $biblio_id ) = @_;
33
34
    my $holds = Koha::Holds->search( { biblionumber => $biblionumber } );
35
33
36
    return $holds->count();
34
    return Koha::Holds->search(
35
        {
36
            biblio_id => $biblio_id,
37
            completed => 0
38
        }
39
    )->count;
37
}
40
}
38
41
39
sub ArticleRequestsActiveCount {
42
sub ArticleRequestsActiveCount {
(-)a/api/v1/swagger/definitions/hold.json (-3 / +11 lines)
Lines 9-15 Link Here
9
      "type": "integer",
9
      "type": "integer",
10
      "description": "Internal patron identifier"
10
      "description": "Internal patron identifier"
11
    },
11
    },
12
    "hold_date": {
12
    "created_date": {
13
      "type": ["string", "null"],
13
      "type": ["string", "null"],
14
      "format": "date",
14
      "format": "date",
15
      "description": "The date the hold was placed"
15
      "description": "The date the hold was placed"
Lines 45-51 Link Here
45
    },
45
    },
46
    "status": {
46
    "status": {
47
      "type": ["string", "null"],
47
      "type": ["string", "null"],
48
      "description": "A one letter code defining what the status of the hold is after it has been confirmed"
48
      "description": "the status the hold is ('placed', 'fulfilled', 'waiting', 'in_transit', 'cancelled')"
49
    },
49
    },
50
    "timestamp": {
50
    "timestamp": {
51
      "type": "string",
51
      "type": "string",
Lines 74-80 Link Here
74
      "type": "boolean",
74
      "type": "boolean",
75
      "description": "Controls if the hold is suspended"
75
      "description": "Controls if the hold is suspended"
76
    },
76
    },
77
    "suspended_until": {
77
    "suspended_until_date": {
78
      "type": ["string", "null"],
78
      "type": ["string", "null"],
79
      "format": "date-time",
79
      "format": "date-time",
80
      "description": "Date until which the hold has been suspended"
80
      "description": "Date until which the hold has been suspended"
Lines 90-95 Link Here
90
    "item_level": {
90
    "item_level": {
91
      "type": "boolean",
91
      "type": "boolean",
92
      "description": "If the hold is placed at item level"
92
      "description": "If the hold is placed at item level"
93
    },
94
    "completed": {
95
      "type": "boolean",
96
      "description": "If it has been completed (i.e. either 'fulfilled' or 'cancelled')"
97
    },
98
    "completed_date": {
99
      "type": ["string", "null"],
100
      "description": "the date this hold was completed (fulfilled or cancelled)"
93
    }
101
    }
94
  },
102
  },
95
  "additionalProperties": false
103
  "additionalProperties": false
(-)a/api/v1/swagger/paths/holds.json (-4 / +8 lines)
Lines 99-105 Link Here
99
          "type": "boolean"
99
          "type": "boolean"
100
        },
100
        },
101
        {
101
        {
102
          "name": "suspended_until",
102
          "name": "suspended_until_date",
103
          "in": "query",
103
          "in": "query",
104
          "description": "Suspended until",
104
          "description": "Suspended until",
105
          "type": "string"
105
          "type": "string"
Lines 228-234 Link Here
228
              "non_priority": {
228
              "non_priority": {
229
                "description": "Set this hold as non priority",
229
                "description": "Set this hold as non priority",
230
                "type": [ "boolean", "null" ]
230
                "type": [ "boolean", "null" ]
231
              }
231
              },
232
              "created_date": {
233
                "type": "string",
234
                "format": "date",
235
                "description": "The date the hold was placed"              }
232
            },
236
            },
233
            "required": [ "patron_id", "pickup_library_id" ],
237
            "required": [ "patron_id", "pickup_library_id" ],
234
            "additionalProperties": false
238
            "additionalProperties": false
Lines 320-326 Link Here
320
                "description": "Internal library identifier for the pickup library",
324
                "description": "Internal library identifier for the pickup library",
321
                "type": "string"
325
                "type": "string"
322
              },
326
              },
323
              "suspended_until": {
327
              "suspended_until_date": {
324
                "description": "Date until which the hold has been suspended",
328
                "description": "Date until which the hold has been suspended",
325
                "type": "string",
329
                "type": "string",
326
                "format": "date-time"
330
                "format": "date-time"
Lines 407-413 Link Here
407
                "description": "Internal library identifier for the pickup library",
411
                "description": "Internal library identifier for the pickup library",
408
                "type": "string"
412
                "type": "string"
409
              },
413
              },
410
              "suspended_until": {
414
              "suspended_until_date": {
411
                "description": "Date until which the hold has been suspended",
415
                "description": "Date until which the hold has been suspended",
412
                "type": "string",
416
                "type": "string",
413
                "format": "date-time"
417
                "format": "date-time"
(-)a/circ/circulation.pl (-1 / +1 lines)
Lines 448-454 if (@$barcodes) { Link Here
448
# BUILD HTML
448
# BUILD HTML
449
# show all reserves of this borrower, and the position of the reservation ....
449
# show all reserves of this borrower, and the position of the reservation ....
450
if ($patron) {
450
if ($patron) {
451
    my $holds = Koha::Holds->search( { borrowernumber => $borrowernumber } ); # FIXME must be Koha::Patron->holds
451
    my $holds = Koha::Holds->search( { patron_id => $borrowernumber } ); # FIXME must be Koha::Patron->holds
452
    my $waiting_holds = $holds->waiting;
452
    my $waiting_holds = $holds->waiting;
453
    $template->param(
453
    $template->param(
454
        holds_count  => $holds->count(),
454
        holds_count  => $holds->count(),
(-)a/circ/returns.pl (-1 / +1 lines)
Lines 335-341 if ($barcode) { Link Here
335
        if (C4::Context->preference("WaitingNotifyAtCheckin") ) {
335
        if (C4::Context->preference("WaitingNotifyAtCheckin") ) {
336
            #Check for waiting holds
336
            #Check for waiting holds
337
            my $patron = Koha::Patrons->find( $borrower->{borrowernumber} );
337
            my $patron = Koha::Patrons->find( $borrower->{borrowernumber} );
338
            my $waiting_holds = $patron->holds->search({ found => 'W', branchcode => $userenv_branch })->count;
338
            my $waiting_holds = $patron->holds->waiting->search({ pickup_library_id => $userenv_branch })->count;
339
            if ($waiting_holds > 0) {
339
            if ($waiting_holds > 0) {
340
                $template->param(
340
                $template->param(
341
                    waiting_holds       => $waiting_holds,
341
                    waiting_holds       => $waiting_holds,
(-)a/installer/data/mysql/en/mandatory/sample_notices.yml (-3 / +3 lines)
Lines 459-468 tables: Link Here
459
            - "<ul>"
459
            - "<ul>"
460
            - "   <li><<items.barcode>></li>"
460
            - "   <li><<items.barcode>></li>"
461
            - "   <li><<items.itemcallnumber>></li>"
461
            - "   <li><<items.itemcallnumber>></li>"
462
            - "   <li><<reserves.waitingdate>></li>"
462
            - "   <li><<holds.waiting_date>></li>"
463
            - "</ul>"
463
            - "</ul>"
464
            - "<p>Notes:"
464
            - "<p>Notes:"
465
            - "<pre><<reserves.reservenotes>></pre>"
465
            - "<pre><<holds.notes>></pre>"
466
            - "</p>"
466
            - "</p>"
467
            - ""
467
            - ""
468
468
Lines 1261-1267 tables: Link Here
1261
          message_transport_type: email
1261
          message_transport_type: email
1262
          lang: default
1262
          lang: default
1263
          content:
1263
          content:
1264
            - "Dear [% borrower.firstname %] [% borrower.surname %],\n\nThe following holds are waiting at [% branch.branchname %]:\n\n[% FOREACH hold IN holds %]\n    [% hold.biblio.title %] : waiting since [% hold.waitingdate | $KohaDates %]\n[% END %]"
1264
            - "Dear [% borrower.firstname %] [% borrower.surname %],\n\nThe following holds are waiting at [% branch.branchname %]:\n\n[% FOREACH hold IN holds %]\n    [% hold.biblio.title %] : waiting since [% hold.waiting_date | $KohaDates %]\n[% END %]"
1265
1265
1266
        - module: serial
1266
        - module: serial
1267
          code: SERIAL_ALERT
1267
          code: SERIAL_ALERT
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/article-requests.tt (-1 / +1 lines)
Lines 53-59 Link Here
53
[% END %]
53
[% END %]
54
[% BLOCK item_status %]
54
[% BLOCK item_status %]
55
    [% IF myitem.onloan %]<span>Checked out</span>
55
    [% IF myitem.onloan %]<span>Checked out</span>
56
    [% ELSIF myitem.holds({ found => ['W', 'T'] }).count > 0 %]<span>On hold</span>
56
    [% ELSIF myitem.holds({ status => ['waiting', 'in_transit'] }).count > 0 %]<span>On hold</span>
57
    [% ELSIF myitem.notforloan > 0 OR myitem.itemtype.notforloan %]<span>Not for loan</span>
57
    [% ELSIF myitem.notforloan > 0 OR myitem.itemtype.notforloan %]<span>Not for loan</span>
58
    [% ELSIF myitem.notforloan < 0 %]<span>On order</span>
58
    [% ELSIF myitem.notforloan < 0 %]<span>On order</span>
59
    [% END %]
59
    [% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/holdshistory.tt (-16 / +16 lines)
Lines 74-114 Link Here
74
          <td>[% INCLUDE 'biblio-title.inc' biblio=hold.biblio link = 1 %]</td>
74
          <td>[% INCLUDE 'biblio-title.inc' biblio=hold.biblio link = 1 %]</td>
75
          <td>[% hold.biblio.author | html %]</td>
75
          <td>[% hold.biblio.author | html %]</td>
76
          <td>[% hold.item.barcode | html %]</td>
76
          <td>[% hold.item.barcode | html %]</td>
77
          <td>[% Branches.GetName( hold.branchcode ) | html %]</td>
77
          <td>[% Branches.GetName( hold.pickup_library_id ) | html %]</td>
78
          <td data-order="[% hold.reservedate | html %]">[% hold.reservedate | $KohaDates %]</td>
78
          <td data-order="[% hold.created_date | html %]">[% hold.created_date | $KohaDates %]</td>
79
          <td data-order="[% hold.expirationdate | html %]">
79
          <td data-order="[% hold.expiration_date | html %]">
80
                [% hold.expirationdate | $KohaDates %]
80
                [% hold.expiration_date | $KohaDates %]
81
          </td>
81
          </td>
82
          <td data-order="[% hold.waitingdate | html %]">
82
          <td data-order="[% hold.waiting_date | html %]">
83
                [% hold.waitingdate | $KohaDates %]
83
                [% hold.waiting_date | $KohaDates %]
84
          </td>
84
          </td>
85
          <td data-order="[% hold.cancellationdate | html %]">
85
          <td data-order="[% hold.completed_date | html %]">
86
                [% hold.cancellationdate | $KohaDates %]
86
                [% hold.completed_date | $KohaDates %]
87
          </td>
87
          </td>
88
          [% IF show_itemtype_column %]
88
          [% IF show_itemtype_column %]
89
            <td>
89
            <td>
90
              [% IF hold.itemtype %]
90
              [% IF hold.item_type %]
91
                  [% ItemTypes.GetDescription( hold.itemtype ) | html %]
91
                  [% ItemTypes.GetDescription( hold.item_type ) | html %]
92
              [% ELSE %]
92
              [% ELSE %]
93
                  <span>Any item type</span>
93
                  <span>Any item type</span>
94
              [% END %]
94
              [% END %]
95
            </td>
95
            </td>
96
          [% END %]
96
          [% END %]
97
          <td>
97
          <td>
98
          [% IF hold.found == 'F' %]
98
          [% IF    hold.status == 'fulfilled' %]
99
              Fulfilled
99
              Fulfilled
100
          [% ELSIF hold.cancellationdate %]
100
          [% ELSIF hold.status == 'cancelled' %]
101
              Cancelled
101
              Cancelled
102
                [% IF hold.cancellation_reason %]
102
                [% IF hold.cancellation_reason %]
103
                    ([% AuthorisedValues.GetByCode('HOLD_CANCELLATION', hold.cancellation_reason) | html %])
103
                    ([% AuthorisedValues.GetByCode('HOLD_CANCELLATION', hold.cancellation_reason) | html %])
104
                [% END %]
104
                [% END %]
105
          [% ELSIF hold.found == 'W' %]
105
          [% ELSIF hold.status == 'waiting' %]
106
              Waiting
106
              Waiting
107
          [% ELSIF hold.found == 'P' %]
107
          [% ELSIF hold.status == 'processing' %]
108
              Processing
108
              Processing
109
          [% ELSIF hold.found == 'T' %]
109
          [% ELSIF hold.status == 'in_transit' %]
110
              In transit
110
              In transit
111
          [% ELSE %]
111
          [% ELSIF hold.status == 'placed' %]
112
              Pending
112
              Pending
113
          [% END %]
113
          [% END %]
114
          </td>
114
          </td>
(-)a/koha-tmpl/intranet-tmpl/prog/js/holds.js (-1 / +1 lines)
Lines 77-83 $(document).ready(function() { Link Here
77
                    },
77
                    },
78
                    {
78
                    {
79
                        "mDataProp": function( oObj ) {
79
                        "mDataProp": function( oObj ) {
80
                            if( oObj.branches.length > 1 && oObj.found !== 'W' && oObj.found !== 'T' ){
80
                            if( oObj.branches.length > 1 && oObj.status !== 'waiting' && oObj.status !== 'in_transit' ){
81
                                var branchSelect='<select priority='+oObj.priority+' class="hold_location_select" reserve_id="'+oObj.reserve_id+'" name="pick-location">';
81
                                var branchSelect='<select priority='+oObj.priority+' class="hold_location_select" reserve_id="'+oObj.reserve_id+'" name="pick-location">';
82
                                for ( var i=0; i < oObj.branches.length; i++ ){
82
                                for ( var i=0; i < oObj.branches.length; i++ ){
83
                                    var selectedbranch;
83
                                    var selectedbranch;
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-holdshistory.tt (-17 / +21 lines)
Lines 115-137 Link Here
115
                                        <td><a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% hold.biblio.biblionumber | uri %]">[% INCLUDE 'biblio-title.inc' biblio=hold.biblio %]</a></td>
115
                                        <td><a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% hold.biblio.biblionumber | uri %]">[% INCLUDE 'biblio-title.inc' biblio=hold.biblio %]</a></td>
116
                                        <td>[% hold.biblio.author | html %]</td>
116
                                        <td>[% hold.biblio.author | html %]</td>
117
                                        <td>[% hold.item.barcode | html %]</td>
117
                                        <td>[% hold.item.barcode | html %]</td>
118
                                        <td>[% Branches.GetName( hold.branchcode ) | html %]</td>
118
                                        <td>[% Branches.GetName( hold.pickup_library_id ) | html %]</td>
119
                                        <td data-order="[% hold.reservedate | html %]">[% hold.reservedate | $KohaDates %]</td>
119
                                        <td data-order="[% hold.created_date | html %]">[% hold.created_date | $KohaDates %]</td>
120
                                        <td data-order="[% hold.expirationdate | html %]">
120
                                        <td data-order="[% hold.expiration_date | html %]">
121
                                            [% IF hold.expirationdate %]
121
                                            [% IF hold.expiration_date %]
122
                                                [% hold.expirationdate | $KohaDates %]
122
                                                [% hold.expiration_date | $KohaDates %]
123
                                            [% END %]
123
                                            [% END %]
124
                                        </td>
124
                                        </td>
125
                                        <td data-order="[% hold.waitingdate | html %]">
125
                                        <td data-order="[% hold.waiting_date | html %]">
126
                                            [% IF hold.waitingdate %]
126
                                            [% IF hold.waiting_date %]
127
                                                [% hold.waitingdate | $KohaDates %]
127
                                                [% hold.waiting_date | $KohaDates %]
128
                                            [% END %]
129
                                        </td>
130
                                        <td data-order="[% hold.cancellationdate | html %]">
131
                                            [% IF hold.cancellationdate %]
132
                                                [% hold.cancellationdate | $KohaDates %]
133
                                            [% END %]
128
                                            [% END %]
134
                                        </td>
129
                                        </td>
130
                                        [% IF hold.status == 'cancelled' %]
131
                                            <td data-order="[% hold.completed_date | html %]">
132
                                                [% IF hold.completed_date %]
133
                                                    [% hold.completed_date | $KohaDates %]
134
                                                [% END %]
135
                                            </td>
136
                                        [% ELSE %]
137
                                            <td></td>
138
                                        [% END %]
135
                                        [% IF show_itemtype_column %]
139
                                        [% IF show_itemtype_column %]
136
                                            <td>
140
                                            <td>
137
                                            [% IF hold.itemtype %]
141
                                            [% IF hold.itemtype %]
Lines 142-154 Link Here
142
                                            </td>
146
                                            </td>
143
                                        [% END %]
147
                                        [% END %]
144
                                        <td>
148
                                        <td>
145
                                        [% IF hold.found == 'F' %]
149
                                        [% IF    hold.status == 'fulfilled' %]
146
                                            Fulfilled
150
                                            Fulfilled
147
                                        [% ELSIF hold.cancellationdate %]
151
                                        [% ELSIF hold.status == 'cancelled' %]
148
                                            Cancelled
152
                                            Cancelled
149
                                        [% ELSIF hold.found == 'W' %]
153
                                        [% ELSIF hold.status == 'waiting' %]
150
                                            Waiting
154
                                            Waiting
151
                                        [% ELSIF hold.found == 'T' %]
155
                                        [% ELSIF hold.status == 'in_transit' %]
152
                                            In transit
156
                                            In transit
153
                                        [% ELSE %]
157
                                        [% ELSE %]
154
                                            Pending
158
                                            Pending
(-)a/members/holdshistory.pl (-11 / +1 lines)
Lines 53-59 unless ( $patron ) { Link Here
53
}
53
}
54
54
55
my $holds;
55
my $holds;
56
my $old_holds;
57
56
58
if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){
57
if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){
59
    # use of 'eq' in the above comparison is intentional -- the
58
    # use of 'eq' in the above comparison is intentional -- the
Lines 61-81 if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){ Link Here
61
    $template->param( is_anonymous => 1 );
60
    $template->param( is_anonymous => 1 );
62
} else {
61
} else {
63
    $holds = $patron->holds;
62
    $holds = $patron->holds;
64
    $old_holds = $patron->old_holds;
65
66
    while (my $hold = $holds->next) {
67
        push @all_holds, $hold;
68
    }
69
70
    while (my $hold = $old_holds->next) {
71
        push @all_holds, $hold;
72
    }
73
}
63
}
74
64
75
$template->param(
65
$template->param(
76
    holdshistoryview => 1,
66
    holdshistoryview => 1,
77
    patron           => $patron,
67
    patron           => $patron,
78
    holds            => \@all_holds,
68
    holds            => $holds
79
);
69
);
80
70
81
output_html_with_http_headers $input, $cookie, $template->output;
71
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/misc/cronjobs/thirdparty/TalkingTech_itiva_outbound.pl (-5 / +5 lines)
Lines 314-330 sub GetWaitingHolds { Link Here
314
    my $patron_branchcode_filter = $patron_branchcode ? "AND borrowers.branchcode = '$patron_branchcode'" : q{};
314
    my $patron_branchcode_filter = $patron_branchcode ? "AND borrowers.branchcode = '$patron_branchcode'" : q{};
315
315
316
    my $query = "SELECT borrowers.borrowernumber, borrowers.cardnumber, borrowers.title as patron_title, borrowers.firstname, borrowers.surname, borrowers.categorycode,
316
    my $query = "SELECT borrowers.borrowernumber, borrowers.cardnumber, borrowers.title as patron_title, borrowers.firstname, borrowers.surname, borrowers.categorycode,
317
                borrowers.phone, borrowers.email, borrowers.branchcode, biblio.biblionumber, biblio.title, items.barcode, reserves.waitingdate,
317
                borrowers.phone, borrowers.email, borrowers.branchcode, biblio.biblionumber, biblio.title, items.barcode, holds.waiting_date,
318
                reserves.branchcode AS site, branches.branchname AS site_name,
318
                holds.pickup_library_id AS site, branches.branchname AS site_name,
319
                TO_DAYS(NOW())-TO_DAYS(reserves.waitingdate) AS days_since_waiting
319
                TO_DAYS(NOW())-TO_DAYS(reserves.waitingdate) AS days_since_waiting
320
                FROM borrowers JOIN reserves USING (borrowernumber)
320
                FROM borrowers JOIN holds ON (borrowers.borrowernumber=holds.patron_id)
321
                JOIN items USING (itemnumber)
321
                JOIN items USING (itemnumber)
322
                JOIN biblio ON (biblio.biblionumber = items.biblionumber)
322
                JOIN biblio ON (biblio.biblionumber = items.biblionumber)
323
                JOIN branches ON (reserves.branchcode = branches.branchcode)
323
                JOIN branches ON (holds.pickup_library_id = branches.branchcode)
324
                JOIN borrower_message_preferences USING (borrowernumber)
324
                JOIN borrower_message_preferences USING (borrowernumber)
325
                JOIN borrower_message_transport_preferences USING (borrower_message_preference_id)
325
                JOIN borrower_message_transport_preferences USING (borrower_message_preference_id)
326
                JOIN message_attributes USING (message_attribute_id)
326
                JOIN message_attributes USING (message_attribute_id)
327
                WHERE ( reserves.found = 'W' )
327
                WHERE ( holds.status = 'waiting' )
328
                AND message_transport_type = 'itiva'
328
                AND message_transport_type = 'itiva'
329
                AND message_name = 'Hold_Filled'
329
                AND message_name = 'Hold_Filled'
330
                $patron_branchcode_filter
330
                $patron_branchcode_filter
(-)a/reserve/request.pl (-25 / +36 lines)
Lines 347-355 foreach my $biblionumber (@biblionumbers) { Link Here
347
        # the patron places must be item level
347
        # the patron places must be item level
348
        my $holds = Koha::Holds->search(
348
        my $holds = Koha::Holds->search(
349
            {
349
            {
350
                borrowernumber => $patron->borrowernumber,
350
                patron_id => $patron->borrowernumber,
351
                biblionumber   => $biblionumber,
351
                biblio_id => $biblionumber,
352
                found          => undef,
352
                status    => 'placed',
353
            }
353
            }
354
        );
354
        );
355
        $force_hold_level = $holds->forced_hold_level();
355
        $force_hold_level = $holds->forced_hold_level();
Lines 366-372 foreach my $biblionumber (@biblionumbers) { Link Here
366
    }
366
    }
367
367
368
368
369
    my $count = Koha::Holds->search( { biblionumber => $biblionumber } )->count();
369
    my $count = Koha::Holds->search(
370
        {
371
            biblio_id => $biblionumber,
372
            completed => 0
373
        }
374
    )->count();
370
    my $totalcount = $count;
375
    my $totalcount = $count;
371
376
372
    # FIXME think @optionloop, is maybe obsolete, or  must be switchable by a systeme preference fixed rank or not
377
    # FIXME think @optionloop, is maybe obsolete, or  must be switchable by a systeme preference fixed rank or not
Lines 511-523 foreach my $biblionumber (@biblionumbers) { Link Here
511
            my $item_object = Koha::Items->find( $itemnumber );
516
            my $item_object = Koha::Items->find( $itemnumber );
512
            my $holds = $item_object->current_holds;
517
            my $holds = $item_object->current_holds;
513
            if ( my $first_hold = $holds->next ) {
518
            if ( my $first_hold = $holds->next ) {
514
                my $p = Koha::Patrons->find( $first_hold->borrowernumber );
519
                my $p = Koha::Patrons->find( $first_hold->patron_id );
515
520
516
                $item->{backgroundcolor} = 'reserved';
521
                $item->{backgroundcolor} = 'reserved';
517
                $item->{reservedate}     = output_pref({ dt => dt_from_string( $first_hold->reservedate ), dateonly => 1 }); # FIXME Should be formatted in the template
522
                $item->{reservedate}     = output_pref({ dt => dt_from_string( $first_hold->created_date ), dateonly => 1 }); # FIXME Should be formatted in the template
518
                $item->{ReservedFor}     = $p;
523
                $item->{ReservedFor}     = $p;
519
                $item->{ExpectedAtLibrary}     = $first_hold->branchcode;
524
                $item->{ExpectedAtLibrary}     = $first_hold->pickup_library_id;
520
                $item->{waitingdate} = $first_hold->waitingdate;
525
                $item->{waitingdate} = $first_hold->waiting_date;
521
            }
526
            }
522
527
523
            # Management of the notforloan document
528
            # Management of the notforloan document
Lines 645-651 foreach my $biblionumber (@biblionumbers) { Link Here
645
650
646
    # existingreserves building
651
    # existingreserves building
647
    my @reserveloop;
652
    my @reserveloop;
648
    my @reserves = Koha::Holds->search( { biblionumber => $biblionumber }, { order_by => 'priority' } );
653
    my @reserves = Koha::Holds->search(
654
        {
655
            biblio_id => $biblionumber,
656
            completed => 0
657
        },
658
        { order_by => 'priority' }
659
    );
649
    foreach my $res (
660
    foreach my $res (
650
        sort {
661
        sort {
651
            my $a_found = $a->found() || '';
662
            my $a_found = $a->found() || '';
Lines 671-678 foreach my $biblionumber (@biblionumbers) { Link Here
671
            $reserve{'holdingbranch'} = $res->item()->holdingbranch();
682
            $reserve{'holdingbranch'} = $res->item()->holdingbranch();
672
            $reserve{'biblionumber'}  = $res->item()->biblionumber();
683
            $reserve{'biblionumber'}  = $res->item()->biblionumber();
673
            $reserve{'barcodenumber'} = $res->item()->barcode();
684
            $reserve{'barcodenumber'} = $res->item()->barcode();
674
            $reserve{'wbrcode'}       = $res->branchcode();
685
            $reserve{'wbrcode'}       = $res->pickup_library_id;
675
            $reserve{'itemnumber'}    = $res->itemnumber();
686
            $reserve{'itemnumber'}    = $res->item_id;
676
            $reserve{'wbrname'}       = $res->branch()->branchname();
687
            $reserve{'wbrname'}       = $res->branch()->branchname();
677
            $reserve{'atdestination'} = $res->is_at_destination();
688
            $reserve{'atdestination'} = $res->is_at_destination();
678
            $reserve{'desk_name'}     = ( $res->desk() ) ? $res->desk()->desk_name() : '' ;
689
            $reserve{'desk_name'}     = ( $res->desk() ) ? $res->desk()->desk_name() : '' ;
Lines 688-711 foreach my $biblionumber (@biblionumbers) { Link Here
688
            }
699
            }
689
        }
700
        }
690
701
691
        $reserve{'expirationdate'} = $res->expirationdate;
702
        $reserve{'expirationdate'} = $res->expiration_date;
692
        $reserve{'date'}           = $res->reservedate;
703
        $reserve{'date'}           = $res->created_date;
693
        $reserve{'borrowernumber'} = $res->borrowernumber();
704
        $reserve{'borrowernumber'} = $res->patron_id;
694
        $reserve{'biblionumber'}   = $res->biblionumber();
705
        $reserve{'biblionumber'}   = $res->biblio_id;
695
        $reserve{'patron'}         = $res->borrower;
706
        $reserve{'patron'}         = $res->borrower;
696
        $reserve{'notes'}          = $res->reservenotes();
707
        $reserve{'notes'}          = $res->notes;
697
        $reserve{'waiting_date'}   = $res->waitingdate();
708
        $reserve{'waiting_date'}   = $res->waiting_date;
698
        $reserve{'ccode'}          = $res->item() ? $res->item()->ccode() : undef;
709
        $reserve{'ccode'}          = $res->item() ? $res->item()->ccode() : undef;
699
        $reserve{'barcode'}        = $res->item() ? $res->item()->barcode() : undef;
710
        $reserve{'barcode'}        = $res->item() ? $res->item()->barcode() : undef;
700
        $reserve{'priority'}       = $res->priority();
711
        $reserve{'priority'}       = $res->priority;
701
        $reserve{'lowestPriority'} = $res->lowestPriority();
712
        $reserve{'lowestPriority'} = $res->lowest_priority;
702
        $reserve{'optionloop'}     = \@optionloop;
713
        $reserve{'optionloop'}     = \@optionloop;
703
        $reserve{'suspend'}        = $res->suspend();
714
        $reserve{'suspend'}        = $res->suspended;
704
        $reserve{'suspend_until'}  = $res->suspend_until();
715
        $reserve{'suspend_until'}  = $res->suspended_until_date;
705
        $reserve{'reserve_id'}     = $res->reserve_id();
716
        $reserve{'reserve_id'}     = $res->id;
706
        $reserve{itemtype}         = $res->itemtype();
717
        $reserve{itemtype}         = $res->item_type;
707
        $reserve{branchcode}       = $res->branchcode();
718
        $reserve{branchcode}       = $res->pickup_library_id;
708
        $reserve{non_priority}     = $res->non_priority();
719
        $reserve{non_priority}     = $res->non_priority;
709
        $reserve{object}           = $res;
720
        $reserve{object}           = $res;
710
721
711
        push( @reserveloop, \%reserve );
722
        push( @reserveloop, \%reserve );
(-)a/t/Koha/Exceptions.t (-2 / +2 lines)
Lines 28-39 subtest 'Koha::Exceptions::Hold tests' => sub { Link Here
28
    use_ok('Koha::Exceptions::Hold');
28
    use_ok('Koha::Exceptions::Hold');
29
29
30
    throws_ok
30
    throws_ok
31
        { Koha::Exceptions::Hold::CannotSuspendFound->throw( status => 'W' ); }
31
        { Koha::Exceptions::Hold::CannotSuspendFound->throw( status => 'waiting' ); }
32
        'Koha::Exceptions::Hold::CannotSuspendFound',
32
        'Koha::Exceptions::Hold::CannotSuspendFound',
33
        'Exception is thrown :-D';
33
        'Exception is thrown :-D';
34
34
35
    # stringify the exception
35
    # stringify the exception
36
    is( "$@", 'Found hold cannot be suspended. Status=W', 'Exception stringified correctly' );
36
    is( "$@", 'Found hold cannot be suspended. Status=waiting', 'Exception stringified correctly' );
37
37
38
    throws_ok
38
    throws_ok
39
        { Koha::Exceptions::Hold::CannotSuspendFound->throw( "Manual message exception" ) }
39
        { Koha::Exceptions::Hold::CannotSuspendFound->throw( "Manual message exception" ) }
(-)a/t/Koha/REST/Plugin/Query.t (-2 / +2 lines)
Lines 108-114 get '/dbic_merge_sorting_date' => sub { Link Here
108
    $attributes = $c->dbic_merge_sorting(
108
    $attributes = $c->dbic_merge_sorting(
109
        {
109
        {
110
            attributes => $attributes,
110
            attributes => $attributes,
111
            params     => { _match => 'exact', _order_by => [ '-hold_date' ] },
111
            params     => { _match => 'exact', _order_by => [ '-created_date' ] },
112
            result_set => $result_set
112
            result_set => $result_set
113
        }
113
        }
114
    );
114
    );
Lines 343-349 subtest 'dbic_merge_sorting() tests' => sub { Link Here
343
      ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
343
      ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
344
      ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
344
      ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
345
        '/order_by' => [
345
        '/order_by' => [
346
            { -desc => 'reservedate' }
346
            { -desc => 'created_date' }
347
        ]
347
        ]
348
      );
348
      );
349
349
(-)a/t/db_dependent/Circulation.t (-32 / +31 lines)
Lines 507-513 subtest "CanBookBeRenewed tests" => sub { Link Here
507
    my $expdate        = undef;
507
    my $expdate        = undef;
508
    my $notes          = '';
508
    my $notes          = '';
509
    my $checkitem      = undef;
509
    my $checkitem      = undef;
510
    my $found          = undef;
510
    my $found          = 'placed';
511
511
512
    my $issue = AddIssue( $renewing_borrower, $item_1->barcode);
512
    my $issue = AddIssue( $renewing_borrower, $item_1->barcode);
513
    my $datedue = dt_from_string( $issue->date_due() );
513
    my $datedue = dt_from_string( $issue->date_due() );
Lines 535-542 subtest "CanBookBeRenewed tests" => sub { Link Here
535
            reservation_date => $resdate,
535
            reservation_date => $resdate,
536
            expiration_date  => $expdate,
536
            expiration_date  => $expdate,
537
            notes            => $notes,
537
            notes            => $notes,
538
            itemnumber       => $checkitem,
538
            itemnumber       => $checkitem
539
            found            => $found,
540
        }
539
        }
541
    );
540
    );
542
541
Lines 566-596 subtest "CanBookBeRenewed tests" => sub { Link Here
566
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
565
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
567
566
568
    # Now let's add an item level hold, we should no longer be able to renew the item
567
    # Now let's add an item level hold, we should no longer be able to renew the item
569
    my $hold = Koha::Database->new()->schema()->resultset('Reserve')->create(
568
    my $hold = Koha::Hold->new(
570
        {
569
        {
571
            borrowernumber => $hold_waiting_borrowernumber,
570
            patron_id   => $hold_waiting_borrowernumber,
572
            biblionumber   => $biblio->biblionumber,
571
            biblio_id   => $biblio->biblionumber,
573
            itemnumber     => $item_1->itemnumber,
572
            item_id     => $item_1->itemnumber,
574
            branchcode     => $branch,
573
            pickup_library_id => $branch,
575
            priority       => 3,
574
            priority    => 3,
576
        }
575
        }
577
    );
576
    )->store;
578
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
577
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
579
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
578
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
580
    $hold->delete();
579
    $hold->delete();
581
580
582
    # Now let's add a waiting hold on the 3rd item, it's no longer available tp check out by just anyone, so we should no longer
581
    # Now let's add a waiting hold on the 3rd item, it's no longer available tp check out by just anyone, so we should no longer
583
    # be able to renew these items
582
    # be able to renew these items
584
    $hold = Koha::Database->new()->schema()->resultset('Reserve')->create(
583
    $hold = Koha::Hold->new(
585
        {
584
        {
586
            borrowernumber => $hold_waiting_borrowernumber,
585
            patron_id => $hold_waiting_borrowernumber,
587
            biblionumber   => $biblio->biblionumber,
586
            biblio_id   => $biblio->biblionumber,
588
            itemnumber     => $item_3->itemnumber,
587
            item_id     => $item_3->itemnumber,
589
            branchcode     => $branch,
588
            pickup_library_id     => $branch,
590
            priority       => 0,
589
            priority       => 0,
591
            found          => 'W'
590
            status          => 'waiting'
592
        }
591
        }
593
    );
592
    )->store;
594
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
593
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
595
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
594
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
596
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
595
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
Lines 605-619 subtest "CanBookBeRenewed tests" => sub { Link Here
605
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
604
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
606
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
605
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
607
606
608
    my $reserveid = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $reserving_borrowernumber })->next->reserve_id;
607
    my $reserveid = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $reserving_borrowernumber })->next->id;
609
    my $reserving_borrower = Koha::Patrons->find( $reserving_borrowernumber )->unblessed;
608
    my $reserving_borrower = Koha::Patrons->find( $reserving_borrowernumber )->unblessed;
610
    AddIssue($reserving_borrower, $item_3->barcode);
609
    AddIssue($reserving_borrower, $item_3->barcode);
611
    my $reserve = $dbh->selectrow_hashref(
610
    my $reserve = $dbh->selectrow_hashref(
612
        'SELECT * FROM old_reserves WHERE reserve_id = ?',
611
        'SELECT * FROM holds WHERE id = ? AND completed = 1',
613
        { Slice => {} },
612
        { Slice => {} },
614
        $reserveid
613
        $reserveid
615
    );
614
    );
616
    is($reserve->{found}, 'F', 'hold marked completed when checking out item that fills it');
615
    is($reserve->{status}, 'fulfilled', 'hold marked completed when checking out item that fills it');
617
616
618
    # Item-level hold, renewal test
617
    # Item-level hold, renewal test
619
    AddReserve(
618
    AddReserve(
Lines 775-781 subtest "CanBookBeRenewed tests" => sub { Link Here
775
    $fines = Koha::Account::Lines->search( { borrowernumber => $renewing_borrower->{borrowernumber}, itemnumber => $item_7->itemnumber } );
774
    $fines = Koha::Account::Lines->search( { borrowernumber => $renewing_borrower->{borrowernumber}, itemnumber => $item_7->itemnumber } );
776
    $fines->delete();
775
    $fines->delete();
777
776
778
    $hold = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $reserving_borrowernumber })->next;
777
    $hold = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $reserving_borrowernumber })->next;
779
    $hold->cancel;
778
    $hold->cancel;
780
779
781
    # Bug 14101
780
    # Bug 14101
Lines 3450-3456 subtest 'Set waiting flag' => sub { Link Here
3450
    my ( $res, $rr ) = AddReturn( $item->barcode, $library_1->{branchcode} );
3449
    my ( $res, $rr ) = AddReturn( $item->barcode, $library_1->{branchcode} );
3451
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3450
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3452
    my $hold = Koha::Holds->find( $reserve_id );
3451
    my $hold = Koha::Holds->find( $reserve_id );
3453
    is( $hold->found, 'T', 'Hold is in transit' );
3452
    is( $hold->status, 'in_transit', 'Hold is in transit' );
3454
3453
3455
    my ( $status ) = CheckReserves($item->itemnumber);
3454
    my ( $status ) = CheckReserves($item->itemnumber);
3456
    is( $status, 'Transferred', 'Hold is not waiting yet');
3455
    is( $status, 'Transferred', 'Hold is not waiting yet');
Lines 3460-3466 subtest 'Set waiting flag' => sub { Link Here
3460
    AddReturn( $item->barcode, $library_2->{branchcode} );
3459
    AddReturn( $item->barcode, $library_2->{branchcode} );
3461
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3460
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3462
    $hold = Koha::Holds->find( $reserve_id );
3461
    $hold = Koha::Holds->find( $reserve_id );
3463
    is( $hold->found, 'W', 'Hold is waiting' );
3462
    is( $hold->status, 'waiting', 'Hold is waiting' );
3464
    ( $status ) = CheckReserves($item->itemnumber);
3463
    ( $status ) = CheckReserves($item->itemnumber);
3465
    is( $status, 'Waiting', 'Now the hold is waiting');
3464
    is( $status, 'Waiting', 'Now the hold is waiting');
3466
3465
Lines 3468-3479 subtest 'Set waiting flag' => sub { Link Here
3468
    set_userenv( $library_1 );
3467
    set_userenv( $library_1 );
3469
    (undef, my $messages, undef, undef ) = AddReturn ( $item->barcode, $library_1->{branchcode} );
3468
    (undef, my $messages, undef, undef ) = AddReturn ( $item->barcode, $library_1->{branchcode} );
3470
    $hold = Koha::Holds->find( $reserve_id );
3469
    $hold = Koha::Holds->find( $reserve_id );
3471
    is( $hold->found, undef, 'Hold is no longer marked waiting' );
3470
    is( $hold->status, 'placed', 'Hold is no longer marked waiting' );
3472
    is( $hold->priority, 1,  "Hold is now priority one again");
3471
    is( $hold->priority, 1,  "Hold is now priority one again");
3473
    is( $hold->waitingdate, undef, "Hold no longer has a waiting date");
3472
    is( $hold->waiting_date, undef, "Hold no longer has a waiting date");
3474
    is( $hold->itemnumber, $item->itemnumber, "Hold has retained its' itemnumber");
3473
    is( $hold->item_id, $item->itemnumber, "Hold has retained its' itemnumber");
3475
    is( $messages->{ResFound}->{ResFound}, "Reserved", "Hold is still returned");
3474
    is( $messages->{ResFound}->{ResFound}, "Reserved", "Hold is still returned");
3476
    is( $messages->{ResFound}->{found}, undef, "Hold is no longer marked found in return message");
3475
    is( $messages->{ResFound}->{status}, 'placed', "Hold is no longer marked found in return message");
3477
    is( $messages->{ResFound}->{priority}, 1, "Hold is priority 1 in return message");
3476
    is( $messages->{ResFound}->{priority}, 1, "Hold is priority 1 in return message");
3478
};
3477
};
3479
3478
Lines 4331-4343 subtest 'Filling a hold should cancel existing transfer' => sub { Link Here
4331
        biblionumber   => $item->biblionumber,
4330
        biblionumber   => $item->biblionumber,
4332
        itemnumber     => $item->itemnumber
4331
        itemnumber     => $item->itemnumber
4333
    });
4332
    });
4334
    my $reserves = Koha::Holds->search({ itemnumber => $item->itemnumber });
4333
    my $reserves = Koha::Holds->search({ item_id => $item->itemnumber });
4335
    is( $reserves->count, 1, "Reserve is placed");
4334
    is( $reserves->count, 1, "Reserve is placed");
4336
    ( undef, $message ) = AddReturn( $item->barcode, $libraryA->branchcode, undef, undef );
4335
    ( undef, $message ) = AddReturn( $item->barcode, $libraryA->branchcode, undef, undef );
4337
    my $reserve = $reserves->next;
4336
    my $reserve = $reserves->next;
4338
    ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 0, $reserve->reserve_id );
4337
    ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 0, $reserve->id );
4339
    $reserve->discard_changes;
4338
    $reserve->discard_changes;
4340
    ok( $reserve->found eq 'W', "Reserve is marked waiting" );
4339
    ok( $reserve->status eq 'waiting', "Reserve is marked waiting" );
4341
    is( Koha::Item::Transfers->search({ itemnumber => $item->itemnumber, datearrived => undef })->count, 0, "No outstanding transfers when hold is waiting");
4340
    is( Koha::Item::Transfers->search({ itemnumber => $item->itemnumber, datearrived => undef })->count, 0, "No outstanding transfers when hold is waiting");
4342
};
4341
};
4343
4342
Lines 4794-4800 subtest 'Checkout should correctly terminate a transfer' => sub { Link Here
4794
    GetOtherReserves( $item->itemnumber )
4793
    GetOtherReserves( $item->itemnumber )
4795
      ;    # To put the Reason, it's what does returns.pl...
4794
      ;    # To put the Reason, it's what does returns.pl...
4796
    my $hold = Koha::Holds->find($reserve_id);
4795
    my $hold = Koha::Holds->find($reserve_id);
4797
    is( $hold->found, 'T', 'Hold is in transit' );
4796
    is( $hold->status, 'in_transit', 'Hold is in transit' );
4798
    my $transfer = $item->get_transfer;
4797
    my $transfer = $item->get_transfer;
4799
    is( $transfer->frombranch, $library_1->branchcode );
4798
    is( $transfer->frombranch, $library_1->branchcode );
4800
    is( $transfer->tobranch,   $library_2->branchcode );
4799
    is( $transfer->tobranch,   $library_2->branchcode );
Lines 4805-4811 subtest 'Checkout should correctly terminate a transfer' => sub { Link Here
4805
    $transfer = $transfer->get_from_storage;
4804
    $transfer = $transfer->get_from_storage;
4806
    isnt( $transfer->datearrived, undef );
4805
    isnt( $transfer->datearrived, undef );
4807
    $hold = $hold->get_from_storage;
4806
    $hold = $hold->get_from_storage;
4808
    is( $hold->found, undef, 'Hold is waiting' );
4807
    is( $hold->status, 'placed', 'Hold is waiting' );
4809
    is( $hold->priority, 1, );
4808
    is( $hold->priority, 1, );
4810
};
4809
};
4811
4810
(-)a/t/db_dependent/Circulation/issue.t (-3 / +2 lines)
Lines 68-75 $dbh->do(q|DELETE FROM borrowers|); Link Here
68
$dbh->do(q|DELETE FROM categories|);
68
$dbh->do(q|DELETE FROM categories|);
69
$dbh->do(q|DELETE FROM accountlines|);
69
$dbh->do(q|DELETE FROM accountlines|);
70
$dbh->do(q|DELETE FROM circulation_rules|);
70
$dbh->do(q|DELETE FROM circulation_rules|);
71
$dbh->do(q|DELETE FROM reserves|);
71
$dbh->do(q|DELETE FROM holds|);
72
$dbh->do(q|DELETE FROM old_reserves|);
73
$dbh->do(q|DELETE FROM statistics|);
72
$dbh->do(q|DELETE FROM statistics|);
74
73
75
# Generate sample datas
74
# Generate sample datas
Lines 484-490 my $reserve_id = AddReserve( Link Here
484
ok( $reserve_id, 'The reserve should have been inserted' );
483
ok( $reserve_id, 'The reserve should have been inserted' );
485
AddIssue( $borrower_2, $barcode_1, dt_from_string, 'cancel' );
484
AddIssue( $borrower_2, $barcode_1, dt_from_string, 'cancel' );
486
my $hold = Koha::Holds->find( $reserve_id );
485
my $hold = Koha::Holds->find( $reserve_id );
487
is( $hold, undef, 'The reserve should have been correctly cancelled' );
486
is( $hold->status, 'cancelled', 'The reserve should have been correctly cancelled' );
488
487
489
# Unseen rewnewals
488
# Unseen rewnewals
490
t::lib::Mocks::mock_preference('UnseenRenewals', 1);
489
t::lib::Mocks::mock_preference('UnseenRenewals', 1);
(-)a/t/db_dependent/DecreaseLoanHighHolds.t (-9 / +9 lines)
Lines 88-103 for my $i ( 0 .. 5 ) { Link Here
88
    my $patron = $patrons[$i];
88
    my $patron = $patrons[$i];
89
    my $hold   = Koha::Hold->new(
89
    my $hold   = Koha::Hold->new(
90
        {
90
        {
91
            borrowernumber => $patron->id,
91
            patron_id => $patron->id,
92
            biblionumber   => $biblio->id,
92
            biblio_id   => $biblio->id,
93
            branchcode     => $library->{branchcode},
93
            pickup_library_id     => $library->{branchcode},
94
        }
94
        }
95
    )->store();
95
    )->store();
96
}
96
}
97
97
98
my $item   = shift(@items);
98
my $item   = shift(@items);
99
my $patron = shift(@patrons);
99
my $patron = shift(@patrons);
100
my $patron_hold = Koha::Holds->find({ borrowernumber => $patron->borrowernumber, biblionumber => $item->biblionumber });
100
my $patron_hold = Koha::Holds->find({ patron_id => $patron->borrowernumber, biblio_id => $item->biblionumber });
101
101
102
Koha::CirculationRules->set_rules(
102
Koha::CirculationRules->set_rules(
103
    {
103
    {
Lines 169-177 for my $i ( 5 .. 10 ) { Link Here
169
    my $patron = $patrons[$i];
169
    my $patron = $patrons[$i];
170
    my $hold   = Koha::Hold->new(
170
    my $hold   = Koha::Hold->new(
171
        {
171
        {
172
            borrowernumber => $patron->id,
172
            patron_id         => $patron->id,
173
            biblionumber   => $biblio->id,
173
            biblio_id         => $biblio->id,
174
            branchcode     => $library->{branchcode},
174
            pickup_library_id => $library->{branchcode},
175
        }
175
        }
176
    )->store();
176
    )->store();
177
}
177
}
Lines 218-228 $unholdable->store(); Link Here
218
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
218
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
219
is( $data->{exceeded}, 1, "Should exceed threshold with one withdrawn item" );
219
is( $data->{exceeded}, 1, "Should exceed threshold with one withdrawn item" );
220
220
221
$patron_hold->found('F')->store;
221
$patron_hold->set_waiting();
222
# 11 holds, threshold is 2 over 9 holdable items = 11
222
# 11 holds, threshold is 2 over 9 holdable items = 11
223
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
223
$data = C4::Circulation::checkHighHolds( $item_hr, $patron_hr );
224
is( $data->{exceeded}, 1, "Should exceed threshold with one withdrawn item" );
224
is( $data->{exceeded}, 1, "Should exceed threshold with one withdrawn item" );
225
$patron_hold->found(undef)->store;
225
$patron_hold->status('placed')->store;
226
226
227
t::lib::Mocks::mock_preference('CircControl', 'PatronLibrary');
227
t::lib::Mocks::mock_preference('CircControl', 'PatronLibrary');
228
228
(-)a/t/db_dependent/Hold.t (-75 / +86 lines)
Lines 66-78 $item->store(); Link Here
66
66
67
my $hold = Koha::Hold->new(
67
my $hold = Koha::Hold->new(
68
    {
68
    {
69
        biblionumber   => $biblionumber,
69
        biblio_id      => $biblionumber,
70
        itemnumber     => $item->id(),
70
        item_id        => $item->id(),
71
        reservedate    => '2017-01-01',
71
        created_date   => '2017-01-01',
72
        waitingdate    => '2000-01-01',
72
        waiting_date   => '2000-01-01',
73
        borrowernumber => $borrower->{borrowernumber},
73
        patron_id      => $borrower->{borrowernumber},
74
        branchcode     => $branches[1]->{branchcode},
74
        pickup_library_id => $branches[1]->{branchcode},
75
        suspend        => 0,
75
        suspended      => 0,
76
        status         => 'placed'
76
    }
77
    }
77
);
78
);
78
$hold->store();
79
$hold->store();
Lines 83-104 my $today = dt_from_string; Link Here
83
is( $hold->age(), $today->delta_days( dt_from_string( '2017-01-01' ) )->in_units( 'days')  , "Age of hold is days from reservedate to now if calendar ignored");
84
is( $hold->age(), $today->delta_days( dt_from_string( '2017-01-01' ) )->in_units( 'days')  , "Age of hold is days from reservedate to now if calendar ignored");
84
is( $hold->age(1), $today->delta_days( dt_from_string( '2017-01-01' ) )->in_units( 'days' ) - 1 , "Age of hold is days from reservedate to now minus 1 if calendar used");
85
is( $hold->age(1), $today->delta_days( dt_from_string( '2017-01-01' ) )->in_units( 'days' ) - 1 , "Age of hold is days from reservedate to now minus 1 if calendar used");
85
86
86
is( $hold->suspend, 0, "Hold is not suspended" );
87
is( $hold->suspended, 0, "Hold is not suspended" );
87
$hold->suspend_hold();
88
$hold->suspend_hold();
88
is( $hold->suspend, 1, "Hold is suspended" );
89
is( $hold->suspended, 1, "Hold is suspended" );
89
$hold->resume();
90
$hold->resume();
90
is( $hold->suspend, 0, "Hold is not suspended" );
91
is( $hold->suspended, 0, "Hold is not suspended" );
91
my $dt = dt_from_string();
92
my $dt = dt_from_string();
92
$hold->suspend_hold( $dt );
93
$hold->suspend_hold( $dt );
93
$dt->truncate( to => 'day' );
94
$dt->truncate( to => 'day' );
94
is( $hold->suspend, 1, "Hold is suspended" );
95
is( $hold->suspended, 1, "Hold is suspended" );
95
is( $hold->suspend_until, "$dt", "Hold is suspended with a date, truncation takes place automatically" );
96
is( $hold->suspended_until_date, "$dt", "Hold is suspended with a date, truncation takes place automatically" );
96
$hold->suspend_hold;
97
$hold->suspend_hold;
97
is( $hold->suspend, 1, "Hold is suspended" );
98
is( $hold->suspended, 1, "Hold is suspended" );
98
is( $hold->suspend_until, undef, "Hold is suspended without a date" );
99
is( $hold->suspended_until_date, undef, "Hold is suspended without a date" );
99
$hold->resume();
100
$hold->resume();
100
is( $hold->suspend, 0, "Hold is not suspended" );
101
is( $hold->suspended, 0, "Hold is not suspended" );
101
is( $hold->suspend_until, undef, "Hold no longer has suspend_until date" );
102
is( $hold->suspended_until_date, undef, "Hold no longer has suspend_until date" );
102
103
103
$item = $hold->item();
104
$item = $hold->item();
104
105
Lines 107-143 ok( $hold_borrower, 'Got hold borrower' ); Link Here
107
is( $hold_borrower->borrowernumber(), $borrower->{borrowernumber}, 'Hold borrower matches correct borrower' );
108
is( $hold_borrower->borrowernumber(), $borrower->{borrowernumber}, 'Hold borrower matches correct borrower' );
108
109
109
t::lib::Mocks::mock_preference( 'ReservesMaxPickUpDelay', '5' );
110
t::lib::Mocks::mock_preference( 'ReservesMaxPickUpDelay', '5' );
110
$hold->found('T');
111
$hold->status('in_transit');
111
isnt( $hold->is_waiting, 1, 'The hold is not waiting (T)' );
112
isnt( $hold->is_waiting, 1, 'The hold is not waiting (T)' );
112
is( $hold->is_found, 1, 'The hold is found');
113
is( $hold->is_found, 1, 'The hold is found');
113
is( $hold->is_in_transit, 1, 'The hold is in transit' );
114
is( $hold->is_in_transit, 1, 'The hold is in transit' );
114
115
115
$hold->found('P');
116
$hold->status('processing');
116
is( $hold->is_found, 1, 'The hold is found');
117
is( $hold->is_found, 1, 'The hold is found');
117
is( $hold->is_in_processing, 1, 'The hold is in processing' );
118
is( $hold->is_in_processing, 1, 'The hold is in processing' );
118
119
119
$hold->found(q{});
120
$hold->status('placed');
120
isnt( $hold->is_waiting, 1, 'The hold is not waiting (W)' );
121
isnt( $hold->is_waiting, 1, 'The hold is not waiting (W)' );
121
is( $hold->is_found, 0, 'The hold is not found' );
122
is( $hold->is_found, 0, 'The hold is not found' );
122
ok( !$hold->is_in_transit, 'The hold is not in transit' );
123
ok( !$hold->is_in_transit, 'The hold is not in transit' );
123
ok( !$hold->is_in_processing, 'The hold is not in processing' );
124
ok( !$hold->is_in_processing, 'The hold is not in processing' );
124
125
125
# Test method is_cancelable_from_opac
126
# Test method is_cancelable_from_opac
126
$hold->found(undef);
127
$hold->status('placed');
127
is( $hold->is_cancelable_from_opac, 1, "Unfound hold is cancelable" );
128
is( $hold->is_cancelable_from_opac, 1, "Unfound hold is cancelable" );
128
$hold->found('W');
129
$hold->status('waiting');
129
is( $hold->is_cancelable_from_opac, 0, "Waiting hold is not cancelable" );
130
is( $hold->is_cancelable_from_opac, 0, "Waiting hold is not cancelable" );
130
$hold->found('T');
131
$hold->status('in_transit');
131
is( $hold->is_cancelable_from_opac, 0, "In transit hold is not cancelable" );
132
is( $hold->is_cancelable_from_opac, 0, "In transit hold is not cancelable" );
132
$hold->found('P');
133
$hold->status('processing');
133
is( $hold->is_cancelable_from_opac, 0, "In processing hold is not cancelable" );
134
is( $hold->is_cancelable_from_opac, 0, "In processing hold is not cancelable" );
134
135
135
# Test method is_at_destination
136
# Test method is_at_destination
136
$hold->found(undef);
137
$hold->status('placed');
137
ok( !$hold->is_at_destination(), "Unfound hold cannot be at destination" );
138
ok( !$hold->is_at_destination(), "Unfound hold cannot be at destination" );
138
$hold->found('T');
139
$hold->status('in_transit');
139
ok( !$hold->is_at_destination(), "In transit hold cannot be at destination" );
140
ok( !$hold->is_at_destination(), "In transit hold cannot be at destination" );
140
$hold->found('W');
141
$hold->status('waiting');
141
ok( !$hold->is_at_destination(), "Waiting hold where hold branchcode is not the same as the item's holdingbranch is not at destination" );
142
ok( !$hold->is_at_destination(), "Waiting hold where hold branchcode is not the same as the item's holdingbranch is not at destination" );
142
$item->holdingbranch( $branches[1]->{branchcode} );
143
$item->holdingbranch( $branches[1]->{branchcode} );
143
ok( $hold->is_at_destination(), "Waiting hold where hold branchcode is the same as the item's holdingbranch is at destination" );
144
ok( $hold->is_at_destination(), "Waiting hold where hold branchcode is the same as the item's holdingbranch is at destination" );
Lines 162-225 subtest "store() tests" => sub { Link Here
162
        'years' );
163
        'years' );
163
164
164
    my $hold = Koha::Hold->new(
165
    my $hold = Koha::Hold->new(
165
        {
166
        {   biblio_id         => $biblio->biblionumber,
166
            biblionumber   => $biblio->biblionumber,
167
            item_id           => $item->id,
167
            itemnumber     => $item->id,
168
            created_date      => '2020-11-30',
168
            reservedate    => '2020-11-30',
169
            waiting_date      => '2020-11-30',
169
            waitingdate    => '2020-11-30',
170
            patron_id         => $borrower->borrowernumber,
170
            borrowernumber => $borrower->borrowernumber,
171
            pickup_library_id => $library->branchcode,
171
            branchcode     => $library->branchcode,
172
            suspended         => 0,
172
            suspend        => 0,
173
        }
173
        }
174
    )->store;
174
    )->store;
175
    $hold->discard_changes;
175
    $hold->discard_changes;
176
176
177
    my $expected_date =
177
    my $expected_date =
178
      dt_from_string( $hold->reservedate )->add( years => 2 );
178
      dt_from_string( $hold->created_date )->add( years => 2 );
179
    is( $hold->expirationdate,
179
    is( $hold->expiration_date,
180
        $expected_date->ymd, 'Default expiration date for new hold is correctly set.' );
180
        $expected_date->ymd, 'Default expiration date for new hold is correctly set.' );
181
181
182
    my $passed_date =
182
    my $passed_date =
183
      dt_from_string( $hold->reservedate )->add( months => 2 );
183
      dt_from_string( $hold->created_date )->add( months => 2 );
184
    $hold = Koha::Hold->new(
184
    $hold = Koha::Hold->new(
185
        {
185
        {   biblio_id         => $biblio->biblionumber,
186
            biblionumber   => $biblio->biblionumber,
186
            item_id           => $item->id,
187
            itemnumber     => $item->id,
187
            created_date      => '2020-11-30',
188
            reservedate    => '2020-11-30',
188
            expiration_date   => $passed_date->ymd,
189
            expirationdate => $passed_date->ymd,
189
            waiting_date      => '2020-11-30',
190
            waitingdate    => '2020-11-30',
190
            patron_id         => $borrower->borrowernumber,
191
            borrowernumber => $borrower->borrowernumber,
191
            pickup_library_id => $library->branchcode,
192
            branchcode     => $library->branchcode,
192
            suspended         => 0,
193
            suspend        => 0,
194
        }
193
        }
195
    )->store;
194
    )->store;
196
    $hold->discard_changes;
195
    $hold->discard_changes;
197
196
198
    is( $hold->expirationdate,
197
    is( $hold->expiration_date,
199
        $passed_date->ymd, 'Passed expiration date for new hold is correctly set.' );
198
        $passed_date->ymd, 'Passed expiration date for new hold is correctly set.' );
200
199
201
    $passed_date->add( months => 1 );
200
    $passed_date->add( months => 1 );
202
    $hold->expirationdate($passed_date->ymd)->store();
201
    $hold->expiration_date($passed_date->ymd)->store();
203
    $hold->discard_changes;
202
    $hold->discard_changes;
204
203
205
    is( $hold->expirationdate,
204
    is( $hold->expiration_date,
206
        $passed_date->ymd, 'Passed expiration date when updating hold is correctly set.' );
205
        $passed_date->ymd, 'Passed expiration date when updating hold is correctly set.' );
207
206
208
    $hold->reservedate($passed_date->ymd)->store();
207
    $hold->created_date($passed_date->ymd)->store();
209
    $hold->discard_changes;
208
    $hold->discard_changes;
210
209
211
    is( $hold->expirationdate,
210
    is( $hold->expiration_date,
212
        $passed_date->add( years => 2 )->ymd, 'Default expiration date correctly set on reservedate update.' );
211
        $passed_date->add( years => 2 )->ymd, 'Default expiration date correctly set on reservedate update.' );
213
212
214
    $hold->set(
213
    $hold->set(
215
        {
214
        {
216
            reservedate    => $passed_date->ymd,
215
            created_date    => $passed_date->ymd,
217
            expirationdate => $passed_date->add( weeks => 2 )->ymd
216
            expiration_date => $passed_date->add( weeks => 2 )->ymd
218
        }
217
        }
219
    )->store();
218
    )->store();
220
    $hold->discard_changes;
219
    $hold->discard_changes;
221
220
222
    is( $hold->expirationdate,
221
    is( $hold->expiration_date,
223
        $passed_date->ymd, 'Passed expiration date when updating hold correctly set (Passing both reservedate and expirationdate.' );
222
        $passed_date->ymd, 'Passed expiration date when updating hold correctly set (Passing both reservedate and expirationdate.' );
224
223
225
    $schema->storage->txn_rollback();
224
    $schema->storage->txn_rollback();
Lines 234-264 subtest "delete() tests" => sub { Link Here
234
    # Disable logging
233
    # Disable logging
235
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
234
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
236
235
237
    my $hold = $builder->build({ source => 'Reserve' });
236
    my $hold    = $builder->build_object({ class => 'Koha::Holds' });
237
    my $hold_id = $hold->id;
238
    my $deleted = $hold->delete;
238
239
239
    my $hold_object = Koha::Holds->find( $hold->{ reserve_id } );
240
    my $deleted = $hold_object->delete;
241
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return the Koha::Hold object if the hold has been correctly deleted' );
240
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return the Koha::Hold object if the hold has been correctly deleted' );
242
    is( Koha::Holds->search({ reserve_id => $hold->{ reserve_id } })->count, 0,
241
    is( Koha::Holds->search({ id => $hold_id })->count, 0,
243
        "Koha::Hold->delete should have deleted the hold" );
242
        "Koha::Hold->delete should have deleted the hold" );
244
243
245
    my $number_of_logs = $schema->resultset('ActionLog')->search(
244
    my $number_of_logs = $schema->resultset('ActionLog')->search(
246
            { module => 'HOLDS', action => 'DELETE', object => $hold->{ reserve_id } } )->count;
245
            { module => 'HOLDS', action => 'DELETE', object => $hold_id } )->count;
247
    is( $number_of_logs, 0, 'With HoldsLogs, Koha::Hold->delete shouldn\'t have been logged' );
246
    is( $number_of_logs, 0, 'With HoldsLogs, Koha::Hold->delete shouldn\'t have been logged' );
248
247
249
    # Enable logging
248
    # Enable logging
250
    t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
249
    t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
251
250
252
    $hold = $builder->build({ source => 'Reserve' });
251
    $hold    = $builder->build_object({ class => 'Koha::Holds' });
252
    $hold_id = $hold->id;
253
    $deleted = $hold->delete;
253
254
254
    $hold_object = Koha::Holds->find( $hold->{ reserve_id } );
255
    $deleted = $hold_object->delete;
256
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return a Koha::Hold object if the hold has been correctly deleted' );
255
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return a Koha::Hold object if the hold has been correctly deleted' );
257
    is( Koha::Holds->search({ reserve_id => $hold->{ reserve_id } })->count, 0,
256
    is( Koha::Holds->search({ id => $hold_id })->count, 0,
258
        "Koha::Hold->delete should have deleted the hold" );
257
        "Koha::Hold->delete should have deleted the hold" );
259
258
260
    $number_of_logs = $schema->resultset('ActionLog')->search(
259
    $number_of_logs = $schema->resultset('ActionLog')->search(
261
            { module => 'HOLDS', action => 'DELETE', object => $hold->{ reserve_id } } )->count;
260
            { module => 'HOLDS', action => 'DELETE', object => $hold_id } )->count;
262
    is( $number_of_logs, 1, 'With HoldsLogs, Koha::Hold->delete should have been logged' );
261
    is( $number_of_logs, 1, 'With HoldsLogs, Koha::Hold->delete should have been logged' );
263
262
264
    $schema->storage->txn_rollback();
263
    $schema->storage->txn_rollback();
Lines 274-281 subtest 'suspend() tests' => sub { Link Here
274
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
273
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
275
274
276
    my $hold = $builder->build_object(
275
    my $hold = $builder->build_object(
277
        {   class => 'Koha::Holds',
276
        {
278
            value => { found => undef, suspend => 0, suspend_until => undef, waitingdate => undef }
277
            class => 'Koha::Holds',
278
            value => {
279
                status               => 'placed',
280
                suspended            => 0,
281
                suspended_until_date => undef,
282
                waiting_date         => undef
283
            }
279
        }
284
        }
280
    );
285
    );
281
286
Lines 284-290 subtest 'suspend() tests' => sub { Link Here
284
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
289
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
285
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
290
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
286
    ok( $suspended->is_suspended, 'The hold is suspended' );
291
    ok( $suspended->is_suspended, 'The hold is suspended' );
287
    is( $suspended->suspend_until, undef, 'It is an indefinite suspension' );
292
    is( $suspended->suspended_until_date, undef, 'It is an indefinite suspension' );
288
293
289
    # resume the hold
294
    # resume the hold
290
    $suspended->resume;
295
    $suspended->resume;
Lines 296-302 subtest 'suspend() tests' => sub { Link Here
296
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
301
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
297
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
302
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
298
    ok( $suspended->is_suspended, 'The hold is suspended' );
303
    ok( $suspended->is_suspended, 'The hold is suspended' );
299
    is( $suspended->suspend_until, $date->truncate( to => 'day' ), 'It is an indefinite suspension' );
304
    is( $suspended->suspended_until_date, $date->truncate( to => 'day' ), 'It is an indefinite suspension' );
300
305
301
    # resume the hold
306
    # resume the hold
302
    $suspended->resume;
307
    $suspended->resume;
Lines 309-315 subtest 'suspend() tests' => sub { Link Here
309
        'Koha::Exceptions::Hold::CannotSuspendFound',
314
        'Koha::Exceptions::Hold::CannotSuspendFound',
310
        'Exception is thrown when a found hold is tried to suspend';
315
        'Exception is thrown when a found hold is tried to suspend';
311
316
312
    is( $@->status, 'W', 'Exception gets the \'status\' parameter set correctly' );
317
    is( $@->status, 'waiting', 'Exception gets the \'status\' parameter set correctly' );
313
318
314
    # set hold found=T
319
    # set hold found=T
315
    $hold->set_transfer;
320
    $hold->set_transfer;
Lines 318-324 subtest 'suspend() tests' => sub { Link Here
318
        'Koha::Exceptions::Hold::CannotSuspendFound',
323
        'Koha::Exceptions::Hold::CannotSuspendFound',
319
        'Exception is thrown when a found hold is tried to suspend';
324
        'Exception is thrown when a found hold is tried to suspend';
320
325
321
    is( $@->status, 'T', 'Exception gets the \'status\' parameter set correctly' );
326
    is( $@->status, 'in_transit', 'Exception gets the \'status\' parameter set correctly' );
322
327
323
    # set hold found=T
328
    # set hold found=T
324
    $hold->set_processing();
329
    $hold->set_processing();
Lines 333-339 subtest 'suspend() tests' => sub { Link Here
333
    $holds_module->mock( 'is_found', 1 );
338
    $holds_module->mock( 'is_found', 1 );
334
339
335
    # bad data case
340
    # bad data case
336
    $hold->found('X');
341
    $hold->status('cancelled');
337
    throws_ok
342
    throws_ok
338
        { $hold->suspend_hold }
343
        { $hold->suspend_hold }
339
        'Koha::Exceptions::Hold::CannotSuspendFound',
344
        'Koha::Exceptions::Hold::CannotSuspendFound',
Lines 341-348 subtest 'suspend() tests' => sub { Link Here
341
346
342
    is( $@->error, 'Unhandled data exception on found hold (id='
347
    is( $@->error, 'Unhandled data exception on found hold (id='
343
                    . $hold->id
348
                    . $hold->id
344
                    . ', found='
349
                    . ', status='
345
                    . $hold->found
350
                    . $hold->status
346
                    . ')' , 'Exception gets the \'status\' parameter set correctly' );
351
                    . ')' , 'Exception gets the \'status\' parameter set correctly' );
347
352
348
    $holds_module->unmock( 'is_found' );
353
    $holds_module->unmock( 'is_found' );
Lines 354-361 subtest 'suspend() tests' => sub { Link Here
354
            { module => 'HOLDS', action => 'SUSPEND', object => $hold->id } )->count;
359
            { module => 'HOLDS', action => 'SUSPEND', object => $hold->id } )->count;
355
360
356
    $hold = $builder->build_object(
361
    $hold = $builder->build_object(
357
        {   class => 'Koha::Holds',
362
        {
358
            value => { suspend => 0, suspend_until => undef, waitingdate => undef, found => undef }
363
            class => 'Koha::Holds',
364
            value => {
365
                suspended            => 0,
366
                suspended_until_date => undef,
367
                waiting_date         => undef,
368
                status               => 'placed'
369
            }
359
        }
370
        }
360
    );
371
    );
361
372
(-)a/t/db_dependent/Holds.t (-53 / +55 lines)
Lines 48-54 my $category = $builder->build({ source => 'Category' }); Link Here
48
my $borrowers_count = 5;
48
my $borrowers_count = 5;
49
49
50
$dbh->do('DELETE FROM itemtypes');
50
$dbh->do('DELETE FROM itemtypes');
51
$dbh->do('DELETE FROM reserves');
51
$dbh->do('DELETE FROM holds');
52
$dbh->do('DELETE FROM circulation_rules');
52
$dbh->do('DELETE FROM circulation_rules');
53
my $insert_sth = $dbh->prepare('INSERT INTO itemtypes (itemtype) VALUES (?)');
53
my $insert_sth = $dbh->prepare('INSERT INTO itemtypes (itemtype) VALUES (?)');
54
$insert_sth->execute('CAN');
54
$insert_sth->execute('CAN');
Lines 98-107 is( $holds->next->priority, 5, "Reserve 5 has a priority of 5" ); Link Here
98
my $item = Koha::Items->find( $itemnumber );
98
my $item = Koha::Items->find( $itemnumber );
99
$holds = $item->current_holds;
99
$holds = $item->current_holds;
100
my $first_hold = $holds->next;
100
my $first_hold = $holds->next;
101
my $reservedate = $first_hold->reservedate;
101
my $reservedate = $first_hold->created_date;
102
my $borrowernumber = $first_hold->borrowernumber;
102
my $borrowernumber = $first_hold->patron_id;
103
my $branch_1code = $first_hold->branchcode;
103
my $branch_1code = $first_hold->pickup_library_id;
104
my $reserve_id = $first_hold->reserve_id;
104
my $reserve_id = $first_hold->id;
105
is( $reservedate, output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 }), "holds_placed_today should return a valid reserve date");
105
is( $reservedate, output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 }), "holds_placed_today should return a valid reserve date");
106
is( $borrowernumber, $borrowernumbers[0], "holds_placed_today should return a valid borrowernumber");
106
is( $borrowernumber, $borrowernumbers[0], "holds_placed_today should return a valid borrowernumber");
107
is( $branch_1code, $branch_1, "holds_placed_today should return a valid branchcode");
107
is( $branch_1code, $branch_1, "holds_placed_today should return a valid branchcode");
Lines 118-138 ok( $hold_item == $hold->item(), "item method returns stashed item" ); Link Here
118
my $hold_branch = $hold->branch();
118
my $hold_branch = $hold->branch();
119
ok( $hold_branch, "Got branch using branch() method" );
119
ok( $hold_branch, "Got branch using branch() method" );
120
ok( $hold_branch == $hold->branch(), "branch method returns stashed branch" );
120
ok( $hold_branch == $hold->branch(), "branch method returns stashed branch" );
121
my $hold_found = $hold->found();
121
my $hold_found = $hold->status();
122
$hold->set({ found => 'W'})->store();
122
$hold->set({ status => 'waiting' })->store();
123
is( Koha::Holds->waiting()->count(), 1, "Koha::Holds->waiting returns waiting holds" );
123
is( Koha::Holds->waiting()->count(), 1, "Koha::Holds->waiting returns waiting holds" );
124
is( Koha::Holds->unfilled()->count(), 4, "Koha::Holds->unfilled returns unfilled holds" );
124
is( Koha::Holds->unfilled()->count(), 4, "Koha::Holds->unfilled returns unfilled holds" );
125
125
126
my $patron = Koha::Patrons->find( $borrowernumbers[0] );
126
my $patron = Koha::Patrons->find( $borrowernumbers[0] );
127
$holds = $patron->holds;
127
$holds = $patron->holds;
128
is( $holds->next->borrowernumber, $borrowernumbers[0], "Test Koha::Patron->holds");
128
is( $holds->next->patron_id, $borrowernumbers[0], "Test Koha::Patron->holds");
129
129
130
130
131
$holds = $item->current_holds;
131
$holds = $item->current_holds;
132
$first_hold = $holds->next;
132
$first_hold = $holds->next;
133
$borrowernumber = $first_hold->borrowernumber;
133
$borrowernumber = $first_hold->patron_id;
134
$branch_1code = $first_hold->branchcode;
134
$branch_1code = $first_hold->pickup_library_id;
135
$reserve_id = $first_hold->reserve_id;
135
$reserve_id = $first_hold->id;
136
136
137
ModReserve({
137
ModReserve({
138
    reserve_id    => $reserve_id,
138
    reserve_id    => $reserve_id,
Lines 144-151 ModReserve({ Link Here
144
144
145
$hold = Koha::Holds->find( $reserve_id );
145
$hold = Koha::Holds->find( $reserve_id );
146
ok( $hold->priority eq '4', "Test ModReserve, priority changed correctly" );
146
ok( $hold->priority eq '4', "Test ModReserve, priority changed correctly" );
147
ok( $hold->suspend, "Test ModReserve, suspend hold" );
147
ok( $hold->suspended, "Test ModReserve, suspend hold" );
148
is( $hold->suspend_until, '2013-01-01 00:00:00', "Test ModReserve, suspend until date" );
148
is( $hold->suspended_until_date, '2013-01-01 00:00:00', "Test ModReserve, suspend until date" );
149
149
150
ModReserve({ # call without reserve_id
150
ModReserve({ # call without reserve_id
151
    rank          => '3',
151
    rank          => '3',
Lines 158-172 ok( $hold->priority eq '3', "Test ModReserve, priority changed correctly" ); Link Here
158
158
159
ToggleSuspend( $reserve_id );
159
ToggleSuspend( $reserve_id );
160
$hold = Koha::Holds->find( $reserve_id );
160
$hold = Koha::Holds->find( $reserve_id );
161
ok( ! $hold->suspend, "Test ToggleSuspend(), no date" );
161
ok( ! $hold->suspended, "Test ToggleSuspend(), no date" );
162
162
163
ToggleSuspend( $reserve_id, '2012-01-01' );
163
ToggleSuspend( $reserve_id, '2012-01-01' );
164
$hold = Koha::Holds->find( $reserve_id );
164
$hold = Koha::Holds->find( $reserve_id );
165
is( $hold->suspend_until, '2012-01-01 00:00:00', "Test ToggleSuspend(), with date" );
165
is( $hold->suspended_until_date, '2012-01-01 00:00:00', "Test ToggleSuspend(), with date" );
166
166
167
AutoUnsuspendReserves();
167
AutoUnsuspendReserves();
168
$hold = Koha::Holds->find( $reserve_id );
168
$hold = Koha::Holds->find( $reserve_id );
169
ok( ! $hold->suspend, "Test AutoUnsuspendReserves()" );
169
ok( ! $hold->suspended, "Test AutoUnsuspendReserves()" );
170
170
171
SuspendAll(
171
SuspendAll(
172
    borrowernumber => $borrowernumber,
172
    borrowernumber => $borrowernumber,
Lines 175-182 SuspendAll( Link Here
175
    suspend_until => '2012-01-01',
175
    suspend_until => '2012-01-01',
176
);
176
);
177
$hold = Koha::Holds->find( $reserve_id );
177
$hold = Koha::Holds->find( $reserve_id );
178
is( $hold->suspend, 1, "Test SuspendAll()" );
178
is( $hold->suspended, 1, "Test SuspendAll()" );
179
is( $hold->suspend_until, '2012-01-01 00:00:00', "Test SuspendAll(), with date" );
179
is( $hold->suspended_until_date, '2012-01-01 00:00:00', "Test SuspendAll(), with date" );
180
180
181
SuspendAll(
181
SuspendAll(
182
    borrowernumber => $borrowernumber,
182
    borrowernumber => $borrowernumber,
Lines 184-191 SuspendAll( Link Here
184
    suspend => 0,
184
    suspend => 0,
185
);
185
);
186
$hold = Koha::Holds->find( $reserve_id );
186
$hold = Koha::Holds->find( $reserve_id );
187
is( $hold->suspend, 0, "Test resuming with SuspendAll()" );
187
is( $hold->suspended, 0, "Test resuming with SuspendAll()" );
188
is( $hold->suspend_until, undef, "Test resuming with SuspendAll(), should have no suspend until date" );
188
is( $hold->suspended_until_date, undef, "Test resuming with SuspendAll(), should have no suspend until date" );
189
189
190
# Add a new hold for the borrower whose hold we canceled earlier, this time at the bib level
190
# Add a new hold for the borrower whose hold we canceled earlier, this time at the bib level
191
    AddReserve(
191
    AddReserve(
Lines 198-223 is( $hold->suspend_until, undef, "Test resuming with SuspendAll(), should have n Link Here
198
198
199
$patron = Koha::Patrons->find( $borrowernumber );
199
$patron = Koha::Patrons->find( $borrowernumber );
200
$holds = $patron->holds;
200
$holds = $patron->holds;
201
my $reserveid = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $borrowernumbers[0] })->next->reserve_id;
201
my $reserveid = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $borrowernumbers[0] })->next->id;
202
ModReserveMinusPriority( $itemnumber, $reserveid );
202
ModReserveMinusPriority( $itemnumber, $reserveid );
203
$holds = $patron->holds;
203
$holds = $patron->holds;
204
is( $holds->search({ itemnumber => $itemnumber })->count, 1, "Test ModReserveMinusPriority()" );
204
is( $holds->search({ item_id => $itemnumber })->count, 1, "Test ModReserveMinusPriority()" );
205
205
206
$holds = $biblio->holds;
206
$holds = $biblio->holds;
207
$hold = $holds->next;
207
$hold = $holds->next;
208
AlterPriority( 'top', $hold->reserve_id, undef, 2, 1, 6 );
208
AlterPriority( 'top', $hold->id, undef, 2, 1, 6 );
209
$hold = Koha::Holds->find( $reserveid );
209
$hold = Koha::Holds->find( $reserveid );
210
is( $hold->priority, '1', "Test AlterPriority(), move to top" );
210
is( $hold->priority, '1', "Test AlterPriority(), move to top" );
211
211
212
AlterPriority( 'down', $hold->reserve_id, undef, 2, 1, 6 );
212
AlterPriority( 'down', $hold->id, undef, 2, 1, 6 );
213
$hold = Koha::Holds->find( $reserveid );
213
$hold = Koha::Holds->find( $reserveid );
214
is( $hold->priority, '2', "Test AlterPriority(), move down" );
214
is( $hold->priority, '2', "Test AlterPriority(), move down" );
215
215
216
AlterPriority( 'up', $hold->reserve_id, 1, 3, 1, 6 );
216
AlterPriority( 'up', $hold->id, 1, 3, 1, 6 );
217
$hold = Koha::Holds->find( $reserveid );
217
$hold = Koha::Holds->find( $reserveid );
218
is( $hold->priority, '1', "Test AlterPriority(), move up" );
218
is( $hold->priority, '1', "Test AlterPriority(), move up" );
219
219
220
AlterPriority( 'bottom', $hold->reserve_id, undef, 2, 1, 6 );
220
AlterPriority( 'bottom', $hold->id, undef, 2, 1, 6 );
221
$hold = Koha::Holds->find( $reserveid );
221
$hold = Koha::Holds->find( $reserveid );
222
is( $hold->priority, '6', "Test AlterPriority(), move to bottom" );
222
is( $hold->priority, '6', "Test AlterPriority(), move to bottom" );
223
223
Lines 317-323 ok( Link Here
317
        }
317
        }
318
    );
318
    );
319
319
320
    my $hhh = Koha::Holds->search({ biblionumber => $biblio->biblionumber });
320
    my $hhh = Koha::Holds->search({ biblio_id => $biblio->biblionumber });
321
    my $hold3 = Koha::Holds->find( $reserveid3 );
321
    my $hold3 = Koha::Holds->find( $reserveid3 );
322
    is( $hold3->priority, 3, "The 3rd hold should have a priority set to 3" );
322
    is( $hold3->priority, 3, "The 3rd hold should have a priority set to 3" );
323
    ModReserve({ reserve_id => $reserveid1, rank => 'del' });
323
    ModReserve({ reserve_id => $reserveid1, rank => 'del' });
Lines 332-340 ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold can be trapped for damag Link Here
332
332
333
$hold = Koha::Hold->new(
333
$hold = Koha::Hold->new(
334
    {
334
    {
335
        borrowernumber => $borrowernumbers[0],
335
        patron_id => $borrowernumbers[0],
336
        itemnumber     => $itemnumber,
336
        item_id   => $itemnumber,
337
        biblionumber   => $biblio->biblionumber,
337
        biblio_id => $biblio->biblionumber,
338
    }
338
    }
339
)->store();
339
)->store();
340
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber )->{status},
340
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber )->{status},
Lines 349-365 ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for d Link Here
349
# Items that are not for loan, but holdable should not be trapped until they are available for loan
349
# Items that are not for loan, but holdable should not be trapped until they are available for loan
350
t::lib::Mocks::mock_preference( 'TrapHoldsOnOrder', 0 );
350
t::lib::Mocks::mock_preference( 'TrapHoldsOnOrder', 0 );
351
Koha::Items->find($itemnumber)->damaged(0)->notforloan(-1)->store;
351
Koha::Items->find($itemnumber)->damaged(0)->notforloan(-1)->store;
352
Koha::Holds->search({ biblionumber => $biblio->id })->delete();
352
Koha::Holds->search({ biblio_id => $biblio->id })->delete();
353
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber)->{status}, 'OK', "Patron can place hold on item that is not for loan but holdable ( notforloan < 0 )" );
353
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber)->{status}, 'OK', "Patron can place hold on item that is not for loan but holdable ( notforloan < 0 )" );
354
$hold = Koha::Hold->new(
354
$hold = Koha::Hold->new(
355
    {
355
    {
356
        borrowernumber => $borrowernumbers[0],
356
        patron_id         => $borrowernumbers[0],
357
        itemnumber     => $itemnumber,
357
        item_id           => $itemnumber,
358
        biblionumber   => $biblio->biblionumber,
358
        biblio_id         => $biblio->biblionumber,
359
        found          => undef,
359
        priority          => 1,
360
        priority       => 1,
360
        pickup_library_id => $branch_1,
361
        reservedate    => dt_from_string,
361
        completed         => 0,
362
        branchcode     => $branch_1,
362
        created_date      => \'NOW()',
363
    }
363
    }
364
)->store();
364
)->store();
365
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for item that is not for loan but holdable ( notforloan < 0 )" );
365
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for item that is not for loan but holdable ( notforloan < 0 )" );
Lines 474-480 subtest 'CanItemBeReserved' => sub { Link Here
474
        my $itemnumber_2_cannot = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_cant, biblionumber => $biblionumber_can })->itemnumber;
474
        my $itemnumber_2_cannot = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_cant, biblionumber => $biblionumber_can })->itemnumber;
475
        my $itemnumber_3_cannot = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_cant_record, biblionumber => $biblionumber_record_cannot })->itemnumber;
475
        my $itemnumber_3_cannot = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_cant_record, biblionumber => $biblionumber_record_cannot })->itemnumber;
476
476
477
        Koha::Holds->search({borrowernumber => $borrowernumbers[0]})->delete;
477
        Koha::Holds->search({patron_id => $borrowernumbers[0]})->delete;
478
478
479
        t::lib::Mocks::mock_preference('item-level_itypes', 1);
479
        t::lib::Mocks::mock_preference('item-level_itypes', 1);
480
        is(
480
        is(
Lines 510-516 subtest 'CanItemBeReserved' => sub { Link Here
510
        my $itemnumber_21 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_2 })->itemnumber;
510
        my $itemnumber_21 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_2 })->itemnumber;
511
        my $itemnumber_22 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_2 })->itemnumber;
511
        my $itemnumber_22 = $builder->build_sample_item({ homebranch => $branch_1, holdingbranch => $branch_1, itype => $itemtype_can, biblionumber => $biblionumber_2 })->itemnumber;
512
512
513
        Koha::Holds->search({borrowernumber => $borrowernumbers[0]})->delete;
513
        Koha::Holds->search({patron_id => $borrowernumbers[0]})->delete;
514
514
515
        # Biblio-level hold
515
        # Biblio-level hold
516
        AddReserve({
516
        AddReserve({
Lines 527-533 subtest 'CanItemBeReserved' => sub { Link Here
527
            );
527
            );
528
        }
528
        }
529
529
530
        Koha::Holds->search({borrowernumber => $borrowernumbers[0]})->delete;
530
        Koha::Holds->search({patron_id => $borrowernumbers[0]})->delete;
531
        # Item-level hold
531
        # Item-level hold
532
        AddReserve({
532
        AddReserve({
533
            branch => $branch_1,
533
            branch => $branch_1,
Lines 669-675 is(CanItemBeReserved($borrowernumbers[0], $itemnumber)->{status}, 'OK', Link Here
669
t::lib::Mocks::mock_preference( 'item-level_itypes',     1 );
669
t::lib::Mocks::mock_preference( 'item-level_itypes',     1 );
670
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
670
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
671
671
672
$dbh->do('DELETE FROM reserves');
672
$dbh->do('DELETE FROM holds');
673
$dbh->do('DELETE FROM issues');
673
$dbh->do('DELETE FROM issues');
674
$dbh->do('DELETE FROM items');
674
$dbh->do('DELETE FROM items');
675
$dbh->do('DELETE FROM biblio');
675
$dbh->do('DELETE FROM biblio');
Lines 715-721 t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' ); Link Here
715
subtest 'Test max_holds per library/patron category' => sub {
715
subtest 'Test max_holds per library/patron category' => sub {
716
    plan tests => 6;
716
    plan tests => 6;
717
717
718
    $dbh->do('DELETE FROM reserves');
718
    $dbh->do('DELETE FROM holds');
719
719
720
    $biblio = $builder->build_sample_biblio;
720
    $biblio = $builder->build_sample_biblio;
721
    $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
721
    $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
Lines 743-749 subtest 'Test max_holds per library/patron category' => sub { Link Here
743
    }
743
    }
744
744
745
    my $count =
745
    my $count =
746
      Koha::Holds->search( { borrowernumber => $borrowernumbers[0] } )->count();
746
      Koha::Holds->search( { patron_id => $borrowernumbers[0] } )->count();
747
    is( $count, 3, 'Patron now has 3 holds' );
747
    is( $count, 3, 'Patron now has 3 holds' );
748
748
749
    my $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
749
    my $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
Lines 928-934 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
928
    # Update last hold so reservedate is in the past, so 2 holds, but different day
928
    # Update last hold so reservedate is in the past, so 2 holds, but different day
929
    $hold = Koha::Holds->find($res_id);
929
    $hold = Koha::Holds->find($res_id);
930
    my $yesterday = dt_from_string() - DateTime::Duration->new( days => 1 );
930
    my $yesterday = dt_from_string() - DateTime::Duration->new( days => 1 );
931
    $hold->reservedate($yesterday)->store;
931
    $hold->created_date($yesterday)->store;
932
932
933
    is_deeply(
933
    is_deeply(
934
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
934
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
Lines 1578-1591 subtest 'CanItemBeReserved rule precedence tests' => sub { Link Here
1578
        { status => 'OK' },
1578
        { status => 'OK' },
1579
        'Patron of specified category can place 1 hold on specified itemtype'
1579
        'Patron of specified category can place 1 hold on specified itemtype'
1580
    );
1580
    );
1581
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
1581
1582
        biblionumber   => $item2->biblionumber,
1582
    AddReserve(
1583
        itemnumber     => $item2->itemnumber,
1583
        {
1584
        found          => undef,
1584
            branchcode     => $library->branchcode,
1585
        priority       => 1,
1585
            borrowernumber => $patron->borrowernumber,
1586
        branchcode     => $library->branchcode,
1586
            biblionumber   => $item2->biblionumber,
1587
        borrowernumber => $patron->borrowernumber,
1587
            priority       => 1,
1588
    }});
1588
            itemnumber     => $item2->itemnumber,
1589
        }
1590
    );
1589
    is_deeply(
1591
    is_deeply(
1590
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1592
        CanItemBeReserved( $patron->borrowernumber, $item->itemnumber, $library->branchcode ),
1591
        { status => 'tooManyReserves', limit => 1 },
1593
        { status => 'tooManyReserves', limit => 1 },
(-)a/t/db_dependent/Holds/DisallowHoldIfItemsAvailable.t (-3 / +3 lines)
Lines 290-299 my $itemtype2 = $builder->build( Link Here
290
my $item3 = $builder->build_sample_item( { itype => $itemtype2 } );
290
my $item3 = $builder->build_sample_item( { itype => $itemtype2 } );
291
291
292
my $hold = $builder->build(
292
my $hold = $builder->build(
293
    {   source => 'Reserve',
293
    {   source => 'Hold',
294
        value  => {
294
        value  => {
295
            itemnumber => $item3->itemnumber,
295
            item_id => $item3->itemnumber,
296
            found      => 'T'
296
            status  => 'in_transit'
297
        }
297
        }
298
    }
298
    }
299
);
299
);
(-)a/t/db_dependent/Holds/HoldItemtypeLimit.t (-1 / +1 lines)
Lines 57-63 my $right_itemtype = $itemtype1->{itemtype}; Link Here
57
my $wrong_itemtype = $itemtype2->{itemtype};
57
my $wrong_itemtype = $itemtype2->{itemtype};
58
my $borrowernumber = $borrower->{borrowernumber};
58
my $borrowernumber = $borrower->{borrowernumber};
59
my $branchcode = $library->{branchcode};
59
my $branchcode = $library->{branchcode};
60
$dbh->do("DELETE FROM reserves");
60
$dbh->do("DELETE FROM holds");
61
$dbh->do("DELETE FROM issues");
61
$dbh->do("DELETE FROM issues");
62
$dbh->do("DELETE FROM items");
62
$dbh->do("DELETE FROM items");
63
$dbh->do("DELETE FROM biblio");
63
$dbh->do("DELETE FROM biblio");
(-)a/t/db_dependent/Holds/LocalHoldsPriority.t (-8 / +8 lines)
Lines 85-113 my ($status, $reserve, $all_reserves); Link Here
85
85
86
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 0 );
86
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 0 );
87
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
87
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
88
ok( $reserve->{borrowernumber} eq $borrowernumbers[0], "Received expected results with LocalHoldsPriority disabled" );
88
ok( $reserve->{patron_id} eq $borrowernumbers[0], "Received expected results with LocalHoldsPriority disabled" );
89
89
90
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
90
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
91
91
92
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
92
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
93
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
93
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
94
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
94
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
95
ok( $reserve->{borrowernumber} eq $borrowernumbers[2], "Received expected results with PickupLibrary/homebranch" );
95
ok( $reserve->{patron_id} eq $borrowernumbers[2], "Received expected results with PickupLibrary/homebranch" );
96
96
97
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
97
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
98
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
98
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
99
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
99
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
100
ok( $reserve->{borrowernumber} eq $borrowernumbers[1], "Received expected results with PickupLibrary/holdingbranch" );
100
ok( $reserve->{patron_id} eq $borrowernumbers[1], "Received expected results with PickupLibrary/holdingbranch" );
101
101
102
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
102
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
103
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
103
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
104
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
104
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
105
ok( $reserve->{borrowernumber} eq $borrowernumbers[2], "Received expected results with HomeLibrary/holdingbranch" );
105
ok( $reserve->{patron_id} eq $borrowernumbers[2], "Received expected results with HomeLibrary/holdingbranch" );
106
106
107
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
107
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
108
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
108
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
109
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
109
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
110
ok( $reserve->{borrowernumber} eq $borrowernumbers[3], "Received expected results with HomeLibrary/homebranch" );
110
ok( $reserve->{patron_id} eq $borrowernumbers[3], "Received expected results with HomeLibrary/homebranch" );
111
111
112
$schema->storage->txn_rollback;
112
$schema->storage->txn_rollback;
113
113
Lines 161-167 subtest "exclude from local holds" => sub { Link Here
161
161
162
    my ($status, $reserve, $all_reserves);
162
    my ($status, $reserve, $all_reserves);
163
    ($status, $reserve, $all_reserves) = CheckReserves($item1->itemnumber);
163
    ($status, $reserve, $all_reserves) = CheckReserves($item1->itemnumber);
164
    is($reserve->{borrowernumber}, $patron_nex_l1->borrowernumber, "Patron not excluded with local holds priorities is next checkout");
164
    is($reserve->{patron_id}, $patron_nex_l1->borrowernumber, "Patron not excluded with local holds priorities is next checkout");
165
165
166
    Koha::Holds->delete;
166
    Koha::Holds->delete;
167
167
Lines 183-189 subtest "exclude from local holds" => sub { Link Here
183
    );
183
    );
184
184
185
    ($status, $reserve, $all_reserves) = CheckReserves($item1->itemnumber);
185
    ($status, $reserve, $all_reserves) = CheckReserves($item1->itemnumber);
186
    is($reserve->{borrowernumber}, $patron_nex_l2->borrowernumber, "Local patron is excluded from priority");
186
    is($reserve->{patron_id}, $patron_nex_l2->borrowernumber, "Local patron is excluded from priority");
187
187
188
    Koha::Holds->delete;
188
    Koha::Holds->delete;
189
189
Lines 205-211 subtest "exclude from local holds" => sub { Link Here
205
    );
205
    );
206
206
207
    ($status, $reserve, $all_reserves) = CheckReserves($item2->itemnumber);
207
    ($status, $reserve, $all_reserves) = CheckReserves($item2->itemnumber);
208
    is($reserve->{borrowernumber}, $patron_nex_l2->borrowernumber, "Patron from other library is next checkout because item is excluded");
208
    is($reserve->{patron_id}, $patron_nex_l2->borrowernumber, "Patron from other library is next checkout because item is excluded");
209
209
210
    $schema->storage->txn_rollback;
210
    $schema->storage->txn_rollback;
211
};
211
};
(-)a/t/db_dependent/Holds/RevertWaitingStatus.t (-2 / +1 lines)
Lines 34-41 $schema->storage->txn_begin; Link Here
34
my $builder = t::lib::TestBuilder->new;
34
my $builder = t::lib::TestBuilder->new;
35
my $dbh = C4::Context->dbh;
35
my $dbh = C4::Context->dbh;
36
36
37
$dbh->do("DELETE FROM reserves");
37
$dbh->do("DELETE FROM holds");
38
$dbh->do("DELETE FROM old_reserves");
39
38
40
my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
39
my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
41
my $itemtype = $builder->build(
40
my $itemtype = $builder->build(
(-)a/t/db_dependent/Holds/WaitingReserves.t (-46 / +50 lines)
Lines 18-24 $schema->storage->txn_begin; Link Here
18
my $dbh = C4::Context->dbh;
18
my $dbh = C4::Context->dbh;
19
$dbh->do(q{DELETE FROM special_holidays});
19
$dbh->do(q{DELETE FROM special_holidays});
20
$dbh->do(q{DELETE FROM repeatable_holidays});
20
$dbh->do(q{DELETE FROM repeatable_holidays});
21
$dbh->do("DELETE FROM reserves");
21
$dbh->do(q{DELETE FROM holds});
22
22
23
my $builder = t::lib::TestBuilder->new();
23
my $builder = t::lib::TestBuilder->new();
24
24
Lines 77-92 $reserve1_reservedate->subtract(days => 20); Link Here
77
my $reserve1_expirationdate = $today->clone;
77
my $reserve1_expirationdate = $today->clone;
78
$reserve1_expirationdate->add(days => 6);
78
$reserve1_expirationdate->add(days => 6);
79
79
80
my $reserve1 = $builder->build({
80
my $r = $builder->build_object({
81
    source => 'Reserve',
81
    class => 'Koha::Holds',
82
    value => {
82
    value => {
83
        borrowernumber => $patron1->{borrowernumber},
83
        patron_id => $patron1->{borrowernumber},
84
        reservedate => $reserve1_reservedate->ymd,
84
        created_date => $reserve1_reservedate->ymd,
85
        expirationdate => undef,
85
        expiration_date => undef,
86
        biblionumber => $biblio->biblionumber,
86
        biblio_id => $biblio->biblionumber,
87
        branchcode => 'LIB1',
87
        pickup_library_id => 'LIB1',
88
        priority => 1,
88
        priority => 1,
89
        found => '',
89
        status => 'placed',
90
        completed => 0
90
    },
91
    },
91
});
92
});
92
93
Lines 94-137 t::lib::Mocks::mock_preference('ExpireReservesMaxPickUpDelay', 1); Link Here
94
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 6);
95
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 6);
95
96
96
ModReserveAffect( $item1->itemnumber, $patron1->{borrowernumber});
97
ModReserveAffect( $item1->itemnumber, $patron1->{borrowernumber});
97
my $r = Koha::Holds->find($reserve1->{reserve_id});
98
$r->discard_changes;
98
99
99
is($r->waitingdate, $today->ymd, 'Waiting date should be set to today' );
100
is($r->waiting_date, $today->ymd, 'Waiting date should be set to today' );
100
is($r->expirationdate, $reserve1_expirationdate->ymd, 'Expiration date should be set to today + 6' );
101
is($r->expiration_date, $reserve1_expirationdate->ymd, 'Expiration date should be set to today + 6' );
101
is($r->found, 'W', 'Reserve status is now "waiting"' );
102
is($r->status, 'waiting', 'Reserve status is now "waiting"' );
102
is($r->priority, 0, 'Priority should be 0' );
103
is($r->priority, 0, 'Priority should be 0' );
103
is($r->itemnumber, $item1->itemnumber, 'Item number should be set correctly' );
104
is($r->item_id, $item1->itemnumber, 'Item number should be set correctly' );
104
105
105
my $reserve2 = $builder->build({
106
my $r2 = $builder->build_object({
106
    source => 'Reserve',
107
    class => 'Koha::Holds',
107
    value => {
108
    value => {
108
        borrowernumber => $patron2->{borrowernumber},
109
        patron_id => $patron2->{borrowernumber},
109
        reservedate => $reserve1_reservedate->ymd,
110
        created_date => $reserve1_reservedate->ymd,
110
        expirationdate => undef,
111
        expiration_date => undef,
111
        biblionumber => $biblio2->biblionumber,
112
        biblio_id => $biblio2->biblionumber,
112
        branchcode => 'LIB1',
113
        pickup_library_id => 'LIB1',
113
        priority => 1,
114
        priority => 1,
114
        found => '',
115
        status => 'placed',
116
        completed => 0
115
    },
117
    },
116
});
118
});
117
119
118
ModReserveAffect( $item2->itemnumber, $patron2->{borrowernumber}, 1);
120
ModReserveAffect( $item2->itemnumber, $patron2->{borrowernumber}, 1);
119
my $r2 = Koha::Holds->find($reserve2->{reserve_id});
121
$r2->discard_changes;
120
122
121
is($r2->found, 'T', '2nd reserve - Reserve status is now "To transfer"' );
123
is($r2->status, 'in_transit', '2nd reserve - Reserve status is now "To transfer"' );
122
is($r2->priority, 0, '2nd reserve - Priority should be 0' );
124
is($r2->priority, 0, '2nd reserve - Priority should be 0' );
123
is($r2->itemnumber, $item2->itemnumber, '2nd reserve - Item number should be set correctly' );
125
is($r2->item_id, $item2->itemnumber, '2nd reserve - Item number should be set correctly' );
124
126
125
my $reserve3 = $builder->build({
127
my $r3 = $builder->build_object({
126
    source => 'Reserve',
128
    class => 'Koha::Holds',
127
    value => {
129
    value => {
128
        borrowernumber => $patron2->{borrowernumber},
130
        patron_id => $patron2->{borrowernumber},
129
        reservedate => $reserve1_reservedate->ymd,
131
        created_date => $reserve1_reservedate->ymd,
130
        expirationdate => undef,
132
        expiration_date => undef,
131
        biblionumber => $biblio3->biblionumber,
133
        biblio_id => $biblio3->biblionumber,
132
        branchcode => 'LIB1',
134
        pickup_library_id => 'LIB1',
133
        priority => 1,
135
        priority => 1,
134
        found => '',
136
        status => 'placed',
137
        completed => 0
135
    },
138
    },
136
});
139
});
137
140
Lines 174-202 ModReserveAffect( $item3->itemnumber, $patron2->{borrowernumber}); Link Here
174
my $expected_expiration = $today->clone;
177
my $expected_expiration = $today->clone;
175
$expected_expiration->add(days => 8);
178
$expected_expiration->add(days => 8);
176
179
177
my $r3 = Koha::Holds->find($reserve3->{reserve_id});
180
$r3->discard_changes;
178
is($r3->expirationdate, $expected_expiration->ymd, 'Expiration date should be set to today + 7' );
181
is($r3->expiration_date, $expected_expiration->ymd, 'Expiration date should be set to today + 7' );
179
182
180
my $reserve4_reservedate = $today->clone;
183
my $reserve4_reservedate = $today->clone;
181
my $requested_expiredate = $today->clone()->add(days => 6);
184
my $requested_expiredate = $today->clone()->add(days => 6);
182
185
183
my $reserve4 = $builder->build({
186
my $r4 = $builder->build_object({
184
    source => 'Reserve',
187
    class => 'Koha::Holds',
185
    value => {
188
    value => {
186
        borrowernumber => $patron2->{borrowernumber},
189
        patron_id => $patron2->{borrowernumber},
187
        reservedate => $reserve4_reservedate->ymd,
190
        created_date => $reserve4_reservedate->ymd,
188
        expirationdate => $requested_expiredate->ymd,
191
        expiration_date => $requested_expiredate->ymd,
189
        biblionumber => $biblio4->biblionumber,
192
        biblio_id => $biblio4->biblionumber,
190
        branchcode => 'LIB1',
193
        pickup_library_id => 'LIB1',
191
        priority => 1,
194
        priority => 1,
192
        found => '',
195
        status => 'placed',
196
        completed => 0
193
    },
197
    },
194
});
198
});
195
199
196
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 10);
200
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 10);
197
ModReserveAffect( $item4->itemnumber, $patron2->{borrowernumber}, 0, $reserve4->{reserve_id});
201
ModReserveAffect( $item4->itemnumber, $patron2->{borrowernumber}, 0, $r4->id );
198
202
199
my $r4 = Koha::Holds->find($reserve4->{reserve_id});
203
$r4->discard_changes;
200
is($r4->expirationdate, $requested_expiredate->ymd, 'Requested expiration date should be kept' );
204
is($r4->expiration_date, $requested_expiredate->ymd, 'Requested expiration date should be kept' );
201
205
202
$schema->storage->txn_rollback;
206
$schema->storage->txn_rollback;
(-)a/t/db_dependent/HoldsQueue.t (-22 / +21 lines)
Lines 111-117 foreach ( $borrower_branchcode, $least_cost_branch_code, @other_branches ) { Link Here
111
}
111
}
112
112
113
# Remove existing reserves, makes debugging easier
113
# Remove existing reserves, makes debugging easier
114
$dbh->do("DELETE FROM reserves");
114
$dbh->do("DELETE FROM holds");
115
my $bibitems = undef;
115
my $bibitems = undef;
116
my $priority = 1;
116
my $priority = 1;
117
# Make a reserve
117
# Make a reserve
Lines 124-130 AddReserve( Link Here
124
    }
124
    }
125
);
125
);
126
#                           $resdate, $expdate, $notes, $title, $checkitem, $found
126
#                           $resdate, $expdate, $notes, $title, $checkitem, $found
127
$dbh->do("UPDATE reserves SET reservedate = DATE_SUB( reservedate, INTERVAL 1 DAY )");
127
$dbh->do("UPDATE holds SET created_date = DATE_SUB( created_date, INTERVAL 1 DAY )");
128
128
129
# Tests
129
# Tests
130
my $use_cost_matrix_sth = $dbh->prepare("UPDATE systempreferences SET value = ? WHERE variable = 'UseTransportCostMatrix'");
130
my $use_cost_matrix_sth = $dbh->prepare("UPDATE systempreferences SET value = ? WHERE variable = 'UseTransportCostMatrix'");
Lines 289-302 $items_insert_sth->execute( $barcode + 0, $branchcodes[0], $branchcodes[0] ); Link Here
289
$items_insert_sth->execute( $barcode + 1, $branchcodes[1], $branchcodes[1] );
289
$items_insert_sth->execute( $barcode + 1, $branchcodes[1], $branchcodes[1] );
290
$items_insert_sth->execute( $barcode + 2, $branchcodes[1], $branchcodes[1] );
290
$items_insert_sth->execute( $barcode + 2, $branchcodes[1], $branchcodes[1] );
291
291
292
$dbh->do("DELETE FROM reserves");
292
$dbh->do("DELETE FROM holds");
293
my $sth = $dbh->prepare(q{
293
my $sth = $dbh->prepare(q{
294
    INSERT INTO reserves (
294
    INSERT INTO holds (
295
        borrowernumber,
295
        patron_id,
296
        biblionumber,
296
        biblio_id,
297
        branchcode,
297
        pickup_library_id,
298
        priority,
298
        priority,
299
        reservedate
299
        created_date
300
    ) VALUES ( ?,?,?,?, CURRENT_DATE() )
300
    ) VALUES ( ?,?,?,?, CURRENT_DATE() )
301
});
301
});
302
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
302
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
Lines 384-390 $dbh->do("DELETE FROM issues"); Link Here
384
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
384
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
385
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
385
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
386
C4::Context->clear_syspref_cache();
386
C4::Context->clear_syspref_cache();
387
$dbh->do("DELETE FROM reserves");
387
$dbh->do("DELETE FROM holds");
388
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
388
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
389
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
389
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
390
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
390
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
Lines 402-408 t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary') Link Here
402
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
402
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
403
t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '1' );
403
t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '1' );
404
C4::Context->clear_syspref_cache();
404
C4::Context->clear_syspref_cache();
405
$dbh->do("DELETE FROM reserves");
405
$dbh->do("DELETE FROM holds");
406
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
406
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
407
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[1], 2 );
407
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[1], 2 );
408
408
Lines 444-450 t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '0' ); Link Here
444
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
444
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
445
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
445
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
446
C4::Context->clear_syspref_cache();
446
C4::Context->clear_syspref_cache();
447
$dbh->do("DELETE FROM reserves");
447
$dbh->do("DELETE FROM holds");
448
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
448
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
449
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
449
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
450
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
450
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
Lines 461-467 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue givi Link Here
461
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
461
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
462
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
462
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
463
C4::Context->clear_syspref_cache();
463
C4::Context->clear_syspref_cache();
464
$dbh->do("DELETE FROM reserves");
464
$dbh->do("DELETE FROM holds");
465
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
465
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
466
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
466
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
467
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
467
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
Lines 478-484 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue givi Link Here
478
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
478
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
479
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
479
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
480
C4::Context->clear_syspref_cache();
480
C4::Context->clear_syspref_cache();
481
$dbh->do("DELETE FROM reserves");
481
$dbh->do("DELETE FROM holds");
482
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
482
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
483
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
483
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
484
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
484
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
Lines 501-507 $borrowernumber = $borrower3->{borrowernumber}; Link Here
501
my $library_A = $library1->{branchcode};
501
my $library_A = $library1->{branchcode};
502
my $library_B = $library2->{branchcode};
502
my $library_B = $library2->{branchcode};
503
my $library_C = $borrower3->{branchcode};
503
my $library_C = $borrower3->{branchcode};
504
$dbh->do("DELETE FROM reserves");
504
$dbh->do("DELETE FROM holds");
505
$dbh->do("DELETE FROM issues");
505
$dbh->do("DELETE FROM issues");
506
$dbh->do("DELETE FROM items");
506
$dbh->do("DELETE FROM items");
507
$dbh->do("DELETE FROM biblio");
507
$dbh->do("DELETE FROM biblio");
Lines 566-572 $itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } Link Here
566
$borrowernumber = $borrower2->{borrowernumber};
566
$borrowernumber = $borrower2->{borrowernumber};
567
$library_A = $library1->{branchcode};
567
$library_A = $library1->{branchcode};
568
$library_B = $library2->{branchcode};
568
$library_B = $library2->{branchcode};
569
$dbh->do("DELETE FROM reserves");
569
$dbh->do("DELETE FROM holds");
570
$dbh->do("DELETE FROM issues");
570
$dbh->do("DELETE FROM issues");
571
$dbh->do("DELETE FROM items");
571
$dbh->do("DELETE FROM items");
572
$dbh->do("DELETE FROM biblio");
572
$dbh->do("DELETE FROM biblio");
Lines 619-625 $borrowernumber = $borrower3->{borrowernumber}; Link Here
619
$library_A = $library1->{branchcode};
619
$library_A = $library1->{branchcode};
620
$library_B = $library2->{branchcode};
620
$library_B = $library2->{branchcode};
621
$library_C = $library3->{branchcode};
621
$library_C = $library3->{branchcode};
622
$dbh->do("DELETE FROM reserves");
622
$dbh->do("DELETE FROM holds");
623
$dbh->do("DELETE FROM issues");
623
$dbh->do("DELETE FROM issues");
624
$dbh->do("DELETE FROM items");
624
$dbh->do("DELETE FROM items");
625
$dbh->do("DELETE FROM biblio");
625
$dbh->do("DELETE FROM biblio");
Lines 829-835 my $wrong_itemtype = $builder->build({ source => 'Itemtype', value => { notforlo Link Here
829
my $right_itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
829
my $right_itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
830
$borrowernumber = $borrower3->{borrowernumber};
830
$borrowernumber = $borrower3->{borrowernumber};
831
my $branchcode = $library1->{branchcode};
831
my $branchcode = $library1->{branchcode};
832
$dbh->do("DELETE FROM reserves");
832
$dbh->do("DELETE FROM holds");
833
$dbh->do("DELETE FROM issues");
833
$dbh->do("DELETE FROM issues");
834
$dbh->do("DELETE FROM items");
834
$dbh->do("DELETE FROM items");
835
$dbh->do("DELETE FROM biblio");
835
$dbh->do("DELETE FROM biblio");
Lines 1205-1211 subtest "Test Local Holds Priority - Ensure no duplicate requests in holds queue Link Here
1205
1205
1206
    $dbh->do("DELETE FROM tmp_holdsqueue");
1206
    $dbh->do("DELETE FROM tmp_holdsqueue");
1207
    $dbh->do("DELETE FROM hold_fill_targets");
1207
    $dbh->do("DELETE FROM hold_fill_targets");
1208
    $dbh->do("DELETE FROM reserves");
1208
    $dbh->do("DELETE FROM holds");
1209
    $dbh->do("DELETE FROM circulation_rules");
1209
    $dbh->do("DELETE FROM circulation_rules");
1210
    Koha::Biblios->delete();
1210
    Koha::Biblios->delete();
1211
1211
Lines 1719-1735 subtest 'Remove holds on check-in match' => sub { Link Here
1719
            AND q.holdingbranch = t.source_branchcode
1719
            AND q.holdingbranch = t.source_branchcode
1720
        WHERE t.reserve_id = ?
1720
        WHERE t.reserve_id = ?
1721
    });
1721
    });
1722
    $sth->execute($hold->reserve_id);
1722
    $sth->execute($hold->id);
1723
    my ($count_1) = $sth->fetchrow_array;
1723
    my ($count_1) = $sth->fetchrow_array;
1724
1724
1725
    is( $count_1, 1, "Holds queue has one element" );
1725
    is( $count_1, 1, "Holds queue has one element" );
1726
1726
1727
    AddReturn( $item->barcode, $item->homebranch, undef, dt_from_string );
1727
    AddReturn( $item->barcode, $item->homebranch, undef, dt_from_string );
1728
1728
1729
    ModReserveAffect( $item->itemnumber, $hold->borrowernumber, 0,
1729
    ModReserveAffect( $item->itemnumber, $hold->patron_id, 0, $hold->id );
1730
        $hold->reserve_id );
1731
1730
1732
    $sth->execute($hold->reserve_id);
1731
    $sth->execute($hold->id);
1733
    my ($count_2) = $sth->fetchrow_array;
1732
    my ($count_2) = $sth->fetchrow_array;
1734
1733
1735
    is( $count_2, 0,
1734
    is( $count_2, 0,
(-)a/t/db_dependent/ILSDI_Services.t (-18 / +19 lines)
Lines 326-336 subtest 'Holds test' => sub { Link Here
326
    $item->damaged(0)->store;
326
    $item->damaged(0)->store;
327
327
328
    my $hold = $builder->build({
328
    my $hold = $builder->build({
329
        source => 'Reserve',
329
        source => 'Hold',
330
        value => {
330
        value => {
331
            borrowernumber => $patron->{borrowernumber},
331
            patron_id => $patron->{borrowernumber},
332
            biblionumber => $item->biblionumber,
332
            biblio_id => $item->biblionumber,
333
            itemnumber => $item->itemnumber
333
            item_id   => $item->itemnumber,
334
            completed => 0
334
        }
335
        }
335
    });
336
    });
336
337
Lines 551-565 subtest 'Holds test for branch transfer limits' => sub { Link Here
551
552
552
    $reply = C4::ILSDI::Services::HoldItem( $query );
553
    $reply = C4::ILSDI::Services::HoldItem( $query );
553
    is( $reply->{code}, undef, "Item hold, Item can be transferred" );
554
    is( $reply->{code}, undef, "Item hold, Item can be transferred" );
554
    my $hold = Koha::Holds->search({ itemnumber => $item->itemnumber, borrowernumber => $patron->{borrowernumber} })->next;
555
    my $hold = Koha::Holds->search({ item_id => $item->itemnumber, patron_id => $patron->{borrowernumber} })->next;
555
    is( $hold->branchcode, $pickup_branch->{branchcode}, 'The library id is correctly set' );
556
    is( $hold->pickup_library_id, $pickup_branch->{branchcode}, 'The library id is correctly set' );
556
557
557
    Koha::Holds->search()->delete();
558
    Koha::Holds->search()->delete();
558
559
559
    $reply = C4::ILSDI::Services::HoldTitle( $query );
560
    $reply = C4::ILSDI::Services::HoldTitle( $query );
560
    is( $reply->{code}, undef, "Record hold, Item con be transferred" );
561
    is( $reply->{code}, undef, "Record hold, Item con be transferred" );
561
    $hold = Koha::Holds->search({ biblionumber => $item->biblionumber, borrowernumber => $patron->{borrowernumber} })->next;
562
    $hold = Koha::Holds->search({ biblio_id => $item->biblionumber, patron_id => $patron->{borrowernumber} })->next;
562
    is( $hold->branchcode, $pickup_branch->{branchcode}, 'The library id is correctly set' );
563
    is( $hold->pickup_library_id, $pickup_branch->{branchcode}, 'The library id is correctly set' );
563
564
564
    $schema->storage->txn_rollback;
565
    $schema->storage->txn_rollback;
565
};
566
};
Lines 605-623 subtest 'Holds test with start_date and end_date' => sub { Link Here
605
606
606
    my $reply = C4::ILSDI::Services::HoldItem( $query );
607
    my $reply = C4::ILSDI::Services::HoldItem( $query );
607
    is ($reply->{pickup_location}, $pickup_library->branchname, "Item hold with date parameters was placed");
608
    is ($reply->{pickup_location}, $pickup_library->branchname, "Item hold with date parameters was placed");
608
    my $hold = Koha::Holds->search({ biblionumber => $item->biblionumber})->next();
609
    my $hold = Koha::Holds->search({ biblio_id => $item->biblionumber})->next();
609
    is( $hold->biblionumber, $item->biblionumber, "correct biblionumber");
610
    is( $hold->biblio_id, $item->biblionumber, "correct biblionumber");
610
    is( $hold->reservedate, '2020-03-20', "Item hold has correct start date" );
611
    is( $hold->created_date, '2020-03-20', "Item hold has correct start date" );
611
    is( $hold->expirationdate, '2020-04-22', "Item hold has correct end date" );
612
    is( $hold->expiration_date, '2020-04-22', "Item hold has correct end date" );
612
613
613
    $hold->delete();
614
    $hold->delete();
614
615
615
    $reply = C4::ILSDI::Services::HoldTitle( $query );
616
    $reply = C4::ILSDI::Services::HoldTitle( $query );
616
    is ($reply->{pickup_location}, $pickup_library->branchname, "Record hold with date parameters was placed");
617
    is ($reply->{pickup_location}, $pickup_library->branchname, "Record hold with date parameters was placed");
617
    $hold = Koha::Holds->search({ biblionumber => $item->biblionumber})->next();
618
    $hold = Koha::Holds->search({ biblio_id => $item->biblionumber})->next();
618
    is( $hold->biblionumber, $item->biblionumber, "correct biblionumber");
619
    is( $hold->biblio_id, $item->biblionumber, "correct biblionumber");
619
    is( $hold->reservedate, '2020-03-20', "Record hold has correct start date" );
620
    is( $hold->created_date, '2020-03-20', "Record hold has correct start date" );
620
    is( $hold->expirationdate, '2020-04-22', "Record hold has correct end date" );
621
    is( $hold->expiration_date, '2020-04-22', "Record hold has correct end date" );
621
622
622
    $schema->storage->txn_rollback;
623
    $schema->storage->txn_rollback;
623
};
624
};
Lines 655-663 subtest 'GetRecords' => sub { Link Here
655
    });
656
    });
656
657
657
    my $hold = $builder->build({
658
    my $hold = $builder->build({
658
        source => 'Reserve',
659
        source => 'Hold',
659
        value => {
660
        value => {
660
            biblionumber => $item->biblionumber,
661
            biblio_id => $item->biblionumber,
661
        }
662
        }
662
    });
663
    });
663
664
(-)a/t/db_dependent/Items/GetItemsForInventory.t (-1 / +1 lines)
Lines 112-118 subtest 'Skip items with waiting holds' => sub { Link Here
112
            biblionumber   => $item_1->biblionumber,
112
            biblionumber   => $item_1->biblionumber,
113
            priority       => 1,
113
            priority       => 1,
114
            itemnumber     => $item_1->itemnumber,
114
            itemnumber     => $item_1->itemnumber,
115
            found          => 'W'
115
            found          => 'waiting'
116
        }
116
        }
117
    );
117
    );
118
    C4::Reserves::AddReserve(
118
    C4::Reserves::AddReserve(
(-)a/t/db_dependent/Items/MoveItemFromBiblio.t (-12 / +12 lines)
Lines 43-60 my $item3 = $builder->build_sample_item( Link Here
43
43
44
44
45
my $bib_level_hold_not_to_move = $builder->build(
45
my $bib_level_hold_not_to_move = $builder->build(
46
    {   source => 'Reserve',
46
    {   source => 'Hold',
47
        value  => { biblionumber => $from_biblio->biblionumber, },
47
        value  => { biblio_id => $from_biblio->biblionumber, },
48
    }
48
    }
49
);
49
);
50
my $item_level_hold_not_to_move = $builder->build(
50
my $item_level_hold_not_to_move = $builder->build(
51
    {   source => 'Reserve',
51
    {   source => 'Hold',
52
        value  => { biblionumber => $from_biblio->biblionumber, itemnumber => $item1->itemnumber },
52
        value  => { biblio_id => $from_biblio->biblionumber, item_id => $item1->itemnumber },
53
    }
53
    }
54
);
54
);
55
my $item_level_hold_to_move = $builder->build(
55
my $item_level_hold_to_move = $builder->build(
56
    {   source => 'Reserve',
56
    {   source => 'Hold',
57
        value  => { biblionumber => $from_biblio->biblionumber, itemnumber => $item2->itemnumber },
57
        value  => { biblio_id => $from_biblio->biblionumber, item_id => $item2->itemnumber },
58
    }
58
    }
59
);
59
);
60
60
Lines 73-85 is( $get_item2->biblionumber, $to_biblio->biblionumber, 'The item2 should have b Link Here
73
my $get_item3 = Koha::Items->find( $item3->itemnumber );
73
my $get_item3 = Koha::Items->find( $item3->itemnumber );
74
is( $get_item3->biblionumber, $to_biblio->biblionumber, 'The item3 should not have been moved' );
74
is( $get_item3->biblionumber, $to_biblio->biblionumber, 'The item3 should not have been moved' );
75
75
76
my $get_bib_level_hold    = Koha::Holds->find( $bib_level_hold_not_to_move->{reserve_id} );
76
my $get_bib_level_hold    = Koha::Holds->find( $bib_level_hold_not_to_move->{id} );
77
my $get_item_level_hold_1 = Koha::Holds->find( $item_level_hold_not_to_move->{reserve_id} );
77
my $get_item_level_hold_1 = Koha::Holds->find( $item_level_hold_not_to_move->{id} );
78
my $get_item_level_hold_2 = Koha::Holds->find( $item_level_hold_to_move->{reserve_id} );
78
my $get_item_level_hold_2 = Koha::Holds->find( $item_level_hold_to_move->{id} );
79
79
80
is( $get_bib_level_hold->biblionumber,    $from_biblio->biblionumber, 'MoveItemFromBiblio should not have moved the biblio-level hold' );
80
is( $get_bib_level_hold->biblio_id,    $from_biblio->biblionumber, 'MoveItemFromBiblio should not have moved the biblio-level hold' );
81
is( $get_item_level_hold_1->biblionumber, $from_biblio->biblionumber, 'MoveItemFromBiblio should not have moved the item-level hold placed on item 1' );
81
is( $get_item_level_hold_1->biblio_id, $from_biblio->biblionumber, 'MoveItemFromBiblio should not have moved the item-level hold placed on item 1' );
82
is( $get_item_level_hold_2->biblionumber, $to_biblio->biblionumber,   'MoveItemFromBiblio should have moved the item-level hold placed on item 2' );
82
is( $get_item_level_hold_2->biblio_id, $to_biblio->biblionumber,   'MoveItemFromBiblio should have moved the item-level hold placed on item 2' );
83
83
84
$schema->storage->txn_rollback;
84
$schema->storage->txn_rollback;
85
85
(-)a/t/db_dependent/Koha/Acquisition/Order.t (-1 / +1 lines)
Lines 860-866 subtest 'cancel() tests' => sub { Link Here
860
            borrowernumber => $patron->borrowernumber,
860
            borrowernumber => $patron->borrowernumber,
861
            biblionumber   => $biblio_id,
861
            biblionumber   => $biblio_id,
862
            itemnumber     => $item_3->id,
862
            itemnumber     => $item_3->id,
863
            found          => 'W',
863
            found          => 'waiting',
864
        }
864
        }
865
    );
865
    );
866
866
(-)a/t/db_dependent/Koha/Biblios.t (-9 / +9 lines)
Lines 77-83 subtest 'holds + current_holds' => sub { Link Here
77
    my $holds = $biblio->holds;
77
    my $holds = $biblio->holds;
78
    is( ref($holds), 'Koha::Holds', '->holds should return a Koha::Holds object' );
78
    is( ref($holds), 'Koha::Holds', '->holds should return a Koha::Holds object' );
79
    is( $holds->count, 1, '->holds should only return 1 hold' );
79
    is( $holds->count, 1, '->holds should only return 1 hold' );
80
    is( $holds->next->borrowernumber, $patron->borrowernumber, '->holds should return the correct hold' );
80
    is( $holds->next->patron_id, $patron->borrowernumber, '->holds should return the correct hold' );
81
    $holds->delete;
81
    $holds->delete;
82
82
83
    # Add a hold in the future
83
    # Add a hold in the future
Lines 98-122 subtest 'holds + current_holds' => sub { Link Here
98
};
98
};
99
99
100
subtest 'waiting_or_in_transit' => sub {
100
subtest 'waiting_or_in_transit' => sub {
101
101
    plan tests => 4;
102
    plan tests => 4;
103
102
    my $item = $builder->build_sample_item;
104
    my $item = $builder->build_sample_item;
103
    my $reserve = $builder->build({
105
    my $hold = $builder->build_object({
104
        source => 'Reserve',
106
        class => 'Koha::Holds',
105
        value => {
107
        value => {
106
            biblionumber => $item->biblionumber,
108
            biblio_id => $item->biblionumber,
107
            found => undef
108
        }
109
        }
109
    });
110
    });
110
111
111
    $reserve = Koha::Holds->find($reserve->{reserve_id});
112
    $biblio = $item->biblio;
112
    $biblio = $item->biblio;
113
113
114
    is($biblio->has_items_waiting_or_intransit, 0, 'Item is neither waiting nor in transit');
114
    is($biblio->has_items_waiting_or_intransit, 0, 'Item is neither waiting nor in transit');
115
115
116
    $reserve->found('W')->store;
116
    $hold->set_waiting();
117
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is waiting');
117
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is waiting');
118
118
119
    $reserve->found('T')->store;
119
    $hold->set_transfer();
120
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is in transit');
120
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is in transit');
121
121
122
    my $transfer = $builder->build({
122
    my $transfer = $builder->build({
Lines 128-134 subtest 'waiting_or_in_transit' => sub { Link Here
128
        }
128
        }
129
    });
129
    });
130
    my $t = Koha::Database->new()->schema()->resultset( 'Branchtransfer' )->find($transfer->{branchtransfer_id});
130
    my $t = Koha::Database->new()->schema()->resultset( 'Branchtransfer' )->find($transfer->{branchtransfer_id});
131
    $reserve->found(undef)->store;
131
    $hold->status('placed')->store;
132
    is($biblio->has_items_waiting_or_intransit, 1, 'Item has transfer');
132
    is($biblio->has_items_waiting_or_intransit, 1, 'Item has transfer');
133
};
133
};
134
134
(-)a/t/db_dependent/Koha/Club/Hold.t (-1 / +1 lines)
Lines 131-137 subtest 'add' => sub { Link Here
131
131
132
    my $hold = Koha::Holds->find($patron_hold->hold_id);
132
    my $hold = Koha::Holds->find($patron_hold->hold_id);
133
133
134
    is($patron_hold->patron_id, $hold->borrowernumber, 'Patron must be the same');
134
    is($patron_hold->patron_id, $hold->patron_id, 'Patron must be the same');
135
135
136
    $schema->storage->txn_rollback;
136
    $schema->storage->txn_rollback;
137
}
137
}
(-)a/t/db_dependent/Koha/Hold.t (-1 / +1 lines)
Lines 127-133 subtest 'set_pickup_location() tests' => sub { Link Here
127
127
128
    $item_hold->set_pickup_location({ library_id => $library_1->branchcode, force => 1 });
128
    $item_hold->set_pickup_location({ library_id => $library_1->branchcode, force => 1 });
129
    $item_hold->discard_changes;
129
    $item_hold->discard_changes;
130
    is( $item_hold->branchcode, $library_1->branchcode, 'branchcode changed because of \'force\'' );
130
    is( $item_hold->pickup_library_id, $library_1->branchcode, 'branchcode changed because of \'force\'' );
131
131
132
    $ret = $item_hold->set_pickup_location({ library_id => $library_2->id });
132
    $ret = $item_hold->set_pickup_location({ library_id => $library_2->id });
133
    is( ref($ret), 'Koha::Hold', 'self is returned' );
133
    is( ref($ret), 'Koha::Hold', 'self is returned' );
(-)a/t/db_dependent/Koha/Holds.t (-58 / +21 lines)
Lines 61-67 subtest 'DB constraints' => sub { Link Here
61
};
61
};
62
62
63
subtest 'cancel' => sub {
63
subtest 'cancel' => sub {
64
    plan tests => 12;
64
65
    plan tests => 13;
66
65
    my $biblioitem = $builder->build_object( { class => 'Koha::Biblioitems' } );
67
    my $biblioitem = $builder->build_object( { class => 'Koha::Biblioitems' } );
66
    my $library    = $builder->build_object( { class => 'Koha::Libraries' } );
68
    my $library    = $builder->build_object( { class => 'Koha::Libraries' } );
67
    my $itemtype   = $builder->build_object( { class => 'Koha::ItemTypes', value => { rentalcharge => 0 } } );
69
    my $itemtype   = $builder->build_object( { class => 'Koha::ItemTypes', value => { rentalcharge => 0 } } );
Lines 102-108 subtest 'cancel' => sub { Link Here
102
104
103
    # There are 3 holds on this records
105
    # There are 3 holds on this records
104
    my $nb_of_holds =
106
    my $nb_of_holds =
105
      Koha::Holds->search( { biblionumber => $item->biblionumber } )->count;
107
      Koha::Holds->search( { biblio_id => $item->biblionumber } )->count;
106
    is( $nb_of_holds, 3,
108
    is( $nb_of_holds, 3,
107
        'There should have 3 holds placed on this biblio record' );
109
        'There should have 3 holds placed on this biblio record' );
108
    my $first_hold  = $holds[0];
110
    my $first_hold  = $holds[0];
Lines 116-129 subtest 'cancel' => sub { Link Here
116
    # Remove the second hold, only 2 should still exist in DB and priorities must have been updated
118
    # Remove the second hold, only 2 should still exist in DB and priorities must have been updated
117
    my $is_cancelled = $second_hold->cancel;
119
    my $is_cancelled = $second_hold->cancel;
118
    is( ref($is_cancelled), 'Koha::Hold',
120
    is( ref($is_cancelled), 'Koha::Hold',
119
        'Koha::Hold->cancel should return the Koha::Hold (?)' )
121
        'Koha::Hold->cancel should return the Koha::Hold (?)' );
122
    $second_hold->discard_changes;
120
      ;    # This is can reconsidered
123
      ;    # This is can reconsidered
121
    is( $second_hold->in_storage, 0,
124
    is( $second_hold->in_storage, 1,
122
        'The hold has been cancelled and does not longer exist in DB' );
125
        'The hold has been cancelled and still exists on the DB' );
126
    is( $second_hold->status, 'cancelled', "Status is 'cancelled'" );
127
    ok( $second_hold->completed, 'Hold marked as comleted' );
128
123
    $nb_of_holds =
129
    $nb_of_holds =
124
      Koha::Holds->search( { biblionumber => $item->biblionumber } )->count;
130
      Koha::Holds->search( { biblio_id => $item->biblionumber, completed => 0 } )->count;
125
    is( $nb_of_holds, 2,
131
    is( $nb_of_holds, 2,
126
        'a hold has been cancelled, there should have only 2 holds placed on this biblio record'
132
        'a hold has been cancelled, there should have only 2 (not completed) holds placed on this biblio record'
127
    );
133
    );
128
134
129
    # discard_changes to refetch
135
    # discard_changes to refetch
Lines 166-172 subtest 'cancel' => sub { Link Here
166
    };
172
    };
167
173
168
    subtest 'waiting hold' => sub {
174
    subtest 'waiting hold' => sub {
169
        plan tests => 1;
175
        plan tests => 2;
170
        my $patron = $builder->build_object({ class => 'Koha::Patrons' });
176
        my $patron = $builder->build_object({ class => 'Koha::Patrons' });
171
        my $reserve_id = C4::Reserves::AddReserve(
177
        my $reserve_id = C4::Reserves::AddReserve(
172
            {
178
            {
Lines 176-187 subtest 'cancel' => sub { Link Here
176
                priority       => 1,
182
                priority       => 1,
177
                title          => "title for fee",
183
                title          => "title for fee",
178
                itemnumber     => $item->itemnumber,
184
                itemnumber     => $item->itemnumber,
179
                found          => 'W',
185
                status         => 'waiting',
180
            }
186
            }
181
        );
187
        );
182
        Koha::Holds->find( $reserve_id )->cancel;
188
        my $hold = Koha::Holds->find( $reserve_id );
183
        my $hold_old = Koha::Old::Holds->find( $reserve_id );
189
        $hold->cancel->discard_changes;
184
        is( $hold_old->found, 'W', 'The found column should have been kept and a hold is cancelled' );
190
        is( $hold->status, 'cancelled', 'The found column should have been kept and a hold is cancelled' );
191
        ok( $hold->completed, 'Hold is marked as completed' );
185
    };
192
    };
186
193
187
    subtest 'HoldsLog' => sub {
194
    subtest 'HoldsLog' => sub {
Lines 208-257 subtest 'cancel' => sub { Link Here
208
        $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'HOLDS', action => 'CANCEL', object => $reserve_id } )->count;
215
        $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'HOLDS', action => 'CANCEL', object => $reserve_id } )->count;
209
        is( $number_of_logs, 1, 'With HoldsLog, Koha::Hold->cancel should have logged' );
216
        is( $number_of_logs, 1, 'With HoldsLog, Koha::Hold->cancel should have logged' );
210
    };
217
    };
211
212
    subtest 'rollback' => sub {
213
        plan tests => 3;
214
        my $patron_category = $builder->build_object(
215
            {
216
                class => 'Koha::Patron::Categories',
217
                value => { reservefee => 0 }
218
            }
219
        );
220
        my $patron = $builder->build_object(
221
            {
222
                class => 'Koha::Patrons',
223
                value => { categorycode => $patron_category->categorycode }
224
            }
225
        );
226
        my $hold_info = {
227
            branchcode     => $library->branchcode,
228
            borrowernumber => $patron->borrowernumber,
229
            biblionumber   => $item->biblionumber,
230
            priority       => 1,
231
            title          => "title for fee",
232
            itemnumber     => $item->itemnumber,
233
        };
234
235
        t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelayCharge',42 );
236
        my $reserve_id = C4::Reserves::AddReserve($hold_info);
237
        my $hold       = Koha::Holds->find($reserve_id);
238
239
        # Add a row with the same id to make the cancel fails
240
        Koha::Old::Hold->new( $hold->unblessed )->store;
241
242
        warning_like {
243
            eval { $hold->cancel( { charge_cancel_fee => 1 } ) };
244
        }
245
        qr{.*DBD::mysql::st execute failed: Duplicate entry.*},
246
          'DBD should have raised an error about dup primary key';
247
248
        $hold = Koha::Holds->find($reserve_id);
249
        is( ref($hold), 'Koha::Hold', 'The hold should not have been deleted' );
250
        is( $patron->account->balance, 0,
251
'If the hold has not been cancelled, the patron should not have been charged'
252
        );
253
    };
254
255
};
218
};
256
219
257
subtest 'cancel with reason' => sub {
220
subtest 'cancel with reason' => sub {
Lines 455-461 subtest 'get_items_that_can_fill' => sub { Link Here
455
            borrowernumber => $patron_2->borrowernumber,
418
            borrowernumber => $patron_2->borrowernumber,
456
            biblionumber   => $biblio->biblionumber,
419
            biblionumber   => $biblio->biblionumber,
457
            priority       => 0,
420
            priority       => 0,
458
            found          => 'W',
421
            found          => 'waiting',
459
            itemnumber     => $item_1->itemnumber,
422
            itemnumber     => $item_1->itemnumber,
460
        }
423
        }
461
    );
424
    );
Lines 477-483 subtest 'get_items_that_can_fill' => sub { Link Here
477
440
478
    my $holds = Koha::Holds->search(
441
    my $holds = Koha::Holds->search(
479
        {
442
        {
480
            reserve_id => [ $reserve_id_1, $reserve_id_2, $waiting_reserve_id, ]
443
            id => [ $reserve_id_1, $reserve_id_2, $waiting_reserve_id, ]
481
        }
444
        }
482
    );
445
    );
483
446
(-)a/t/db_dependent/Koha/Items.t (-6 / +6 lines)
Lines 1382-1395 subtest 'holds' => sub { Link Here
1382
        biblionumber => $biblio->biblionumber,
1382
        biblionumber => $biblio->biblionumber,
1383
    });
1383
    });
1384
    is($item->holds->count, 0, "Nothing returned if no holds");
1384
    is($item->holds->count, 0, "Nothing returned if no holds");
1385
    my $hold1 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'T' }});
1385
    my $hold1 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'in_transit', completed => 0 }});
1386
    my $hold2 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'W' }});
1386
    my $hold2 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'waiting', completed => 0 }});
1387
    my $hold3 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'W' }});
1387
    my $hold3 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'waiting', completed => 0 }});
1388
1388
1389
    is($item->holds()->count,3,"Three holds found");
1389
    is($item->holds()->count,3,"Three holds found");
1390
    is($item->holds({found => 'W'})->count,2,"Two waiting holds found");
1390
    is($item->holds({status => 'waiting'})->count,2,"Two waiting holds found");
1391
    is_deeply($item->holds({found => 'T'})->next->unblessed,$hold1,"Found transit holds matches the hold");
1391
    is_deeply($item->holds({status => 'in_transit'})->next->unblessed,$hold1,"Found transit holds matches the hold");
1392
    is($item->holds({found => undef})->count, 0,"Nothing returned if no matching holds");
1392
    is($item->holds({status => 'placed'})->count, 0,"Nothing returned if no matching holds");
1393
};
1393
};
1394
1394
1395
subtest 'biblio' => sub {
1395
subtest 'biblio' => sub {
(-)a/t/db_dependent/Koha/Object.t (-2 / +2 lines)
Lines 272-278 subtest "to_api() tests" => sub { Link Here
272
272
273
    my $biblio = $builder->build_sample_biblio();
273
    my $biblio = $builder->build_sample_biblio();
274
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
274
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
275
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { itemnumber => $item->itemnumber } });
275
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { item_id => $item->itemnumber, completed => 0 } });
276
276
277
    my $embeds = { 'items' => {} };
277
    my $embeds = { 'items' => {} };
278
278
Lines 297-303 subtest "to_api() tests" => sub { Link Here
297
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
297
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
298
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
298
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
299
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
299
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
300
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->reserve_id, 'Hold matches');
300
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->id, 'Hold matches');
301
    is_deeply($biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root');
301
    is_deeply($biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root');
302
302
303
    my $hold_api = $hold->to_api(
303
    my $hold_api = $hold->to_api(
(-)a/t/db_dependent/Koha/Objects.t (-3 / +3 lines)
Lines 338-344 subtest "to_api() tests" => sub { Link Here
338
    my $hold_1   = $builder->build_object(
338
    my $hold_1   = $builder->build_object(
339
        {
339
        {
340
            class => 'Koha::Holds',
340
            class => 'Koha::Holds',
341
            value => { itemnumber => $item_1->itemnumber }
341
            value => { item_id => $item_1->itemnumber, completed => 0 }
342
        }
342
        }
343
    );
343
    );
344
344
Lines 347-353 subtest "to_api() tests" => sub { Link Here
347
    my $hold_2   = $builder->build_object(
347
    my $hold_2   = $builder->build_object(
348
        {
348
        {
349
            class => 'Koha::Holds',
349
            class => 'Koha::Holds',
350
            value => { itemnumber => $item_2->itemnumber }
350
            value => { item_id => $item_2->itemnumber, completed => 0 }
351
        }
351
        }
352
    );
352
    );
353
353
Lines 391-397 subtest "to_api() tests" => sub { Link Here
391
        ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
391
        ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
392
        is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches');
392
        is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches');
393
        ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
393
        ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
394
        is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->reserve_id, 'Hold matches');
394
        is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->id, 'Hold matches');
395
395
396
        $i++;
396
        $i++;
397
    }
397
    }
(-)a/t/db_dependent/Koha/Patrons.t (-8 / +8 lines)
Lines 469-476 subtest "delete" => sub { Link Here
469
    my $patron           = $builder->build( { source => 'Borrower' } );
469
    my $patron           = $builder->build( { source => 'Borrower' } );
470
    my $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} );
470
    my $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} );
471
    my $hold             = $builder->build(
471
    my $hold             = $builder->build(
472
        {   source => 'Reserve',
472
        {   source => 'Hold',
473
            value  => { borrowernumber => $patron->{borrowernumber} }
473
            value  => { patron_id => $patron->{borrowernumber}, completed => 0 }
474
        }
474
        }
475
    );
475
    );
476
    my $list = $builder->build(
476
    my $list = $builder->build(
Lines 485-493 subtest "delete" => sub { Link Here
485
485
486
    is( Koha::Patrons->find( $patron->{borrowernumber} ), undef, 'Koha::Patron->delete should have deleted the patron' );
486
    is( Koha::Patrons->find( $patron->{borrowernumber} ), undef, 'Koha::Patron->delete should have deleted the patron' );
487
487
488
    is (Koha::Old::Holds->search( { reserve_id => $hold->{ reserve_id } } )->count, 1, q|Koha::Patron->delete should have cancelled patron's holds| );
488
    is (Koha::Holds->search( { id => $hold->{id}, status => 'cancelled' } )->count, 1, q|Koha::Patron->delete should have cancelled patron's holds| );
489
489
490
    is( Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have cancelled patron's holds 2| );
490
    is( Koha::Holds->search( { patron_id => $patron->{borrowernumber}, completed => 0 } )->count, 0, q|Koha::Patron->delete should have cancelled patron's holds 2| );
491
491
492
    is( Koha::Virtualshelves->search( { owner => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have deleted patron's lists| );
492
    is( Koha::Virtualshelves->search( { owner => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have deleted patron's lists| );
493
493
Lines 993-1000 subtest 'holds and old_holds' => sub { Link Here
993
    is( $holds->count, 2, 'There should be 2 holds placed by this patron' );
993
    is( $holds->count, 2, 'There should be 2 holds placed by this patron' );
994
994
995
    my $old_holds = $patron->old_holds;
995
    my $old_holds = $patron->old_holds;
996
    is( ref($old_holds), 'Koha::Old::Holds',
996
    is( ref($old_holds), 'Koha::Holds',
997
        'Koha::Patron->old_holds should return a Koha::Old::Holds objects' );
997
        'Koha::Patron->old_holds should return a Koha::Holds objects' );
998
    is( $old_holds->count, 0, 'There should not be any old holds yet');
998
    is( $old_holds->count, 0, 'There should not be any old holds yet');
999
999
1000
    my $hold = $holds->next;
1000
    my $hold = $holds->next;
Lines 1606-1612 subtest 'BorrowersLog tests' => sub { Link Here
1606
$schema->storage->txn_rollback;
1606
$schema->storage->txn_rollback;
1607
1607
1608
subtest 'Test Koha::Patrons::merge' => sub {
1608
subtest 'Test Koha::Patrons::merge' => sub {
1609
    plan tests => 110;
1609
    plan tests => 106;
1610
1610
1611
    my $schema = Koha::Database->new()->schema();
1611
    my $schema = Koha::Database->new()->schema();
1612
1612
Lines 2028-2034 subtest 'lock' => sub { Link Here
2028
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
2028
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
2029
    my $hold = $builder->build_object({
2029
    my $hold = $builder->build_object({
2030
        class => 'Koha::Holds',
2030
        class => 'Koha::Holds',
2031
        value => { borrowernumber => $patron1->borrowernumber },
2031
        value => { patron_id => $patron1->borrowernumber, completed => 0 },
2032
    });
2032
    });
2033
2033
2034
    t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 3 );
2034
    t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 3 );
(-)a/t/db_dependent/Koha/Z3950Responder/Session.t (-1 / +1 lines)
Lines 32-38 subtest 'add_item_status' => sub { Link Here
32
    my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField( "items.itemnumber" );
32
    my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField( "items.itemnumber" );
33
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
33
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
34
    my $item_field_1 = scalar $item_marc_1->field($itemtag);
34
    my $item_field_1 = scalar $item_marc_1->field($itemtag);
35
    $builder->build({ source => 'Reserve', value=> { itemnumber => $item_1->itemnumber } });
35
    $builder->build({ source => 'Hold', value=> { item_id => $item_1->itemnumber } });
36
    $builder->build(
36
    $builder->build(
37
        {
37
        {
38
            source => 'Branchtransfer',
38
            source => 'Branchtransfer',
(-)a/t/db_dependent/Koha/Z3950Responder/Session2.t (-1 / +1 lines)
Lines 55-61 subtest 'add_item_status' => sub { Link Here
55
    );
55
    );
56
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
56
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
57
    my $item_field_1 = scalar $item_marc_1->field('952');
57
    my $item_field_1 = scalar $item_marc_1->field('952');
58
    $builder->build({ source => 'Reserve', value=> { itemnumber => $item_1->itemnumber } });
58
    $builder->build({ source => 'Hold', value=> { item_id => $item_1->itemnumber } });
59
    $builder->build(
59
    $builder->build(
60
        {
60
        {
61
            source => 'Branchtransfer',
61
            source => 'Branchtransfer',
(-)a/t/db_dependent/Letters/TemplateToolkit.t (-17 / +17 lines)
Lines 70-77 my $hold = $builder->build_object( Link Here
70
    {
70
    {
71
        class => 'Koha::Holds',
71
        class => 'Koha::Holds',
72
        value => {
72
        value => {
73
            borrowernumber => $patron->{borrowernumber},
73
            patron_id => $patron->{borrowernumber},
74
            biblionumber   => $item->biblionumber
74
            biblio_id   => $item->biblionumber
75
        }
75
        }
76
    }
76
    }
77
);
77
);
Lines 191-208 $prepared_letter = GetPreparedLetter( Link Here
191
is( $prepared_letter->{content}, $news->id(), 'News object used correctly for content' );
191
is( $prepared_letter->{content}, $news->id(), 'News object used correctly for content' );
192
is( $prepared_letter->{title}, $news->id(), 'News object used correctly for title' );
192
is( $prepared_letter->{title}, $news->id(), 'News object used correctly for title' );
193
193
194
$sth->execute( "TEST_HOLD", "[% hold.borrowernumber %]", "[% hold.id %]" );
194
$sth->execute( "TEST_HOLD", "[% hold.patron_id %]", "[% hold.id %]" );
195
$prepared_letter = GetPreparedLetter(
195
$prepared_letter = GetPreparedLetter(
196
    (
196
    (
197
        module      => 'test',
197
        module      => 'test',
198
        letter_code => 'TEST_HOLD',
198
        letter_code => 'TEST_HOLD',
199
        tables      => {
199
        tables      => {
200
            reserves => { borrowernumber => $patron->{borrowernumber}, biblionumber => $item->biblionumber },
200
            holds => {
201
                patron_id => $patron->{borrowernumber},
202
                biblio_id => $item->biblionumber
203
            },
201
        },
204
        },
202
    )
205
    )
203
);
206
);
204
is( $prepared_letter->{content}, $hold->id(), 'Hold object used correctly for content' );
207
is( $prepared_letter->{content}, $hold->id,        'Hold object used correctly for content' );
205
is( $prepared_letter->{title}, $hold->borrowernumber, 'Hold object used correctly for title' );
208
is( $prepared_letter->{title},   $hold->patron_id, 'Hold object used correctly for title' );
206
209
207
eval {
210
eval {
208
    $prepared_letter = GetPreparedLetter(
211
    $prepared_letter = GetPreparedLetter(
Lines 210-222 eval { Link Here
210
            module      => 'test',
213
            module      => 'test',
211
            letter_code => 'TEST_HOLD',
214
            letter_code => 'TEST_HOLD',
212
            tables      => {
215
            tables      => {
213
                reserves => [ $patron->{borrowernumber}, $item->biblionumber ],
216
                holds => [ $patron->{borrowernumber}, $item->biblionumber ],
214
            },
217
            },
215
        )
218
        )
216
    )
219
    )
217
};
220
};
218
my $croak = $@;
221
my $croak = $@;
219
like( $croak, qr{^Multiple foreign keys \(table reserves\) should be passed using an hashref.*}, "GetPreparedLetter should not be called with arrayref for multiple FK" );
222
like( $croak, qr{^Multiple foreign keys \(table holds\) should be passed using an hashref.*}, "GetPreparedLetter should not be called with arrayref for multiple FK" );
220
223
221
# Bug 16942
224
# Bug 16942
222
$prepared_letter = GetPreparedLetter(
225
$prepared_letter = GetPreparedLetter(
Lines 228-235 $prepared_letter = GetPreparedLetter( Link Here
228
            'borrowers'   => $patron,
231
            'borrowers'   => $patron,
229
            'biblio'      => $item->biblionumber,
232
            'biblio'      => $item->biblionumber,
230
            'biblioitems' => $item->biblioitemnumber,
233
            'biblioitems' => $item->biblioitemnumber,
231
            'reserves'    => $hold->unblessed,
234
            'holds'       => $hold->unblessed,
232
            'items'       => $hold->itemnumber,
235
            'items'       => $hold->item_id,
233
        }
236
        }
234
    )
237
    )
235
);
238
);
Lines 302-308 subtest 'regression tests' => sub { Link Here
302
    my $patron  = $builder->build( { source => 'Borrower' } );
305
    my $patron  = $builder->build( { source => 'Borrower' } );
303
    my $item1 = $builder->build_sample_item(
306
    my $item1 = $builder->build_sample_item(
304
        {
307
        {
305
            barcode        => 'a_t_barcode',
306
            library        => $library->{branchcode},
308
            library        => $library->{branchcode},
307
            itype          => 'BK',
309
            itype          => 'BK',
308
            itemcallnumber => 'itemcallnumber1',
310
            itemcallnumber => 'itemcallnumber1',
Lines 312-318 subtest 'regression tests' => sub { Link Here
312
    $item1 = $item1->unblessed;
314
    $item1 = $item1->unblessed;
313
    my $item2   = $builder->build_sample_item(
315
    my $item2   = $builder->build_sample_item(
314
        {
316
        {
315
            barcode        => 'another_t_barcode',
316
            library        => $library->{branchcode},
317
            library        => $library->{branchcode},
317
            itype          => 'BK',
318
            itype          => 'BK',
318
            itemcallnumber => 'itemcallnumber2',
319
            itemcallnumber => 'itemcallnumber2',
Lines 322-328 subtest 'regression tests' => sub { Link Here
322
    $item2 = $item2->unblessed;
323
    $item2 = $item2->unblessed;
323
    my $item3   = $builder->build_sample_item(
324
    my $item3   = $builder->build_sample_item(
324
        {
325
        {
325
            barcode        => 'another_t_barcode_3',
326
            library        => $library->{branchcode},
326
            library        => $library->{branchcode},
327
            itype          => 'BK',
327
            itype          => 'BK',
328
            itemcallnumber => 'itemcallnumber3',
328
            itemcallnumber => 'itemcallnumber3',
Lines 572-581 You have [% count %] items due Link Here
572
<ul>
572
<ul>
573
   <li><<items.barcode>></li>
573
   <li><<items.barcode>></li>
574
   <li><<items.itemcallnumber>></li>
574
   <li><<items.itemcallnumber>></li>
575
   <li><<reserves.waitingdate>></li>
575
   <li><<holds.waiting_date>></li>
576
</ul>
576
</ul>
577
<p>Notes:
577
<p>Notes:
578
<pre><<reserves.reserve_id>>=<<reserves.reservenotes>></pre>
578
<pre><<holds.id>>=<<holds.notes>></pre>
579
</p>
579
</p>
580
EOF
580
EOF
581
581
Lines 606-615 EOF Link Here
606
<ul>
606
<ul>
607
   <li>[% item.barcode %]</li>
607
   <li>[% item.barcode %]</li>
608
   <li>[% item.itemcallnumber %]</li>
608
   <li>[% item.itemcallnumber %]</li>
609
   <li>[% hold.waitingdate | \$KohaDates %]</li>
609
   <li>[% hold.waiting_date | \$KohaDates %]</li>
610
</ul>
610
</ul>
611
<p>Notes:
611
<p>Notes:
612
<pre>[% hold.reserve_id %]=[% hold.reservenotes %]</pre>
612
<pre>[% hold.id %]=[% hold.notes %]</pre>
613
</p>
613
</p>
614
EOF
614
EOF
615
615
(-)a/t/db_dependent/Reserves.t (-85 / +72 lines)
Lines 123-129 my ($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber, $barcod Link Here
123
123
124
is($status, "Reserved", "CheckReserves Test 1");
124
is($status, "Reserved", "CheckReserves Test 1");
125
125
126
ok(exists($reserve->{reserve_id}), 'CheckReserves() include reserve_id in its response');
126
ok(exists($reserve->{id}), 'CheckReserves() include reserve_id in its response');
127
127
128
($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber);
128
($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber);
129
is($status, "Reserved", "CheckReserves Test 2");
129
is($status, "Reserved", "CheckReserves Test 2");
Lines 267-280 ModReserveAffect($itemnum_cpl, $requesters{$branch_3}, 0); Link Here
267
267
268
# Now it should have different priorities.
268
# Now it should have different priorities.
269
my $biblio = Koha::Biblios->find( $bibnum2 );
269
my $biblio = Koha::Biblios->find( $bibnum2 );
270
my $holds = $biblio->holds({}, { order_by => 'reserve_id' });;
270
my $holds = $biblio->holds({ completed => 0 }, { order_by => 'id' });;
271
is($holds->next->priority, 0, 'Item is correctly waiting');
271
is($holds->next->priority, 0, 'Item is correctly waiting');
272
is($holds->next->priority, 1, 'Item is correctly priority 1');
272
is($holds->next->priority, 1, 'Item is correctly priority 1');
273
is($holds->next->priority, 2, 'Item is correctly priority 2');
273
is($holds->next->priority, 2, 'Item is correctly priority 2');
274
274
275
my @reserves = Koha::Holds->search({ borrowernumber => $requesters{$branch_3} })->waiting();
275
my @reserves = Koha::Holds->search({ patron_id => $requesters{$branch_3} })->waiting();
276
is( @reserves, 1, 'GetWaiting got only the waiting reserve' );
276
is( @reserves, 1, 'GetWaiting got only the waiting reserve' );
277
is( $reserves[0]->borrowernumber(), $requesters{$branch_3}, 'GetWaiting got the reserve for the correct borrower' );
277
is( $reserves[0]->patron_id(), $requesters{$branch_3}, 'GetWaiting got the reserve for the correct borrower' );
278
278
279
279
280
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum2));
280
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum2));
Lines 312-318 my $messages; Link Here
312
# the one placed by the CPL patron, as the other two patron's hold
312
# the one placed by the CPL patron, as the other two patron's hold
313
# requests cannot be filled by that item per policy.
313
# requests cannot be filled by that item per policy.
314
(undef, $messages, undef, undef) = AddReturn('bug10272_CPL', $branch_2);
314
(undef, $messages, undef, undef) = AddReturn('bug10272_CPL', $branch_2);
315
is( $messages->{ResFound}->{borrowernumber},
315
is( $messages->{ResFound}->{patron_id},
316
    $requesters{$branch_1},
316
    $requesters{$branch_1},
317
    'restrictive library\'s items only fill requests by own patrons (bug 10272)');
317
    'restrictive library\'s items only fill requests by own patrons (bug 10272)');
318
318
Lines 324-342 is( $messages->{ResFound}->{borrowernumber}, Link Here
324
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', '' );
324
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', '' );
325
325
326
(undef, $messages, undef, undef) = AddReturn('bug10272_FPL', $branch_2);
326
(undef, $messages, undef, undef) = AddReturn('bug10272_FPL', $branch_2);
327
is( $messages->{ResFound}->{borrowernumber},
327
is( $messages->{ResFound}->{patron_id},
328
    $requesters{$branch_3},
328
    $requesters{$branch_3},
329
    'for generous library, its items fill first hold request in line (bug 10272)');
329
    'for generous library, its items fill first hold request in line (bug 10272)');
330
330
331
$biblio = Koha::Biblios->find( $biblionumber );
331
$biblio = Koha::Biblios->find( $biblionumber );
332
$holds = $biblio->holds;
332
$holds = $biblio->holds;
333
is($holds->count, 1, "Only one reserves for this biblio");
333
is($holds->count, 1, "Only one reserves for this biblio");
334
$holds->next->reserve_id;
335
334
336
# Tests for bug 9761 (ConfirmFutureHolds): new CheckReserves lookahead parameter, and corresponding change in AddReturn
335
# Tests for bug 9761 (ConfirmFutureHolds): new CheckReserves lookahead parameter, and corresponding change in AddReturn
337
# Note that CheckReserve uses its lookahead parameter and does not check ConfirmFutureHolds pref (it should be passed if needed like AddReturn does)
336
# Note that CheckReserve uses its lookahead parameter and does not check ConfirmFutureHolds pref (it should be passed if needed like AddReturn does)
338
# Test 9761a: Add a reserve without date, CheckReserve should return it
337
# Test 9761a: Add a reserve without date, CheckReserve should return it
339
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
338
$dbh->do("DELETE FROM holds WHERE biblio_id=?",undef,($bibnum));
340
AddReserve(
339
AddReserve(
341
    {
340
    {
342
        branchcode     => $branch_1,
341
        branchcode     => $branch_1,
Lines 414-420 ok(defined($letter), 'can successfully generate hold slip (bug 10949)'); Link Here
414
413
415
# Tests for bug 9788: Does Koha::Item->current_holds return a future wait?
414
# Tests for bug 9788: Does Koha::Item->current_holds return a future wait?
416
# 9788a: current_holds does not return future next available hold
415
# 9788a: current_holds does not return future next available hold
417
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
416
$dbh->do("DELETE FROM holds WHERE biblio_id=?",undef,($bibnum));
418
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 2);
417
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 2);
419
t::lib::Mocks::mock_preference('AllowHoldDateInFuture', 1);
418
t::lib::Mocks::mock_preference('AllowHoldDateInFuture', 1);
420
$resdate= dt_from_string();
419
$resdate= dt_from_string();
Lines 432-441 AddReserve( Link Here
432
431
433
$holds = $item->current_holds;
432
$holds = $item->current_holds;
434
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
433
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
435
my $future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
434
my $future_holds = $holds->search({ created_date => { '>' => $dtf->format_date( dt_from_string ) } } );
436
is( $future_holds->count, 0, 'current_holds does not return a future next available hold');
435
is( $future_holds->count, 0, 'current_holds does not return a future next available hold');
437
# 9788b: current_holds does not return future item level hold
436
# 9788b: current_holds does not return future item level hold
438
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
437
$dbh->do("DELETE FROM holds WHERE biblio_id=?",undef,($bibnum));
439
AddReserve(
438
AddReserve(
440
    {
439
    {
441
        branchcode       => $branch_1,
440
        branchcode       => $branch_1,
Lines 446-460 AddReserve( Link Here
446
        itemnumber       => $item->itemnumber,
445
        itemnumber       => $item->itemnumber,
447
    }
446
    }
448
); #item level hold
447
); #item level hold
449
$future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
448
$future_holds = $holds->search({ created_date => { '>' => $dtf->format_date( dt_from_string ) } } );
450
is( $future_holds->count, 0, 'current_holds does not return a future item level hold' );
449
is( $future_holds->count, 0, 'current_holds does not return a future item level hold' );
451
# 9788c: current_holds returns future wait (confirmed future hold)
450
# 9788c: current_holds returns future wait (confirmed future hold)
452
ModReserveAffect( $item->itemnumber,  $requesters{$branch_1} , 0); #confirm hold
451
ModReserveAffect( $item->itemnumber,  $requesters{$branch_1} , 0); #confirm hold
453
$future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
452
$future_holds = $holds->search({ created_date => { '>' => $dtf->format_date( dt_from_string ) } } );
454
is( $future_holds->count, 1, 'current_holds returns a future wait (confirmed future hold)' );
453
is( $future_holds->count, 1, 'current_holds returns a future wait (confirmed future hold)' );
455
# End of tests for bug 9788
454
# End of tests for bug 9788
456
455
457
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
456
$dbh->do("DELETE FROM holds WHERE biblio_id=?",undef,($bibnum));
458
# Tests for CalculatePriority (bug 8918)
457
# Tests for CalculatePriority (bug 8918)
459
my $p = C4::Reserves::CalculatePriority($bibnum2);
458
my $p = C4::Reserves::CalculatePriority($bibnum2);
460
is($p, 4, 'CalculatePriority should now return priority 4');
459
is($p, 4, 'CalculatePriority should now return priority 4');
Lines 469-475 AddReserve( Link Here
469
$p = C4::Reserves::CalculatePriority($bibnum2);
468
$p = C4::Reserves::CalculatePriority($bibnum2);
470
is($p, 5, 'CalculatePriority should now return priority 5');
469
is($p, 5, 'CalculatePriority should now return priority 5');
471
#some tests on bibnum
470
#some tests on bibnum
472
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
471
$dbh->do("DELETE FROM holds WHERE biblio_id=?",undef,($bibnum));
473
$p = C4::Reserves::CalculatePriority($bibnum);
472
$p = C4::Reserves::CalculatePriority($bibnum);
474
is($p, 1, 'CalculatePriority should now return priority 1');
473
is($p, 1, 'CalculatePriority should now return priority 1');
475
#add a new reserve and confirm it to waiting
474
#add a new reserve and confirm it to waiting
Lines 519-525 is($p, 3, 'CalculatePriority should now return priority 3'); Link Here
519
# End of tests for bug 8918
518
# End of tests for bug 8918
520
519
521
# Tests for cancel reserves by users from OPAC.
520
# Tests for cancel reserves by users from OPAC.
522
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
521
$dbh->do('DELETE FROM holds', undef, ($bibnum));
523
AddReserve(
522
AddReserve(
524
    {
523
    {
525
        branchcode     => $branch_1,
524
        branchcode     => $branch_1,
Lines 534-542 is( CanReserveBeCanceledFromOpac(), undef, Link Here
534
    'CanReserveBeCanceledFromOpac should return undef if called without any parameter'
533
    'CanReserveBeCanceledFromOpac should return undef if called without any parameter'
535
);
534
);
536
is(
535
is(
537
    CanReserveBeCanceledFromOpac( $canres->{resserve_id} ),
536
    CanReserveBeCanceledFromOpac( $canres->{id} ),
538
    undef,
537
    undef,
539
    'CanReserveBeCanceledFromOpac should return undef if called without the reserve_id'
538
    'CanReserveBeCanceledFromOpac should return undef if called without the id'
540
);
539
);
541
is(
540
is(
542
    CanReserveBeCanceledFromOpac( undef, $requesters{CPL} ),
541
    CanReserveBeCanceledFromOpac( undef, $requesters{CPL} ),
Lines 544-561 is( Link Here
544
    'CanReserveBeCanceledFromOpac should return undef if called without borrowernumber'
543
    'CanReserveBeCanceledFromOpac should return undef if called without borrowernumber'
545
);
544
);
546
545
547
my $cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
546
my $cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
548
is($cancancel, 1, 'Can user cancel its own reserve');
547
is($cancancel, 1, 'Can user cancel its own reserve');
549
548
550
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_2});
549
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_2});
551
is($cancancel, 0, 'Other user cant cancel reserve');
550
is($cancancel, 0, 'Other user cant cancel reserve');
552
551
553
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 1);
552
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 1);
554
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
553
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
555
is($cancancel, 0, 'Reserve in transfer status cant be canceled');
554
is($cancancel, 0, 'Reserve in transfer status cant be canceled');
556
555
557
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
556
$dbh->do('DELETE FROM holds', undef, ($bibnum));
558
is( CanReserveBeCanceledFromOpac($canres->{resserve_id}, $requesters{$branch_1}), undef,
557
is( CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1}), undef,
559
    'Cannot cancel a deleted hold' );
558
    'Cannot cancel a deleted hold' );
560
559
561
AddReserve(
560
AddReserve(
Lines 569-575 AddReserve( Link Here
569
(undef, $canres, undef) = CheckReserves($item->itemnumber);
568
(undef, $canres, undef) = CheckReserves($item->itemnumber);
570
569
571
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 0);
570
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 0);
572
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
571
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
573
is($cancancel, 0, 'Reserve in waiting status cant be canceled');
572
is($cancancel, 0, 'Reserve in waiting status cant be canceled');
574
573
575
# End of tests for bug 12876
574
# End of tests for bug 12876
Lines 637-643 Koha::CirculationRules->set_rules( Link Here
637
636
638
# tests for MoveReserve in relation to ConfirmFutureHolds (BZ 14526)
637
# tests for MoveReserve in relation to ConfirmFutureHolds (BZ 14526)
639
#   hold from A pos 1, today, no fut holds: MoveReserve should fill it
638
#   hold from A pos 1, today, no fut holds: MoveReserve should fill it
640
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
639
$dbh->do('DELETE FROM holds');
641
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 0);
640
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 0);
642
t::lib::Mocks::mock_preference('AllowHoldDateInFuture', 1);
641
t::lib::Mocks::mock_preference('AllowHoldDateInFuture', 1);
643
AddReserve(
642
AddReserve(
Lines 658-664 AddReserve( Link Here
658
        borrowernumber => $borrowernumber,
657
        borrowernumber => $borrowernumber,
659
        biblionumber   => $bibnum,
658
        biblionumber   => $bibnum,
660
        priority       => 1,
659
        priority       => 1,
661
        found          => 'W',
660
        found          => 'waiting',
662
    }
661
    }
663
);
662
);
664
MoveReserve( $item->itemnumber, $borrowernumber );
663
MoveReserve( $item->itemnumber, $borrowernumber );
Lines 680-686 AddReserve( Link Here
680
MoveReserve( $item->itemnumber, $borrowernumber );
679
MoveReserve( $item->itemnumber, $borrowernumber );
681
($status)=CheckReserves( $item->itemnumber, undef, 1 );
680
($status)=CheckReserves( $item->itemnumber, undef, 1 );
682
is( $status, 'Reserved', 'MoveReserve did not fill future hold');
681
is( $status, 'Reserved', 'MoveReserve did not fill future hold');
683
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
682
$dbh->do('DELETE FROM holds', undef, ($bibnum));
684
#   hold from A pos 1, tomorrow, fut holds=2: MoveReserve should fill it
683
#   hold from A pos 1, tomorrow, fut holds=2: MoveReserve should fill it
685
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 2);
684
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 2);
686
AddReserve(
685
AddReserve(
Lines 724-730 AddReserve( Link Here
724
MoveReserve( $item->itemnumber, $borrowernumber );
723
MoveReserve( $item->itemnumber, $borrowernumber );
725
($status)=CheckReserves( $item->itemnumber, undef, 3 );
724
($status)=CheckReserves( $item->itemnumber, undef, 3 );
726
is( $status, 'Reserved', 'MoveReserve did not fill future hold of 3 days');
725
is( $status, 'Reserved', 'MoveReserve did not fill future hold of 3 days');
727
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
726
$dbh->do('DELETE FROM holds', undef, ($bibnum));
728
727
729
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
728
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
730
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
729
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
Lines 832-844 subtest 'ReservesNeedReturns' => sub { Link Here
832
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 1); # Test with feature disabled
831
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 1); # Test with feature disabled
833
    my $hold = place_item_hold( $patron, $item, $library, $priority );
832
    my $hold = place_item_hold( $patron, $item, $library, $priority );
834
    is( $hold->priority, $priority, 'If ReservesNeedReturns is 1, priority must not have been set to changed' );
833
    is( $hold->priority, $priority, 'If ReservesNeedReturns is 1, priority must not have been set to changed' );
835
    is( $hold->found, undef, 'If ReservesNeedReturns is 1, found must not have been set waiting' );
834
    is( $hold->status, 'placed', 'If ReservesNeedReturns is 1, status must not have been set waiting' );
836
    $hold->delete;
835
    $hold->delete;
837
836
838
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 0); # '0' means 'Automatically mark a hold as found and waiting'
837
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 0); # '0' means 'Automatically mark a hold as status and waiting'
839
    $hold = place_item_hold( $patron, $item, $library, $priority );
838
    $hold = place_item_hold( $patron, $item, $library, $priority );
840
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
839
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
841
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
840
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and no other status, status must have been set waiting' );
842
    $hold->delete;
841
    $hold->delete;
843
842
844
    $item->onloan('2010-01-01')->store;
843
    $item->onloan('2010-01-01')->store;
Lines 854-864 subtest 'ReservesNeedReturns' => sub { Link Here
854
    t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1); # '0' means damaged holds not allowed
853
    t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1); # '0' means damaged holds not allowed
855
    $hold = place_item_hold( $patron, $item, $library, $priority );
854
    $hold = place_item_hold( $patron, $item, $library, $priority );
856
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and damaged holds allowed, priority must have been set to 0' );
855
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and damaged holds allowed, priority must have been set to 0' );
857
    is( $hold->found,  'W', 'If ReservesNeedReturns is 0 and damaged holds allowed, found must have been set waiting' );
856
    is( $hold->status,  'waiting', 'If ReservesNeedReturns is 0 and damaged holds allowed, status must have been set waiting' );
858
    $hold->delete;
857
    $hold->delete;
859
858
860
    my $hold_1 = place_item_hold( $patron, $item, $library, $priority );
859
    my $hold_1 = place_item_hold( $patron, $item, $library, $priority );
861
    is( $hold_1->found,  'W', 'First hold on item is set to waiting with ReservesNeedReturns set to 0' );
860
    is( $hold_1->status,  'waiting', 'First hold on item is set to waiting with ReservesNeedReturns set to 0' );
862
    is( $hold_1->priority, 0, 'First hold on item is set to waiting with ReservesNeedReturns set to 0' );
861
    is( $hold_1->priority, 0, 'First hold on item is set to waiting with ReservesNeedReturns set to 0' );
863
    $hold = place_item_hold( $patron_2, $item, $library, $priority );
862
    $hold = place_item_hold( $patron_2, $item, $library, $priority );
864
    is( $hold->priority, 1, 'If ReservesNeedReturns is 0 but item already on hold priority must be set to 1' );
863
    is( $hold->priority, 1, 'If ReservesNeedReturns is 0 but item already on hold priority must be set to 1' );
Lines 875-895 subtest 'ReservesNeedReturns' => sub { Link Here
875
    });
874
    });
876
    $item->damaged(0)->store;
875
    $item->damaged(0)->store;
877
    $hold = place_item_hold( $patron, $item, $library, $priority );
876
    $hold = place_item_hold( $patron, $item, $library, $priority );
878
    is( $hold->found, undef, 'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
877
    is( $hold->status, 'placed', 'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
879
    is( $hold->priority, 1,  'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
878
    is( $hold->priority, 1,  'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
880
    $hold->delete;
879
    $hold->delete;
881
    $transfer->delete;
880
    $transfer->delete;
882
881
883
    $hold = place_item_hold( $patron, $item, $library, $priority );
882
    $hold = place_item_hold( $patron, $item, $library, $priority );
884
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
883
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
885
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
884
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
886
    $hold_1 = place_item_hold( $patron, $item, $library, $priority );
885
    $hold_1 = place_item_hold( $patron, $item, $library, $priority );
887
    is( $hold_1->priority, 1, 'If ReservesNeedReturns is 0 but item has a hold priority is 1' );
886
    is( $hold_1->priority, 1, 'If ReservesNeedReturns is 0 but item has a hold priority is 1' );
888
    $hold_1->suspend(1)->store; # We suspend the hold
887
    $hold_1->suspended(1)->store; # We suspend the hold
889
    $hold->delete; # Delete the waiting hold
888
    $hold->delete; # Delete the waiting hold
890
    $hold = place_item_hold( $patron, $item, $library, $priority );
889
    $hold = place_item_hold( $patron, $item, $library, $priority );
891
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and other hold(s) suspended, priority must have been set to 0' );
890
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and other hold(s) suspended, priority must have been set to 0' );
892
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and other  hold(s) suspended, found must have been set waiting' );
891
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and other  hold(s) suspended, found must have been set waiting' );
893
892
894
893
895
894
Lines 935-940 subtest 'reserves.item_level_hold' => sub { Link Here
935
934
936
    subtest 'item level hold' => sub {
935
    subtest 'item level hold' => sub {
937
        plan tests => 2;
936
        plan tests => 2;
937
938
        $schema->storage->txn_begin;
939
938
        my $reserve_id = AddReserve(
940
        my $reserve_id = AddReserve(
939
            {
941
            {
940
                branchcode     => $item->homebranch,
942
                branchcode     => $item->homebranch,
Lines 946-965 subtest 'reserves.item_level_hold' => sub { Link Here
946
        );
948
        );
947
949
948
        my $hold = Koha::Holds->find($reserve_id);
950
        my $hold = Koha::Holds->find($reserve_id);
949
        is( $hold->item_level_hold, 1, 'item_level_hold should be set when AddReserve is called with a specific item' );
951
        is( $hold->item_level, 1, 'item_level should be set when AddReserve is called with a specific item' );
950
952
951
        # Mark it waiting
953
        # Mark it waiting
952
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 1 );
954
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber );
953
955
954
        # Revert the waiting status
956
        # Revert the waiting status
955
        C4::Reserves::RevertWaitingStatus(
957
        C4::Reserves::RevertWaitingStatus(
956
            { itemnumber => $item->itemnumber } );
958
            { itemnumber => $item->itemnumber } );
957
959
958
        $hold = Koha::Holds->find($reserve_id);
960
        $hold->discard_changes;
959
961
960
        is( $hold->itemnumber, $item->itemnumber, 'Itemnumber should not be removed when the waiting status is revert' );
962
        is( $hold->item_id, $item->itemnumber, 'Itemnumber should not be removed when the waiting status is revert' );
961
963
962
        $hold->delete;    # cleanup
964
        $schema->storage->txn_rollback;
963
    };
965
    };
964
966
965
    subtest 'biblio level hold' => sub {
967
    subtest 'biblio level hold' => sub {
Lines 974-992 subtest 'reserves.item_level_hold' => sub { Link Here
974
        );
976
        );
975
977
976
        my $hold = Koha::Holds->find($reserve_id);
978
        my $hold = Koha::Holds->find($reserve_id);
977
        is( $hold->item_level_hold, 0, 'item_level_hold should not be set when AddReserve is called without a specific item' );
979
        is( $hold->item_level, 0, 'item_level should not be set when AddReserve is called without a specific item' );
978
980
979
        # Mark it waiting
981
        # Mark it waiting
980
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 1 );
982
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber );
981
983
982
        $hold = Koha::Holds->find($reserve_id);
984
        $hold = Koha::Holds->find($reserve_id);
983
        is( $hold->itemnumber, $item->itemnumber, 'Itemnumber should be set on hold confirmation' );
985
        is( $hold->item_id, $item->itemnumber, 'Itemnumber should be set on hold confirmation' );
984
986
985
        # Revert the waiting status
987
        # Revert the waiting status
986
        C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
988
        C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
987
989
988
        $hold = Koha::Holds->find($reserve_id);
990
        $hold = Koha::Holds->find($reserve_id);
989
        is( $hold->itemnumber, undef, 'Itemnumber should be removed when the waiting status is revert' );
991
        is( $hold->item_id, undef, 'Itemnumber should be removed when the waiting status is revert' );
990
992
991
        $hold->delete;
993
        $hold->delete;
992
    };
994
    };
Lines 1024-1039 subtest 'MoveReserve additional test' => sub { Link Here
1024
            itemnumber     => $item_1->itemnumber,
1026
            itemnumber     => $item_1->itemnumber,
1025
        }
1027
        }
1026
    );
1028
    );
1027
    is($patron_1->holds->next()->reserve_id, $reserve_1, "The 1st patron has a hold");
1029
    is($patron_1->holds->next()->id, $reserve_1, "The 1st patron has a hold");
1028
    is($patron_2->holds->next()->reserve_id, $reserve_2, "The 2nd patron has a hold");
1030
    is($patron_2->holds->next()->id, $reserve_2, "The 2nd patron has a hold");
1029
1031
1030
    # Fake the holds queue
1032
    # Fake the holds queue
1031
    $dbh->do(q{INSERT INTO hold_fill_targets VALUES (?, ?, ?, ?, ?,?)},undef,($patron_1->borrowernumber,$biblio->biblionumber,$item_1->itemnumber,$item_1->homebranch,0,$reserve_1));
1033
    $dbh->do(q{INSERT INTO hold_fill_targets VALUES (?, ?, ?, ?, ?,?)},undef,($patron_1->borrowernumber,$biblio->biblionumber,$item_1->itemnumber,$item_1->homebranch,0,$reserve_1));
1032
1034
1033
    # The 2nd hold should be filed even if the item is preselected for the first hold
1035
    # The 2nd hold should be filed even if the item is preselected for the first hold
1034
    MoveReserve($item_1->itemnumber,$patron_2->borrowernumber);
1036
    MoveReserve($item_1->itemnumber,$patron_2->borrowernumber);
1035
    is($patron_2->holds->count, 0, "The 2nd patrons no longer has a hold");
1037
    is($patron_2->holds({ completed => 0 })->count, 0, "The 2nd patrons no longer has a hold");
1036
    is($patron_2->old_holds->next()->reserve_id, $reserve_2, "The 2nd patrons hold was filled and moved to old holds");
1038
    is($patron_2->holds({ completed => 1 })->next()->id, $reserve_2, "The 2nd patrons hold was filled and moved to old holds");
1037
1039
1038
};
1040
};
1039
1041
Lines 1089-1106 subtest 'CheckReserves additional tests' => sub { Link Here
1089
        {
1091
        {
1090
            class => "Koha::Holds",
1092
            class => "Koha::Holds",
1091
            value => {
1093
            value => {
1092
                found            => undef,
1093
                priority         => 1,
1094
                priority         => 1,
1094
                itemnumber       => undef,
1095
                item_id          => undef,
1095
                biblionumber     => $item->biblionumber,
1096
                biblio_id        => $item->biblionumber,
1096
                waitingdate      => undef,
1097
                item_level       => 0,
1097
                cancellationdate => undef,
1098
                lowest_priority  => 0,
1098
                item_level_hold  => 0,
1099
                expiration_date  => undef,
1099
                lowestPriority   => 0,
1100
                expirationdate   => undef,
1101
                suspend_until    => undef,
1102
                suspend          => 0,
1103
                itemtype         => undef,
1104
            }
1100
            }
1105
        }
1101
        }
1106
    );
1102
    );
Lines 1108-1126 subtest 'CheckReserves additional tests' => sub { Link Here
1108
        {
1104
        {
1109
            class => "Koha::Holds",
1105
            class => "Koha::Holds",
1110
            value => {
1106
            value => {
1111
                found            => undef,
1112
                priority         => 2,
1107
                priority         => 2,
1113
                biblionumber     => $item->biblionumber,
1108
                biblio_id        => $item->biblionumber,
1114
                borrowernumber   => $reserve1->borrowernumber,
1109
                patron_id        => $reserve1->patron_id,
1115
                itemnumber       => undef,
1110
                item_id          => undef,
1116
                waitingdate      => undef,
1111
                suspended_until  => undef,
1117
                cancellationdate => undef,
1112
                suspended        => 0,
1118
                item_level_hold  => 0,
1113
                item_type        => undef,
1119
                lowestPriority   => 0,
1120
                expirationdate   => undef,
1121
                suspend_until    => undef,
1122
                suspend          => 0,
1123
                itemtype         => undef,
1124
            }
1114
            }
1125
        }
1115
        }
1126
    );
1116
    );
Lines 1129-1136 subtest 'CheckReserves additional tests' => sub { Link Here
1129
        {
1119
        {
1130
            source => 'TmpHoldsqueue',
1120
            source => 'TmpHoldsqueue',
1131
            value  => {
1121
            value  => {
1132
                borrowernumber => $reserve1->borrowernumber,
1122
                borrowernumber => $reserve1->patron_id,
1133
                biblionumber   => $reserve1->biblionumber,
1123
                biblionumber   => $reserve1->biblio_id,
1134
            }
1124
            }
1135
        }
1125
        }
1136
    );
1126
    );
Lines 1138-1160 subtest 'CheckReserves additional tests' => sub { Link Here
1138
        {
1128
        {
1139
            source => 'HoldFillTarget',
1129
            source => 'HoldFillTarget',
1140
            value  => {
1130
            value  => {
1141
                borrowernumber     => $reserve1->borrowernumber,
1131
                borrowernumber     => $reserve1->patron_id,
1142
                biblionumber       => $reserve1->biblionumber,
1132
                biblionumber       => $reserve1->biblio_id,
1143
                itemnumber         => $item->itemnumber,
1133
                itemnumber         => $item->itemnumber,
1144
                item_level_request => 0,
1134
                item_level_request => 0,
1145
            }
1135
            }
1146
        }
1136
        }
1147
    );
1137
    );
1148
1138
1149
    ModReserveAffect( $item->itemnumber, $reserve1->borrowernumber, 1,
1139
    ModReserveAffect( $item->itemnumber, $reserve1->patron_id, 1, $reserve1->id );
1150
        $reserve1->reserve_id );
1140
    my ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item->itemnumber );
1151
    my ( $status, $matched_reserve, $possible_reserves ) =
1152
      CheckReserves( $item->itemnumber );
1153
1141
1154
    is( $status, 'Transferred', "We found a reserve" );
1142
    is( $status, 'Transferred', "We found a reserve" );
1155
    is( $matched_reserve->{reserve_id},
1143
    is( $matched_reserve->{id}, $reserve1->id, 'We got the Transit reserve' );
1156
        $reserve1->reserve_id, "We got the Transit reserve" );
1144
    is( scalar @$possible_reserves, 2,         'We do get both reserves' );
1157
    is( scalar @$possible_reserves, 2, 'We do get both reserves' );
1158
1145
1159
    my $patron_B = $builder->build_object({ class => "Koha::Patrons" });
1146
    my $patron_B = $builder->build_object({ class => "Koha::Patrons" });
1160
    my $item_A = $builder->build_sample_item;
1147
    my $item_A = $builder->build_sample_item;
Lines 1327-1333 subtest 'ModReserveAffect logging' => sub { Link Here
1327
    ok( $hold->is_waiting, 'Hold has been set waiting' );
1314
    ok( $hold->is_waiting, 'Hold has been set waiting' );
1328
    isnt( $hold->timestamp, $previous_timestamp, 'The timestamp has been modified' );
1315
    isnt( $hold->timestamp, $previous_timestamp, 'The timestamp has been modified' );
1329
1316
1330
    my $log = Koha::ActionLogs->search({ module => 'HOLDS', action => 'MODIFY', object => $hold->reserve_id })->next;
1317
    my $log = Koha::ActionLogs->search({ module => 'HOLDS', action => 'MODIFY', object => $hold->id })->next;
1331
    my $expected = sprintf q{'timestamp' => '%s'}, $hold->timestamp;
1318
    my $expected = sprintf q{'timestamp' => '%s'}, $hold->timestamp;
1332
    like( $log->info, qr{$expected}, 'Timestamp logged is the current one' );
1319
    like( $log->info, qr{$expected}, 'Timestamp logged is the current one' );
1333
};
1320
};
(-)a/t/db_dependent/Reserves/AutoUnsuspendReserves.t (-16 / +16 lines)
Lines 43-52 subtest 'AutoUnsuspendReserves test' => sub { Link Here
43
    my $hold_1 = $builder->build_object({
43
    my $hold_1 = $builder->build_object({
44
        class => 'Koha::Holds',
44
        class => 'Koha::Holds',
45
        value => {
45
        value => {
46
            expirationdate => undef,
46
            expiration_date => undef,
47
            cancellationdate => undef,
47
            completed_date  => undef,
48
            priority => 5,
48
            priority => 5,
49
            found => undef,
49
            status => 'placed',
50
        },
50
        },
51
    });
51
    });
52
52
Lines 56-65 subtest 'AutoUnsuspendReserves test' => sub { Link Here
56
    my $hold_2 = $builder->build_object({
56
    my $hold_2 = $builder->build_object({
57
        class => 'Koha::Holds',
57
        class => 'Koha::Holds',
58
        value => {
58
        value => {
59
            expirationdate => undef,
59
            expiration_date => undef,
60
            cancellationdate => undef,
60
            completed_date  => undef,
61
            priority => 6,
61
            priority => 6,
62
            found => undef,
62
            status => 'placed',
63
        },
63
        },
64
    });
64
    });
65
65
Lines 84-94 subtest 'AutoUnsuspendReserves test' => sub { Link Here
84
        my $hold_3 = $builder->build_object(
84
        my $hold_3 = $builder->build_object(
85
            {   class => 'Koha::Holds',
85
            {   class => 'Koha::Holds',
86
                value => {
86
                value => {
87
                    expirationdate   => undef,
87
                    expiration_date   => undef,
88
                    cancellationdate => undef,
88
                    completed_date    => undef,
89
                    priority         => 5,
89
                    priority          => 5,
90
                    found            => undef,
90
                    status            => 'placed',
91
                    suspend_until    => undef,
91
                    suspended_until_date => undef,
92
                }
92
                }
93
            }
93
            }
94
        );
94
        );
Lines 121-130 subtest 'AutoUnsuspendReserves test' => sub { Link Here
121
        my $hold_4 = $builder->build_object(
121
        my $hold_4 = $builder->build_object(
122
            {   class => 'Koha::Holds',
122
            {   class => 'Koha::Holds',
123
                value => {
123
                value => {
124
                    expirationdate   => undef,
124
                    expiration_date   => undef,
125
                    cancellationdate => undef,
125
                    completed_date    => undef,
126
                    priority         => 5,
126
                    priority          => 5,
127
                    found            => undef
127
                    status            => 'placed'
128
                }
128
                }
129
            }
129
            }
130
        );
130
        );
Lines 137-143 subtest 'AutoUnsuspendReserves test' => sub { Link Here
137
        AutoUnsuspendReserves();
137
        AutoUnsuspendReserves();
138
138
139
        $hold_4->discard_changes;
139
        $hold_4->discard_changes;
140
        ok(!defined($hold_4->suspend_until), 'Hold suspended until today should be unsuspended.');
140
        ok(!defined($hold_4->suspended_until_date), 'Hold suspended until today should be unsuspended.');
141
141
142
        my $new_logs_count = $schema->resultset('ActionLog')
142
        my $new_logs_count = $schema->resultset('ActionLog')
143
            ->search( { module => 'HOLDS', action => 'RESUME' } )->count;
143
            ->search( { module => 'HOLDS', action => 'RESUME' } )->count;
(-)a/t/db_dependent/Reserves/CancelExpiredReserves.t (-103 / +127 lines)
Lines 16-22 my $schema = Koha::Database->new->schema; Link Here
16
$schema->storage->txn_begin;
16
$schema->storage->txn_begin;
17
17
18
subtest 'CancelExpiredReserves tests incl. holidays' => sub {
18
subtest 'CancelExpiredReserves tests incl. holidays' => sub {
19
    plan tests => 4;
19
    plan tests => 6;
20
20
21
    my $builder = t::lib::TestBuilder->new();
21
    my $builder = t::lib::TestBuilder->new();
22
22
Lines 33-84 subtest 'CancelExpiredReserves tests incl. holidays' => sub { Link Here
33
    $reserve1_expirationdate->add(days => 1);
33
    $reserve1_expirationdate->add(days => 1);
34
34
35
    # Reserve not expired
35
    # Reserve not expired
36
    my $reserve1 = $builder->build({
36
    my $reserve1 = $builder->build_object(
37
        source => 'Reserve',
37
        {
38
        value => {
38
            class => 'Koha::Holds',
39
            reservedate => $reserve_reservedate,
39
            value => {
40
            expirationdate => $reserve1_expirationdate,
40
                created_date    => $reserve_reservedate,
41
            cancellationdate => undef,
41
                expiration_date => $reserve1_expirationdate,
42
            priority => 0,
42
                completed_date  => undef,
43
            found => 'W',
43
                priority        => 0,
44
        },
44
                status          => 'waiting',
45
    });
45
                completed       => 0,
46
            },
47
        }
48
    );
46
49
47
    CancelExpiredReserves();
50
    CancelExpiredReserves();
48
    my $r1 = Koha::Holds->find($reserve1->{reserve_id});
51
    my $r1 = Koha::Holds->find($reserve1->id);
49
    ok($r1, 'Reserve 1 should not be canceled.');
52
    ok($r1, 'Reserve 1 should not be canceled.');
50
53
51
    my $reserve2_expirationdate = $today->clone;
54
    my $reserve2_expirationdate = $today->clone;
52
    $reserve2_expirationdate->subtract(days => 1);
55
    $reserve2_expirationdate->subtract(days => 1);
53
56
54
    # Reserve expired
57
    # Reserve expired
55
    my $reserve2 = $builder->build({
58
    my $reserve2 = $builder->build_object(
56
        source => 'Reserve',
59
        {
57
        value => {
60
            class => 'Koha::Holds',
58
            reservedate => $reserve_reservedate,
61
            value => {
59
            expirationdate => $reserve2_expirationdate,
62
                created_date    => $reserve_reservedate,
60
            cancellationdate => undef,
63
                expiration_date => $reserve2_expirationdate,
61
            priority => 0,
64
                completed_date  => undef,
62
            found => 'W',
65
                priority        => 0,
63
        },
66
                status          => 'waiting',
64
    });
67
                completed       => 0,
68
            },
69
        }
70
    );
65
71
66
    CancelExpiredReserves();
72
    CancelExpiredReserves();
67
    my $r2 = Koha::Holds->find($reserve2->{reserve_id});
73
    my $r2 = Koha::Holds->find($reserve2->id);
68
    is($r2, undef,'reserve 2 should be canceled.');
74
    is(ref($r2), 'Koha::Hold', 'reserve 2 is still there.');
75
    is($r2->status, 'cancelled', 'reserve 2 should be canceled.');
76
    is($r2->completed, 1, 'reserve 2 should be completed.');
69
77
70
    # Reserve expired on holiday
78
    # Reserve expired on holiday
71
    my $reserve3 = $builder->build({
79
    my $reserve3 = $builder->build_object(
72
        source => 'Reserve',
80
        {
73
        value => {
81
            class => 'Koha::Holds',
74
            reservedate => $reserve_reservedate,
82
            value => {
75
            expirationdate => $reserve2_expirationdate,
83
                created_date      => $reserve_reservedate,
76
            branchcode => 'LIB1',
84
                expiration_date   => $reserve2_expirationdate,
77
            cancellationdate => undef,
85
                pickup_library_id => 'LIB1',
78
            priority => 0,
86
                completed_date    => undef,
79
            found => 'W',
87
                priority          => 0,
80
        },
88
                status            => 'waiting',
81
    });
89
            },
90
        }
91
    );
82
92
83
    Koha::Caches->get_instance()->flush_all();
93
    Koha::Caches->get_instance()->flush_all();
84
    my $holiday = $builder->build({
94
    my $holiday = $builder->build({
Lines 94-106 subtest 'CancelExpiredReserves tests incl. holidays' => sub { Link Here
94
    });
104
    });
95
105
96
    CancelExpiredReserves();
106
    CancelExpiredReserves();
97
    my $r3 = Koha::Holds->find($reserve3->{reserve_id});
107
    $reserve3->discard_changes;
98
    ok($r3,'Reserve 3 should not be canceled.');
108
    is($reserve3->status, 'waiting','Reserve 3 should not be canceled.');
99
109
100
    t::lib::Mocks::mock_preference('ExpireReservesOnHolidays', 1);
110
    t::lib::Mocks::mock_preference('ExpireReservesOnHolidays', 1);
101
    CancelExpiredReserves();
111
    CancelExpiredReserves();
102
    $r3 = Koha::Holds->find($reserve3->{reserve_id});
112
    $reserve3->discard_changes;
103
    is($r3, undef,'Reserve 3 should be canceled.');
113
    is($reserve3->status, 'cancelled', 'Reserve 3 should be cancelled.');
104
};
114
};
105
115
106
subtest 'Test handling of waiting reserves by CancelExpiredReserves' => sub {
116
subtest 'Test handling of waiting reserves by CancelExpiredReserves' => sub {
Lines 119-163 subtest 'Test handling of waiting reserves by CancelExpiredReserves' => sub { Link Here
119
    my $expdate = dt_from_string->add( days => -2 );
129
    my $expdate = dt_from_string->add( days => -2 );
120
    my $notexpdate = dt_from_string->add( days => 2 );
130
    my $notexpdate = dt_from_string->add( days => 2 );
121
131
122
    my $hold1 = Koha::Hold->new({
132
    my $hold1 = Koha::Hold->new(
123
        branchcode => $branchcode,
133
        {
124
        borrowernumber => $borrowernumber,
134
            pickup_library_id => $branchcode,
125
        biblionumber => $item->biblionumber,
135
            patron_id         => $borrowernumber,
126
        priority => 1,
136
            biblio_id         => $item->biblionumber,
127
        reservedate => $resdate,
137
            priority          => 1,
128
        expirationdate => $notexpdate,
138
            created_date      => $resdate,
129
        found => undef,
139
            expiration_date   => $notexpdate,
130
    })->store;
140
            status            => 'placed',
131
141
        }
132
    my $hold2 = Koha::Hold->new({
142
    )->store;
133
        branchcode => $branchcode,
143
134
        borrowernumber => $borrowernumber,
144
    my $hold2 = Koha::Hold->new(
135
        biblionumber => $item->biblionumber,
145
        {
136
        priority => 2,
146
            pickup_library_id => $branchcode,
137
        reservedate => $resdate,
147
            patron_id         => $borrowernumber,
138
        expirationdate => $expdate,
148
            biblio_id         => $item->biblionumber,
139
        found => undef,
149
            priority          => 2,
140
    })->store;
150
            created_date      => $resdate,
141
151
            expiration_date   => $expdate,
142
    my $hold3 = Koha::Hold->new({
152
            status            => 'placed',
143
        branchcode => $branchcode,
153
        }
144
        borrowernumber => $borrowernumber,
154
    )->store;
145
        biblionumber => $item->biblionumber,
155
146
        itemnumber => $itemnumber,
156
    my $hold3 = Koha::Hold->new(
147
        priority => 0,
157
        {
148
        reservedate => $resdate,
158
            pickup_library_id => $branchcode,
149
        expirationdate => $expdate,
159
            patron_id         => $borrowernumber,
150
        found => 'W',
160
            biblio_id         => $item->biblionumber,
151
    })->store;
161
            item_id           => $itemnumber,
162
            priority          => 0,
163
            created_date      => $resdate,
164
            expiration_date   => $expdate,
165
            status            => 'waiting',
166
        }
167
    )->store;
152
168
153
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
169
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
154
    CancelExpiredReserves();
170
    CancelExpiredReserves();
155
    my $count1 = Koha::Holds->search->count;
171
    my $count1 = Koha::Holds->search({ completed => 0 })->count;
156
    is( $count1, 2, 'Only the non-waiting expired holds should be cancelled');
172
    is( $count1, 2, 'Only the non-waiting expired holds should be cancelled');
157
173
158
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
174
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
159
    CancelExpiredReserves();
175
    CancelExpiredReserves();
160
    my $count2 = Koha::Holds->search->count;
176
    my $count2 = Koha::Holds->search({ completed => 0 })->count;
161
    is( $count2, 1, 'Also the waiting expired hold should be cancelled now');
177
    is( $count2, 1, 'Also the waiting expired hold should be cancelled now');
162
178
163
};
179
};
Lines 169-226 subtest 'Test handling of in transit reserves by CancelExpiredReserves' => sub { Link Here
169
185
170
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
186
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
171
    my $expdate = dt_from_string->add( days => -2 );
187
    my $expdate = dt_from_string->add( days => -2 );
172
    my $reserve = $builder->build({
188
    my $reserve = $builder->build_object({
173
        source => 'Reserve',
189
        class => 'Koha::Holds',
174
        value  => {
190
        value  => {
175
            expirationdate => '2018-01-01',
191
            expiration_date      => '2018-01-01',
176
            found => 'T',
192
            status               => 'in_transit',
177
            cancellationdate => undef,
193
            suspended            => 0,
178
            suspend => 0,
194
            completed            => 0,
179
            suspend_until => undef
195
            cancellation_date    => undef,
196
            suspended_until_date => undef,
180
        }
197
        }
181
    });
198
    });
182
    my $count = Koha::Holds->search->count;
199
200
    my $active = Koha::Holds->search({ completed => 0 });
201
    my $count = $active->count;
202
183
    CancelExpiredReserves();
203
    CancelExpiredReserves();
184
    is(Koha::Holds->search->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay set");
204
    is($active->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay set");
185
205
186
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
206
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
187
    my $reserve2 = $builder->build({
207
    my $reserve2 = $builder->build_object({
188
        source => 'Reserve',
208
        class => 'Koha::Holds',
189
        value  => {
209
        value  => {
190
            expirationdate => '2018-01-01',
210
            expiration_date      => '2018-01-01',
191
            found => 'T',
211
            status               => 'in_transit',
192
            cancellationdate => undef,
212
            cancellation_date    => undef,
193
            suspend => 0,
213
            suspended            => 0,
194
            suspend_until => undef
214
            suspended_until_date => undef,
215
            completed            => 0,
195
        }
216
        }
196
    });
217
    });
197
    CancelExpiredReserves();
218
    CancelExpiredReserves();
198
    is(Koha::Holds->search->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay unset");
219
    is($active->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay unset");
199
220
200
};
221
};
201
222
202
subtest 'Test handling of cancellation reason if passed' => sub {
223
subtest 'Test handling of cancellation reason if passed' => sub {
203
    plan tests => 2;
224
    plan tests => 3;
204
225
205
    my $builder = t::lib::TestBuilder->new();
226
    my $builder = t::lib::TestBuilder->new();
206
227
207
    my $expdate = dt_from_string->add( days => -2 );
228
    my $expdate = dt_from_string->add( days => -2 );
208
    my $reserve = $builder->build({
229
    my $hold = $builder->build_object(
209
        source => 'Reserve',
230
        {   class => 'Koha::Holds',
210
        value  => {
231
            value => {
211
            expirationdate => '2018-01-01',
232
                expiration_date    => '2018-01-01',
212
            found => 'T',
233
                status             => 'in_transit',
213
            cancellationdate => undef,
234
                cancellation_date  => undef,
214
            suspend => 0,
235
                suspended          => 0,
215
            suspend_until => undef
236
                suspend_until_date => undef
237
            }
216
        }
238
        }
217
    });
239
    );
218
    my $reserve_id = $reserve->{reserve_id};
240
219
    my $count = Koha::Holds->search->count;
241
    # Cancel the hold
220
    CancelExpiredReserves("EXPIRED");
242
    CancelExpiredReserves("EXPIRED");
221
    is(Koha::Holds->search->count, $count-1, "Hold is cancelled when reason is passed");
243
    $hold->discard_changes;
222
    my $old_reserve = Koha::Old::Holds->find($reserve_id);
244
223
    is($old_reserve->cancellation_reason, 'EXPIRED', "Hold cancellation_reason was set correctly");
245
    is( $hold->status, 'cancelled', "Hold is cancelled when reason is passed");
246
    is( $hold->completed, 1, "Hold is completed");
247
    is( $hold->cancellation_reason, 'EXPIRED', "Hold cancellation_reason was set correctly");
224
};
248
};
225
249
226
$schema->storage->txn_rollback;
250
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Reserves/GetReserveFee.t (-7 / +7 lines)
Lines 119-137 subtest 'Integration with AddReserve' => sub { Link Here
119
        plan tests => 3;
119
        plan tests => 3;
120
120
121
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
121
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
122
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
122
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?",      undef, $biblio->biblionumber );
123
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
123
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
124
        addreserve( $patron1->{borrowernumber} );
124
        addreserve( $patron1->{borrowernumber} );
125
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - No fee charged for patron 1 if not issued' );
125
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - No fee charged for patron 1 if not issued' );
126
126
127
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_placed');
127
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_placed');
128
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
128
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?",      undef, $biblio->biblionumber );
129
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
129
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
130
        addreserve( $patron1->{borrowernumber} );
130
        addreserve( $patron1->{borrowernumber} );
131
        is( acctlines( $patron1->{borrowernumber} ), 1, 'any_time_is_placed - Patron should be always charged' );
131
        is( acctlines( $patron1->{borrowernumber} ), 1, 'any_time_is_placed - Patron should be always charged' );
132
132
133
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_collected');
133
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_collected');
134
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
134
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?",      undef, $biblio->biblionumber );
135
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
135
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
136
        addreserve( $patron1->{borrowernumber} );
136
        addreserve( $patron1->{borrowernumber} );
137
        is( acctlines( $patron1->{borrowernumber} ), 0, 'any_time_is_collected - Patron should not be charged when placing a hold' );
137
        is( acctlines( $patron1->{borrowernumber} ), 0, 'any_time_is_collected - Patron should not be charged when placing a hold' );
Lines 143-154 subtest 'Integration with AddReserve' => sub { Link Here
143
        C4::Circulation::AddIssue( $patron2, $item1->barcode, '2015-12-31', 0, undef, 0, {} );
143
        C4::Circulation::AddIssue( $patron2, $item1->barcode, '2015-12-31', 0, undef, 0, {} );
144
144
145
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
145
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
146
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
146
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?",      undef, $biblio->biblionumber );
147
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
147
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
148
        addreserve( $patron1->{borrowernumber} );
148
        addreserve( $patron1->{borrowernumber} );
149
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - Patron should not be charged if items are not all checked out' );
149
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - Patron should not be charged if items are not all checked out' );
150
150
151
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
151
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?",      undef, $biblio->biblionumber );
152
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
152
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
153
        addreserve( $patron3->{borrowernumber} );
153
        addreserve( $patron3->{borrowernumber} );
154
        addreserve( $patron1->{borrowernumber} );
154
        addreserve( $patron1->{borrowernumber} );
Lines 156-162 subtest 'Integration with AddReserve' => sub { Link Here
156
        is( acctlines( $patron1->{borrowernumber} ), 1, 'not_always - Patron should be charged if all the items are not checked out and at least 1 hold is already placed' );
156
        is( acctlines( $patron1->{borrowernumber} ), 1, 'not_always - Patron should be charged if all the items are not checked out and at least 1 hold is already placed' );
157
157
158
        C4::Circulation::AddIssue( $patron3, $item2->barcode, '2015-12-31', 0, undef, 0, {} );
158
        C4::Circulation::AddIssue( $patron3, $item2->barcode, '2015-12-31', 0, undef, 0, {} );
159
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
159
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->biblionumber );
160
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
160
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
161
        addreserve( $patron1->{borrowernumber} );
161
        addreserve( $patron1->{borrowernumber} );
162
        is( acctlines( $patron1->{borrowernumber} ), 1, 'not_always - Patron should be charged if all items are checked out' );
162
        is( acctlines( $patron1->{borrowernumber} ), 1, 'not_always - Patron should be charged if all items are checked out' );
Lines 167-173 subtest 'Integration with AddIssue' => sub { Link Here
167
    plan tests => 5;
167
    plan tests => 5;
168
168
169
    $dbh->do( "DELETE FROM issues       WHERE borrowernumber = ?", undef, $patron1->{borrowernumber} );
169
    $dbh->do( "DELETE FROM issues       WHERE borrowernumber = ?", undef, $patron1->{borrowernumber} );
170
    $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
170
    $dbh->do( "DELETE FROM holds        WHERE biblio_id=?",      undef, $biblio->biblionumber );
171
    $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
171
    $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
172
172
173
    t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
173
    t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
(-)a/t/db_dependent/Reserves/MultiplePerRecord.t (-9 / +9 lines)
Lines 184-208 is( $max, 9, 'GetMaxPatronHoldsForRecord returns max of 9 because Library specif Link Here
184
184
185
Koha::CirculationRules->delete();
185
Koha::CirculationRules->delete();
186
186
187
my $holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
187
my $holds = Koha::Holds->search( { patron_id => $patron->{borrowernumber} } );
188
is( $holds->forced_hold_level, undef, "No holds does not force an item or record level hold" );
188
is( $holds->forced_hold_level, undef, "No holds does not force an item or record level hold" );
189
189
190
# Test Koha::Holds::forced_hold_level
190
# Test Koha::Holds::forced_hold_level
191
my $hold = Koha::Hold->new({
191
my $hold = Koha::Hold->new({
192
    borrowernumber => $patron->{borrowernumber},
192
    patron_id => $patron->{borrowernumber},
193
    reservedate => '1981-06-10',
193
    created_date => '1981-06-10',
194
    biblionumber => $biblio->biblionumber,
194
    biblio_id => $biblio->biblionumber,
195
    branchcode => $library->{branchcode},
195
    pickup_library_id => $library->{branchcode},
196
    priority => 1,
196
    priority => 1,
197
})->store();
197
})->store();
198
198
199
$holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
199
$holds = Koha::Holds->search( { patron_id => $patron->{borrowernumber} } );
200
is( $holds->forced_hold_level, 'record', "Record level hold forces record level holds" );
200
is( $holds->forced_hold_level, 'record', "Record level hold forces record level holds" );
201
201
202
$hold->itemnumber( $item1->itemnumber );
202
$hold->item_id( $item1->itemnumber );
203
$hold->store();
203
$hold->store();
204
204
205
$holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
205
$holds = Koha::Holds->search( { patron_id => $patron->{borrowernumber} } );
206
is( $holds->forced_hold_level, 'item', "Item level hold forces item level holds" );
206
is( $holds->forced_hold_level, 'item', "Item level hold forces item level holds" );
207
207
208
$hold->delete();
208
$hold->delete();
Lines 247-253 ok( $hold_id, 'Second hold was placed' ); Link Here
247
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->biblionumber);
247
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->biblionumber);
248
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
248
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
249
249
250
Koha::Holds->find($hold_id)->found("W")->store;
250
Koha::Holds->find($hold_id)->set_waiting;
251
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->biblionumber);
251
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->biblionumber);
252
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
252
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
253
253
(-)a/t/db_dependent/Reserves/ReserveSlip.t (-13 / +14 lines)
Lines 31-37 $schema->storage->txn_begin; Link Here
31
31
32
my $dbh = C4::Context->dbh;
32
my $dbh = C4::Context->dbh;
33
$dbh->do(q|DELETE FROM letter|);
33
$dbh->do(q|DELETE FROM letter|);
34
$dbh->do(q|DELETE FROM reserves|);
34
$dbh->do(q|DELETE FROM holds|);
35
35
36
my $builder = t::lib::TestBuilder->new();
36
my $builder = t::lib::TestBuilder->new();
37
my $library = $builder->build(
37
my $library = $builder->build(
Lines 66-89 my $item2 = $builder->build_sample_item( Link Here
66
66
67
my $hold1 = Koha::Hold->new(
67
my $hold1 = Koha::Hold->new(
68
    {
68
    {
69
        biblionumber   => $biblio->biblionumber,
69
        biblio_id         => $biblio->biblionumber,
70
        itemnumber     => $item1->itemnumber,
70
        item_id           => $item1->itemnumber,
71
        waitingdate    => '2000-01-01',
71
        waiting_date      => '2000-01-01',
72
        borrowernumber => $patron->{borrowernumber},
72
        patron_id         => $patron->{borrowernumber},
73
        branchcode     => $library->{branchcode},
73
        pickup_library_id => $library->{branchcode},
74
    }
74
    }
75
)->store;
75
)->store;
76
76
77
my $hold2 = Koha::Hold->new(
77
my $hold2 = Koha::Hold->new(
78
    {
78
    {
79
        biblionumber   => $biblio->biblionumber,
79
        biblio_id         => $biblio->biblionumber,
80
        itemnumber     => $item2->itemnumber,
80
        item_id           => $item2->itemnumber,
81
        waitingdate    => '2000-01-01',
81
        waiting_date      => '2000-01-01',
82
        borrowernumber => $patron->{borrowernumber},
82
        patron_id         => $patron->{borrowernumber},
83
        branchcode     => $library->{branchcode},
83
        pickup_library_id => $library->{branchcode},
84
    }
84
    }
85
)->store;
85
)->store;
86
86
87
87
my $letter = $builder->build(
88
my $letter = $builder->build(
88
    {
89
    {
89
        source => 'Letter',
90
        source => 'Letter',
Lines 101-113 my $letter = $builder->build( Link Here
101
is ( ReserveSlip(), undef, "No hold slip returned if invalid or undef borrowernumber and/or biblionumber" );
102
is ( ReserveSlip(), undef, "No hold slip returned if invalid or undef borrowernumber and/or biblionumber" );
102
is ( ReserveSlip({
103
is ( ReserveSlip({
103
        branchcode     => $library->{branchcode},
104
        branchcode     => $library->{branchcode},
104
        reserve_id     => $hold1->reserve_id,
105
        reserve_id     => $hold1->id,
105
    })->{code},
106
    })->{code},
106
    'HOLD_SLIP', "Get a hold slip from library, patron and biblio" );
107
    'HOLD_SLIP', "Get a hold slip from library, patron and biblio" );
107
108
108
is (ReserveSlip({
109
is (ReserveSlip({
109
        branchcode     => $library->{branchcode},
110
        branchcode     => $library->{branchcode},
110
        reserve_id     => $hold1->reserve_id,
111
        reserve_id     => $hold1->id,
111
    })->{content},
112
    })->{content},
112
    sprintf( "Hold found for %s: Please pick up %s with barcode %s at %s.", $patron->{firstname}, $biblio->title, $item1->barcode, $library->{branchcode}),"Hold slip contains correctly parsed content");
113
    sprintf( "Hold found for %s: Please pick up %s with barcode %s at %s.", $patron->{firstname}, $biblio->title, $item1->barcode, $library->{branchcode}),"Hold slip contains correctly parsed content");
113
114
(-)a/t/db_dependent/TestBuilder.t (-6 / +11 lines)
Lines 67-75 subtest 'Start with some trivial tests' => sub { Link Here
67
subtest 'Build all sources' => sub {
67
subtest 'Build all sources' => sub {
68
    plan tests => 1;
68
    plan tests => 1;
69
69
70
    my $excluded_sources = {
71
        Reserve    => 1, # view
72
        OldReserve => 1, # view
73
    };
70
    my @sources = $builder->schema->sources;
74
    my @sources = $builder->schema->sources;
71
    my @source_in_failure;
75
    my @source_in_failure;
72
    for my $source ( @sources ) {
76
    for my $source ( grep { not $excluded_sources->{$_} } @sources ) {
73
        my $res;
77
        my $res;
74
        # Skip the source if it is a view
78
        # Skip the source if it is a view
75
        next if $schema->source($source)->isa('DBIx::Class::ResultSource::View');
79
        next if $schema->source($source)->isa('DBIx::Class::ResultSource::View');
Lines 250-260 subtest 'Test build with NULL values' => sub { Link Here
250
    is( $info->{is_nullable} && $item && !defined( $item->{barcode} ), 1,
254
    is( $info->{is_nullable} && $item && !defined( $item->{barcode} ), 1,
251
        'Barcode can be NULL' );
255
        'Barcode can be NULL' );
252
    # Nullable FK
256
    # Nullable FK
253
    $params = { source => 'Reserve', value  => { itemnumber => undef }};
257
    $params = { source => 'Hold', value  => { item_id => undef }};
254
    my $reserve = $builder->build( $params );
258
    my $hold = $builder->build( $params );
255
    $info = $schema->source( 'Reserve' )->column_info( 'itemnumber' );
259
    $info = $schema->source( 'Hold' )->column_info( 'item_id' );
256
    is( $reserve && $info->{is_nullable} && $info->{is_foreign_key} &&
260
    is( $hold && $info->{is_nullable} && $info->{is_foreign_key} &&
257
        !defined( $reserve->{itemnumber} ), 1, 'Nullable FK' );
261
        !defined( $hold->{item_id} ), 1, 'Nullable FK' );
258
};
262
};
259
263
260
264
Lines 396-401 subtest 'build_object() tests' => sub { Link Here
396
            $module =~ s|^.*/(Koha.*)\.pm$|$1|;
400
            $module =~ s|^.*/(Koha.*)\.pm$|$1|;
397
            $module =~ s|/|::|g;
401
            $module =~ s|/|::|g;
398
            next if $module eq 'Koha::Objects';
402
            next if $module eq 'Koha::Objects';
403
            next if $module eq 'Koha::Old::Holds'; #This is a view now
399
            eval "require $module";
404
            eval "require $module";
400
            my $object = $builder->build_object( { class => $module } );
405
            my $object = $builder->build_object( { class => $module } );
401
            is( ref($object), $module->object_class, "Testing $module" );
406
            is( ref($object), $module->object_class, "Testing $module" );
(-)a/t/db_dependent/XSLT.t (-4 / +5 lines)
Lines 117-126 subtest 'buildKohaItemsNamespace status tests' => sub { Link Here
117
    like($xml,qr{<status>In transit</status>},"In-transit status takes precedence over Damaged");
117
    like($xml,qr{<status>In transit</status>},"In-transit status takes precedence over Damaged");
118
118
119
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
119
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
120
        biblionumber => $item->biblionumber,
120
        biblio_id => $item->biblionumber,
121
        itemnumber   => $item->itemnumber,
121
        item_id   => $item->itemnumber,
122
        found        => 'W',
122
        status    => 'waiting',
123
        priority     => 0,
123
        priority  => 0,
124
        completed => 0,
124
        }
125
        }
125
    });
126
    });
126
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
127
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
(-)a/t/db_dependent/api/v1/holds.t (-46 / +55 lines)
Lines 162-169 my $post_data = { Link Here
162
    expiration_date   => output_pref( { dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 } ),
162
    expiration_date   => output_pref( { dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 } ),
163
};
163
};
164
my $patch_data = {
164
my $patch_data = {
165
    priority        => 2,
165
    priority             => 2,
166
    suspended_until => output_pref( { dt => $suspended_until, dateformat => 'rfc3339' } ),
166
    suspended_until_date => output_pref( { dt => $suspended_until, dateformat => 'rfc3339' } ),
167
};
167
};
168
168
169
subtest "Test endpoints without authentication" => sub {
169
subtest "Test endpoints without authentication" => sub {
Lines 320-326 subtest 'test AllowHoldDateInFuture' => sub { Link Here
320
320
321
    plan tests => 6;
321
    plan tests => 6;
322
322
323
    $dbh->do('DELETE FROM reserves');
323
    $dbh->do('DELETE FROM holds');
324
324
325
    my $future_hold_date = DateTime->now->add(days => 10)->truncate( to => 'day' );
325
    my $future_hold_date = DateTime->now->add(days => 10)->truncate( to => 'day' );
326
326
Lines 329-336 subtest 'test AllowHoldDateInFuture' => sub { Link Here
329
        biblio_id         => $biblio_1->biblionumber,
329
        biblio_id         => $biblio_1->biblionumber,
330
        item_id           => $item_1->itemnumber,
330
        item_id           => $item_1->itemnumber,
331
        pickup_library_id => $branchcode,
331
        pickup_library_id => $branchcode,
332
        expiration_date   => output_pref( { dt => $expiration_date,  dateformat => 'rfc3339', dateonly => 1 } ),
332
        expiration_date   => output_pref({ dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 }),
333
        hold_date         => output_pref( { dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 } ),
333
        created_date      => output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }),
334
    };
334
    };
335
335
336
    t::lib::Mocks::mock_preference( 'AllowHoldDateInFuture', 0 );
336
    t::lib::Mocks::mock_preference( 'AllowHoldDateInFuture', 0 );
Lines 349-355 subtest 'test AllowHoldDateInFuture' => sub { Link Here
349
349
350
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
350
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
351
      ->status_is(201)
351
      ->status_is(201)
352
      ->json_is('/hold_date', output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }));
352
      ->json_is('/created_date', output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }));
353
};
353
};
354
354
355
$schema->storage->txn_rollback;
355
$schema->storage->txn_rollback;
Lines 471-477 subtest 'suspend and resume tests' => sub { Link Here
471
471
472
    my $hold = $builder->build_object(
472
    my $hold = $builder->build_object(
473
        {   class => 'Koha::Holds',
473
        {   class => 'Koha::Holds',
474
            value => { suspend => 0, suspend_until => undef, waitingdate => undef, found => undef }
474
            value => {
475
                suspended    => 0,
476
                waiting_date => undef,
477
                suspended_until_date => undef,
478
                completed => 0
479
            }
475
        }
480
        }
476
    );
481
    );
477
482
Lines 482-488 subtest 'suspend and resume tests' => sub { Link Here
482
    $hold->discard_changes;    # refresh object
487
    $hold->discard_changes;    # refresh object
483
488
484
    ok( $hold->is_suspended, 'Hold is suspended' );
489
    ok( $hold->is_suspended, 'Hold is suspended' );
485
    $t->json_is('/end_date', undef, 'Hold suspension has no end date');
490
    $t->json_is('/suspended_until_date', undef, 'Hold suspension has no end date');
486
491
487
    my $end_date = output_pref({
492
    my $end_date = output_pref({
488
      dt         => dt_from_string( undef ),
493
      dt         => dt_from_string( undef ),
Lines 498-504 subtest 'suspend and resume tests' => sub { Link Here
498
    $t->json_is(
503
    $t->json_is(
499
      '/end_date',
504
      '/end_date',
500
      output_pref({
505
      output_pref({
501
        dt         => dt_from_string( $hold->suspend_until ),
506
        dt         => dt_from_string( $hold->suspended_until_date ),
502
        dateformat => 'rfc3339',
507
        dateformat => 'rfc3339',
503
        dateonly   => 1
508
        dateonly   => 1
504
      }),
509
      }),
Lines 531-543 subtest 'suspend and resume tests' => sub { Link Here
531
536
532
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
537
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
533
      ->status_is( 400, 'Cannot suspend waiting hold' )
538
      ->status_is( 400, 'Cannot suspend waiting hold' )
534
      ->json_is( '/error', 'Found hold cannot be suspended. Status=W' );
539
      ->json_is( '/error', 'Found hold cannot be suspended. Status=waiting' );
535
540
536
    $hold->set_transfer->discard_changes;
541
    $hold->set_transfer->discard_changes;
537
542
538
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
543
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
539
      ->status_is( 400, 'Cannot suspend hold on transfer' )
544
      ->status_is( 400, 'Cannot suspend hold on transfer' )
540
      ->json_is( '/error', 'Found hold cannot be suspended. Status=T' );
545
      ->json_is( '/error', 'Found hold cannot be suspended. Status=in_transit' );
541
546
542
    $schema->storage->txn_rollback;
547
    $schema->storage->txn_rollback;
543
};
548
};
Lines 837-856 subtest 'pickup_locations() tests' => sub { Link Here
837
        {
842
        {
838
            class => 'Koha::Holds',
843
            class => 'Koha::Holds',
839
            value => {
844
            value => {
840
                itemnumber     => undef,
845
                item_id   => undef,
841
                biblionumber   => $item->biblionumber,
846
                biblio_id => $item->biblionumber,
842
                borrowernumber => $patron->borrowernumber
847
                patron_id => $patron->borrowernumber,
848
                completed => 0,
843
            }
849
            }
844
        }
850
        }
845
    );
851
    );
852
846
    # item-level hold
853
    # item-level hold
847
    my $hold_2 = $builder->build_object(
854
    my $hold_2 = $builder->build_object(
848
        {
855
        {
849
            class => 'Koha::Holds',
856
            class => 'Koha::Holds',
850
            value => {
857
            value => {
851
                itemnumber     => $item->itemnumber,
858
                item_id   => $item->itemnumber,
852
                biblionumber   => $item->biblionumber,
859
                biblio_id => $item->biblionumber,
853
                borrowernumber => $patron->borrowernumber
860
                patron_id => $patron->borrowernumber,
861
                completed => 0,
854
            }
862
            }
855
        }
863
        }
856
    );
864
    );
Lines 943-952 subtest 'edit() tests' => sub { Link Here
943
        {
951
        {
944
            class => "Koha::Holds",
952
            class => "Koha::Holds",
945
            value => {
953
            value => {
946
                biblionumber => $biblio->biblionumber,
954
                biblio_id         => $biblio->biblionumber,
947
                branchcode   => $library_3->branchcode,
955
                pickup_library_id => $library_3->branchcode,
948
                itemnumber   => undef,
956
                item_id           => undef,
949
                priority     => 1,
957
                priority          => 1,
958
                completed         => 0,
950
            }
959
            }
951
        }
960
        }
952
    );
961
    );
Lines 970-976 subtest 'edit() tests' => sub { Link Here
970
      ->json_is({ error => 'The supplied pickup location is not valid' });
979
      ->json_is({ error => 'The supplied pickup location is not valid' });
971
980
972
    $biblio_hold->discard_changes;
981
    $biblio_hold->discard_changes;
973
    is( $biblio_hold->branchcode, $library_3->branchcode, 'branchcode remains untouched' );
982
    is( $biblio_hold->pickup_library_id, $library_3->branchcode, 'pickup_library_id remains untouched' );
974
983
975
    $t->patch_ok( "//$userid:$password@/api/v1/holds/" . $biblio_hold->id
984
    $t->patch_ok( "//$userid:$password@/api/v1/holds/" . $biblio_hold->id
976
          => { 'x-koha-override' => 'any' }
985
          => { 'x-koha-override' => 'any' }
Lines 991-997 subtest 'edit() tests' => sub { Link Here
991
      ->status_is(200);
1000
      ->status_is(200);
992
1001
993
    $biblio_hold->discard_changes;
1002
    $biblio_hold->discard_changes;
994
    is( $biblio_hold->branchcode, $library_2->id, 'Pickup location changed correctly' );
1003
    is( $biblio_hold->pickup_library_id, $library_2->id, 'Pickup location changed correctly' );
995
1004
996
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
1005
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
997
          . $biblio_hold->id
1006
          . $biblio_hold->id
Lines 999-1015 subtest 'edit() tests' => sub { Link Here
999
      ->status_is(200);
1008
      ->status_is(200);
1000
1009
1001
    $biblio_hold->discard_changes;
1010
    $biblio_hold->discard_changes;
1002
    is( $biblio_hold->branchcode, $library_2->id, 'Pickup location changed correctly' );
1011
    is( $biblio_hold->pickup_library_id, $library_2->id, 'Pickup location changed correctly' );
1003
1012
1004
    # Test item-level holds
1013
    # Test item-level holds
1005
    my $item_hold = $builder->build_object(
1014
    my $item_hold = $builder->build_object(
1006
        {
1015
        {
1007
            class => "Koha::Holds",
1016
            class => "Koha::Holds",
1008
            value => {
1017
            value => {
1009
                biblionumber => $biblio->biblionumber,
1018
                biblio_id         => $biblio->biblionumber,
1010
                branchcode   => $library_3->branchcode,
1019
                pickup_library_id => $library_3->branchcode,
1011
                itemnumber   => $item->itemnumber,
1020
                item_id           => $item->itemnumber,
1012
                priority     => 1,
1021
                priority          => 1,
1022
                completed         => 0,
1013
            }
1023
            }
1014
        }
1024
        }
1015
    );
1025
    );
Lines 1033-1039 subtest 'edit() tests' => sub { Link Here
1033
      ->json_is({ error => 'The supplied pickup location is not valid' });
1043
      ->json_is({ error => 'The supplied pickup location is not valid' });
1034
1044
1035
    $item_hold->discard_changes;
1045
    $item_hold->discard_changes;
1036
    is( $item_hold->branchcode, $library_3->branchcode, 'branchcode remains untouched' );
1046
    is( $item_hold->pickup_library_id, $library_3->branchcode, 'branchcode remains untouched' );
1037
1047
1038
    $t->patch_ok( "//$userid:$password@/api/v1/holds/" . $item_hold->id
1048
    $t->patch_ok( "//$userid:$password@/api/v1/holds/" . $item_hold->id
1039
          => { 'x-koha-override' => 'any' }
1049
          => { 'x-koha-override' => 'any' }
Lines 1059-1065 subtest 'edit() tests' => sub { Link Here
1059
      ->status_is(200);
1069
      ->status_is(200);
1060
1070
1061
    $item_hold->discard_changes;
1071
    $item_hold->discard_changes;
1062
    is( $item_hold->branchcode, $library_2->id, 'Pickup location changed correctly' );
1072
    is( $item_hold->pickup_library_id, $library_2->id, 'Pickup location changed correctly' );
1063
1073
1064
    $schema->storage->txn_rollback;
1074
    $schema->storage->txn_rollback;
1065
};
1075
};
Lines 1131-1140 subtest 'add() tests' => sub { Link Here
1131
        {
1141
        {
1132
            class => "Koha::Holds",
1142
            class => "Koha::Holds",
1133
            value => {
1143
            value => {
1134
                biblionumber => $biblio->biblionumber,
1144
                biblio_id         => $biblio->biblionumber,
1135
                branchcode   => $library_3->branchcode,
1145
                pickup_library_id => $library_3->branchcode,
1136
                itemnumber   => undef,
1146
                item_id           => undef,
1137
                priority     => 1,
1147
                priority          => 1,
1138
            }
1148
            }
1139
        }
1149
        }
1140
    );
1150
    );
Lines 1160-1169 subtest 'add() tests' => sub { Link Here
1160
        {
1170
        {
1161
            class => "Koha::Holds",
1171
            class => "Koha::Holds",
1162
            value => {
1172
            value => {
1163
                biblionumber => $biblio->biblionumber,
1173
                biblio_id         => $biblio->biblionumber,
1164
                branchcode   => $library_3->branchcode,
1174
                pickup_library_id => $library_3->branchcode,
1165
                itemnumber   => $item->itemnumber,
1175
                item_id           => $item->itemnumber,
1166
                priority     => 1,
1176
                priority          => 1,
1167
            }
1177
            }
1168
        }
1178
        }
1169
    );
1179
    );
Lines 1250-1256 subtest 'PUT /holds/{hold_id}/pickup_location tests' => sub { Link Here
1250
      ->status_is(200)
1260
      ->status_is(200)
1251
      ->json_is({ pickup_library_id => $library_2->branchcode });
1261
      ->json_is({ pickup_library_id => $library_2->branchcode });
1252
1262
1253
    is( $hold->discard_changes->branchcode->branchcode, $library_2->branchcode, 'pickup library adjusted correctly' );
1263
    is( $hold->discard_changes->pickup_library_id, $library_2->branchcode, 'pickup library adjusted correctly' );
1254
1264
1255
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
1265
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
1256
          . $hold->id
1266
          . $hold->id
Lines 1258-1264 subtest 'PUT /holds/{hold_id}/pickup_location tests' => sub { Link Here
1258
      ->status_is(400)
1268
      ->status_is(400)
1259
      ->json_is({ error => '[The supplied pickup location is not valid]' });
1269
      ->json_is({ error => '[The supplied pickup location is not valid]' });
1260
1270
1261
    is( $hold->discard_changes->branchcode->branchcode, $library_2->branchcode, 'pickup library unchanged' );
1271
    is( $hold->discard_changes->pickup_library_id, $library_2->branchcode, 'pickup library unchanged' );
1262
1272
1263
    # item-level hold
1273
    # item-level hold
1264
    $hold = Koha::Holds->find(
1274
    $hold = Koha::Holds->find(
Lines 1280-1286 subtest 'PUT /holds/{hold_id}/pickup_location tests' => sub { Link Here
1280
      ->status_is(400)
1290
      ->status_is(400)
1281
      ->json_is({ error => '[The supplied pickup location is not valid]' });
1291
      ->json_is({ error => '[The supplied pickup location is not valid]' });
1282
1292
1283
    is( $hold->discard_changes->branchcode->branchcode, $library_1->branchcode, 'pickup library unchanged' );
1293
    is( $hold->discard_changes->pickup_library_id, $library_1->branchcode, 'pickup library unchanged' );
1284
1294
1285
    t::lib::Mocks::mock_preference( 'AllowHoldPolicyOverride', 1 );
1295
    t::lib::Mocks::mock_preference( 'AllowHoldPolicyOverride', 1 );
1286
1296
Lines 1293-1299 subtest 'PUT /holds/{hold_id}/pickup_location tests' => sub { Link Here
1293
      ->status_is(200)
1303
      ->status_is(200)
1294
      ->json_is({ pickup_library_id => $library_2->branchcode });
1304
      ->json_is({ pickup_library_id => $library_2->branchcode });
1295
1305
1296
    is( $hold->discard_changes->branchcode->branchcode, $library_2->branchcode, 'pickup library changed' );
1306
    is( $hold->discard_changes->pickup_library_id, $library_2->branchcode, 'pickup library changed' );
1297
1307
1298
    t::lib::Mocks::mock_preference( 'AllowHoldPolicyOverride', 0 );
1308
    t::lib::Mocks::mock_preference( 'AllowHoldPolicyOverride', 0 );
1299
1309
Lines 1303-1309 subtest 'PUT /holds/{hold_id}/pickup_location tests' => sub { Link Here
1303
      ->status_is(200)
1313
      ->status_is(200)
1304
      ->json_is({ pickup_library_id => $library_2->branchcode });
1314
      ->json_is({ pickup_library_id => $library_2->branchcode });
1305
1315
1306
    is( $hold->discard_changes->branchcode->branchcode, $library_2->branchcode, 'pickup library adjusted correctly' );
1316
    is( $hold->discard_changes->pickup_library_id, $library_2->branchcode, 'pickup library adjusted correctly' );
1307
1317
1308
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
1318
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
1309
          . $hold->id
1319
          . $hold->id
Lines 1311-1317 subtest 'PUT /holds/{hold_id}/pickup_location tests' => sub { Link Here
1311
      ->status_is(400)
1321
      ->status_is(400)
1312
      ->json_is({ error => '[The supplied pickup location is not valid]' });
1322
      ->json_is({ error => '[The supplied pickup location is not valid]' });
1313
1323
1314
    is( $hold->discard_changes->branchcode->branchcode, $library_2->branchcode, 'invalid pickup library not used' );
1324
    is( $hold->discard_changes->pickup_library_id, $library_2->branchcode, 'invalid pickup library not used' );
1315
1325
1316
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
1326
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
1317
          . $hold->id
1327
          . $hold->id
Lines 1321-1327 subtest 'PUT /holds/{hold_id}/pickup_location tests' => sub { Link Here
1321
      ->status_is(400)
1331
      ->status_is(400)
1322
      ->json_is({ error => '[The supplied pickup location is not valid]' });
1332
      ->json_is({ error => '[The supplied pickup location is not valid]' });
1323
1333
1324
    is( $hold->discard_changes->branchcode->branchcode, $library_2->branchcode, 'invalid pickup library not used, even if x-koha-override is passed' );
1334
    is( $hold->discard_changes->pickup_library_id, $library_2->branchcode, 'invalid pickup library not used, even if x-koha-override is passed' );
1325
1335
1326
    $schema->storage->txn_rollback;
1336
    $schema->storage->txn_rollback;
1327
};
1337
};
1328
- 

Return to bug 25260