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

(-)a/C4/Circulation.pm (-12 / +12 lines)
Lines 1024-1030 sub CanBookBeIssued { Link Here
1024
        # See if the item is on reserve.
1024
        # See if the item is on reserve.
1025
        my ( $restype, $res ) = C4::Reserves::CheckReserves( $item_object->itemnumber );
1025
        my ( $restype, $res ) = C4::Reserves::CheckReserves( $item_object->itemnumber );
1026
        if ($restype) {
1026
        if ($restype) {
1027
            my $resbor = $res->{'borrowernumber'};
1027
            my $resbor = $res->{'patron_id'};
1028
            if ( $resbor ne $patron->borrowernumber ) {
1028
            if ( $resbor ne $patron->borrowernumber ) {
1029
                my $patron = Koha::Patrons->find( $resbor );
1029
                my $patron = Koha::Patrons->find( $resbor );
1030
                if ( $restype eq "Waiting" )
1030
                if ( $restype eq "Waiting" )
Lines 1036-1043 sub CanBookBeIssued { Link Here
1036
                    $needsconfirmation{'ressurname'} = $patron->surname;
1036
                    $needsconfirmation{'ressurname'} = $patron->surname;
1037
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1037
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1038
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1038
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1039
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1039
                    $needsconfirmation{'resbranchcode'} = $res->{pickup_library_id};
1040
                    $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'};
1040
                    $needsconfirmation{'reswaitingdate'} = $res->{'waiting_date'};
1041
                }
1041
                }
1042
                elsif ( $restype eq "Reserved" ) {
1042
                elsif ( $restype eq "Reserved" ) {
1043
                    # The item is on reserve for someone else.
1043
                    # The item is on reserve for someone else.
Lines 1046-1053 sub CanBookBeIssued { Link Here
1046
                    $needsconfirmation{'ressurname'} = $patron->surname;
1046
                    $needsconfirmation{'ressurname'} = $patron->surname;
1047
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1047
                    $needsconfirmation{'rescardnumber'} = $patron->cardnumber;
1048
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1048
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1049
                    $needsconfirmation{'resbranchcode'} = $patron->branchcode;
1049
                    $needsconfirmation{'resbranchcode'} = $patron->pickup_library_id;
1050
                    $needsconfirmation{'resreservedate'} = $res->{reservedate};
1050
                    $needsconfirmation{'resreservedate'} = $res->{placing_date};
1051
                }
1051
                }
1052
            }
1052
            }
1053
        }
1053
        }
Lines 1190-1196 sub checkHighHolds { Link Here
1190
        due_date    => undef,
1190
        due_date    => undef,
1191
    };
1191
    };
1192
1192
1193
    my $holds = Koha::Holds->search( { biblionumber => $item->{'biblionumber'} } );
1193
    my $holds = Koha::Holds->search( { biblio_id => $item->{'biblionumber'} } );
1194
1194
1195
    if ( $holds->count() ) {
1195
    if ( $holds->count() ) {
1196
        $return_data->{outstanding} = $holds->count();
1196
        $return_data->{outstanding} = $holds->count();
Lines 2018-2025 sub AddReturn { Link Here
2018
                "UPDATE branchtransfers SET datearrived = now() WHERE itemnumber= ? AND datearrived IS NULL"
2018
                "UPDATE branchtransfers SET datearrived = now() WHERE itemnumber= ? AND datearrived IS NULL"
2019
            );
2019
            );
2020
            $sth->execute( $item->itemnumber );
2020
            $sth->execute( $item->itemnumber );
2021
            # if we have a reservation with valid transfer, we can set it's status to 'W'
2021
            # if we have a reservation with valid transfer, we can set it's status to 'waiting'
2022
            C4::Reserves::ModReserveStatus($item->itemnumber, 'W');
2022
            C4::Reserves::ModReserveStatus($item->itemnumber, 'waiting');
2023
        } else {
2023
        } else {
2024
            $messages->{'WrongTransfer'}     = $tobranch;
2024
            $messages->{'WrongTransfer'}     = $tobranch;
2025
            $messages->{'WrongTransferItem'} = $item->itemnumber;
2025
            $messages->{'WrongTransferItem'} = $item->itemnumber;
Lines 2082-2088 sub AddReturn { Link Here
2082
    my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2082
    my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2083
    ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->itemnumber, undef, $lookahead ) unless ( $item->withdrawn );
2083
    ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->itemnumber, undef, $lookahead ) unless ( $item->withdrawn );
2084
    # 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)
2084
    # 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)
2085
    if ( $resfound eq "Waiting" and $branch ne $resrec->{branchcode} ) {
2085
    if ( $resfound && $resfound eq "Waiting" and $branch ne $resrec->{pickup_library_id} ) {
2086
        my $hold = C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
2086
        my $hold = C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
2087
        $resfound = 'Reserved';
2087
        $resfound = 'Reserved';
2088
        $resrec = $hold->unblessed;
2088
        $resrec = $hold->unblessed;
Lines 2844-2850 sub CanBookBeRenewed { Link Here
2844
    {
2844
    {
2845
        my $schema = Koha::Database->new()->schema();
2845
        my $schema = Koha::Database->new()->schema();
2846
2846
2847
        my $item_holds = $schema->resultset('Reserve')->search( { itemnumber => $itemnumber, found => undef } )->count();
2847
        my $item_holds = Koha::Holds->search( { item_id => $itemnumber, status => 'placed', completed => 0 } )->count();
2848
        if ($item_holds) {
2848
        if ($item_holds) {
2849
            # There is an item level hold on this item, no other item can fill the hold
2849
            # There is an item level hold on this item, no other item can fill the hold
2850
            $resfound = 1;
2850
            $resfound = 1;
Lines 2854-2860 sub CanBookBeRenewed { Link Here
2854
            # Get all other items that could possibly fill reserves
2854
            # Get all other items that could possibly fill reserves
2855
            my @itemnumbers = $schema->resultset('Item')->search(
2855
            my @itemnumbers = $schema->resultset('Item')->search(
2856
                {
2856
                {
2857
                    biblionumber => $resrec->{biblionumber},
2857
                    biblionumber => $resrec->{biblio_id},
2858
                    onloan       => undef,
2858
                    onloan       => undef,
2859
                    notforloan   => 0,
2859
                    notforloan   => 0,
2860
                    -not         => { itemnumber => $itemnumber }
2860
                    -not         => { itemnumber => $itemnumber }
Lines 2869-2875 sub CanBookBeRenewed { Link Here
2869
                  C4::Reserves::CheckReserves( $itemnumber, undef, undef, \@borrowernumbers );
2869
                  C4::Reserves::CheckReserves( $itemnumber, undef, undef, \@borrowernumbers );
2870
2870
2871
                if ($reserve_found) {
2871
                if ($reserve_found) {
2872
                    push( @borrowernumbers, $reserve->{borrowernumber} );
2872
                    push( @borrowernumbers, $reserve->{patron_id} );
2873
                }
2873
                }
2874
                else {
2874
                else {
2875
                    last;
2875
                    last;
(-)a/C4/Letters.pm (-5 / +5 lines)
Lines 745-751 sub _parseletter_sth { Link Here
745
    ($table eq 'items'        )    ? "SELECT * FROM $table WHERE     itemnumber = ?"                                  :
745
    ($table eq 'items'        )    ? "SELECT * FROM $table WHERE     itemnumber = ?"                                  :
746
    ($table eq 'issues'       )    ? "SELECT * FROM $table WHERE     itemnumber = ?"                                  :
746
    ($table eq 'issues'       )    ? "SELECT * FROM $table WHERE     itemnumber = ?"                                  :
747
    ($table eq 'old_issues'   )    ? "SELECT * FROM $table WHERE     itemnumber = ? ORDER BY timestamp DESC LIMIT 1"  :
747
    ($table eq 'old_issues'   )    ? "SELECT * FROM $table WHERE     itemnumber = ? ORDER BY timestamp DESC LIMIT 1"  :
748
    ($table eq 'reserves'     )    ? "SELECT * FROM $table WHERE borrowernumber = ? and biblionumber = ?"             :
748
    ($table eq 'holds'     )       ? "SELECT * FROM $table WHERE patron_id = ? and biblio_id = ?"             :
749
    ($table eq 'borrowers'    )    ? "SELECT * FROM $table WHERE borrowernumber = ?"                                  :
749
    ($table eq 'borrowers'    )    ? "SELECT * FROM $table WHERE borrowernumber = ?"                                  :
750
    ($table eq 'branches'     )    ? "SELECT * FROM $table WHERE     branchcode = ?"                                  :
750
    ($table eq 'branches'     )    ? "SELECT * FROM $table WHERE     branchcode = ?"                                  :
751
    ($table eq 'suggestions'  )    ? "SELECT * FROM $table WHERE   suggestionid = ?"                                  :
751
    ($table eq 'suggestions'  )    ? "SELECT * FROM $table WHERE   suggestionid = ?"                                  :
Lines 791-798 sub _parseletter { Link Here
791
        $values->{'dateexpiry'} = output_pref({ dt => dt_from_string( $values->{'dateexpiry'} ), dateonly => 1 });
791
        $values->{'dateexpiry'} = output_pref({ dt => dt_from_string( $values->{'dateexpiry'} ), dateonly => 1 });
792
    }
792
    }
793
793
794
    if ( $table eq 'reserves' && $values->{'waitingdate'} ) {
794
    if ( $table eq 'holds' && $values->{'waiting_date'} ) {
795
        $values->{'waitingdate'} = output_pref({ dt => dt_from_string( $values->{'waitingdate'} ), dateonly => 1 });
795
        $values->{'waiting_date'} = output_pref({ dt => dt_from_string( $values->{'waiting_date'} ), dateonly => 1 });
796
    }
796
    }
797
797
798
    if ($letter->{content} && $letter->{content} =~ /<<today>>/) {
798
    if ($letter->{content} && $letter->{content} =~ /<<today>>/) {
Lines 1515-1525 sub _get_tt_params { Link Here
1515
            plural   => 'orders',
1515
            plural   => 'orders',
1516
            pk       => 'ordernumber',
1516
            pk       => 'ordernumber',
1517
        },
1517
        },
1518
        reserves => {
1518
        holds => {
1519
            module   => 'Koha::Holds',
1519
            module   => 'Koha::Holds',
1520
            singular => 'hold',
1520
            singular => 'hold',
1521
            plural   => 'holds',
1521
            plural   => 'holds',
1522
            fk       => [ 'borrowernumber', 'biblionumber' ],
1522
            fk       => [ 'patron_id', 'biblio_id' ],
1523
        },
1523
        },
1524
        serial => {
1524
        serial => {
1525
            module   => 'Koha::Serials',
1525
            module   => 'Koha::Serials',
(-)a/C4/Members.pm (-1 / +1 lines)
Lines 234-240 sub patronflags { Link Here
234
        $flags{'ODUES'} = \%flaginfo;
234
        $flags{'ODUES'} = \%flaginfo;
235
    }
235
    }
236
236
237
    my $waiting_holds = $patron->holds->search({ found => 'W' });
237
    my $waiting_holds = $patron->holds->search({ status => 'waiting' });
238
    my $nowaiting = $waiting_holds->count;
238
    my $nowaiting = $waiting_holds->count;
239
    if ( $nowaiting > 0 ) {
239
    if ( $nowaiting > 0 ) {
240
        my %flaginfo;
240
        my %flaginfo;
(-)a/C4/Reserves.pm (-246 / +250 lines)
Lines 38-49 use Koha::Calendar; Link Here
38
use Koha::CirculationRules;
38
use Koha::CirculationRules;
39
use Koha::Database;
39
use Koha::Database;
40
use Koha::DateUtils;
40
use Koha::DateUtils;
41
use Koha::Hold;
42
use Koha::Holds;
41
use Koha::Holds;
43
use Koha::ItemTypes;
42
use Koha::ItemTypes;
44
use Koha::Items;
43
use Koha::Items;
45
use Koha::Libraries;
44
use Koha::Libraries;
46
use Koha::Old::Hold;
47
use Koha::Patrons;
45
use Koha::Patrons;
48
46
49
use Carp;
47
use Carp;
Lines 170-176 The following tables are available witin the HOLDPLACED message: Link Here
170
    reserves
168
    reserves
171
169
172
=cut
170
=cut
173
171
use Carp::Always;
174
sub AddReserve {
172
sub AddReserve {
175
    my ($params)       = @_;
173
    my ($params)       = @_;
176
    my $branch         = $params->{branchcode};
174
    my $branch         = $params->{branchcode};
Lines 212-218 sub AddReserve { Link Here
212
            && !$item->current_holds->count )
210
            && !$item->current_holds->count )
213
        {
211
        {
214
            $priority = 0;
212
            $priority = 0;
215
            $found = 'W';
213
            $found = 'waiting';
216
        }
214
        }
217
    }
215
    }
218
216
Lines 225-231 sub AddReserve { Link Here
225
    my $waitingdate;
223
    my $waitingdate;
226
224
227
    # If the reserv had the waiting status, we had the value of the resdate
225
    # If the reserv had the waiting status, we had the value of the resdate
228
    if ( $found && $found eq 'W' ) {
226
    if ( $found && $found eq 'waiting' ) {
229
        $waitingdate = $resdate;
227
        $waitingdate = $resdate;
230
    }
228
    }
231
229
Lines 235-255 sub AddReserve { Link Here
235
    # updates take place here
233
    # updates take place here
236
    my $hold = Koha::Hold->new(
234
    my $hold = Koha::Hold->new(
237
        {
235
        {
238
            borrowernumber => $borrowernumber,
236
            patron_id      => $borrowernumber,
239
            biblionumber   => $biblionumber,
237
            biblio_id      => $biblionumber,
240
            reservedate    => $resdate,
238
            placing_date   => $resdate,
241
            branchcode     => $branch,
239
            pickup_library_id => $branch,
242
            priority       => $priority,
240
            priority       => $priority,
243
            reservenotes   => $notes,
241
            notes          => $notes,
244
            itemnumber     => $checkitem,
242
            item_id        => $checkitem,
245
            found          => $found,
243
            status         => $found,
246
            waitingdate    => $waitingdate,
244
            waiting_date   => $waitingdate,
247
            expirationdate => $expdate,
245
            expiration_date => $expdate,
248
            itemtype       => $itemtype,
246
            item_type      => $itemtype,
249
            item_level_hold => $checkitem ? 1 : 0,
247
            item_level     => $checkitem ? 1 : 0,
250
        }
248
        }
251
    )->store();
249
    )->store();
252
    $hold->set_waiting() if $found && $found eq 'W';
250
    $hold->set_waiting() if $found && $found eq 'waiting';
253
251
254
    logaction( 'HOLDS', 'CREATE', $hold->id, Dumper($hold->unblessed) )
252
    logaction( 'HOLDS', 'CREATE', $hold->id, Dumper($hold->unblessed) )
255
        if C4::Context->preference('HoldsLog');
253
        if C4::Context->preference('HoldsLog');
Lines 373-393 sub CanItemBeReserved { Link Here
373
371
374
    # Check that the patron doesn't have an item level hold on this item already
372
    # Check that the patron doesn't have an item level hold on this item already
375
    return { status =>'itemAlreadyOnHold' }
373
    return { status =>'itemAlreadyOnHold' }
376
      if Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count();
374
      if Koha::Holds->search( { patron_id => $borrowernumber, item_id => $itemnumber, completed=>0 } )->count();
377
375
378
    my $controlbranch = C4::Context->preference('ReservesControlBranch');
376
    my $controlbranch = C4::Context->preference('ReservesControlBranch');
379
377
380
    my $querycount = q{
378
    my $querycount = q{
381
        SELECT count(*) AS count
379
        SELECT count(*) AS count
382
          FROM reserves
380
          FROM holds
383
     LEFT JOIN items USING (itemnumber)
381
     LEFT JOIN items ON (holds.item_id=items.itemnumber)
384
     LEFT JOIN biblioitems ON (reserves.biblionumber=biblioitems.biblionumber)
382
     LEFT JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
385
     LEFT JOIN borrowers USING (borrowernumber)
383
     LEFT JOIN borrowers ON (holds.patron_id=borrowers.borrowernumber)
386
         WHERE borrowernumber = ?
384
         WHERE completed = 0 and borrowernumber = ?
387
    };
385
    };
388
386
389
    my $branchcode  = "";
387
    my $branchcode  = "";
390
    my $branchfield = "reserves.branchcode";
388
    my $branchfield = "holds.pickup_library_id";
391
389
392
    if ( $controlbranch eq "ItemHomeLibrary" ) {
390
    if ( $controlbranch eq "ItemHomeLibrary" ) {
393
        $branchfield = "items.homebranch";
391
        $branchfield = "items.homebranch";
Lines 411-418 sub CanItemBeReserved { Link Here
411
409
412
    my $holds = Koha::Holds->search(
410
    my $holds = Koha::Holds->search(
413
        {
411
        {
414
            borrowernumber => $borrowernumber,
412
            patron_id => $borrowernumber,
415
            biblionumber   => $item->biblionumber,
413
            biblio_id => $item->biblionumber,
416
        }
414
        }
417
    );
415
    );
418
    if (   defined $holds_per_record && $holds_per_record ne ''
416
    if (   defined $holds_per_record && $holds_per_record ne ''
Lines 421-428 sub CanItemBeReserved { Link Here
421
    }
419
    }
422
420
423
    my $today_holds = Koha::Holds->search({
421
    my $today_holds = Koha::Holds->search({
424
        borrowernumber => $borrowernumber,
422
        patron_id    => $borrowernumber,
425
        reservedate    => dt_from_string->date
423
        placing_date => dt_from_string->date
426
    });
424
    });
427
425
428
    if (   defined $holds_per_day && $holds_per_day ne ''
426
    if (   defined $holds_per_day && $holds_per_day ne ''
Lines 474-480 sub CanItemBeReserved { Link Here
474
    if ( $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
472
    if ( $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
475
        my $total_holds_count = Koha::Holds->search(
473
        my $total_holds_count = Koha::Holds->search(
476
            {
474
            {
477
                borrowernumber => $borrower->{borrowernumber}
475
                patron_id => $borrower->{borrowernumber}
478
            }
476
            }
479
        )->count();
477
        )->count();
480
478
Lines 554-561 sub CanReserveBeCanceledFromOpac { Link Here
554
    return unless $reserve_id and $borrowernumber;
552
    return unless $reserve_id and $borrowernumber;
555
    my $reserve = Koha::Holds->find($reserve_id);
553
    my $reserve = Koha::Holds->find($reserve_id);
556
554
557
    return 0 unless $reserve->borrowernumber == $borrowernumber;
555
    return 0 if $reserve->completed;
558
    return 0 if ( $reserve->found eq 'W' ) or ( $reserve->found eq 'T' );
556
    return 0 unless $reserve->patron_id == $borrowernumber;
557
    return 0 if ( $reserve->status eq 'waiting' ) or ( $reserve->status eq 'in_transit' );
559
558
560
    return 1;
559
    return 1;
561
560
Lines 576-594 sub GetOtherReserves { Link Here
576
    my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber);
575
    my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber);
577
    if ($checkreserves) {
576
    if ($checkreserves) {
578
        my $item = Koha::Items->find($itemnumber);
577
        my $item = Koha::Items->find($itemnumber);
579
        if ( $item->holdingbranch ne $checkreserves->{'branchcode'} ) {
578
        if ( $item->holdingbranch ne $checkreserves->{pickup_library_id} ) {
580
            $messages->{'transfert'} = $checkreserves->{'branchcode'};
579
            $messages->{'transfert'} = $checkreserves->{pickup_library_id};
581
            #minus priorities of others reservs
580
            #minus priorities of others reservs
582
            ModReserveMinusPriority(
581
            ModReserveMinusPriority(
583
                $itemnumber,
582
                $itemnumber,
584
                $checkreserves->{'reserve_id'},
583
                $checkreserves->{id},
585
            );
584
            );
586
585
587
            #launch the subroutine dotransfer
586
            #launch the subroutine dotransfer
588
            C4::Items::ModItemTransfer(
587
            C4::Items::ModItemTransfer(
589
                $itemnumber,
588
                $itemnumber,
590
                $item->holdingbranch,
589
                $item->holdingbranch,
591
                $checkreserves->{'branchcode'},
590
                $checkreserves->{pickup_library_id},
592
                'Reserve'
591
                'Reserve'
593
              ),
592
              ),
594
              ;
593
              ;
Lines 599-610 sub GetOtherReserves { Link Here
599
            $messages->{'waiting'} = 1;
598
            $messages->{'waiting'} = 1;
600
            ModReserveMinusPriority(
599
            ModReserveMinusPriority(
601
                $itemnumber,
600
                $itemnumber,
602
                $checkreserves->{'reserve_id'},
601
                $checkreserves->{id},
603
            );
602
            );
604
            ModReserveStatus($itemnumber,'W');
603
            ModReserveStatus($itemnumber,'waiting');
605
        }
604
        }
606
605
607
        $nextreservinfo = $checkreserves->{'borrowernumber'};
606
        $nextreservinfo = $checkreserves->{patron_id};
608
    }
607
    }
609
608
610
    return ( $messages, $nextreservinfo );
609
    return ( $messages, $nextreservinfo );
Lines 696-713 sub GetReserveStatus { Link Here
696
695
697
    my $dbh = C4::Context->dbh;
696
    my $dbh = C4::Context->dbh;
698
697
699
    my ($sth, $found, $priority);
698
    my ($sth, $status, $priority);
700
    if ( $itemnumber ) {
699
    if ( $itemnumber ) {
701
        $sth = $dbh->prepare("SELECT found, priority FROM reserves WHERE itemnumber = ? order by priority LIMIT 1");
700
        $sth = $dbh->prepare(q{
701
            SELECT status, priority FROM holds WHERE item_id = ? AND completed = 0 order by priority LIMIT 1
702
        });
702
        $sth->execute($itemnumber);
703
        $sth->execute($itemnumber);
703
        ($found, $priority) = $sth->fetchrow_array;
704
        my $h = Koha::Holds->search({item_id => $itemnumber});
704
    }
705
        ($status, $priority) = $sth->fetchrow_array;
705
706
    if(defined $found) {
707
        return 'Waiting'  if $found eq 'W' and $priority == 0;
708
        return 'Finished' if $found eq 'F';
709
    }
706
    }
710
707
708
    return 'Waiting'  if defined $status and $status eq 'waiting' and $priority == 0;
709
    return 'Finished' if defined $status and $status eq 'fulfilled';
711
    return 'Reserved' if defined $priority && $priority > 0;
710
    return 'Reserved' if defined $priority && $priority > 0;
712
711
713
    return ''; # empty string here will remove need for checking undef, or less log lines
712
    return ''; # empty string here will remove need for checking undef, or less log lines
Lines 748-754 sub CheckReserves { Link Here
748
    my $sth;
747
    my $sth;
749
    my $select;
748
    my $select;
750
    if (C4::Context->preference('item-level_itypes')){
749
    if (C4::Context->preference('item-level_itypes')){
751
	$select = "
750
    $select = "
752
           SELECT items.biblionumber,
751
           SELECT items.biblionumber,
753
           items.biblioitemnumber,
752
           items.biblioitemnumber,
754
           itemtypes.notforloan,
753
           itemtypes.notforloan,
Lines 763-769 sub CheckReserves { Link Here
763
        ";
762
        ";
764
    }
763
    }
765
    else {
764
    else {
766
	$select = "
765
    $select = "
767
           SELECT items.biblionumber,
766
           SELECT items.biblionumber,
768
           items.biblioitemnumber,
767
           items.biblioitemnumber,
769
           itemtypes.notforloan,
768
           itemtypes.notforloan,
Lines 810-817 sub CheckReserves { Link Here
810
809
811
        my $priority = 10000000;
810
        my $priority = 10000000;
812
        foreach my $res (@reserves) {
811
        foreach my $res (@reserves) {
813
            if ( $res->{'itemnumber'} && $res->{'itemnumber'} == $itemnumber && $res->{'priority'} == 0) {
812
            if ( $res->{item_id} && $res->{item_id} == $itemnumber && $res->{priority} == 0) {
814
                if ($res->{'found'} eq 'W') {
813
                if ($res->{status} eq 'waiting') {
815
                    return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
814
                    return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
816
                } else {
815
                } else {
817
                    return ( "Reserved", $res, \@reserves ); # Found determinated hold, e. g. the tranferred one
816
                    return ( "Reserved", $res, \@reserves ); # Found determinated hold, e. g. the tranferred one
Lines 822-835 sub CheckReserves { Link Here
822
                my $local_hold_match;
821
                my $local_hold_match;
823
822
824
                if ($LocalHoldsPriority) {
823
                if ($LocalHoldsPriority) {
825
                    $patron = Koha::Patrons->find( $res->{borrowernumber} );
824
                    $patron = Koha::Patrons->find( $res->{patron_id} );
826
                    $item = Koha::Items->find($itemnumber);
825
                    $item = Koha::Items->find($itemnumber);
827
826
828
                    my $local_holds_priority_item_branchcode =
827
                    my $local_holds_priority_item_branchcode =
829
                      $item->$LocalHoldsPriorityItemControl;
828
                      $item->$LocalHoldsPriorityItemControl;
830
                    my $local_holds_priority_patron_branchcode =
829
                    my $local_holds_priority_patron_branchcode =
831
                      ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
830
                      ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
832
                      ? $res->{branchcode}
831
                      ? $res->{pickup_library_id}
833
                      : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )
832
                      : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )
834
                      ? $patron->branchcode
833
                      ? $patron->branchcode
835
                      : undef;
834
                      : undef;
Lines 839-848 sub CheckReserves { Link Here
839
                }
838
                }
840
839
841
                # See if this item is more important than what we've got so far
840
                # See if this item is more important than what we've got so far
842
                if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
841
                if ( ( $res->{priority} && $res->{priority} < $priority ) || $local_hold_match ) {
843
                    $item ||= Koha::Items->find($itemnumber);
842
                    $item ||= Koha::Items->find($itemnumber);
844
                    next if $res->{itemtype} && $res->{itemtype} ne $item->effective_itemtype;
843
                    next if $res->{item_type} && $res->{item_type} ne $item->effective_itemtype;
845
                    $patron ||= Koha::Patrons->find( $res->{borrowernumber} );
844
                    $patron ||= Koha::Patrons->find( $res->{patron_id} );
846
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
845
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
847
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
846
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
848
                    next if ($branchitemrule->{'holdallowed'} == 0);
847
                    next if ($branchitemrule->{'holdallowed'} == 0);
Lines 850-859 sub CheckReserves { Link Here
850
                    my $library = Koha::Libraries->find({branchcode=>$item->homebranch});
849
                    my $library = Koha::Libraries->find({branchcode=>$item->homebranch});
851
                    next if (($branchitemrule->{'holdallowed'} == 3) && (!$library->validate_hold_sibling({branchcode => $patron->branchcode}) ));
850
                    next if (($branchitemrule->{'holdallowed'} == 3) && (!$library->validate_hold_sibling({branchcode => $patron->branchcode}) ));
852
                    my $hold_fulfillment_policy = $branchitemrule->{hold_fulfillment_policy};
851
                    my $hold_fulfillment_policy = $branchitemrule->{hold_fulfillment_policy};
853
                    next if ( ($hold_fulfillment_policy eq 'holdgroup') && (!$library->validate_hold_sibling({branchcode => $res->{branchcode}})) );
852
                    next if ( ($hold_fulfillment_policy eq 'holdgroup') && (!$library->validate_hold_sibling({branchcode => $res->{pickup_library_id}})) );
854
                    next if ( ($hold_fulfillment_policy eq 'homebranch') && ($res->{branchcode} ne $item->$hold_fulfillment_policy) );
853
                    next if ( ($hold_fulfillment_policy eq 'homebranch') && ($res->{pickup_library_id} ne $item->$hold_fulfillment_policy) );
855
                    next if ( ($hold_fulfillment_policy eq 'holdingbranch') && ($res->{branchcode} ne $item->$hold_fulfillment_policy) );
854
                    next if ( ($hold_fulfillment_policy eq 'holdingbranch') && ($res->{pickup_library_id} ne $item->$hold_fulfillment_policy) );
856
                    next unless $item->can_be_transferred( { to => Koha::Libraries->find( $res->{branchcode} ) } );
855
                    next unless $item->can_be_transferred( { to => Koha::Libraries->find( $res->{pickup_library_id} ) } );
857
                    $priority = $res->{'priority'};
856
                    $priority = $res->{'priority'};
858
                    $highest  = $res;
857
                    $highest  = $res;
859
                    last if $local_hold_match;
858
                    last if $local_hold_match;
Lines 886-904 sub CancelExpiredReserves { Link Here
886
    my $expireWaiting = C4::Context->preference('ExpireReservesMaxPickUpDelay');
885
    my $expireWaiting = C4::Context->preference('ExpireReservesMaxPickUpDelay');
887
886
888
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
887
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
889
    my $params = { expirationdate => { '<', $dtf->format_date($today) } };
888
    my $params = { expiration_date => { '<', $dtf->format_date($today) } };
890
    $params->{found} = [ { '!=', 'W' }, undef ]  unless $expireWaiting;
889
    $params->{status} = [ { '!=', 'waiting' }, undef ]  unless $expireWaiting;
891
890
892
    # FIXME To move to Koha::Holds->search_expired (?)
891
    # FIXME To move to Koha::Holds->search_expired (?)
893
    my $holds = Koha::Holds->search( $params );
892
    my $holds = Koha::Holds->search( $params );
894
893
895
    while ( my $hold = $holds->next ) {
894
    while ( my $hold = $holds->next ) {
896
        my $calendar = Koha::Calendar->new( branchcode => $hold->branchcode );
895
        my $calendar = Koha::Calendar->new( branchcode => $hold->pickup_library_id );
897
896
898
        next if !$cancel_on_holidays && $calendar->is_holiday( $today );
897
        next if !$cancel_on_holidays && $calendar->is_holiday( $today );
899
898
900
        my $cancel_params = {};
899
        my $cancel_params = {};
901
        if ( $hold->found eq 'W' ) {
900
        if ( $hold->status eq 'waiting' ) {
902
            $cancel_params->{charge_cancel_fee} = 1;
901
            $cancel_params->{charge_cancel_fee} = 1;
903
        }
902
        }
904
        $hold->cancel( $cancel_params );
903
        $hold->cancel( $cancel_params );
Lines 909-922 sub CancelExpiredReserves { Link Here
909
908
910
  AutoUnsuspendReserves();
909
  AutoUnsuspendReserves();
911
910
912
Unsuspends all suspended reserves with a suspend_until date from before today.
911
Unsuspends all suspended reserves with a suspended_until date from before today.
913
912
914
=cut
913
=cut
915
914
916
sub AutoUnsuspendReserves {
915
sub AutoUnsuspendReserves {
917
    my $today = dt_from_string();
916
    my $today = dt_from_string();
918
917
919
    my @holds = Koha::Holds->search( { suspend_until => { '<=' => $today->ymd() } } );
918
    my @holds = Koha::Holds->search( { suspended_until_date => { '<=' => $today->ymd() } } );
920
919
921
    map { $_->resume() } @holds;
920
    map { $_->resume() } @holds;
922
}
921
}
Lines 975-984 sub ModReserve { Link Here
975
974
976
    my $hold;
975
    my $hold;
977
    unless ( $reserve_id ) {
976
    unless ( $reserve_id ) {
978
        my $holds = Koha::Holds->search({ biblionumber => $biblionumber, borrowernumber => $borrowernumber, itemnumber => $itemnumber });
977
        my $holds = Koha::Holds->search({ biblio_id => $biblionumber, patron_id => $borrowernumber, item_id => $itemnumber });
979
        return unless $holds->count; # FIXME Should raise an exception
978
        return unless $holds->count; # FIXME Should raise an exception
980
        $hold = $holds->next;
979
        $hold = $holds->next;
981
        $reserve_id = $hold->reserve_id;
980
        $reserve_id = $hold->id;
982
    }
981
    }
983
982
984
    $hold ||= Koha::Holds->find($reserve_id);
983
    $hold ||= Koha::Holds->find($reserve_id);
Lines 987-1007 sub ModReserve { Link Here
987
        $hold->cancel;
986
        $hold->cancel;
988
    }
987
    }
989
    elsif ($rank =~ /^\d+/ and $rank > 0) {
988
    elsif ($rank =~ /^\d+/ and $rank > 0) {
990
        logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
989
        logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->unblessed) )
991
            if C4::Context->preference('HoldsLog');
990
            if C4::Context->preference('HoldsLog');
992
991
993
        my $properties = {
992
        my $properties = {
994
            priority    => $rank,
993
            priority     => $rank,
995
            branchcode  => $branchcode,
994
            pickup_library_id => $branchcode,
996
            itemnumber  => $itemnumber,
995
            item_id      => $itemnumber,
997
            found       => undef,
996
            status       => 'placed',
998
            waitingdate => undef
997
            waiting_date => undef
999
        };
998
        };
1000
        if (exists $params->{reservedate}) {
999
        if (exists $params->{reservedate}) {
1001
            $properties->{reservedate} = $params->{reservedate} || undef;
1000
            $properties->{placing_date} = $params->{reservedate} || undef;
1002
        }
1001
        }
1003
        if (exists $params->{expirationdate}) {
1002
        if (exists $params->{expirationdate}) {
1004
            $properties->{expirationdate} = $params->{expirationdate} || undef;
1003
            $properties->{expiration_date} = $params->{expirationdate} || undef;
1005
        }
1004
        }
1006
1005
1007
        $hold->set($properties)->store();
1006
        $hold->set($properties)->store();
Lines 1013-1019 sub ModReserve { Link Here
1013
            } else {
1012
            } else {
1014
                # If the hold is suspended leave the hold suspended, but convert it to an indefinite hold.
1013
                # If the hold is suspended leave the hold suspended, but convert it to an indefinite hold.
1015
                # If the hold is not suspended, this does nothing.
1014
                # If the hold is not suspended, this does nothing.
1016
                $hold->set( { suspend_until => undef } )->store();
1015
                $hold->set( { suspended_until_date => undef } )->store();
1017
            }
1016
            }
1018
        }
1017
        }
1019
1018
Lines 1035-1071 whose keys are fields from the reserves table in the Koha database. Link Here
1035
1034
1036
sub ModReserveFill {
1035
sub ModReserveFill {
1037
    my ($res) = @_;
1036
    my ($res) = @_;
1038
    my $reserve_id = $res->{'reserve_id'};
1037
    my $reserve_id = $res->{'id'};
1039
1038
1040
    my $hold = Koha::Holds->find($reserve_id);
1039
    my $hold = Koha::Holds->find($reserve_id);
1041
    # get the priority on this record....
1040
    # get the priority on this record....
1042
    my $priority = $hold->priority;
1041
    my $priority = $hold->priority;
1043
1042
1044
    # update the hold statuses, no need to store it though, we will be deleting it anyway
1043
    # update the hold statuses, no need to store it though, we will be deleting it anyway
1044
    # FIXME: Add Koha::Hold->set_filled and add the correct log
1045
    $hold->set(
1045
    $hold->set(
1046
        {
1046
        {
1047
            found    => 'F',
1047
            status    => 'fulfilled',
1048
            priority => 0,
1048
            priority  => 0,
1049
            completed => 1,
1050
            completion_date => \'NOW()'
1049
        }
1051
        }
1050
    );
1052
    );
1051
1053
1052
    logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
1054
    logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->unblessed) )
1053
        if C4::Context->preference('HoldsLog');
1055
        if C4::Context->preference('HoldsLog');
1054
1056
1055
    # FIXME Must call Koha::Hold->cancel ? => No, should call ->filled and add the correct log
1057
    $hold->store();
1056
    Koha::Old::Hold->new( $hold->unblessed() )->store();
1057
1058
    $hold->delete();
1059
1058
1060
    if ( C4::Context->preference('HoldFeeMode') eq 'any_time_is_collected' ) {
1059
    if ( C4::Context->preference('HoldFeeMode') eq 'any_time_is_collected' ) {
1061
        my $reserve_fee = GetReserveFee( $hold->borrowernumber, $hold->biblionumber );
1060
        my $reserve_fee = GetReserveFee( $hold->patron_id, $hold->biblio_id );
1062
        ChargeReserveFee( $hold->borrowernumber, $reserve_fee, $hold->biblio->title );
1061
        ChargeReserveFee( $hold->patron_id, $reserve_fee, $hold->biblio->title );
1063
    }
1062
    }
1064
1063
1065
    # now fix the priority on the others (if the priority wasn't
1064
    # now fix the priority on the others (if the priority wasn't
1066
    # already sorted!)....
1065
    # already sorted!)....
1067
    unless ( $priority == 0 ) {
1066
    unless ( $priority == 0 ) {
1068
        _FixPriority( { reserve_id => $reserve_id, biblionumber => $hold->biblionumber } );
1067
        _FixPriority( { reserve_id => $reserve_id, biblionumber => $hold->biblio_id } );
1069
    }
1068
    }
1070
}
1069
}
1071
1070
Lines 1087-1093 sub ModReserveStatus { Link Here
1087
    my ($itemnumber, $newstatus) = @_;
1086
    my ($itemnumber, $newstatus) = @_;
1088
    my $dbh = C4::Context->dbh;
1087
    my $dbh = C4::Context->dbh;
1089
1088
1090
    my $query = "UPDATE reserves SET found = ?, waitingdate = NOW() WHERE itemnumber = ? AND found IS NULL AND priority = 0";
1089
    my $query = "UPDATE holds SET status = ?, waiting_date = NOW() WHERE item_id = ? AND status='placed' AND priority = 0";
1091
    my $sth_set = $dbh->prepare($query);
1090
    my $sth_set = $dbh->prepare($query);
1092
    $sth_set->execute( $newstatus, $itemnumber );
1091
    $sth_set->execute( $newstatus, $itemnumber );
1093
1092
Lines 1131-1149 sub ModReserveAffect { Link Here
1131
    # Find hold by id if we have it
1130
    # Find hold by id if we have it
1132
    $hold = Koha::Holds->find( $reserve_id ) if $reserve_id;
1131
    $hold = Koha::Holds->find( $reserve_id ) if $reserve_id;
1133
    # Find item level hold for this item if there is one
1132
    # Find item level hold for this item if there is one
1134
    $hold ||= Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->next();
1133
    $hold ||= Koha::Holds->search( { patron_id => $borrowernumber, item_id => $itemnumber } )->next();
1135
    # Find record level hold if there is no item level hold
1134
    # Find record level hold if there is no item level hold
1136
    $hold ||= Koha::Holds->search( { borrowernumber => $borrowernumber, biblionumber => $biblionumber } )->next();
1135
    $hold ||= Koha::Holds->search( { patron_id => $borrowernumber, biblio_id => $biblionumber } )->next();
1137
1136
1138
    return unless $hold;
1137
    return unless $hold;
1139
1138
1140
    my $already_on_shelf = $hold->found && $hold->found eq 'W';
1139
    my $already_on_shelf = $hold->status eq 'waiting';
1141
1140
1142
    $hold->itemnumber($itemnumber);
1141
    $hold->item_id($itemnumber);
1143
    $hold->set_waiting($transferToDo);
1142
    $hold->set_waiting($transferToDo);
1144
1143
1145
    if( !$transferToDo ){
1144
    if( !$transferToDo ){
1146
        _koha_notify_reserve( $hold->reserve_id ) unless $already_on_shelf;
1145
        _koha_notify_reserve( $hold->id ) unless $already_on_shelf;
1147
        my $transfers = Koha::Item::Transfers->search({
1146
        my $transfers = Koha::Item::Transfers->search({
1148
            itemnumber => $itemnumber,
1147
            itemnumber => $itemnumber,
1149
            datearrived => undef
1148
            datearrived => undef
Lines 1161-1167 sub ModReserveAffect { Link Here
1161
      CartToShelf( $itemnumber );
1160
      CartToShelf( $itemnumber );
1162
    }
1161
    }
1163
1162
1164
    logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
1163
    logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->unblessed) )
1165
        if C4::Context->preference('HoldsLog');
1164
        if C4::Context->preference('HoldsLog');
1166
1165
1167
    return;
1166
    return;
Lines 1178-1192 function to cancel reserv,check other reserves, and transfer document if it's ne Link Here
1178
sub ModReserveCancelAll {
1177
sub ModReserveCancelAll {
1179
    my $messages;
1178
    my $messages;
1180
    my $nextreservinfo;
1179
    my $nextreservinfo;
1181
    my ( $itemnumber, $borrowernumber ) = @_;
1180
    my ( $item_id, $patron_id ) = @_;
1182
1181
1183
    #step 1 : cancel the reservation
1182
    #step 1 : cancel the reservation
1184
    my $holds = Koha::Holds->search({ itemnumber => $itemnumber, borrowernumber => $borrowernumber });
1183
    my $holds = Koha::Holds->search({ item_id => $item_id, patron_id => $patron_id });
1185
    return unless $holds->count;
1184
    return unless $holds->count;
1186
    $holds->next->cancel;
1185
    $holds->next->cancel;
1187
1186
1188
    #step 2 launch the subroutine of the others reserves
1187
    #step 2 launch the subroutine of the others reserves
1189
    ( $messages, $nextreservinfo ) = GetOtherReserves($itemnumber);
1188
    ( $messages, $nextreservinfo ) = GetOtherReserves($item_id);
1190
1189
1191
    return ( $messages, $nextreservinfo );
1190
    return ( $messages, $nextreservinfo );
1192
}
1191
}
Lines 1200-1216 Reduce the values of queued list Link Here
1200
=cut
1199
=cut
1201
1200
1202
sub ModReserveMinusPriority {
1201
sub ModReserveMinusPriority {
1203
    my ( $itemnumber, $reserve_id ) = @_;
1202
    my ( $item_id, $reserve_id ) = @_;
1204
1203
1205
    #first step update the value of the first person on reserv
1204
    #first step update the value of the first person on reserv
1206
    my $dbh   = C4::Context->dbh;
1205
    my $dbh   = C4::Context->dbh;
1207
    my $query = "
1206
    my $query = "
1208
        UPDATE reserves
1207
        UPDATE holds
1209
        SET    priority = 0 , itemnumber = ?
1208
        SET    priority = 0 , item_id = ?
1210
        WHERE  reserve_id = ?
1209
        WHERE  id = ?
1211
    ";
1210
    ";
1212
    my $sth_upd = $dbh->prepare($query);
1211
    my $sth_upd = $dbh->prepare($query);
1213
    $sth_upd->execute( $itemnumber, $reserve_id );
1212
    $sth_upd->execute( $item_id, $reserve_id );
1214
    # second step update all others reserves
1213
    # second step update all others reserves
1215
    _FixPriority({ reserve_id => $reserve_id, rank => '0' });
1214
    _FixPriority({ reserve_id => $reserve_id, rank => '0' });
1216
}
1215
}
Lines 1348-1355 sub AlterPriority { Link Here
1348
    my $hold = Koha::Holds->find( $reserve_id );
1347
    my $hold = Koha::Holds->find( $reserve_id );
1349
    return unless $hold;
1348
    return unless $hold;
1350
1349
1351
    if ( $hold->cancellationdate ) {
1350
    if ( $hold->completion_date and $hold->status eq 'cancelled' ) {
1352
        warn "I cannot alter the priority for reserve_id $reserve_id, the reserve has been cancelled (" . $hold->cancellationdate . ')';
1351
        warn "I cannot alter the priority for reserve_id $reserve_id, the reserve has been cancelled (" . $hold->completion_date . ')';
1353
        return;
1352
        return;
1354
    }
1353
    }
1355
1354
Lines 1381-1387 sub ToggleLowestPriority { Link Here
1381
1380
1382
    my $dbh = C4::Context->dbh;
1381
    my $dbh = C4::Context->dbh;
1383
1382
1384
    my $sth = $dbh->prepare( "UPDATE reserves SET lowestPriority = NOT lowestPriority WHERE reserve_id = ?");
1383
    my $sth = $dbh->prepare( "UPDATE holds SET lowest_priority = NOT lowest_priority WHERE id = ?");
1385
    $sth->execute( $reserve_id );
1384
    $sth->execute( $reserve_id );
1386
1385
1387
    _FixPriority({ reserve_id => $reserve_id, rank => '999999' });
1386
    _FixPriority({ reserve_id => $reserve_id, rank => '999999' });
Lines 1441-1449 sub SuspendAll { Link Here
1441
    return unless ( $borrowernumber || $biblionumber );
1440
    return unless ( $borrowernumber || $biblionumber );
1442
1441
1443
    my $params;
1442
    my $params;
1444
    $params->{found}          = undef;
1443
    $params->{status} = 'placed';
1445
    $params->{borrowernumber} = $borrowernumber if $borrowernumber;
1444
    $params->{patron_id} = $borrowernumber if $borrowernumber;
1446
    $params->{biblionumber}   = $biblionumber if $biblionumber;
1445
    $params->{biblio_id} = $biblionumber if $biblionumber;
1447
1446
1448
    my @holds = Koha::Holds->search($params);
1447
    my @holds = Koha::Holds->search($params);
1449
1448
Lines 1503-1517 sub _FixPriority { Link Here
1503
    my $hold;
1502
    my $hold;
1504
    if ( $reserve_id ) {
1503
    if ( $reserve_id ) {
1505
        $hold = Koha::Holds->find( $reserve_id );
1504
        $hold = Koha::Holds->find( $reserve_id );
1506
        if (!defined $hold){
1507
            # may have already been checked out and hold fulfilled
1508
            $hold = Koha::Old::Holds->find( $reserve_id );
1509
        }
1510
        return unless $hold;
1505
        return unless $hold;
1511
    }
1506
    }
1512
1507
1513
    unless ( $biblionumber ) { # FIXME This is a very weird API
1508
    unless ( $biblionumber ) { # FIXME This is a very weird API
1514
        $biblionumber = $hold->biblionumber;
1509
        $biblionumber = $hold->biblio_id;
1515
    }
1510
    }
1516
1511
1517
    if ( $rank eq "del" ) { # FIXME will crash if called without $hold
1512
    if ( $rank eq "del" ) { # FIXME will crash if called without $hold
Lines 1521-1530 sub _FixPriority { Link Here
1521
1516
1522
        # make sure priority for waiting or in-transit items is 0
1517
        # make sure priority for waiting or in-transit items is 0
1523
        my $query = "
1518
        my $query = "
1524
            UPDATE reserves
1519
            UPDATE holds
1525
            SET    priority = 0
1520
            SET    priority = 0
1526
            WHERE reserve_id = ?
1521
            WHERE  id = ?
1527
            AND found IN ('W', 'T')
1522
            AND status IN ('waiting', 'in_transit')
1528
        ";
1523
        ";
1529
        my $sth = $dbh->prepare($query);
1524
        my $sth = $dbh->prepare($query);
1530
        $sth->execute( $reserve_id );
1525
        $sth->execute( $reserve_id );
Lines 1533-1542 sub _FixPriority { Link Here
1533
1528
1534
    # get whats left
1529
    # get whats left
1535
    my $query = "
1530
    my $query = "
1536
        SELECT reserve_id, borrowernumber, reservedate
1531
        SELECT id
1537
        FROM   reserves
1532
        FROM   holds
1538
        WHERE  biblionumber   = ?
1533
        WHERE  biblio_id   = ?
1539
          AND  ((found <> 'W' AND found <> 'T') OR found IS NULL)
1534
          AND  completed = 0
1535
          AND  status = 'placed'
1540
        ORDER BY priority ASC
1536
        ORDER BY priority ASC
1541
    ";
1537
    ";
1542
    my $sth = $dbh->prepare($query);
1538
    my $sth = $dbh->prepare($query);
Lines 1550-1556 sub _FixPriority { Link Here
1550
    my $i;
1546
    my $i;
1551
    my $key = -1;    # to allow for 0 to be a valid result
1547
    my $key = -1;    # to allow for 0 to be a valid result
1552
    for ( $i = 0 ; $i < @priority ; $i++ ) {
1548
    for ( $i = 0 ; $i < @priority ; $i++ ) {
1553
        if ( $reserve_id && $reserve_id == $priority[$i]->{'reserve_id'} ) {
1549
        if ( $reserve_id && $reserve_id == $priority[$i]->{'id'} ) {
1554
            $key = $i;    # save the index
1550
            $key = $i;    # save the index
1555
            last;
1551
            last;
1556
        }
1552
        }
Lines 1566-1590 sub _FixPriority { Link Here
1566
1562
1567
    # now fix the priority on those that are left....
1563
    # now fix the priority on those that are left....
1568
    $query = "
1564
    $query = "
1569
        UPDATE reserves
1565
        UPDATE holds
1570
        SET    priority = ?
1566
        SET    priority = ?
1571
        WHERE  reserve_id = ?
1567
        WHERE  id = ?
1572
    ";
1568
    ";
1573
    $sth = $dbh->prepare($query);
1569
    $sth = $dbh->prepare($query);
1574
    for ( my $j = 0 ; $j < @priority ; $j++ ) {
1570
    for ( my $j = 0 ; $j < @priority ; $j++ ) {
1575
        $sth->execute(
1571
        $sth->execute(
1576
            $j + 1,
1572
            $j + 1,
1577
            $priority[$j]->{'reserve_id'}
1573
            $priority[$j]->{'id'}
1578
        );
1574
        );
1579
    }
1575
    }
1580
1576
1581
    $sth = $dbh->prepare( "SELECT reserve_id FROM reserves WHERE lowestPriority = 1 ORDER BY priority" );
1577
    $sth = $dbh->prepare( "SELECT id FROM holds WHERE lowest_priority = 1 ORDER BY priority" );
1582
    $sth->execute();
1578
    $sth->execute();
1583
1579
1584
    unless ( $ignoreSetLowestRank ) {
1580
    unless ( $ignoreSetLowestRank ) {
1585
      while ( my $res = $sth->fetchrow_hashref() ) {
1581
      while ( my $res = $sth->fetchrow_hashref() ) {
1586
        _FixPriority({
1582
        _FixPriority({
1587
            reserve_id => $res->{'reserve_id'},
1583
            reserve_id => $res->{'id'},
1588
            rank => '999999',
1584
            rank => '999999',
1589
            ignoreSetLowestRank => 1
1585
            ignoreSetLowestRank => 1
1590
        });
1586
        });
Lines 1621-1648 sub _Findgroupreserve { Link Here
1621
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1617
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1622
    # check for exact targeted match
1618
    # check for exact targeted match
1623
    my $item_level_target_query = qq{
1619
    my $item_level_target_query = qq{
1624
        SELECT reserves.biblionumber        AS biblionumber,
1620
        SELECT holds.biblio_id         AS biblio_id,
1625
               reserves.borrowernumber      AS borrowernumber,
1621
               holds.patron_id         AS patron_id,
1626
               reserves.reservedate         AS reservedate,
1622
               holds.placing_date      AS placing_date,
1627
               reserves.branchcode          AS branchcode,
1623
               holds.pickup_library_id AS pickup_library_id,
1628
               reserves.cancellationdate    AS cancellationdate,
1624
               holds.completion_date   AS completion_date,
1629
               reserves.found               AS found,
1625
               holds.status            AS status,
1630
               reserves.reservenotes        AS reservenotes,
1626
               holds.notes             AS notes,
1631
               reserves.priority            AS priority,
1627
               holds.priority          AS priority,
1632
               reserves.timestamp           AS timestamp,
1628
               holds.timestamp         AS timestamp,
1633
               biblioitems.biblioitemnumber AS biblioitemnumber,
1629
               biblioitems.biblioitemnumber AS biblioitemnumber,
1634
               reserves.itemnumber          AS itemnumber,
1630
               holds.item_id           AS item_id,
1635
               reserves.reserve_id          AS reserve_id,
1631
               holds.id                AS id,
1636
               reserves.itemtype            AS itemtype
1632
               holds.item_type         AS item_type
1637
        FROM reserves
1633
        FROM holds
1638
        JOIN biblioitems USING (biblionumber)
1634
        JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
1639
        JOIN hold_fill_targets USING (biblionumber, borrowernumber, itemnumber)
1635
        JOIN hold_fill_targets ON (
1640
        WHERE found IS NULL
1636
                holds.biblio_id=hold_fill_targets.biblionumber
1637
            AND holds.patron_id=hold_fill_targets.borrowernumber
1638
            AND holds.item_id=hold_fill_targets.itemnumber)
1639
        WHERE status='placed'
1641
        AND priority > 0
1640
        AND priority > 0
1642
        AND item_level_request = 1
1641
        AND completed = 0
1643
        AND itemnumber = ?
1642
        AND item_level = 1
1644
        AND reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1643
        AND item_id = ?
1645
        AND suspend = 0
1644
        AND placing_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1645
        AND suspended = 0
1646
        ORDER BY priority
1646
        ORDER BY priority
1647
    };
1647
    };
1648
    my $sth = $dbh->prepare($item_level_target_query);
1648
    my $sth = $dbh->prepare($item_level_target_query);
Lines 1650-1683 sub _Findgroupreserve { Link Here
1650
    my @results;
1650
    my @results;
1651
    if ( my $data = $sth->fetchrow_hashref ) {
1651
    if ( my $data = $sth->fetchrow_hashref ) {
1652
        push( @results, $data )
1652
        push( @results, $data )
1653
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1653
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1654
    }
1654
    }
1655
    return @results if @results;
1655
    return @results if @results;
1656
1656
1657
    # check for title-level targeted match
1657
    # check for title-level targeted match
1658
    my $title_level_target_query = qq{
1658
    my $title_level_target_query = qq{
1659
        SELECT reserves.biblionumber        AS biblionumber,
1659
        SELECT holds.biblio_id         AS biblio_id,
1660
               reserves.borrowernumber      AS borrowernumber,
1660
               holds.patron_id         AS patron_id,
1661
               reserves.reservedate         AS reservedate,
1661
               holds.placing_date      AS placing_date,
1662
               reserves.branchcode          AS branchcode,
1662
               holds.pickup_library_id AS pickup_library_id,
1663
               reserves.cancellationdate    AS cancellationdate,
1663
               holds.completion_date   AS completion_date,
1664
               reserves.found               AS found,
1664
               holds.status            AS status,
1665
               reserves.reservenotes        AS reservenotes,
1665
               holds.notes             AS notes,
1666
               reserves.priority            AS priority,
1666
               holds.priority          AS priority,
1667
               reserves.timestamp           AS timestamp,
1667
               holds.timestamp         AS timestamp,
1668
               biblioitems.biblioitemnumber AS biblioitemnumber,
1668
               biblioitems.biblioitemnumber AS biblioitemnumber,
1669
               reserves.itemnumber          AS itemnumber,
1669
               holds.item_id           AS item_id,
1670
               reserves.reserve_id          AS reserve_id,
1670
               holds.id                AS id,
1671
               reserves.itemtype            AS itemtype
1671
               holds.item_type         AS item_type
1672
        FROM reserves
1672
        FROM holds
1673
        JOIN biblioitems USING (biblionumber)
1673
        JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
1674
        JOIN hold_fill_targets USING (biblionumber, borrowernumber)
1674
        JOIN hold_fill_targets ON (
1675
        WHERE found IS NULL
1675
                holds.biblio_id=hold_fill_targets.biblionumber
1676
            AND holds.patron_id=hold_fill_targets.borrowernumber)
1677
        WHERE status='placed'
1676
        AND priority > 0
1678
        AND priority > 0
1677
        AND item_level_request = 0
1679
        AND completed = 0
1680
        AND item_level = 0
1678
        AND hold_fill_targets.itemnumber = ?
1681
        AND hold_fill_targets.itemnumber = ?
1679
        AND reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1682
        AND placing_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1680
        AND suspend = 0
1683
        AND suspended = 0
1681
        ORDER BY priority
1684
        ORDER BY priority
1682
    };
1685
    };
1683
    $sth = $dbh->prepare($title_level_target_query);
1686
    $sth = $dbh->prepare($title_level_target_query);
Lines 1685-1713 sub _Findgroupreserve { Link Here
1685
    @results = ();
1688
    @results = ();
1686
    if ( my $data = $sth->fetchrow_hashref ) {
1689
    if ( my $data = $sth->fetchrow_hashref ) {
1687
        push( @results, $data )
1690
        push( @results, $data )
1688
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1691
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1689
    }
1692
    }
1690
    return @results if @results;
1693
    return @results if @results;
1691
1694
1692
    my $query = qq{
1695
    my $query = qq{
1693
        SELECT reserves.biblionumber               AS biblionumber,
1696
        SELECT holds.biblio_id                  AS biblio_id,
1694
               reserves.borrowernumber             AS borrowernumber,
1697
               holds.patron_id                  AS patron_id,
1695
               reserves.reservedate                AS reservedate,
1698
               holds.placing_date               AS placing_date,
1696
               reserves.waitingdate                AS waitingdate,
1699
               holds.waiting_date               AS waiting_date,
1697
               reserves.branchcode                 AS branchcode,
1700
               holds.pickup_library_id          AS pickup_library_id,
1698
               reserves.cancellationdate           AS cancellationdate,
1701
               holds.completion_date            AS completion_date,
1699
               reserves.found                      AS found,
1702
               holds.status                     AS status,
1700
               reserves.reservenotes               AS reservenotes,
1703
               holds.notes                      AS notes,
1701
               reserves.priority                   AS priority,
1704
               holds.priority                   AS priority,
1702
               reserves.timestamp                  AS timestamp,
1705
               holds.timestamp                  AS timestamp,
1703
               reserves.itemnumber                 AS itemnumber,
1706
               holds.item_id                    AS item_id,
1704
               reserves.reserve_id                 AS reserve_id,
1707
               holds.id                         AS id,
1705
               reserves.itemtype                   AS itemtype
1708
               holds.item_type                  AS item_type
1706
        FROM reserves
1709
        FROM holds
1707
        WHERE reserves.biblionumber = ?
1710
        WHERE holds.biblio_id = ?
1708
          AND (reserves.itemnumber IS NULL OR reserves.itemnumber = ?)
1711
          AND (holds.item_id IS NULL OR holds.item_id = ?)
1709
          AND reserves.reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1712
          AND holds.placing_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1710
          AND suspend = 0
1713
          AND suspended = 0
1714
          AND completed = 0
1711
          ORDER BY priority
1715
          ORDER BY priority
1712
    };
1716
    };
1713
    $sth = $dbh->prepare($query);
1717
    $sth = $dbh->prepare($query);
Lines 1715-1721 sub _Findgroupreserve { Link Here
1715
    @results = ();
1719
    @results = ();
1716
    while ( my $data = $sth->fetchrow_hashref ) {
1720
    while ( my $data = $sth->fetchrow_hashref ) {
1717
        push( @results, $data )
1721
        push( @results, $data )
1718
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1722
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1719
    }
1723
    }
1720
    return @results;
1724
    return @results;
1721
}
1725
}
Lines 1751-1757 The following tables are availalbe witin the notice: Link Here
1751
sub _koha_notify_reserve {
1755
sub _koha_notify_reserve {
1752
    my $reserve_id = shift;
1756
    my $reserve_id = shift;
1753
    my $hold = Koha::Holds->find($reserve_id);
1757
    my $hold = Koha::Holds->find($reserve_id);
1754
    my $borrowernumber = $hold->borrowernumber;
1758
    my $borrowernumber = $hold->patron_id;
1755
1759
1756
    my $patron = Koha::Patrons->find( $borrowernumber );
1760
    my $patron = Koha::Patrons->find( $borrowernumber );
1757
1761
Lines 1763-1783 sub _koha_notify_reserve { Link Here
1763
            message_name => 'Hold_Filled'
1767
            message_name => 'Hold_Filled'
1764
    } );
1768
    } );
1765
1769
1766
    my $library = Koha::Libraries->find( $hold->branchcode )->unblessed;
1770
    my $library = Koha::Libraries->find( $hold->pickup_library_id )->unblessed;
1767
1771
1768
    my $admin_email_address = $library->{branchemail} || C4::Context->preference('KohaAdminEmailAddress');
1772
    my $admin_email_address = $library->{branchemail} || C4::Context->preference('KohaAdminEmailAddress');
1769
1773
1770
    my %letter_params = (
1774
    my %letter_params = (
1771
        module => 'reserves',
1775
        module => 'reserves',
1772
        branchcode => $hold->branchcode,
1776
        branchcode => $hold->pickup_library_id,
1773
        lang => $patron->lang,
1777
        lang => $patron->lang,
1774
        tables => {
1778
        tables => {
1775
            'branches'       => $library,
1779
            'branches'       => $library,
1776
            'borrowers'      => $patron->unblessed,
1780
            'borrowers'      => $patron->unblessed,
1777
            'biblio'         => $hold->biblionumber,
1781
            'biblio'         => $hold->biblio_id,
1778
            'biblioitems'    => $hold->biblionumber,
1782
            'biblioitems'    => $hold->biblio_id,
1779
            'reserves'       => $hold->unblessed,
1783
            'reserves'       => $hold->unblessed,
1780
            'items'          => $hold->itemnumber,
1784
            'items'          => $hold->item_id,
1781
        },
1785
        },
1782
    );
1786
    );
1783
1787
Lines 1840-1846 sub _ShiftPriorityByDateAndPriority { Link Here
1840
    my ( $biblio, $resdate, $new_priority ) = @_;
1844
    my ( $biblio, $resdate, $new_priority ) = @_;
1841
1845
1842
    my $dbh = C4::Context->dbh;
1846
    my $dbh = C4::Context->dbh;
1843
    my $query = "SELECT priority FROM reserves WHERE biblionumber = ? AND ( reservedate > ? OR priority > ? ) ORDER BY priority ASC LIMIT 1";
1847
    my $query = "SELECT priority FROM holds WHERE biblio_id = ? AND ( placing_date > ? OR priority > ? ) AND completed = 0 ORDER BY priority ASC LIMIT 1";
1844
    my $sth = $dbh->prepare( $query );
1848
    my $sth = $dbh->prepare( $query );
1845
    $sth->execute( $biblio, $resdate, $new_priority );
1849
    $sth->execute( $biblio, $resdate, $new_priority );
1846
    my $min_priority = $sth->fetchrow;
1850
    my $min_priority = $sth->fetchrow;
Lines 1848-1867 sub _ShiftPriorityByDateAndPriority { Link Here
1848
    $new_priority = $min_priority if ( $min_priority );
1852
    $new_priority = $min_priority if ( $min_priority );
1849
1853
1850
    # Shift the priority up by one; works in conjunction with the next SQL statement
1854
    # Shift the priority up by one; works in conjunction with the next SQL statement
1851
    $query = "UPDATE reserves
1855
    $query = "UPDATE holds
1852
              SET priority = priority+1
1856
              SET priority = priority+1
1853
              WHERE biblionumber = ?
1857
              WHERE biblio_id = ?
1854
              AND borrowernumber = ?
1858
              AND patron_id = ?
1855
              AND reservedate = ?
1859
              AND placing_date = ?
1856
              AND found IS NULL";
1860
              AND status = 'placed'";
1857
    my $sth_update = $dbh->prepare( $query );
1861
    my $sth_update = $dbh->prepare( $query );
1858
1862
1859
    # Select all reserves for the biblio with priority greater than $new_priority, and order greatest to least
1863
    # Select all reserves for the biblio with priority greater than $new_priority, and order greatest to least
1860
    $query = "SELECT borrowernumber, reservedate FROM reserves WHERE priority >= ? AND biblionumber = ? ORDER BY priority DESC";
1864
    $query = "SELECT patron_id, placing_date FROM holds WHERE priority >= ? AND biblio_id = ? ORDER BY priority DESC";
1861
    $sth = $dbh->prepare( $query );
1865
    $sth = $dbh->prepare( $query );
1862
    $sth->execute( $new_priority, $biblio );
1866
    $sth->execute( $new_priority, $biblio );
1863
    while ( my $row = $sth->fetchrow_hashref ) {
1867
    while ( my $row = $sth->fetchrow_hashref ) {
1864
	$sth_update->execute( $biblio, $row->{borrowernumber}, $row->{reservedate} );
1868
    $sth_update->execute( $biblio, $row->{patron_id}, $row->{placing_date} );
1865
    }
1869
    }
1866
1870
1867
    return $new_priority;  # so the caller knows what priority they wind up receiving
1871
    return $new_priority;  # so the caller knows what priority they wind up receiving
Lines 1885-1893 sub MoveReserve { Link Here
1885
    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
1889
    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
1886
    return unless $res;
1890
    return unless $res;
1887
1891
1888
    my $biblionumber     =  $res->{biblionumber};
1892
    my $biblionumber = $res->{biblio_id};
1889
1893
1890
    if ($res->{borrowernumber} == $borrowernumber) {
1894
    if ($res->{patron_id} == $borrowernumber) {
1891
        ModReserveFill($res);
1895
        ModReserveFill($res);
1892
    }
1896
    }
1893
    else {
1897
    else {
Lines 1896-1903 sub MoveReserve { Link Here
1896
        # Find this item in the reserves
1900
        # Find this item in the reserves
1897
1901
1898
        my $borr_res  = Koha::Holds->search({
1902
        my $borr_res  = Koha::Holds->search({
1899
            borrowernumber => $borrowernumber,
1903
            patron_id => $borrowernumber,
1900
            biblionumber   => $biblionumber,
1904
            biblio_id => $biblionumber,
1901
        },{
1905
        },{
1902
            order_by       => 'priority'
1906
            order_by       => 'priority'
1903
        })->next();
1907
        })->next();
Lines 1911-1917 sub MoveReserve { Link Here
1911
            RevertWaitingStatus({ itemnumber => $itemnumber });
1915
            RevertWaitingStatus({ itemnumber => $itemnumber });
1912
        }
1916
        }
1913
        elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item
1917
        elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item
1914
            my $hold = Koha::Holds->find( $res->{reserve_id} );
1918
            my $hold = Koha::Holds->find( $res->{id} );
1915
            $hold->cancel;
1919
            $hold->cancel;
1916
        }
1920
        }
1917
    }
1921
    }
Lines 1928-1960 This shifts the holds from C<$from_biblio> to C<$to_biblio> and reorders them by Link Here
1928
sub MergeHolds {
1932
sub MergeHolds {
1929
    my ( $dbh, $to_biblio, $from_biblio ) = @_;
1933
    my ( $dbh, $to_biblio, $from_biblio ) = @_;
1930
    my $sth = $dbh->prepare(
1934
    my $sth = $dbh->prepare(
1931
        "SELECT count(*) as reserve_count FROM reserves WHERE biblionumber = ?"
1935
        "SELECT count(*) as reserve_count FROM holds WHERE biblio_id = ? AND completed = 0"
1932
    );
1936
    );
1933
    $sth->execute($from_biblio);
1937
    $sth->execute($from_biblio);
1934
    if ( my $data = $sth->fetchrow_hashref() ) {
1938
    if ( my $data = $sth->fetchrow_hashref() ) {
1935
1939
1936
        # holds exist on old record, if not we don't need to do anything
1940
        # holds exist on old record, if not we don't need to do anything
1937
        $sth = $dbh->prepare(
1941
        $sth = $dbh->prepare(
1938
            "UPDATE reserves SET biblionumber = ? WHERE biblionumber = ?");
1942
            "UPDATE holds SET biblio_id = ? WHERE biblio_id = ?");
1939
        $sth->execute( $to_biblio, $from_biblio );
1943
        $sth->execute( $to_biblio, $from_biblio );
1940
1944
1941
        # Reorder by date
1945
        # Reorder by date
1942
        # don't reorder those already waiting
1946
        # don't reorder those already waiting
1943
1947
1944
        $sth = $dbh->prepare(
1948
        $sth = $dbh->prepare(
1945
"SELECT * FROM reserves WHERE biblionumber = ? AND (found <> ? AND found <> ? OR found is NULL) ORDER BY reservedate ASC"
1949
            "SELECT id FROM holds WHERE biblio_id = ? AND status = 'placed' AND completed = 0 ORDER BY placing_date ASC"
1946
        );
1950
        );
1947
        my $upd_sth = $dbh->prepare(
1951
        my $upd_sth = $dbh->prepare(
1948
"UPDATE reserves SET priority = ? WHERE biblionumber = ? AND borrowernumber = ?
1952
            "UPDATE holds SET priority = ? WHERE id = ? "
1949
        AND reservedate = ? AND (itemnumber = ? or itemnumber is NULL) "
1950
        );
1953
        );
1951
        $sth->execute( $to_biblio, 'W', 'T' );
1954
        $sth->execute( $to_biblio );
1952
        my $priority = 1;
1955
        my $priority = 1;
1953
        while ( my $reserve = $sth->fetchrow_hashref() ) {
1956
        while ( my $reserve = $sth->fetchrow_hashref() ) {
1954
            $upd_sth->execute(
1957
            $upd_sth->execute(
1955
                $priority,                    $to_biblio,
1958
                $priority,
1956
                $reserve->{'borrowernumber'}, $reserve->{'reservedate'},
1959
                $reserve->{'id'}
1957
                $reserve->{'itemnumber'}
1958
            );
1960
            );
1959
            $priority++;
1961
            $priority++;
1960
        }
1962
        }
Lines 1985-2024 sub RevertWaitingStatus { Link Here
1985
1987
1986
    ## Get the waiting reserve we want to revert
1988
    ## Get the waiting reserve we want to revert
1987
    my $query = "
1989
    my $query = "
1988
        SELECT * FROM reserves
1990
        SELECT * FROM holds
1989
        WHERE itemnumber = ?
1991
        WHERE item_id = ?
1990
        AND found IS NOT NULL
1992
        AND status <> 'placed' AND completed = 0
1991
    ";
1993
    ";
1992
    my $sth = $dbh->prepare( $query );
1994
    my $sth = $dbh->prepare( $query );
1993
    $sth->execute( $itemnumber );
1995
    $sth->execute( $itemnumber );
1994
    my $reserve = $sth->fetchrow_hashref();
1996
    my $reserve = $sth->fetchrow_hashref();
1995
1997
1996
    my $hold = Koha::Holds->find( $reserve->{reserve_id} ); # TODO Remove the next raw SQL statements and use this instead
1998
    my $hold = Koha::Holds->find( $reserve->{id} ); # TODO Remove the next raw SQL statements and use this instead
1997
1999
1998
    ## Increment the priority of all other non-waiting
2000
    ## Increment the priority of all other non-waiting
1999
    ## reserves for this bib record
2001
    ## reserves for this bib record
2000
    $query = "
2002
    $query = "
2001
        UPDATE reserves
2003
        UPDATE holds
2002
        SET
2004
        SET
2003
          priority = priority + 1
2005
          priority = priority + 1
2004
        WHERE
2006
        WHERE
2005
          biblionumber =  ?
2007
          biblio_id =  ?
2006
        AND
2008
        AND
2007
          priority > 0
2009
          priority > 0
2008
    ";
2010
    ";
2009
    $sth = $dbh->prepare( $query );
2011
    $sth = $dbh->prepare( $query );
2010
    $sth->execute( $reserve->{'biblionumber'} );
2012
    $sth->execute( $reserve->{'biblio_id'} );
2011
2013
2012
    $hold->set(
2014
    $hold->set(
2013
        {
2015
        {
2014
            priority    => 1,
2016
            priority     => 1,
2015
            found       => undef,
2017
            status       => 'placed',
2016
            waitingdate => undef,
2018
            waiting_date => undef,
2017
            itemnumber  => $hold->item_level_hold ? $hold->itemnumber : undef,
2019
            item_id      => $hold->item_level ? $hold->item_id : undef,
2018
        }
2020
        }
2019
    )->store();
2021
    )->store();
2020
2022
2021
    _FixPriority( { biblionumber => $reserve->{biblionumber} } );
2023
    _FixPriority( { biblionumber => $reserve->{biblio_id} } );
2022
2024
2023
    return $hold;
2025
    return $hold;
2024
}
2026
}
Lines 2066-2082 sub ReserveSlip { Link Here
2066
2068
2067
        $hold = Koha::Holds->search(
2069
        $hold = Koha::Holds->search(
2068
            {
2070
            {
2069
                biblionumber   => $biblionumber,
2071
                biblio_id  => $biblionumber,
2070
                borrowernumber => $borrowernumber,
2072
                patron_id  => $borrowernumber,
2071
                itemnumber     => $itemnumber
2073
                item_id    => $itemnumber,
2074
                completed  => 0
2072
            }
2075
            }
2073
        )->next;
2076
        )->next;
2074
    }
2077
    }
2075
    else {
2078
    else {
2076
        $hold = Koha::Holds->search(
2079
        $hold = Koha::Holds->search(
2077
            {
2080
            {
2078
                biblionumber   => $biblionumber,
2081
                biblio_id => $biblionumber,
2079
                borrowernumber => $borrowernumber
2082
                patron_id => $borrowernumber,
2083
                completed => 0
2080
            }
2084
            }
2081
        )->next;
2085
        )->next;
2082
    }
2086
    }
Lines 2091-2101 sub ReserveSlip { Link Here
2091
        lang => $patron->lang,
2095
        lang => $patron->lang,
2092
        tables => {
2096
        tables => {
2093
            'reserves'    => $reserve,
2097
            'reserves'    => $reserve,
2094
            'branches'    => $reserve->{branchcode},
2098
            'branches'    => $reserve->{pickup_library_id},
2095
            'borrowers'   => $reserve->{borrowernumber},
2099
            'borrowers'   => $reserve->{patron_id},
2096
            'biblio'      => $reserve->{biblionumber},
2100
            'biblio'      => $reserve->{biblio_id},
2097
            'biblioitems' => $reserve->{biblionumber},
2101
            'biblioitems' => $reserve->{biblio_id},
2098
            'items'       => $reserve->{itemnumber},
2102
            'items'       => $reserve->{item_id},
2099
        },
2103
        },
2100
    );
2104
    );
2101
}
2105
}
Lines 2149-2165 sub CalculatePriority { Link Here
2149
    my ( $biblionumber, $resdate ) = @_;
2153
    my ( $biblionumber, $resdate ) = @_;
2150
2154
2151
    my $sql = q{
2155
    my $sql = q{
2152
        SELECT COUNT(*) FROM reserves
2156
        SELECT COUNT(*) FROM holds
2153
        WHERE biblionumber = ?
2157
        WHERE biblio_id = ?
2154
        AND   priority > 0
2158
        AND   priority > 0
2155
        AND   (found IS NULL OR found = '')
2159
        AND   status='placed'
2156
    };
2160
    };
2157
    #skip found==W or found==T (waiting or transit holds)
2161
    #skip status==W or status==T (waiting or transit holds)
2158
    if( $resdate ) {
2162
    if( $resdate ) {
2159
        $sql.= ' AND ( reservedate <= ? )';
2163
        $sql.= ' AND ( placing_date <= ? )';
2160
    }
2164
    }
2161
    else {
2165
    else {
2162
        $sql.= ' AND ( reservedate < NOW() )';
2166
        $sql.= ' AND ( placing_date < NOW() )';
2163
    }
2167
    }
2164
    my $dbh = C4::Context->dbh();
2168
    my $dbh = C4::Context->dbh();
2165
    my @row = $dbh->selectrow_array(
2169
    my @row = $dbh->selectrow_array(
Lines 2176-2194 sub CalculatePriority { Link Here
2176
    my $bool = IsItemFoundHold( $itemnumber );
2180
    my $bool = IsItemFoundHold( $itemnumber );
2177
2181
2178
    Returns true if the item is currently on hold
2182
    Returns true if the item is currently on hold
2179
    and that hold has a non-null found status ( W, T, etc. )
2183
    and that hold has a status of waiting or in_transit
2180
2184
2181
=cut
2185
=cut
2182
2186
2183
sub IsItemOnHoldAndFound {
2187
sub IsItemOnHoldAndFound {
2184
    my ($itemnumber) = @_;
2188
    my ($itemnumber) = @_;
2185
2189
2186
    my $rs = Koha::Database->new()->schema()->resultset('Reserve');
2190
    my $rs = Koha::Database->new()->schema()->resultset('Hold');
2187
2191
2188
    my $found = $rs->count(
2192
    my $found = $rs->count(
2189
        {
2193
        {
2190
            itemnumber => $itemnumber,
2194
            item_id => $itemnumber,
2191
            found      => { '!=' => undef }
2195
            status      => { '-in' => ['waiting', 'in_transit'] }
2192
        }
2196
        }
2193
    );
2197
    );
2194
2198
(-)a/C4/SIP/ILS/Patron.pm (-2 / +2 lines)
Lines 505-515 sub _get_outstanding_holds { Link Here
505
    my $borrowernumber = shift;
505
    my $borrowernumber = shift;
506
506
507
    my $patron = Koha::Patrons->find( $borrowernumber );
507
    my $patron = Koha::Patrons->find( $borrowernumber );
508
    my $holds = $patron->holds->search( { -or => [ { found => undef }, { found => { '!=' => 'W' } } ] } );
508
    my $holds = $patron->holds->search( { completed => 0, status => {'!=' => 'waiting'} } );
509
    my @holds;
509
    my @holds;
510
    while ( my $hold = $holds->next ) {
510
    while ( my $hold = $holds->next ) {
511
        my $item;
511
        my $item;
512
        if ($hold->itemnumber) {
512
        if ($hold->item_id) {
513
            $item = $hold->item;
513
            $item = $hold->item;
514
        }
514
        }
515
        else {
515
        else {
(-)a/C4/SIP/ILS/Transaction/Hold.pm (-1 / +1 lines)
Lines 96-102 sub drop_hold { Link Here
96
	}
96
	}
97
97
98
    my $item = Koha::Items->find({ barcode => $self->{item}->id });
98
    my $item = Koha::Items->find({ barcode => $self->{item}->id });
99
    my $holds = $item->holds->search({ borrowernumber => $patron->borrowernumber });
99
    my $holds = $item->holds->search({ patron_id => $patron->borrowernumber });
100
100
101
    return $self unless $holds->count;
101
    return $self unless $holds->count;
102
102
(-)a/C4/XSLT.pm (-1 / +1 lines)
Lines 303-309 sub buildKohaItemsNamespace { Link Here
303
            'me.biblionumber' => $biblionumber,
303
            'me.biblionumber' => $biblionumber,
304
            'me.itemnumber'   => { not_in => $hidden_items }
304
            'me.itemnumber'   => { not_in => $hidden_items }
305
        },
305
        },
306
        { prefetch => [ 'branchtransfers', 'reserves' ] }
306
        { prefetch => [ 'branchtransfers', 'holds' ] }
307
    );
307
    );
308
308
309
    my $shelflocations =
309
    my $shelflocations =
(-)a/Koha/Acquisition/Order.pm (-1 / +1 lines)
Lines 201-207 sub current_item_level_holds { Link Here
201
201
202
    return $biblio->current_holds->search(
202
    return $biblio->current_holds->search(
203
        {
203
        {
204
            itemnumber => {
204
            item_id => {
205
                -in => \@item_numbers
205
                -in => \@item_numbers
206
            }
206
            }
207
        }
207
        }
(-)a/Koha/Biblio.pm (-4 / +5 lines)
Lines 442-448 return the current holds placed on this record Link Here
442
sub holds {
442
sub holds {
443
    my ( $self, $params, $attributes ) = @_;
443
    my ( $self, $params, $attributes ) = @_;
444
    $attributes->{order_by} = 'priority' unless exists $attributes->{order_by};
444
    $attributes->{order_by} = 'priority' unless exists $attributes->{order_by};
445
    my $hold_rs = $self->_result->reserves->search( $params, $attributes );
445
    $params->{completed} = 0 unless exists $params->{completed};
446
    my $hold_rs = $self->_result->holds->search( $params, $attributes );
446
    return Koha::Holds->_new_from_dbic($hold_rs);
447
    return Koha::Holds->_new_from_dbic($hold_rs);
447
}
448
}
448
449
Lines 459-465 sub current_holds { Link Here
459
    my ($self) = @_;
460
    my ($self) = @_;
460
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
461
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
461
    return $self->holds(
462
    return $self->holds(
462
        { reservedate => { '<=' => $dtf->format_date(dt_from_string) } } );
463
        { completed => 0, placing_date => { '<=' => $dtf->format_date(dt_from_string) } } );
463
}
464
}
464
465
465
=head3 biblioitem
466
=head3 biblioitem
Lines 520-527 Tells if this bibliographic record has items waiting or in transit. Link Here
520
sub has_items_waiting_or_intransit {
521
sub has_items_waiting_or_intransit {
521
    my ( $self ) = @_;
522
    my ( $self ) = @_;
522
523
523
    if ( Koha::Holds->search({ biblionumber => $self->id,
524
    if ( Koha::Holds->search({ biblio_id => $self->id,
524
                               found => ['W', 'T'] })->count ) {
525
                               status => ['waiting', 'in_transit'] })->count ) {
525
        return 1;
526
        return 1;
526
    }
527
    }
527
528
(-)a/Koha/Item.pm (-7 / +9 lines)
Lines 249-255 sub safe_to_delete { Link Here
249
249
250
    # check it doesn't have a waiting reserve
250
    # check it doesn't have a waiting reserve
251
    return "book_reserved"
251
    return "book_reserved"
252
      if $self->holds->search( { found => [ 'W', 'T' ] } )->count;
252
      if $self->holds->search( { status => [ 'waiting', 'in_transit' ], completed => 0 } )->count;
253
253
254
    return "linked_analytics"
254
    return "linked_analytics"
255
      if C4::Items::GetAnalyticsCount( $self->itemnumber ) > 0;
255
      if C4::Items::GetAnalyticsCount( $self->itemnumber ) > 0;
Lines 365-371 Return holds attached to an item, optionally accept a hashref of params to pass Link Here
365
365
366
sub holds {
366
sub holds {
367
    my ( $self,$params ) = @_;
367
    my ( $self,$params ) = @_;
368
    my $holds_rs = $self->_result->reserves->search($params);
368
    $params->{completed} = 0 unless exists $params->{completed};
369
    my $holds_rs = $self->_result->holds->search($params);
369
    return Koha::Holds->_new_from_dbic( $holds_rs );
370
    return Koha::Holds->_new_from_dbic( $holds_rs );
370
}
371
}
371
372
Lines 616-629 sub current_holds { Link Here
616
    my $attributes = { order_by => 'priority' };
617
    my $attributes = { order_by => 'priority' };
617
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
618
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
618
    my $params = {
619
    my $params = {
619
        itemnumber => $self->itemnumber,
620
        item_id => $self->itemnumber,
620
        suspend => 0,
621
        suspended => 0,
621
        -or => [
622
        -or => [
622
            reservedate => { '<=' => $dtf->format_date(dt_from_string) },
623
            placing_date => { '<=' => $dtf->format_date(dt_from_string) },
623
            waitingdate => { '!=' => undef },
624
            waiting_date => { '!=' => undef },
624
        ],
625
        ],
626
        completed => 0
625
    };
627
    };
626
    my $hold_rs = $self->_result->reserves->search( $params, $attributes );
628
    my $hold_rs = $self->_result->holds->search( $params, $attributes );
627
    return Koha::Holds->_new_from_dbic($hold_rs);
629
    return Koha::Holds->_new_from_dbic($hold_rs);
628
}
630
}
629
631
(-)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 1129-1136 Return all the holds placed by this patron Link Here
1129
=cut
1128
=cut
1130
1129
1131
sub holds {
1130
sub holds {
1132
    my ($self) = @_;
1131
    my ($self, $params) = @_;
1133
    my $holds_rs = $self->_result->reserves->search( {}, { order_by => 'reservedate' } );
1132
    $params->{completed} = 0 unless exists $params->{completed};
1133
    my $holds_rs = $self->_result->holds->search( $params, { order_by => 'placing_date' } );
1134
    return Koha::Holds->_new_from_dbic($holds_rs);
1134
    return Koha::Holds->_new_from_dbic($holds_rs);
1135
}
1135
}
1136
1136
Lines 1144-1151 Return all the historical holds for this patron Link Here
1144
1144
1145
sub old_holds {
1145
sub old_holds {
1146
    my ($self) = @_;
1146
    my ($self) = @_;
1147
    my $old_holds_rs = $self->_result->old_reserves->search( {}, { order_by => 'reservedate' } );
1147
    my $old_holds_rs = $self->_result->holds->search( { completed => 1 }, { order_by => 'placing_date' } );
1148
    return Koha::Old::Holds->_new_from_dbic($old_holds_rs);
1148
    return Koha::Holds->_new_from_dbic($old_holds_rs);
1149
}
1149
}
1150
1150
1151
=head3 return_claims
1151
=head3 return_claims
(-)a/Koha/REST/V1/Auth.pm (-11 / +9 lines)
Lines 300-309 sub validate_query_parameters { Link Here
300
Allows access to object for its owner.
300
Allows access to object for its owner.
301
301
302
There are endpoints that should allow access for the object owner even if they
302
There are endpoints that should allow access for the object owner even if they
303
do not have the required permission, e.g. access an own reserve. This can be
303
do not have the required permission, e.g. access an own hold. This can be
304
achieved by defining the operation as follows:
304
achieved by defining the operation as follows:
305
305
306
"/holds/{reserve_id}": {
306
"/holds/{hold_id}": {
307
    "get": {
307
    "get": {
308
        ...,
308
        ...,
309
        "x-koha-authorization": {
309
        "x-koha-authorization": {
Lines 367-373 sub check_object_ownership { Link Here
367
        borrowernumber  => \&_object_ownership_by_patron_id,
367
        borrowernumber  => \&_object_ownership_by_patron_id,
368
        patron_id       => \&_object_ownership_by_patron_id,
368
        patron_id       => \&_object_ownership_by_patron_id,
369
        checkout_id     => \&_object_ownership_by_checkout_id,
369
        checkout_id     => \&_object_ownership_by_checkout_id,
370
        reserve_id      => \&_object_ownership_by_reserve_id,
370
        hold_id      => \&_object_ownership_by_hold_id,
371
    };
371
    };
372
372
373
    foreach my $param ( keys %{ $parameters } ) {
373
    foreach my $param ( keys %{ $parameters } ) {
Lines 431-450 sub _object_ownership_by_checkout_id { Link Here
431
            && $user->borrowernumber == $issue->borrowernumber;
431
            && $user->borrowernumber == $issue->borrowernumber;
432
}
432
}
433
433
434
=head3 _object_ownership_by_reserve_id
434
=head3 _object_ownership_by_hold_id
435
435
436
Finds a Koha::Hold-object by C<$reserve_id> and checks if it
436
Finds a Koha::Hold-object by C<$hold_id> and checks if it
437
belongs to C<$user>.
437
belongs to C<$user>.
438
438
439
TODO: Also compare against old_reserves
440
441
=cut
439
=cut
442
440
443
sub _object_ownership_by_reserve_id {
441
sub _object_ownership_by_hold_id {
444
    my ($c, $user, $reserve_id) = @_;
442
    my ($c, $user, $hold_id) = @_;
445
443
446
    my $reserve = Koha::Holds->find($reserve_id);
444
    my $hold = Koha::Holds->find($hold_id);
447
    return $reserve && $user->borrowernumber == $reserve->borrowernumber;
445
    return $hold && $user->borrowernumber == $hold->borrowernumber;
448
}
446
}
449
447
450
=head3 _basic_auth
448
=head3 _basic_auth
(-)a/Koha/REST/V1/Holds.pm (-14 / +14 lines)
Lines 43-49 sub list { Link Here
43
    my $c = shift->openapi->valid_input or return;
43
    my $c = shift->openapi->valid_input or return;
44
44
45
    return try {
45
    return try {
46
        my $holds_set = Koha::Holds->new;
46
        my $holds_set = Koha::Holds->search({completed=>0});
47
        my $holds     = $c->objects->search( $holds_set );
47
        my $holds     = $c->objects->search( $holds_set );
48
        return $c->render( status => 200, openapi => $holds );
48
        return $c->render( status => 200, openapi => $holds );
49
    }
49
    }
Lines 73-81 sub add { Link Here
73
        my $item_type         = $body->{item_type};
73
        my $item_type         = $body->{item_type};
74
        my $expiration_date   = $body->{expiration_date};
74
        my $expiration_date   = $body->{expiration_date};
75
        my $notes             = $body->{notes};
75
        my $notes             = $body->{notes};
76
        my $hold_date         = $body->{hold_date};
76
        my $placing_date      = $body->{placing_date};
77
77
78
        if(!C4::Context->preference( 'AllowHoldDateInFuture' ) && $hold_date) {
78
        if(!C4::Context->preference( 'AllowHoldDateInFuture' ) && $placing_date) {
79
            return $c->render(
79
            return $c->render(
80
                status  => 400,
80
                status  => 400,
81
                openapi => { error => "Hold date in future not allowed" }
81
                openapi => { error => "Hold date in future not allowed" }
Lines 155-161 sub add { Link Here
155
                borrowernumber   => $patron_id,
155
                borrowernumber   => $patron_id,
156
                biblionumber     => $biblio_id,
156
                biblionumber     => $biblio_id,
157
                priority         => $priority,
157
                priority         => $priority,
158
                reservation_date => $hold_date,
158
                reservation_date => $placing_date,
159
                expiration_date  => $expiration_date,
159
                expiration_date  => $expiration_date,
160
                notes            => $notes,
160
                notes            => $notes,
161
                title            => $biblio->title,
161
                title            => $biblio->title,
Lines 208-214 sub edit { Link Here
208
208
209
    return try {
209
    return try {
210
        my $hold_id = $c->validation->param('hold_id');
210
        my $hold_id = $c->validation->param('hold_id');
211
        my $hold = Koha::Holds->find( $hold_id );
211
        my $hold = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
212
212
213
        unless ($hold) {
213
        unless ($hold) {
214
            return $c->render( status  => 404,
214
            return $c->render( status  => 404,
Lines 217-233 sub edit { Link Here
217
217
218
        my $body = $c->req->json;
218
        my $body = $c->req->json;
219
219
220
        my $pickup_library_id = $body->{pickup_library_id} // $hold->branchcode;
220
        my $pickup_library_id = $body->{pickup_library_id} // $hold->pickup_library_id;
221
        my $priority          = $body->{priority} // $hold->priority;
221
        my $priority          = $body->{priority} // $hold->priority;
222
        # suspended_until can also be set to undef
222
        # suspended_until can also be set to undef
223
        my $suspended_until   = exists $body->{suspended_until} ? $body->{suspended_until} : $hold->suspend_until;
223
        my $suspended_until   = exists $body->{suspended_until_date} ? $body->{suspended_until_date} : $hold->suspended_until_date;
224
224
225
        my $params = {
225
        my $params = {
226
            reserve_id    => $hold_id,
226
            reserve_id    => $hold_id,
227
            branchcode    => $pickup_library_id,
227
            branchcode    => $pickup_library_id,
228
            rank          => $priority,
228
            rank          => $priority,
229
            suspend_until => $suspended_until ? output_pref(dt_from_string($suspended_until, 'rfc3339')) : '',
229
            suspend_until => $suspended_until ? output_pref(dt_from_string($suspended_until, 'rfc3339')) : '',
230
            itemnumber    => $hold->itemnumber
230
            itemnumber    => $hold->item_id
231
        };
231
        };
232
232
233
        C4::Reserves::ModReserve($params);
233
        C4::Reserves::ModReserve($params);
Lines 253-259 sub delete { Link Here
253
    my $c = shift->openapi->valid_input or return;
253
    my $c = shift->openapi->valid_input or return;
254
254
255
    my $hold_id = $c->validation->param('hold_id');
255
    my $hold_id = $c->validation->param('hold_id');
256
    my $hold    = Koha::Holds->find($hold_id);
256
    my $hold    = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
257
257
258
    unless ($hold) {
258
    unless ($hold) {
259
        return $c->render( status => 404, openapi => { error => "Hold not found." } );
259
        return $c->render( status => 404, openapi => { error => "Hold not found." } );
Lines 282-288 sub suspend { Link Here
282
    my $c = shift->openapi->valid_input or return;
282
    my $c = shift->openapi->valid_input or return;
283
283
284
    my $hold_id  = $c->validation->param('hold_id');
284
    my $hold_id  = $c->validation->param('hold_id');
285
    my $hold     = Koha::Holds->find($hold_id);
285
    my $hold     = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
286
    my $body     = $c->req->json;
286
    my $body     = $c->req->json;
287
    my $end_date = ($body) ? $body->{end_date} : undef;
287
    my $end_date = ($body) ? $body->{end_date} : undef;
288
288
Lines 296-304 sub suspend { Link Here
296
        $hold->discard_changes;
296
        $hold->discard_changes;
297
        $c->res->headers->location( $c->req->url->to_string );
297
        $c->res->headers->location( $c->req->url->to_string );
298
        my $suspend_end_date;
298
        my $suspend_end_date;
299
        if ($hold->suspend_until) {
299
        if ($hold->suspended_until_date) {
300
            $suspend_end_date = output_pref({
300
            $suspend_end_date = output_pref({
301
                dt         => dt_from_string( $hold->suspend_until ),
301
                dt         => dt_from_string( $hold->suspended_until_date ),
302
                dateformat => 'rfc3339',
302
                dateformat => 'rfc3339',
303
                dateonly   => 1
303
                dateonly   => 1
304
                }
304
                }
Lines 330-336 sub resume { Link Here
330
    my $c = shift->openapi->valid_input or return;
330
    my $c = shift->openapi->valid_input or return;
331
331
332
    my $hold_id = $c->validation->param('hold_id');
332
    my $hold_id = $c->validation->param('hold_id');
333
    my $hold    = Koha::Holds->find($hold_id);
333
    my $hold    = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
334
    my $body    = $c->req->json;
334
    my $body    = $c->req->json;
335
335
336
    unless ($hold) {
336
    unless ($hold) {
Lines 356-362 sub update_priority { Link Here
356
    my $c = shift->openapi->valid_input or return;
356
    my $c = shift->openapi->valid_input or return;
357
357
358
    my $hold_id = $c->validation->param('hold_id');
358
    my $hold_id = $c->validation->param('hold_id');
359
    my $hold = Koha::Holds->find($hold_id);
359
    my $hold = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
360
360
361
    unless ($hold) {
361
    unless ($hold) {
362
        return $c->render(
362
        return $c->render(
(-)a/Koha/Schema/Result/Hold.pm (-4 / +4 lines)
Lines 97-103 __PACKAGE__->table("holds"); Link Here
97
  data_type: 'enum'
97
  data_type: 'enum'
98
  default_value: 'placed'
98
  default_value: 'placed'
99
  extra: {list => ["placed","fulfilled","waiting","in_transit","cancelled"]}
99
  extra: {list => ["placed","fulfilled","waiting","in_transit","cancelled"]}
100
  is_nullable: 1
100
  is_nullable: 0
101
101
102
=head2 timestamp
102
=head2 timestamp
103
103
Lines 184-190 __PACKAGE__->add_columns( Link Here
184
    extra => {
184
    extra => {
185
      list => ["placed", "fulfilled", "waiting", "in_transit", "cancelled"],
185
      list => ["placed", "fulfilled", "waiting", "in_transit", "cancelled"],
186
    },
186
    },
187
    is_nullable => 1,
187
    is_nullable => 0,
188
  },
188
  },
189
  "timestamp",
189
  "timestamp",
190
  {
190
  {
Lines 331-338 __PACKAGE__->belongs_to( Link Here
331
);
331
);
332
332
333
333
334
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2020-04-22 19:21:03
334
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-04-23 12:55:08
335
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:rpFBfRe1swRgNQsdQPiTtg
335
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:hACjwpQwyEtJ694l+rtpLw
336
336
337
__PACKAGE__->add_columns(
337
__PACKAGE__->add_columns(
338
    '+completed'  => { is_boolean => 1 },
338
    '+completed'  => { is_boolean => 1 },
(-)a/Koha/Schema/Result/OldReserve.pm (-5 / +5 lines)
Lines 21-27 __PACKAGE__->table_class("DBIx::Class::ResultSource::View"); Link Here
21
=cut
21
=cut
22
22
23
__PACKAGE__->table("old_reserves");
23
__PACKAGE__->table("old_reserves");
24
__PACKAGE__->result_source_instance->view_definition("select `dbic`.`holds`.`id` AS `reserve_id`,`dbic`.`holds`.`patron_id` AS `borrowernumber`,`dbic`.`holds`.`placing_date` AS `reservedate`,`dbic`.`holds`.`biblio_id` AS `biblionumber`,`dbic`.`holds`.`pickup_library_id` AS `branchcode`,(case when (`dbic`.`holds`.`status` = 'cancelled') then `dbic`.`holds`.`completion_date` else NULL end) AS `cancellationdate`,`dbic`.`holds`.`notes` AS `reservenotes`,`dbic`.`holds`.`priority` AS `priority`,(case when (`dbic`.`holds`.`status` = 'fulfilled') then 'F' else NULL end) AS `found`,`dbic`.`holds`.`timestamp` AS `timestamp`,`dbic`.`holds`.`item_id` AS `itemnumber`,`dbic`.`holds`.`waiting_date` AS `waitingdate`,`dbic`.`holds`.`expiration_date` AS `expirationdate`,`dbic`.`holds`.`lowest_priority` AS `lowestPriority`,`dbic`.`holds`.`suspended` AS `suspend`,`dbic`.`holds`.`suspended_until_date` AS `suspend_until`,`dbic`.`holds`.`item_type` AS `itemtype`,`dbic`.`holds`.`item_level` AS `item_level_hold` from `dbic`.`holds` where (`dbic`.`holds`.`completed` = 1)");
24
__PACKAGE__->result_source_instance->view_definition("select `dbic`.`holds`.`id` AS `reserve_id`,`dbic`.`holds`.`patron_id` AS `borrowernumber`,`dbic`.`holds`.`placing_date` AS `reservedate`,`dbic`.`holds`.`biblio_id` AS `biblionumber`,`dbic`.`holds`.`pickup_library_id` AS `branchcode`,case when `dbic`.`holds`.`status` = 'cancelled' then `dbic`.`holds`.`completion_date` else NULL end AS `cancellationdate`,`dbic`.`holds`.`notes` AS `reservenotes`,`dbic`.`holds`.`priority` AS `priority`,case when `dbic`.`holds`.`status` = 'fulfilled' then 'F' else NULL end AS `found`,`dbic`.`holds`.`timestamp` AS `timestamp`,`dbic`.`holds`.`item_id` AS `itemnumber`,`dbic`.`holds`.`waiting_date` AS `waitingdate`,`dbic`.`holds`.`expiration_date` AS `expirationdate`,`dbic`.`holds`.`lowest_priority` AS `lowestPriority`,`dbic`.`holds`.`suspended` AS `suspend`,`dbic`.`holds`.`suspended_until_date` AS `suspend_until`,`dbic`.`holds`.`item_type` AS `itemtype`,`dbic`.`holds`.`item_level` AS `item_level_hold` from `dbic`.`holds` where `dbic`.`holds`.`completed` = 1");
25
25
26
=head1 ACCESSORS
26
=head1 ACCESSORS
27
27
Lines 82-88 __PACKAGE__->result_source_instance->view_definition("select `dbic`.`holds`.`id` Link Here
82
82
83
  data_type: 'timestamp'
83
  data_type: 'timestamp'
84
  datetime_undef_if_invalid: 1
84
  datetime_undef_if_invalid: 1
85
  default_value: '0000-00-00 00:00:00'
85
  default_value: current_timestamp
86
  is_nullable: 0
86
  is_nullable: 0
87
87
88
=head2 itemnumber
88
=head2 itemnumber
Lines 158-164 __PACKAGE__->add_columns( Link Here
158
  {
158
  {
159
    data_type => "timestamp",
159
    data_type => "timestamp",
160
    datetime_undef_if_invalid => 1,
160
    datetime_undef_if_invalid => 1,
161
    default_value => "0000-00-00 00:00:00",
161
    default_value => \"current_timestamp",
162
    is_nullable => 0,
162
    is_nullable => 0,
163
  },
163
  },
164
  "itemnumber",
164
  "itemnumber",
Lines 189-196 __PACKAGE__->add_columns( Link Here
189
);
189
);
190
190
191
191
192
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2020-04-22 19:21:04
192
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-04-23 12:55:08
193
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:j84bBLVB23oDE0csBcI8+A
193
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:3TEDHR07dWzKIII7kRWa9g
194
194
195
__PACKAGE__->add_columns(
195
__PACKAGE__->add_columns(
196
    '+item_level_hold' => { is_boolean => 1 },
196
    '+item_level_hold' => { is_boolean => 1 },
(-)a/Koha/Schema/Result/Reserve.pm (-5 / +5 lines)
Lines 21-27 __PACKAGE__->table_class("DBIx::Class::ResultSource::View"); Link Here
21
=cut
21
=cut
22
22
23
__PACKAGE__->table("reserves");
23
__PACKAGE__->table("reserves");
24
__PACKAGE__->result_source_instance->view_definition("select `dbic`.`holds`.`id` AS `reserve_id`,`dbic`.`holds`.`patron_id` AS `borrowernumber`,`dbic`.`holds`.`placing_date` AS `reservedate`,`dbic`.`holds`.`biblio_id` AS `biblionumber`,`dbic`.`holds`.`pickup_library_id` AS `branchcode`,NULL AS `cancellationdate`,`dbic`.`holds`.`notes` AS `reservenotes`,`dbic`.`holds`.`priority` AS `priority`,(case when (`dbic`.`holds`.`status` = 'waiting') then 'W' when (`dbic`.`holds`.`status` = 'in_transit') then 'T' else NULL end) AS `found`,`dbic`.`holds`.`timestamp` AS `timestamp`,`dbic`.`holds`.`item_id` AS `itemnumber`,`dbic`.`holds`.`waiting_date` AS `waitingdate`,`dbic`.`holds`.`expiration_date` AS `expirationdate`,`dbic`.`holds`.`lowest_priority` AS `lowestPriority`,`dbic`.`holds`.`suspended` AS `suspend`,`dbic`.`holds`.`suspended_until_date` AS `suspend_until`,`dbic`.`holds`.`item_type` AS `itemtype`,`dbic`.`holds`.`item_level` AS `item_level_hold` from `dbic`.`holds` where (`dbic`.`holds`.`completed` = 0)");
24
__PACKAGE__->result_source_instance->view_definition("select `dbic`.`holds`.`id` AS `reserve_id`,`dbic`.`holds`.`patron_id` AS `borrowernumber`,`dbic`.`holds`.`placing_date` AS `reservedate`,`dbic`.`holds`.`biblio_id` AS `biblionumber`,`dbic`.`holds`.`pickup_library_id` AS `branchcode`,NULL AS `cancellationdate`,`dbic`.`holds`.`notes` AS `reservenotes`,`dbic`.`holds`.`priority` AS `priority`,case when `dbic`.`holds`.`status` = 'waiting' then 'W' when `dbic`.`holds`.`status` = 'in_transit' then 'T' else NULL end AS `found`,`dbic`.`holds`.`timestamp` AS `timestamp`,`dbic`.`holds`.`item_id` AS `itemnumber`,`dbic`.`holds`.`waiting_date` AS `waitingdate`,`dbic`.`holds`.`expiration_date` AS `expirationdate`,`dbic`.`holds`.`lowest_priority` AS `lowestPriority`,`dbic`.`holds`.`suspended` AS `suspend`,`dbic`.`holds`.`suspended_until_date` AS `suspend_until`,`dbic`.`holds`.`item_type` AS `itemtype`,`dbic`.`holds`.`item_level` AS `item_level_hold` from `dbic`.`holds` where `dbic`.`holds`.`completed` = 0");
25
25
26
=head1 ACCESSORS
26
=head1 ACCESSORS
27
27
Lines 81-87 __PACKAGE__->result_source_instance->view_definition("select `dbic`.`holds`.`id` Link Here
81
81
82
  data_type: 'timestamp'
82
  data_type: 'timestamp'
83
  datetime_undef_if_invalid: 1
83
  datetime_undef_if_invalid: 1
84
  default_value: '0000-00-00 00:00:00'
84
  default_value: current_timestamp
85
  is_nullable: 0
85
  is_nullable: 0
86
86
87
=head2 itemnumber
87
=head2 itemnumber
Lines 157-163 __PACKAGE__->add_columns( Link Here
157
  {
157
  {
158
    data_type => "timestamp",
158
    data_type => "timestamp",
159
    datetime_undef_if_invalid => 1,
159
    datetime_undef_if_invalid => 1,
160
    default_value => "0000-00-00 00:00:00",
160
    default_value => \"current_timestamp",
161
    is_nullable => 0,
161
    is_nullable => 0,
162
  },
162
  },
163
  "itemnumber",
163
  "itemnumber",
Lines 188-195 __PACKAGE__->add_columns( Link Here
188
);
188
);
189
189
190
190
191
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2020-04-22 19:21:04
191
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-04-23 12:55:08
192
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:5rN+zc7MxGkvUsCfihsq2Q
192
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:CQKx3fKQhJO9UQrLf92PrQ
193
193
194
__PACKAGE__->add_columns(
194
__PACKAGE__->add_columns(
195
    '+item_level_hold' => { is_boolean => 1 },
195
    '+item_level_hold' => { is_boolean => 1 },
(-)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
    "placing_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 37-43 Link Here
37
    },
37
    },
38
    "status": {
38
    "status": {
39
      "type": ["string", "null"],
39
      "type": ["string", "null"],
40
      "description": "A one letter code defining what the status of the hold is after it has been confirmed"
40
      "description": "the status the hold is ('placed', 'fulfilled', 'waiting', 'in_transit', 'cancelled')"
41
    },
41
    },
42
    "timestamp": {
42
    "timestamp": {
43
      "type": "string",
43
      "type": "string",
Lines 66-72 Link Here
66
      "type": "boolean",
66
      "type": "boolean",
67
      "description": "Controls if the hold is suspended"
67
      "description": "Controls if the hold is suspended"
68
    },
68
    },
69
    "suspended_until": {
69
    "suspended_until_date": {
70
      "type": ["string", "null"],
70
      "type": ["string", "null"],
71
      "format": "date-time",
71
      "format": "date-time",
72
      "description": "Date until which the hold has been suspended"
72
      "description": "Date until which the hold has been suspended"
Lines 78-83 Link Here
78
    "item_level": {
78
    "item_level": {
79
      "type": "boolean",
79
      "type": "boolean",
80
      "description": "If the hold is placed at item level"
80
      "description": "If the hold is placed at item level"
81
    },
82
    "completed": {
83
      "type": "boolean",
84
      "description": "If it has been completed (i.e. either 'fulfilled' or 'cancelled')"
85
    },
86
    "completion_date": {
87
      "type": ["string", "null"],
88
      "description": "the date this hold was completed (fulfilled or cancelled)"
81
    }
89
    }
82
  }
90
  }
83
}
91
}
(-)a/api/v1/swagger/paths/holds.json (-2 / +2 lines)
Lines 280-290 Link Here
280
                "type": "integer",
280
                "type": "integer",
281
                "minimum": 1
281
                "minimum": 1
282
              },
282
              },
283
              "branchcode": {
283
              "pickup_library_id": {
284
                "description": "Pickup location",
284
                "description": "Pickup location",
285
                "type": "string"
285
                "type": "string"
286
              },
286
              },
287
              "suspend_until": {
287
              "suspend_until_date": {
288
                "description": "Suspend until",
288
                "description": "Suspend until",
289
                "type": "string",
289
                "type": "string",
290
                "format": "date"
290
                "format": "date"
(-)a/reserve/request.pl (-1 / +1 lines)
Lines 635-641 foreach my $biblionumber (@biblionumbers) { Link Here
635
635
636
    # existingreserves building
636
    # existingreserves building
637
    my @reserveloop;
637
    my @reserveloop;
638
    my @reserves = Koha::Holds->search( { biblionumber => $biblionumber }, { order_by => 'priority' } );
638
    my @reserves = Koha::Holds->search( { biblio_id => $biblionumber }, { order_by => 'priority' } );
639
    foreach my $res (
639
    foreach my $res (
640
        sort {
640
        sort {
641
            my $a_found = $a->found() || '';
641
            my $a_found = $a->found() || '';
(-)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 => [ '-placing_date' ] },
112
            result_set => $result_set
112
            result_set => $result_set
113
        }
113
        }
114
    );
114
    );
Lines 331-337 subtest 'dbic_merge_sorting() tests' => sub { Link Here
331
      ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
331
      ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
332
      ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
332
      ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
333
        '/order_by' => [
333
        '/order_by' => [
334
            { -desc => 'reservedate' }
334
            { -desc => 'placing_date' }
335
        ]
335
        ]
336
      );
336
      );
337
337
(-)a/t/db_dependent/Circulation.t (-28 / +28 lines)
Lines 415-445 subtest "CanBookBeRenewed tests" => sub { Link Here
415
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
415
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
416
416
417
    # Now let's add an item level hold, we should no longer be able to renew the item
417
    # Now let's add an item level hold, we should no longer be able to renew the item
418
    my $hold = Koha::Database->new()->schema()->resultset('Reserve')->create(
418
    my $hold = Koha::Hold->new(
419
        {
419
        {
420
            borrowernumber => $hold_waiting_borrowernumber,
420
            patron_id   => $hold_waiting_borrowernumber,
421
            biblionumber   => $biblio->biblionumber,
421
            biblio_id   => $biblio->biblionumber,
422
            itemnumber     => $item_1->itemnumber,
422
            item_id     => $item_1->itemnumber,
423
            branchcode     => $branch,
423
            pickup_library_id => $branch,
424
            priority       => 3,
424
            priority    => 3,
425
        }
425
        }
426
    );
426
    )->store;
427
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
427
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
428
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
428
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
429
    $hold->delete();
429
    $hold->delete();
430
430
431
    # 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
431
    # 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
432
    # be able to renew these items
432
    # be able to renew these items
433
    $hold = Koha::Database->new()->schema()->resultset('Reserve')->create(
433
    $hold = Koha::Hold->new(
434
        {
434
        {
435
            borrowernumber => $hold_waiting_borrowernumber,
435
            patron_id => $hold_waiting_borrowernumber,
436
            biblionumber   => $biblio->biblionumber,
436
            biblio_id   => $biblio->biblionumber,
437
            itemnumber     => $item_3->itemnumber,
437
            item_id     => $item_3->itemnumber,
438
            branchcode     => $branch,
438
            pickup_library_id     => $branch,
439
            priority       => 0,
439
            priority       => 0,
440
            found          => 'W'
440
            status          => 'waiting'
441
        }
441
        }
442
    );
442
    )->store;
443
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
443
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
444
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
444
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
445
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
445
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
Lines 454-468 subtest "CanBookBeRenewed tests" => sub { Link Here
454
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
454
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
455
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
455
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
456
456
457
    my $reserveid = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $reserving_borrowernumber })->next->reserve_id;
457
    my $reserveid = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $reserving_borrowernumber })->next->id;
458
    my $reserving_borrower = Koha::Patrons->find( $reserving_borrowernumber )->unblessed;
458
    my $reserving_borrower = Koha::Patrons->find( $reserving_borrowernumber )->unblessed;
459
    AddIssue($reserving_borrower, $item_3->barcode);
459
    AddIssue($reserving_borrower, $item_3->barcode);
460
    my $reserve = $dbh->selectrow_hashref(
460
    my $reserve = $dbh->selectrow_hashref(
461
        'SELECT * FROM old_reserves WHERE reserve_id = ?',
461
        'SELECT * FROM holds WHERE id = ? AND completed = 1',
462
        { Slice => {} },
462
        { Slice => {} },
463
        $reserveid
463
        $reserveid
464
    );
464
    );
465
    is($reserve->{found}, 'F', 'hold marked completed when checking out item that fills it');
465
    is($reserve->{status}, 'fulfilled', 'hold marked completed when checking out item that fills it');
466
466
467
    # Item-level hold, renewal test
467
    # Item-level hold, renewal test
468
    AddReserve(
468
    AddReserve(
Lines 606-612 subtest "CanBookBeRenewed tests" => sub { Link Here
606
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is overdue');
606
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is overdue');
607
607
608
608
609
    $hold = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $reserving_borrowernumber })->next;
609
    $hold = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $reserving_borrowernumber })->next;
610
    $hold->cancel;
610
    $hold->cancel;
611
611
612
    # Bug 14101
612
    # Bug 14101
Lines 2965-2971 subtest 'Set waiting flag' => sub { Link Here
2965
    my ( $res, $rr ) = AddReturn( $item->{barcode}, $library_1->{branchcode} );
2965
    my ( $res, $rr ) = AddReturn( $item->{barcode}, $library_1->{branchcode} );
2966
    ModReserveAffect( $item->{itemnumber}, undef, $do_transfer, $reserve_id );
2966
    ModReserveAffect( $item->{itemnumber}, undef, $do_transfer, $reserve_id );
2967
    my $hold = Koha::Holds->find( $reserve_id );
2967
    my $hold = Koha::Holds->find( $reserve_id );
2968
    is( $hold->found, 'T', 'Hold is in transit' );
2968
    is( $hold->status, 'in_transit', 'Hold is in transit' );
2969
2969
2970
    my ( $status ) = CheckReserves($item->{itemnumber});
2970
    my ( $status ) = CheckReserves($item->{itemnumber});
2971
    is( $status, 'Reserved', 'Hold is not waiting yet');
2971
    is( $status, 'Reserved', 'Hold is not waiting yet');
Lines 2975-2981 subtest 'Set waiting flag' => sub { Link Here
2975
    AddReturn( $item->{barcode}, $library_2->{branchcode} );
2975
    AddReturn( $item->{barcode}, $library_2->{branchcode} );
2976
    ModReserveAffect( $item->{itemnumber}, undef, $do_transfer, $reserve_id );
2976
    ModReserveAffect( $item->{itemnumber}, undef, $do_transfer, $reserve_id );
2977
    $hold = Koha::Holds->find( $reserve_id );
2977
    $hold = Koha::Holds->find( $reserve_id );
2978
    is( $hold->found, 'W', 'Hold is waiting' );
2978
    is( $hold->status, 'waiting', 'Hold is waiting' );
2979
    ( $status ) = CheckReserves($item->{itemnumber});
2979
    ( $status ) = CheckReserves($item->{itemnumber});
2980
    is( $status, 'Waiting', 'Now the hold is waiting');
2980
    is( $status, 'Waiting', 'Now the hold is waiting');
2981
2981
Lines 2983-2994 subtest 'Set waiting flag' => sub { Link Here
2983
    set_userenv( $library_1 );
2983
    set_userenv( $library_1 );
2984
    (undef, my $messages, undef, undef ) = AddReturn ( $item->{barcode}, $library_1->{branchcode} );
2984
    (undef, my $messages, undef, undef ) = AddReturn ( $item->{barcode}, $library_1->{branchcode} );
2985
    $hold = Koha::Holds->find( $reserve_id );
2985
    $hold = Koha::Holds->find( $reserve_id );
2986
    is( $hold->found, undef, 'Hold is no longer marked waiting' );
2986
    is( $hold->status, 'placed', 'Hold is no longer marked waiting' );
2987
    is( $hold->priority, 1,  "Hold is now priority one again");
2987
    is( $hold->priority, 1,  "Hold is now priority one again");
2988
    is( $hold->waitingdate, undef, "Hold no longer has a waiting date");
2988
    is( $hold->waiting_date, undef, "Hold no longer has a waiting date");
2989
    is( $hold->itemnumber, $item->{itemnumber}, "Hold has retained its' itemnumber");
2989
    is( $hold->item_id, $item->{itemnumber}, "Hold has retained its' itemnumber");
2990
    is( $messages->{ResFound}->{ResFound}, "Reserved", "Hold is still returned");
2990
    is( $messages->{ResFound}->{ResFound}, "Reserved", "Hold is still returned");
2991
    is( $messages->{ResFound}->{found}, undef, "Hold is no longer marked found in return message");
2991
    is( $messages->{ResFound}->{status}, 'placed', "Hold is no longer marked found in return message");
2992
    is( $messages->{ResFound}->{priority}, 1, "Hold is priority 1 in return message");
2992
    is( $messages->{ResFound}->{priority}, 1, "Hold is priority 1 in return message");
2993
};
2993
};
2994
2994
Lines 3022-3028 subtest 'Cancel transfers on lost items' => sub { Link Here
3022
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3022
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3023
    C4::Circulation::transferbook( $library_2->{branchcode}, $item->barcode );
3023
    C4::Circulation::transferbook( $library_2->{branchcode}, $item->barcode );
3024
    my $hold = Koha::Holds->find( $reserve_id );
3024
    my $hold = Koha::Holds->find( $reserve_id );
3025
    is( $hold->found, 'T', 'Hold is in transit' );
3025
    is( $hold->status, 'in_transit', 'Hold is in transit' );
3026
3026
3027
    #Check transfer exists and the items holding branch is the transfer destination branch before marking it as lost
3027
    #Check transfer exists and the items holding branch is the transfer destination branch before marking it as lost
3028
    my ($datesent,$frombranch,$tobranch) = GetTransfers($item->itemnumber);
3028
    my ($datesent,$frombranch,$tobranch) = GetTransfers($item->itemnumber);
Lines 3844-3856 subtest 'Filling a hold should cancel existing transfer' => sub { Link Here
3844
        biblionumber   => $item->biblionumber,
3844
        biblionumber   => $item->biblionumber,
3845
        itemnumber     => $item->itemnumber
3845
        itemnumber     => $item->itemnumber
3846
    });
3846
    });
3847
    my $reserves = Koha::Holds->search({ itemnumber => $item->itemnumber });
3847
    my $reserves = Koha::Holds->search({ item_id => $item->itemnumber });
3848
    is( $reserves->count, 1, "Reserve is placed");
3848
    is( $reserves->count, 1, "Reserve is placed");
3849
    ( undef, $message ) = AddReturn( $item->barcode, $libraryA->branchcode, undef, undef );
3849
    ( undef, $message ) = AddReturn( $item->barcode, $libraryA->branchcode, undef, undef );
3850
    my $reserve = $reserves->next;
3850
    my $reserve = $reserves->next;
3851
    ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 0, $reserve->reserve_id );
3851
    ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 0, $reserve->id );
3852
    $reserve->discard_changes;
3852
    $reserve->discard_changes;
3853
    ok( $reserve->found eq 'W', "Reserve is marked waiting" );
3853
    ok( $reserve->status eq 'waiting', "Reserve is marked waiting" );
3854
    is( Koha::Item::Transfers->search({ itemnumber => $item->itemnumber, datearrived => undef })->count, 0, "No outstanding transfers when hold is waiting");
3854
    is( Koha::Item::Transfers->search({ itemnumber => $item->itemnumber, datearrived => undef })->count, 0, "No outstanding transfers when hold is waiting");
3855
};
3855
};
3856
3856
(-)a/t/db_dependent/Circulation/issue.t (-3 / +2 lines)
Lines 69-76 $dbh->do(q|DELETE FROM borrowers|); Link Here
69
$dbh->do(q|DELETE FROM categories|);
69
$dbh->do(q|DELETE FROM categories|);
70
$dbh->do(q|DELETE FROM accountlines|);
70
$dbh->do(q|DELETE FROM accountlines|);
71
$dbh->do(q|DELETE FROM circulation_rules|);
71
$dbh->do(q|DELETE FROM circulation_rules|);
72
$dbh->do(q|DELETE FROM reserves|);
72
$dbh->do(q|DELETE FROM holds|);
73
$dbh->do(q|DELETE FROM old_reserves|);
74
$dbh->do(q|DELETE FROM statistics|);
73
$dbh->do(q|DELETE FROM statistics|);
75
74
76
# Generate sample datas
75
# Generate sample datas
Lines 478-484 my $reserve_id = AddReserve( Link Here
478
ok( $reserve_id, 'The reserve should have been inserted' );
477
ok( $reserve_id, 'The reserve should have been inserted' );
479
AddIssue( $borrower_2, $barcode_1, dt_from_string, 'cancel' );
478
AddIssue( $borrower_2, $barcode_1, dt_from_string, 'cancel' );
480
my $hold = Koha::Holds->find( $reserve_id );
479
my $hold = Koha::Holds->find( $reserve_id );
481
is( $hold, undef, 'The reserve should have been correctly cancelled' );
480
is( $hold->status, 'cancelled', 'The reserve should have been correctly cancelled' );
482
481
483
#End transaction
482
#End transaction
484
$schema->storage->txn_rollback;
483
$schema->storage->txn_rollback;
(-)a/t/db_dependent/DecreaseLoanHighHolds.t (-6 / +6 lines)
Lines 86-94 for my $i ( 0 .. 5 ) { Link Here
86
    my $patron = $patrons[$i];
86
    my $patron = $patrons[$i];
87
    my $hold   = Koha::Hold->new(
87
    my $hold   = Koha::Hold->new(
88
        {
88
        {
89
            borrowernumber => $patron->id,
89
            patron_id => $patron->id,
90
            biblionumber   => $biblio->id,
90
            biblio_id   => $biblio->id,
91
            branchcode     => $library->{branchcode},
91
            pickup_library_id     => $library->{branchcode},
92
        }
92
        }
93
    )->store();
93
    )->store();
94
}
94
}
Lines 146-154 for my $i ( 5 .. 10 ) { Link Here
146
    my $patron = $patrons[$i];
146
    my $patron = $patrons[$i];
147
    my $hold   = Koha::Hold->new(
147
    my $hold   = Koha::Hold->new(
148
        {
148
        {
149
            borrowernumber => $patron->id,
149
            patron_id         => $patron->id,
150
            biblionumber   => $biblio->id,
150
            biblio_id         => $biblio->id,
151
            branchcode     => $library->{branchcode},
151
            pickup_library_id => $library->{branchcode},
152
        }
152
        }
153
    )->store();
153
    )->store();
154
}
154
}
(-)a/t/db_dependent/Hold.t (-45 / +58 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
        placing_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-136 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(q{});
116
$hold->status(q{});
116
isnt( $hold->is_waiting, 1, 'The hold is not waiting (W)' );
117
isnt( $hold->is_waiting, 1, 'The hold is not waiting (W)' );
117
is( $hold->is_found, 0, 'The hold is not found' );
118
is( $hold->is_found, 0, 'The hold is not found' );
118
ok( !$hold->is_in_transit, 'The hold is not in transit' );
119
ok( !$hold->is_in_transit, 'The hold is not in transit' );
119
120
120
# Test method is_cancelable_from_opac
121
# Test method is_cancelable_from_opac
121
$hold->found(undef);
122
$hold->status('placed');
122
is( $hold->is_cancelable_from_opac, 1, "Unfound hold is cancelable" );
123
is( $hold->is_cancelable_from_opac, 1, "Unfound hold is cancelable" );
123
$hold->found('W');
124
$hold->status('waiting');
124
is( $hold->is_cancelable_from_opac, 0, "Waiting hold is not cancelable" );
125
is( $hold->is_cancelable_from_opac, 0, "Waiting hold is not cancelable" );
125
$hold->found('T');
126
$hold->status('in_transit');
126
is( $hold->is_cancelable_from_opac, 0, "In transit hold is not cancelable" );
127
is( $hold->is_cancelable_from_opac, 0, "In transit hold is not cancelable" );
127
128
128
# Test method is_at_destination
129
# Test method is_at_destination
129
$hold->found(undef);
130
$hold->status('placed');
130
ok( !$hold->is_at_destination(), "Unfound hold cannot be at destination" );
131
ok( !$hold->is_at_destination(), "Unfound hold cannot be at destination" );
131
$hold->found('T');
132
$hold->status('in_transit');
132
ok( !$hold->is_at_destination(), "In transit hold cannot be at destination" );
133
ok( !$hold->is_at_destination(), "In transit hold cannot be at destination" );
133
$hold->found('W');
134
$hold->status('waiting');
134
ok( !$hold->is_at_destination(), "Waiting hold where hold branchcode is not the same as the item's holdingbranch is not at destination" );
135
ok( !$hold->is_at_destination(), "Waiting hold where hold branchcode is not the same as the item's holdingbranch is not at destination" );
135
$item->holdingbranch( $branches[1]->{branchcode} );
136
$item->holdingbranch( $branches[1]->{branchcode} );
136
ok( $hold->is_at_destination(), "Waiting hold where hold branchcode is the same as the item's holdingbranch is at destination" );
137
ok( $hold->is_at_destination(), "Waiting hold where hold branchcode is the same as the item's holdingbranch is at destination" );
Lines 146-176 subtest "delete() tests" => sub { Link Here
146
    # Disable logging
147
    # Disable logging
147
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
148
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
148
149
149
    my $hold = $builder->build({ source => 'Reserve' });
150
    my $hold    = $builder->build_object({ class => 'Koha::Holds' });
151
    my $hold_id = $hold->id;
152
    my $deleted = $hold->delete;
150
153
151
    my $hold_object = Koha::Holds->find( $hold->{ reserve_id } );
152
    my $deleted = $hold_object->delete;
153
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return the Koha::Hold object if the hold has been correctly deleted' );
154
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return the Koha::Hold object if the hold has been correctly deleted' );
154
    is( Koha::Holds->search({ reserve_id => $hold->{ reserve_id } })->count, 0,
155
    is( Koha::Holds->search({ id => $hold_id })->count, 0,
155
        "Koha::Hold->delete should have deleted the hold" );
156
        "Koha::Hold->delete should have deleted the hold" );
156
157
157
    my $number_of_logs = $schema->resultset('ActionLog')->search(
158
    my $number_of_logs = $schema->resultset('ActionLog')->search(
158
            { module => 'HOLDS', action => 'DELETE', object => $hold->{ reserve_id } } )->count;
159
            { module => 'HOLDS', action => 'DELETE', object => $hold_id } )->count;
159
    is( $number_of_logs, 0, 'With HoldsLogs, Koha::Hold->delete shouldn\'t have been logged' );
160
    is( $number_of_logs, 0, 'With HoldsLogs, Koha::Hold->delete shouldn\'t have been logged' );
160
161
161
    # Enable logging
162
    # Enable logging
162
    t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
163
    t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
163
164
164
    $hold = $builder->build({ source => 'Reserve' });
165
    $hold    = $builder->build_object({ class => 'Koha::Holds' });
166
    $hold_id = $hold->id;
167
    $deleted = $hold->delete;
165
168
166
    $hold_object = Koha::Holds->find( $hold->{ reserve_id } );
167
    $deleted = $hold_object->delete;
168
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return a Koha::Hold object if the hold has been correctly deleted' );
169
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return a Koha::Hold object if the hold has been correctly deleted' );
169
    is( Koha::Holds->search({ reserve_id => $hold->{ reserve_id } })->count, 0,
170
    is( Koha::Holds->search({ id => $hold_id })->count, 0,
170
        "Koha::Hold->delete should have deleted the hold" );
171
        "Koha::Hold->delete should have deleted the hold" );
171
172
172
    $number_of_logs = $schema->resultset('ActionLog')->search(
173
    $number_of_logs = $schema->resultset('ActionLog')->search(
173
            { module => 'HOLDS', action => 'DELETE', object => $hold->{ reserve_id } } )->count;
174
            { module => 'HOLDS', action => 'DELETE', object => $hold_id } )->count;
174
    is( $number_of_logs, 1, 'With HoldsLogs, Koha::Hold->delete should have been logged' );
175
    is( $number_of_logs, 1, 'With HoldsLogs, Koha::Hold->delete should have been logged' );
175
176
176
    $schema->storage->txn_rollback();
177
    $schema->storage->txn_rollback();
Lines 186-193 subtest 'suspend() tests' => sub { Link Here
186
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
187
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
187
188
188
    my $hold = $builder->build_object(
189
    my $hold = $builder->build_object(
189
        {   class => 'Koha::Holds',
190
        {
190
            value => { found => undef, suspend => 0, suspend_until => undef, waitingdate => undef }
191
            class => 'Koha::Holds',
192
            value => {
193
                status               => 'placed',
194
                suspended            => 0,
195
                suspended_until_date => undef,
196
                waiting_date         => undef
197
            }
191
        }
198
        }
192
    );
199
    );
193
200
Lines 196-202 subtest 'suspend() tests' => sub { Link Here
196
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
203
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
197
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
204
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
198
    ok( $suspended->is_suspended, 'The hold is suspended' );
205
    ok( $suspended->is_suspended, 'The hold is suspended' );
199
    is( $suspended->suspend_until, undef, 'It is an indefinite suspension' );
206
    is( $suspended->suspended_until_date, undef, 'It is an indefinite suspension' );
200
207
201
    # resume the hold
208
    # resume the hold
202
    $suspended->resume;
209
    $suspended->resume;
Lines 208-214 subtest 'suspend() tests' => sub { Link Here
208
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
215
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
209
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
216
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
210
    ok( $suspended->is_suspended, 'The hold is suspended' );
217
    ok( $suspended->is_suspended, 'The hold is suspended' );
211
    is( $suspended->suspend_until, $date->truncate( to => 'day' ), 'It is an indefinite suspension' );
218
    is( $suspended->suspended_until_date, $date->truncate( to => 'day' ), 'It is an indefinite suspension' );
212
219
213
    # resume the hold
220
    # resume the hold
214
    $suspended->resume;
221
    $suspended->resume;
Lines 221-227 subtest 'suspend() tests' => sub { Link Here
221
        'Koha::Exceptions::Hold::CannotSuspendFound',
228
        'Koha::Exceptions::Hold::CannotSuspendFound',
222
        'Exception is thrown when a found hold is tried to suspend';
229
        'Exception is thrown when a found hold is tried to suspend';
223
230
224
    is( $@->status, 'W', 'Exception gets the \'status\' parameter set correctly' );
231
    is( $@->status, 'waiting', 'Exception gets the \'status\' parameter set correctly' );
225
232
226
    # set hold found=T
233
    # set hold found=T
227
    $hold->set_waiting(1);
234
    $hold->set_waiting(1);
Lines 230-242 subtest 'suspend() tests' => sub { Link Here
230
        'Koha::Exceptions::Hold::CannotSuspendFound',
237
        'Koha::Exceptions::Hold::CannotSuspendFound',
231
        'Exception is thrown when a found hold is tried to suspend';
238
        'Exception is thrown when a found hold is tried to suspend';
232
239
233
    is( $@->status, 'T', 'Exception gets the \'status\' parameter set correctly' );
240
    is( $@->status, 'in_transit', 'Exception gets the \'status\' parameter set correctly' );
234
241
235
    my $holds_module = Test::MockModule->new('Koha::Hold');
242
    my $holds_module = Test::MockModule->new('Koha::Hold');
236
    $holds_module->mock( 'is_found', 1 );
243
    $holds_module->mock( 'is_found', 1 );
237
244
238
    # bad data case
245
    # bad data case
239
    $hold->found('X');
246
    $hold->status('cancelled');
240
    throws_ok
247
    throws_ok
241
        { $hold->suspend_hold }
248
        { $hold->suspend_hold }
242
        'Koha::Exceptions::Hold::CannotSuspendFound',
249
        'Koha::Exceptions::Hold::CannotSuspendFound',
Lines 244-251 subtest 'suspend() tests' => sub { Link Here
244
251
245
    is( $@->error, 'Unhandled data exception on found hold (id='
252
    is( $@->error, 'Unhandled data exception on found hold (id='
246
                    . $hold->id
253
                    . $hold->id
247
                    . ', found='
254
                    . ', status='
248
                    . $hold->found
255
                    . $hold->status
249
                    . ')' , 'Exception gets the \'status\' parameter set correctly' );
256
                    . ')' , 'Exception gets the \'status\' parameter set correctly' );
250
257
251
    $holds_module->unmock( 'is_found' );
258
    $holds_module->unmock( 'is_found' );
Lines 257-264 subtest 'suspend() tests' => sub { Link Here
257
            { module => 'HOLDS', action => 'SUSPEND', object => $hold->id } )->count;
264
            { module => 'HOLDS', action => 'SUSPEND', object => $hold->id } )->count;
258
265
259
    $hold = $builder->build_object(
266
    $hold = $builder->build_object(
260
        {   class => 'Koha::Holds',
267
        {
261
            value => { suspend => 0, suspend_until => undef, waitingdate => undef, found => undef }
268
            class => 'Koha::Holds',
269
            value => {
270
                suspended            => 0,
271
                suspended_until_date => undef,
272
                waiting_date         => undef,
273
                status               => 'placed'
274
            }
262
        }
275
        }
263
    );
276
    );
264
277
(-)a/t/db_dependent/Holds.t (-34 / +34 lines)
Lines 46-52 my $category = $builder->build({ source => 'Category' }); Link Here
46
my $borrowers_count = 5;
46
my $borrowers_count = 5;
47
47
48
$dbh->do('DELETE FROM itemtypes');
48
$dbh->do('DELETE FROM itemtypes');
49
$dbh->do('DELETE FROM reserves');
49
$dbh->do('DELETE FROM holds');
50
$dbh->do('DELETE FROM circulation_rules');
50
$dbh->do('DELETE FROM circulation_rules');
51
my $insert_sth = $dbh->prepare('INSERT INTO itemtypes (itemtype) VALUES (?)');
51
my $insert_sth = $dbh->prepare('INSERT INTO itemtypes (itemtype) VALUES (?)');
52
$insert_sth->execute('CAN');
52
$insert_sth->execute('CAN');
Lines 96-105 is( $holds->next->priority, 5, "Reserve 5 has a priority of 5" ); Link Here
96
my $item = Koha::Items->find( $itemnumber );
96
my $item = Koha::Items->find( $itemnumber );
97
$holds = $item->current_holds;
97
$holds = $item->current_holds;
98
my $first_hold = $holds->next;
98
my $first_hold = $holds->next;
99
my $reservedate = $first_hold->reservedate;
99
my $reservedate = $first_hold->placing_date;
100
my $borrowernumber = $first_hold->borrowernumber;
100
my $borrowernumber = $first_hold->patron_id;
101
my $branch_1code = $first_hold->branchcode;
101
my $branch_1code = $first_hold->pickup_library_id;
102
my $reserve_id = $first_hold->reserve_id;
102
my $reserve_id = $first_hold->id;
103
is( $reservedate, output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 }), "holds_placed_today should return a valid reserve date");
103
is( $reservedate, output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 }), "holds_placed_today should return a valid reserve date");
104
is( $borrowernumber, $borrowernumbers[0], "holds_placed_today should return a valid borrowernumber");
104
is( $borrowernumber, $borrowernumbers[0], "holds_placed_today should return a valid borrowernumber");
105
is( $branch_1code, $branch_1, "holds_placed_today should return a valid branchcode");
105
is( $branch_1code, $branch_1, "holds_placed_today should return a valid branchcode");
Lines 116-136 ok( $hold_item == $hold->item(), "item method returns stashed item" ); Link Here
116
my $hold_branch = $hold->branch();
116
my $hold_branch = $hold->branch();
117
ok( $hold_branch, "Got branch using branch() method" );
117
ok( $hold_branch, "Got branch using branch() method" );
118
ok( $hold_branch == $hold->branch(), "branch method returns stashed branch" );
118
ok( $hold_branch == $hold->branch(), "branch method returns stashed branch" );
119
my $hold_found = $hold->found();
119
my $hold_found = $hold->status();
120
$hold->set({ found => 'W'})->store();
120
$hold->set({ status => 'waiting' })->store();
121
is( Koha::Holds->waiting()->count(), 1, "Koha::Holds->waiting returns waiting holds" );
121
is( Koha::Holds->waiting()->count(), 1, "Koha::Holds->waiting returns waiting holds" );
122
is( Koha::Holds->unfilled()->count(), 4, "Koha::Holds->unfilled returns unfilled holds" );
122
is( Koha::Holds->unfilled()->count(), 4, "Koha::Holds->unfilled returns unfilled holds" );
123
123
124
my $patron = Koha::Patrons->find( $borrowernumbers[0] );
124
my $patron = Koha::Patrons->find( $borrowernumbers[0] );
125
$holds = $patron->holds;
125
$holds = $patron->holds;
126
is( $holds->next->borrowernumber, $borrowernumbers[0], "Test Koha::Patron->holds");
126
is( $holds->next->patron_id, $borrowernumbers[0], "Test Koha::Patron->holds");
127
127
128
128
129
$holds = $item->current_holds;
129
$holds = $item->current_holds;
130
$first_hold = $holds->next;
130
$first_hold = $holds->next;
131
$borrowernumber = $first_hold->borrowernumber;
131
$borrowernumber = $first_hold->patron_id;
132
$branch_1code = $first_hold->branchcode;
132
$branch_1code = $first_hold->pickup_library_id;
133
$reserve_id = $first_hold->reserve_id;
133
$reserve_id = $first_hold->id;
134
134
135
ModReserve({
135
ModReserve({
136
    reserve_id    => $reserve_id,
136
    reserve_id    => $reserve_id,
Lines 142-149 ModReserve({ Link Here
142
142
143
$hold = Koha::Holds->find( $reserve_id );
143
$hold = Koha::Holds->find( $reserve_id );
144
ok( $hold->priority eq '4', "Test ModReserve, priority changed correctly" );
144
ok( $hold->priority eq '4', "Test ModReserve, priority changed correctly" );
145
ok( $hold->suspend, "Test ModReserve, suspend hold" );
145
ok( $hold->suspended, "Test ModReserve, suspend hold" );
146
is( $hold->suspend_until, '2013-01-01 00:00:00', "Test ModReserve, suspend until date" );
146
is( $hold->suspended_until_date, '2013-01-01 00:00:00', "Test ModReserve, suspend until date" );
147
147
148
ModReserve({ # call without reserve_id
148
ModReserve({ # call without reserve_id
149
    rank          => '3',
149
    rank          => '3',
Lines 156-170 ok( $hold->priority eq '3', "Test ModReserve, priority changed correctly" ); Link Here
156
156
157
ToggleSuspend( $reserve_id );
157
ToggleSuspend( $reserve_id );
158
$hold = Koha::Holds->find( $reserve_id );
158
$hold = Koha::Holds->find( $reserve_id );
159
ok( ! $hold->suspend, "Test ToggleSuspend(), no date" );
159
ok( ! $hold->suspended, "Test ToggleSuspend(), no date" );
160
160
161
ToggleSuspend( $reserve_id, '2012-01-01' );
161
ToggleSuspend( $reserve_id, '2012-01-01' );
162
$hold = Koha::Holds->find( $reserve_id );
162
$hold = Koha::Holds->find( $reserve_id );
163
is( $hold->suspend_until, '2012-01-01 00:00:00', "Test ToggleSuspend(), with date" );
163
is( $hold->suspended_until_date, '2012-01-01 00:00:00', "Test ToggleSuspend(), with date" );
164
164
165
AutoUnsuspendReserves();
165
AutoUnsuspendReserves();
166
$hold = Koha::Holds->find( $reserve_id );
166
$hold = Koha::Holds->find( $reserve_id );
167
ok( ! $hold->suspend, "Test AutoUnsuspendReserves()" );
167
ok( ! $hold->suspended, "Test AutoUnsuspendReserves()" );
168
168
169
SuspendAll(
169
SuspendAll(
170
    borrowernumber => $borrowernumber,
170
    borrowernumber => $borrowernumber,
Lines 173-180 SuspendAll( Link Here
173
    suspend_until => '2012-01-01',
173
    suspend_until => '2012-01-01',
174
);
174
);
175
$hold = Koha::Holds->find( $reserve_id );
175
$hold = Koha::Holds->find( $reserve_id );
176
is( $hold->suspend, 1, "Test SuspendAll()" );
176
is( $hold->suspended, 1, "Test SuspendAll()" );
177
is( $hold->suspend_until, '2012-01-01 00:00:00', "Test SuspendAll(), with date" );
177
is( $hold->suspended_until_date, '2012-01-01 00:00:00', "Test SuspendAll(), with date" );
178
178
179
SuspendAll(
179
SuspendAll(
180
    borrowernumber => $borrowernumber,
180
    borrowernumber => $borrowernumber,
Lines 182-189 SuspendAll( Link Here
182
    suspend => 0,
182
    suspend => 0,
183
);
183
);
184
$hold = Koha::Holds->find( $reserve_id );
184
$hold = Koha::Holds->find( $reserve_id );
185
is( $hold->suspend, 0, "Test resuming with SuspendAll()" );
185
is( $hold->suspended, 0, "Test resuming with SuspendAll()" );
186
is( $hold->suspend_until, undef, "Test resuming with SuspendAll(), should have no suspend until date" );
186
is( $hold->suspended_until_date, undef, "Test resuming with SuspendAll(), should have no suspend until date" );
187
187
188
# Add a new hold for the borrower whose hold we canceled earlier, this time at the bib level
188
# Add a new hold for the borrower whose hold we canceled earlier, this time at the bib level
189
    AddReserve(
189
    AddReserve(
Lines 196-221 is( $hold->suspend_until, undef, "Test resuming with SuspendAll(), should have n Link Here
196
196
197
$patron = Koha::Patrons->find( $borrowernumber );
197
$patron = Koha::Patrons->find( $borrowernumber );
198
$holds = $patron->holds;
198
$holds = $patron->holds;
199
my $reserveid = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $borrowernumbers[0] })->next->reserve_id;
199
my $reserveid = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $borrowernumbers[0] })->next->id;
200
ModReserveMinusPriority( $itemnumber, $reserveid );
200
ModReserveMinusPriority( $itemnumber, $reserveid );
201
$holds = $patron->holds;
201
$holds = $patron->holds;
202
is( $holds->next->itemnumber, $itemnumber, "Test ModReserveMinusPriority()" );
202
is( $holds->next->item_id, $itemnumber, "Test ModReserveMinusPriority()" );
203
203
204
$holds = $biblio->holds;
204
$holds = $biblio->holds;
205
$hold = $holds->next;
205
$hold = $holds->next;
206
AlterPriority( 'top', $hold->reserve_id, undef, 2, 1, 6 );
206
AlterPriority( 'top', $hold->id, undef, 2, 1, 6 );
207
$hold = Koha::Holds->find( $reserveid );
207
$hold = Koha::Holds->find( $reserveid );
208
is( $hold->priority, '1', "Test AlterPriority(), move to top" );
208
is( $hold->priority, '1', "Test AlterPriority(), move to top" );
209
209
210
AlterPriority( 'down', $hold->reserve_id, undef, 2, 1, 6 );
210
AlterPriority( 'down', $hold->id, undef, 2, 1, 6 );
211
$hold = Koha::Holds->find( $reserveid );
211
$hold = Koha::Holds->find( $reserveid );
212
is( $hold->priority, '2', "Test AlterPriority(), move down" );
212
is( $hold->priority, '2', "Test AlterPriority(), move down" );
213
213
214
AlterPriority( 'up', $hold->reserve_id, 1, 3, 1, 6 );
214
AlterPriority( 'up', $hold->id, 1, 3, 1, 6 );
215
$hold = Koha::Holds->find( $reserveid );
215
$hold = Koha::Holds->find( $reserveid );
216
is( $hold->priority, '1', "Test AlterPriority(), move up" );
216
is( $hold->priority, '1', "Test AlterPriority(), move up" );
217
217
218
AlterPriority( 'bottom', $hold->reserve_id, undef, 2, 1, 6 );
218
AlterPriority( 'bottom', $hold->id, undef, 2, 1, 6 );
219
$hold = Koha::Holds->find( $reserveid );
219
$hold = Koha::Holds->find( $reserveid );
220
is( $hold->priority, '6', "Test AlterPriority(), move to bottom" );
220
is( $hold->priority, '6', "Test AlterPriority(), move to bottom" );
221
221
Lines 315-321 ok( Link Here
315
        }
315
        }
316
    );
316
    );
317
317
318
    my $hhh = Koha::Holds->search({ biblionumber => $biblio->biblionumber });
318
    my $hhh = Koha::Holds->search({ biblio_id => $biblio->biblionumber });
319
    my $hold3 = Koha::Holds->find( $reserveid3 );
319
    my $hold3 = Koha::Holds->find( $reserveid3 );
320
    is( $hold3->priority, 3, "The 3rd hold should have a priority set to 3" );
320
    is( $hold3->priority, 3, "The 3rd hold should have a priority set to 3" );
321
    ModReserve({ reserve_id => $reserveid1, rank => 'del' });
321
    ModReserve({ reserve_id => $reserveid1, rank => 'del' });
Lines 330-338 ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold can be trapped for damag Link Here
330
330
331
$hold = Koha::Hold->new(
331
$hold = Koha::Hold->new(
332
    {
332
    {
333
        borrowernumber => $borrowernumbers[0],
333
        patron_id => $borrowernumbers[0],
334
        itemnumber     => $itemnumber,
334
        item_id   => $itemnumber,
335
        biblionumber   => $biblio->biblionumber,
335
        biblio_id => $biblio->biblionumber,
336
    }
336
    }
337
)->store();
337
)->store();
338
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber )->{status},
338
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber )->{status},
Lines 431-437 is(CanItemBeReserved($borrowernumbers[0], $itemnumber)->{status}, 'OK', Link Here
431
t::lib::Mocks::mock_preference( 'item-level_itypes',     1 );
431
t::lib::Mocks::mock_preference( 'item-level_itypes',     1 );
432
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
432
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
433
433
434
$dbh->do('DELETE FROM reserves');
434
$dbh->do('DELETE FROM holds');
435
$dbh->do('DELETE FROM issues');
435
$dbh->do('DELETE FROM issues');
436
$dbh->do('DELETE FROM items');
436
$dbh->do('DELETE FROM items');
437
$dbh->do('DELETE FROM biblio');
437
$dbh->do('DELETE FROM biblio');
Lines 475-481 t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' ); Link Here
475
subtest 'Test max_holds per library/patron category' => sub {
475
subtest 'Test max_holds per library/patron category' => sub {
476
    plan tests => 6;
476
    plan tests => 6;
477
477
478
    $dbh->do('DELETE FROM reserves');
478
    $dbh->do('DELETE FROM holds');
479
479
480
    $biblio = $builder->build_sample_biblio;
480
    $biblio = $builder->build_sample_biblio;
481
    $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
481
    $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
Lines 503-509 subtest 'Test max_holds per library/patron category' => sub { Link Here
503
    }
503
    }
504
504
505
    my $count =
505
    my $count =
506
      Koha::Holds->search( { borrowernumber => $borrowernumbers[0] } )->count();
506
      Koha::Holds->search( { patron_id => $borrowernumbers[0] } )->count();
507
    is( $count, 3, 'Patron now has 3 holds' );
507
    is( $count, 3, 'Patron now has 3 holds' );
508
508
509
    my $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
509
    my $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
Lines 694-700 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
694
    # Update last hold so reservedate is in the past, so 2 holds, but different day
694
    # Update last hold so reservedate is in the past, so 2 holds, but different day
695
    $hold = Koha::Holds->find($res_id);
695
    $hold = Koha::Holds->find($res_id);
696
    my $yesterday = dt_from_string() - DateTime::Duration->new( days => 1 );
696
    my $yesterday = dt_from_string() - DateTime::Duration->new( days => 1 );
697
    $hold->reservedate($yesterday)->store;
697
    $hold->placing_date($yesterday)->store;
698
698
699
    is_deeply(
699
    is_deeply(
700
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
700
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
(-)a/t/db_dependent/Holds/DisallowHoldIfItemsAvailable.t (-4 / +5 lines)
Lines 259-269 my $itemtype2 = $builder->build({ Link Here
259
})->{itemtype};
259
})->{itemtype};
260
my $item3 = $builder->build_sample_item({ itype => $itemtype2 });
260
my $item3 = $builder->build_sample_item({ itype => $itemtype2 });
261
261
262
my $hold = $builder->build({
262
my $hold = $builder->build_object({
263
    source => 'Reserve',
263
    class => 'Koha::Holds',
264
    value =>{
264
    value =>{
265
        itemnumber => $item3->itemnumber,
265
        item_id   => $item3->itemnumber,
266
        found => 'T'
266
        status    => 'in_transit',
267
        completed => 0
267
    }
268
    }
268
});
269
});
269
270
(-)a/t/db_dependent/Holds/LocalHoldsPriority.t (-5 / +5 lines)
Lines 85-110 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[1], "Received expected results with HomeLibrary/holdingbranch" );
105
ok( $reserve->{patron_id} eq $borrowernumbers[1], "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[2], "Received expected results with HomeLibrary/homebranch" );
110
ok( $reserve->{patron_id} eq $borrowernumbers[2], "Received expected results with HomeLibrary/homebranch" );
(-)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 119-134 $reserve1_reservedate->subtract(days => 20); Link Here
119
my $reserve1_expirationdate = $today->clone;
119
my $reserve1_expirationdate = $today->clone;
120
$reserve1_expirationdate->add(days => 6);
120
$reserve1_expirationdate->add(days => 6);
121
121
122
my $reserve1 = $builder->build({
122
my $r = $builder->build_object({
123
    source => 'Reserve',
123
    class => 'Koha::Holds',
124
    value => {
124
    value => {
125
        borrowernumber => $patron1->{borrowernumber},
125
        patron_id => $patron1->{borrowernumber},
126
        reservedate => $reserve1_reservedate->ymd,
126
        placing_date => $reserve1_reservedate->ymd,
127
        expirationdate => undef,
127
        expiration_date => undef,
128
        biblionumber => $biblio->{biblionumber},
128
        biblio_id => $biblio->{biblionumber},
129
        branchcode => 'LIB1',
129
        pickup_library_id => 'LIB1',
130
        priority => 1,
130
        priority => 1,
131
        found => '',
131
        status => 'placed',
132
        completed => 0
132
    },
133
    },
133
});
134
});
134
135
Lines 136-179 t::lib::Mocks::mock_preference('ExpireReservesMaxPickUpDelay', 1); Link Here
136
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 6);
137
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 6);
137
138
138
ModReserveAffect( $item1->{itemnumber}, $patron1->{borrowernumber});
139
ModReserveAffect( $item1->{itemnumber}, $patron1->{borrowernumber});
139
my $r = Koha::Holds->find($reserve1->{reserve_id});
140
$r->discard_changes;
140
141
141
is($r->waitingdate, $today->ymd, 'Waiting date should be set to today' );
142
is($r->waiting_date, $today->ymd, 'Waiting date should be set to today' );
142
is($r->expirationdate, $reserve1_expirationdate->ymd, 'Expiration date should be set to today + 6' );
143
is($r->expiration_date, $reserve1_expirationdate->ymd, 'Expiration date should be set to today + 6' );
143
is($r->found, 'W', 'Reserve status is now "waiting"' );
144
is($r->status, 'waiting', 'Reserve status is now "waiting"' );
144
is($r->priority, 0, 'Priority should be 0' );
145
is($r->priority, 0, 'Priority should be 0' );
145
is($r->itemnumber, $item1->{itemnumber}, 'Item number should be set correctly' );
146
is($r->item_id, $item1->{itemnumber}, 'Item number should be set correctly' );
146
147
147
my $reserve2 = $builder->build({
148
my $r2 = $builder->build_object({
148
    source => 'Reserve',
149
    class => 'Koha::Holds',
149
    value => {
150
    value => {
150
        borrowernumber => $patron2->{borrowernumber},
151
        patron_id => $patron2->{borrowernumber},
151
        reservedate => $reserve1_reservedate->ymd,
152
        placing_date => $reserve1_reservedate->ymd,
152
        expirationdate => undef,
153
        expiration_date => undef,
153
        biblionumber => $biblio2->{biblionumber},
154
        biblio_id => $biblio2->{biblionumber},
154
        branchcode => 'LIB1',
155
        pickup_library_id => 'LIB1',
155
        priority => 1,
156
        priority => 1,
156
        found => '',
157
        status => 'placed',
158
        completed => 0
157
    },
159
    },
158
});
160
});
159
161
160
ModReserveAffect( $item2->{itemnumber}, $patron2->{borrowernumber}, 1);
162
ModReserveAffect( $item2->{itemnumber}, $patron2->{borrowernumber}, 1);
161
my $r2 = Koha::Holds->find($reserve2->{reserve_id});
163
$r2->discard_changes;
162
164
163
is($r2->found, 'T', '2nd reserve - Reserve status is now "To transfer"' );
165
is($r2->status, 'in_transit', '2nd reserve - Reserve status is now "To transfer"' );
164
is($r2->priority, 0, '2nd reserve - Priority should be 0' );
166
is($r2->priority, 0, '2nd reserve - Priority should be 0' );
165
is($r2->itemnumber, $item2->{itemnumber}, '2nd reserve - Item number should be set correctly' );
167
is($r2->item_id, $item2->{itemnumber}, '2nd reserve - Item number should be set correctly' );
166
168
167
my $reserve3 = $builder->build({
169
my $r3 = $builder->build_object({
168
    source => 'Reserve',
170
    class => 'Koha::Holds',
169
    value => {
171
    value => {
170
        borrowernumber => $patron2->{borrowernumber},
172
        patron_id => $patron2->{borrowernumber},
171
        reservedate => $reserve1_reservedate->ymd,
173
        placing_date => $reserve1_reservedate->ymd,
172
        expirationdate => undef,
174
        expiration_date => undef,
173
        biblionumber => $biblio3->{biblionumber},
175
        biblio_id => $biblio3->{biblionumber},
174
        branchcode => 'LIB1',
176
        pickup_library_id => 'LIB1',
175
        priority => 1,
177
        priority => 1,
176
        found => '',
178
        status => 'placed',
179
        completed => 0
177
    },
180
    },
178
});
181
});
179
182
Lines 216-244 ModReserveAffect( $item3->{itemnumber}, $patron2->{borrowernumber}); Link Here
216
my $expected_expiration = $today->clone;
219
my $expected_expiration = $today->clone;
217
$expected_expiration->add(days => 8);
220
$expected_expiration->add(days => 8);
218
221
219
my $r3 = Koha::Holds->find($reserve3->{reserve_id});
222
$r3->discard_changes;
220
is($r3->expirationdate, $expected_expiration->ymd, 'Expiration date should be set to today + 7' );
223
is($r3->expiration_date, $expected_expiration->ymd, 'Expiration date should be set to today + 7' );
221
224
222
my $reserve4_reservedate = $today->clone;
225
my $reserve4_reservedate = $today->clone;
223
my $requested_expiredate = $today->clone()->add(days => 6);
226
my $requested_expiredate = $today->clone()->add(days => 6);
224
227
225
my $reserve4 = $builder->build({
228
my $r4 = $builder->build_object({
226
    source => 'Reserve',
229
    class => 'Koha::Holds',
227
    value => {
230
    value => {
228
        borrowernumber => $patron2->{borrowernumber},
231
        patron_id => $patron2->{borrowernumber},
229
        reservedate => $reserve4_reservedate->ymd,
232
        placing_date => $reserve4_reservedate->ymd,
230
        expirationdate => $requested_expiredate->ymd,
233
        expiration_date => $requested_expiredate->ymd,
231
        biblionumber => $biblio4->{biblionumber},
234
        biblio_id => $biblio4->{biblionumber},
232
        branchcode => 'LIB1',
235
        pickup_library_id => 'LIB1',
233
        priority => 1,
236
        priority => 1,
234
        found => '',
237
        status => 'placed',
238
        completed => 0
235
    },
239
    },
236
});
240
});
237
241
238
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 10);
242
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 10);
239
ModReserveAffect( $item4->{itemnumber}, $patron2->{borrowernumber}, 0, $reserve4->{reserve_id});
243
ModReserveAffect( $item4->{itemnumber}, $patron2->{borrowernumber}, 0, $r4->id );
240
244
241
my $r4 = Koha::Holds->find($reserve4->{reserve_id});
245
$r4->discard_changes;
242
is($r4->expirationdate, $requested_expiredate->ymd, 'Requested expiration date should be kept' );
246
is($r4->expiration_date, $requested_expiredate->ymd, 'Requested expiration date should be kept' );
243
247
244
$schema->storage->txn_rollback;
248
$schema->storage->txn_rollback;
(-)a/t/db_dependent/HoldsQueue.t (-18 / +18 lines)
Lines 110-116 foreach ( $borrower_branchcode, $least_cost_branch_code, @other_branches ) { Link Here
110
}
110
}
111
111
112
# Remove existing reserves, makes debugging easier
112
# Remove existing reserves, makes debugging easier
113
$dbh->do("DELETE FROM reserves");
113
$dbh->do("DELETE FROM holds");
114
my $bibitems = undef;
114
my $bibitems = undef;
115
my $priority = 1;
115
my $priority = 1;
116
# Make a reserve
116
# Make a reserve
Lines 123-129 AddReserve( Link Here
123
    }
123
    }
124
);
124
);
125
#                           $resdate, $expdate, $notes, $title, $checkitem, $found
125
#                           $resdate, $expdate, $notes, $title, $checkitem, $found
126
$dbh->do("UPDATE reserves SET reservedate = DATE_SUB( reservedate, INTERVAL 1 DAY )");
126
$dbh->do("UPDATE holds SET placing_date = DATE_SUB( placing_date, INTERVAL 1 DAY )");
127
127
128
# Tests
128
# Tests
129
my $use_cost_matrix_sth = $dbh->prepare("UPDATE systempreferences SET value = ? WHERE variable = 'UseTransportCostMatrix'");
129
my $use_cost_matrix_sth = $dbh->prepare("UPDATE systempreferences SET value = ? WHERE variable = 'UseTransportCostMatrix'");
Lines 281-294 $items_insert_sth->execute( $barcode + 0, $branchcodes[0], $branchcodes[0] ); Link Here
281
$items_insert_sth->execute( $barcode + 1, $branchcodes[1], $branchcodes[1] );
281
$items_insert_sth->execute( $barcode + 1, $branchcodes[1], $branchcodes[1] );
282
$items_insert_sth->execute( $barcode + 2, $branchcodes[1], $branchcodes[1] );
282
$items_insert_sth->execute( $barcode + 2, $branchcodes[1], $branchcodes[1] );
283
283
284
$dbh->do("DELETE FROM reserves");
284
$dbh->do("DELETE FROM holds");
285
my $sth = $dbh->prepare(q{
285
my $sth = $dbh->prepare(q{
286
    INSERT INTO reserves ( 
286
    INSERT INTO holds (
287
        borrowernumber,
287
        patron_id,
288
        biblionumber,
288
        biblio_id,
289
        branchcode,
289
        pickup_library_id,
290
        priority,
290
        priority,
291
        reservedate
291
        placing_date
292
    ) VALUES ( ?,?,?,?, CURRENT_DATE() )
292
    ) VALUES ( ?,?,?,?, CURRENT_DATE() )
293
});
293
});
294
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
294
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
Lines 376-382 $dbh->do("DELETE FROM issues"); Link Here
376
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
376
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
377
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
377
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
378
C4::Context->clear_syspref_cache();
378
C4::Context->clear_syspref_cache();
379
$dbh->do("DELETE FROM reserves");
379
$dbh->do("DELETE FROM holds");
380
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
380
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
381
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
381
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
382
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
382
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
Lines 394-400 t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary') Link Here
394
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
394
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
395
t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '1' );
395
t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '1' );
396
C4::Context->clear_syspref_cache();
396
C4::Context->clear_syspref_cache();
397
$dbh->do("DELETE FROM reserves");
397
$dbh->do("DELETE FROM holds");
398
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
398
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
399
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[1], 2 );
399
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[1], 2 );
400
400
Lines 436-442 t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '0' ); Link Here
436
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
436
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
437
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
437
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
438
C4::Context->clear_syspref_cache();
438
C4::Context->clear_syspref_cache();
439
$dbh->do("DELETE FROM reserves");
439
$dbh->do("DELETE FROM holds");
440
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
440
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
441
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
441
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
442
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
442
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
Lines 453-459 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue givi Link Here
453
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
453
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
454
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
454
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
455
C4::Context->clear_syspref_cache();
455
C4::Context->clear_syspref_cache();
456
$dbh->do("DELETE FROM reserves");
456
$dbh->do("DELETE FROM holds");
457
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
457
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
458
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
458
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
459
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
459
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
Lines 470-476 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue givi Link Here
470
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
470
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
471
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
471
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
472
C4::Context->clear_syspref_cache();
472
C4::Context->clear_syspref_cache();
473
$dbh->do("DELETE FROM reserves");
473
$dbh->do("DELETE FROM holds");
474
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
474
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
475
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
475
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
476
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
476
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
Lines 493-499 $borrowernumber = $borrower3->{borrowernumber}; Link Here
493
my $library_A = $library1->{branchcode};
493
my $library_A = $library1->{branchcode};
494
my $library_B = $library2->{branchcode};
494
my $library_B = $library2->{branchcode};
495
my $library_C = $borrower3->{branchcode};
495
my $library_C = $borrower3->{branchcode};
496
$dbh->do("DELETE FROM reserves");
496
$dbh->do("DELETE FROM holds");
497
$dbh->do("DELETE FROM issues");
497
$dbh->do("DELETE FROM issues");
498
$dbh->do("DELETE FROM items");
498
$dbh->do("DELETE FROM items");
499
$dbh->do("DELETE FROM biblio");
499
$dbh->do("DELETE FROM biblio");
Lines 558-564 $itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } Link Here
558
$borrowernumber = $borrower2->{borrowernumber};
558
$borrowernumber = $borrower2->{borrowernumber};
559
$library_A = $library1->{branchcode};
559
$library_A = $library1->{branchcode};
560
$library_B = $library2->{branchcode};
560
$library_B = $library2->{branchcode};
561
$dbh->do("DELETE FROM reserves");
561
$dbh->do("DELETE FROM holds");
562
$dbh->do("DELETE FROM issues");
562
$dbh->do("DELETE FROM issues");
563
$dbh->do("DELETE FROM items");
563
$dbh->do("DELETE FROM items");
564
$dbh->do("DELETE FROM biblio");
564
$dbh->do("DELETE FROM biblio");
Lines 611-617 $borrowernumber = $borrower3->{borrowernumber}; Link Here
611
$library_A = $library1->{branchcode};
611
$library_A = $library1->{branchcode};
612
$library_B = $library2->{branchcode};
612
$library_B = $library2->{branchcode};
613
$library_C = $library3->{branchcode};
613
$library_C = $library3->{branchcode};
614
$dbh->do("DELETE FROM reserves");
614
$dbh->do("DELETE FROM holds");
615
$dbh->do("DELETE FROM issues");
615
$dbh->do("DELETE FROM issues");
616
$dbh->do("DELETE FROM items");
616
$dbh->do("DELETE FROM items");
617
$dbh->do("DELETE FROM biblio");
617
$dbh->do("DELETE FROM biblio");
Lines 819-825 my $wrong_itemtype = $builder->build({ source => 'Itemtype', value => { notforlo Link Here
819
my $right_itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
819
my $right_itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
820
$borrowernumber = $borrower3->{borrowernumber};
820
$borrowernumber = $borrower3->{borrowernumber};
821
my $branchcode = $library1->{branchcode};
821
my $branchcode = $library1->{branchcode};
822
$dbh->do("DELETE FROM reserves");
822
$dbh->do("DELETE FROM holds");
823
$dbh->do("DELETE FROM issues");
823
$dbh->do("DELETE FROM issues");
824
$dbh->do("DELETE FROM items");
824
$dbh->do("DELETE FROM items");
825
$dbh->do("DELETE FROM biblio");
825
$dbh->do("DELETE FROM biblio");
Lines 1103-1109 subtest "Test Local Holds Priority - Ensure no duplicate requests in holds queue Link Here
1103
1103
1104
    $dbh->do("DELETE FROM tmp_holdsqueue");
1104
    $dbh->do("DELETE FROM tmp_holdsqueue");
1105
    $dbh->do("DELETE FROM hold_fill_targets");
1105
    $dbh->do("DELETE FROM hold_fill_targets");
1106
    $dbh->do("DELETE FROM reserves");
1106
    $dbh->do("DELETE FROM holds");
1107
    $dbh->do("DELETE FROM circulation_rules");
1107
    $dbh->do("DELETE FROM circulation_rules");
1108
    Koha::Biblios->delete();
1108
    Koha::Biblios->delete();
1109
1109
(-)a/t/db_dependent/ILSDI_Services.t (-12 / +13 lines)
Lines 340-350 subtest 'Holds test' => sub { Link Here
340
    $item_o->damaged(0)->store;
340
    $item_o->damaged(0)->store;
341
341
342
    my $hold = $builder->build({
342
    my $hold = $builder->build({
343
        source => 'Reserve',
343
        source => 'Hold',
344
        value => {
344
        value => {
345
            borrowernumber => $patron->{borrowernumber},
345
            patron_id => $patron->{borrowernumber},
346
            biblionumber => $biblio->{biblionumber},
346
            biblio_id => $biblio->{biblionumber},
347
            itemnumber => $item->{itemnumber}
347
            item_id => $item->{itemnumber},
348
            completed => 0
348
        }
349
        }
349
    });
350
    });
350
351
Lines 586-604 subtest 'Holds test with start_date and end_date' => sub { Link Here
586
587
587
    my $reply = C4::ILSDI::Services::HoldItem( $query );
588
    my $reply = C4::ILSDI::Services::HoldItem( $query );
588
    is ($reply->{pickup_location}, $pickup_library->branchname, "Item hold with date parameters was placed");
589
    is ($reply->{pickup_location}, $pickup_library->branchname, "Item hold with date parameters was placed");
589
    my $hold = Koha::Holds->search({ biblionumber => $item->biblionumber})->next();
590
    my $hold = Koha::Holds->search({ biblio_id => $item->biblionumber})->next();
590
    is( $hold->biblionumber, $item->biblionumber, "correct biblionumber");
591
    is( $hold->biblio_id, $item->biblionumber, "correct biblionumber");
591
    is( $hold->reservedate, '2020-03-20', "Item hold has correct start date" );
592
    is( $hold->placing_date, '2020-03-20', "Item hold has correct start date" );
592
    is( $hold->expirationdate, '2020-04-22', "Item hold has correct end date" );
593
    is( $hold->expiration_date, '2020-04-22', "Item hold has correct end date" );
593
594
594
    $hold->delete();
595
    $hold->delete();
595
596
596
    $reply = C4::ILSDI::Services::HoldTitle( $query );
597
    $reply = C4::ILSDI::Services::HoldTitle( $query );
597
    is ($reply->{pickup_location}, $pickup_library->branchname, "Record hold with date parameters was placed");
598
    is ($reply->{pickup_location}, $pickup_library->branchname, "Record hold with date parameters was placed");
598
    $hold = Koha::Holds->search({ biblionumber => $item->biblionumber})->next();
599
    $hold = Koha::Holds->search({ biblio_id => $item->biblionumber})->next();
599
    is( $hold->biblionumber, $item->biblionumber, "correct biblionumber");
600
    is( $hold->biblio_id, $item->biblionumber, "correct biblionumber");
600
    is( $hold->reservedate, '2020-03-20', "Record hold has correct start date" );
601
    is( $hold->placing_date, '2020-03-20', "Record hold has correct start date" );
601
    is( $hold->expirationdate, '2020-04-22', "Record hold has correct end date" );
602
    is( $hold->expiration_date, '2020-04-22', "Record hold has correct end date" );
602
603
603
    $schema->storage->txn_rollback;
604
    $schema->storage->txn_rollback;
604
};
605
};
(-)a/t/db_dependent/Items/GetItemsForInventory.t (-1 / +1 lines)
Lines 107-113 subtest 'Skip items with waiting holds' => sub { Link Here
107
            biblionumber   => $item_1->biblionumber,
107
            biblionumber   => $item_1->biblionumber,
108
            priority       => 1,
108
            priority       => 1,
109
            itemnumber     => $item_1->itemnumber,
109
            itemnumber     => $item_1->itemnumber,
110
            found          => 'W'
110
            found          => 'waiting'
111
        }
111
        }
112
    );
112
    );
113
    C4::Reserves::AddReserve(
113
    C4::Reserves::AddReserve(
(-)a/t/db_dependent/Items/MoveItemFromBiblio.t (-12 / +12 lines)
Lines 57-74 my $item3 = $builder->build( Link Here
57
);
57
);
58
58
59
my $bib_level_hold_not_to_move = $builder->build(
59
my $bib_level_hold_not_to_move = $builder->build(
60
    {   source => 'Reserve',
60
    {   source => 'Hold',
61
        value  => { biblionumber => $from_biblio->{biblionumber}, },
61
        value  => { biblio_id => $from_biblio->{biblionumber}, completed => 0},
62
    }
62
    }
63
);
63
);
64
my $item_level_hold_not_to_move = $builder->build(
64
my $item_level_hold_not_to_move = $builder->build(
65
    {   source => 'Reserve',
65
    {   source => 'Hold',
66
        value  => { biblionumber => $from_biblio->{biblionumber}, itemnumber => $item1->{itemnumber} },
66
        value  => { biblio_id => $from_biblio->{biblionumber}, item_id => $item1->{itemnumber}, completed => 0 },
67
    }
67
    }
68
);
68
);
69
my $item_level_hold_to_move = $builder->build(
69
my $item_level_hold_to_move = $builder->build(
70
    {   source => 'Reserve',
70
    {   source => 'Hold',
71
        value  => { biblionumber => $from_biblio->{biblionumber}, itemnumber => $item2->{itemnumber} },
71
        value  => { biblio_id => $from_biblio->{biblionumber}, item_id => $item2->{itemnumber}, completed => 0 },
72
    }
72
    }
73
);
73
);
74
74
Lines 87-99 is( $get_item2->biblionumber, $to_biblio->{biblionumber}, 'The item2 should have Link Here
87
my $get_item3 = Koha::Items->find( $item3->{itemnumber} );
87
my $get_item3 = Koha::Items->find( $item3->{itemnumber} );
88
is( $get_item3->biblionumber, $to_biblio->{biblionumber}, 'The item3 should not have been moved' );
88
is( $get_item3->biblionumber, $to_biblio->{biblionumber}, 'The item3 should not have been moved' );
89
89
90
my $get_bib_level_hold    = Koha::Holds->find( $bib_level_hold_not_to_move->{reserve_id} );
90
my $get_bib_level_hold    = Koha::Holds->find( $bib_level_hold_not_to_move->{id} );
91
my $get_item_level_hold_1 = Koha::Holds->find( $item_level_hold_not_to_move->{reserve_id} );
91
my $get_item_level_hold_1 = Koha::Holds->find( $item_level_hold_not_to_move->{id} );
92
my $get_item_level_hold_2 = Koha::Holds->find( $item_level_hold_to_move->{reserve_id} );
92
my $get_item_level_hold_2 = Koha::Holds->find( $item_level_hold_to_move->{id} );
93
93
94
is( $get_bib_level_hold->biblionumber,    $from_biblio->{biblionumber}, 'MoveItemFromBiblio should not have moved the biblio-level hold' );
94
is( $get_bib_level_hold->biblio_id,    $from_biblio->{biblionumber}, 'MoveItemFromBiblio should not have moved the biblio-level hold' );
95
is( $get_item_level_hold_1->biblionumber, $from_biblio->{biblionumber}, 'MoveItemFromBiblio should not have moved the item-level hold placed on item 1' );
95
is( $get_item_level_hold_1->biblio_id, $from_biblio->{biblionumber}, 'MoveItemFromBiblio should not have moved the item-level hold placed on item 1' );
96
is( $get_item_level_hold_2->biblionumber, $to_biblio->{biblionumber},   'MoveItemFromBiblio should have moved the item-level hold placed on item 2' );
96
is( $get_item_level_hold_2->biblio_id, $to_biblio->{biblionumber},   'MoveItemFromBiblio should have moved the item-level hold placed on item 2' );
97
97
98
$schema->storage->txn_rollback;
98
$schema->storage->txn_rollback;
99
99
(-)a/t/db_dependent/Koha/Biblios.t (-9 / +9 lines)
Lines 74-80 subtest 'holds + current_holds' => sub { Link Here
74
    my $holds = $biblio->holds;
74
    my $holds = $biblio->holds;
75
    is( ref($holds), 'Koha::Holds', '->holds should return a Koha::Holds object' );
75
    is( ref($holds), 'Koha::Holds', '->holds should return a Koha::Holds object' );
76
    is( $holds->count, 1, '->holds should only return 1 hold' );
76
    is( $holds->count, 1, '->holds should only return 1 hold' );
77
    is( $holds->next->borrowernumber, $patron->borrowernumber, '->holds should return the correct hold' );
77
    is( $holds->next->patron_id, $patron->borrowernumber, '->holds should return the correct hold' );
78
    $holds->delete;
78
    $holds->delete;
79
79
80
    # Add a hold in the future
80
    # Add a hold in the future
Lines 103-125 subtest 'waiting_or_in_transit' => sub { Link Here
103
            biblionumber => $biblio->{biblionumber}
103
            biblionumber => $biblio->{biblionumber}
104
        }
104
        }
105
    });
105
    });
106
    my $reserve = $builder->build({
106
    my $reserve = $builder->build_object({
107
        source => 'Reserve',
107
        class => 'Koha::Holds',
108
        value => {
108
        value => {
109
            biblionumber => $biblio->{biblionumber},
109
            biblio_id => $biblio->{biblionumber},
110
            found => undef
110
            status => 'placed',
111
            completed => 0
111
        }
112
        }
112
    });
113
    });
113
114
114
    $reserve = Koha::Holds->find($reserve->{reserve_id});
115
    $biblio = Koha::Biblios->find($biblio->{biblionumber});
115
    $biblio = Koha::Biblios->find($biblio->{biblionumber});
116
116
117
    is($biblio->has_items_waiting_or_intransit, 0, 'Item is neither waiting nor in transit');
117
    is($biblio->has_items_waiting_or_intransit, 0, 'Item is neither waiting nor in transit');
118
118
119
    $reserve->found('W')->store;
119
    $reserve->status('waiting')->store;
120
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is waiting');
120
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is waiting');
121
121
122
    $reserve->found('T')->store;
122
    $reserve->status('in_transit')->store;
123
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is in transit');
123
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is in transit');
124
124
125
    my $transfer = $builder->build({
125
    my $transfer = $builder->build({
Lines 130-136 subtest 'waiting_or_in_transit' => sub { Link Here
130
        }
130
        }
131
    });
131
    });
132
    my $t = Koha::Database->new()->schema()->resultset( 'Branchtransfer' )->find($transfer->{branchtransfer_id});
132
    my $t = Koha::Database->new()->schema()->resultset( 'Branchtransfer' )->find($transfer->{branchtransfer_id});
133
    $reserve->found(undef)->store;
133
    $reserve->status('placed')->store;
134
    is($biblio->has_items_waiting_or_intransit, 1, 'Item has transfer');
134
    is($biblio->has_items_waiting_or_intransit, 1, 'Item has transfer');
135
};
135
};
136
136
(-)a/t/db_dependent/Koha/Club/Hold.t (-1 / +1 lines)
Lines 80-86 subtest 'add' => sub { Link Here
80
80
81
    my $hold = Koha::Holds->find($patron_hold->hold_id);
81
    my $hold = Koha::Holds->find($patron_hold->hold_id);
82
82
83
    is($patron_hold->patron_id, $hold->borrowernumber, 'Patron must be the same');
83
    is($patron_hold->patron_id, $hold->patron_id, 'Patron must be the same');
84
84
85
    $schema->storage->txn_rollback;
85
    $schema->storage->txn_rollback;
86
}
86
}
(-)a/t/db_dependent/Koha/Holds.t (-56 / +19 lines)
Lines 59-65 subtest 'DB constraints' => sub { Link Here
59
};
59
};
60
60
61
subtest 'cancel' => sub {
61
subtest 'cancel' => sub {
62
    plan tests => 12;
62
63
    plan tests => 13;
64
63
    my $biblioitem = $builder->build_object( { class => 'Koha::Biblioitems' } );
65
    my $biblioitem = $builder->build_object( { class => 'Koha::Biblioitems' } );
64
    my $library    = $builder->build_object( { class => 'Koha::Libraries' } );
66
    my $library    = $builder->build_object( { class => 'Koha::Libraries' } );
65
    my $itemtype   = $builder->build_object( { class => 'Koha::ItemTypes', value => { rentalcharge => 0 } } );
67
    my $itemtype   = $builder->build_object( { class => 'Koha::ItemTypes', value => { rentalcharge => 0 } } );
Lines 100-106 subtest 'cancel' => sub { Link Here
100
102
101
    # There are 3 holds on this records
103
    # There are 3 holds on this records
102
    my $nb_of_holds =
104
    my $nb_of_holds =
103
      Koha::Holds->search( { biblionumber => $item->biblionumber } )->count;
105
      Koha::Holds->search( { biblio_id => $item->biblionumber } )->count;
104
    is( $nb_of_holds, 3,
106
    is( $nb_of_holds, 3,
105
        'There should have 3 holds placed on this biblio record' );
107
        'There should have 3 holds placed on this biblio record' );
106
    my $first_hold  = $holds[0];
108
    my $first_hold  = $holds[0];
Lines 114-127 subtest 'cancel' => sub { Link Here
114
    # Remove the second hold, only 2 should still exist in DB and priorities must have been updated
116
    # Remove the second hold, only 2 should still exist in DB and priorities must have been updated
115
    my $is_cancelled = $second_hold->cancel;
117
    my $is_cancelled = $second_hold->cancel;
116
    is( ref($is_cancelled), 'Koha::Hold',
118
    is( ref($is_cancelled), 'Koha::Hold',
117
        'Koha::Hold->cancel should return the Koha::Hold (?)' )
119
        'Koha::Hold->cancel should return the Koha::Hold (?)' );
120
    $second_hold->discard_changes;
118
      ;    # This is can reconsidered
121
      ;    # This is can reconsidered
119
    is( $second_hold->in_storage, 0,
122
    is( $second_hold->in_storage, 1,
120
        'The hold has been cancelled and does not longer exist in DB' );
123
        'The hold has been cancelled and still exists on the DB' );
124
    is( $second_hold->status, 'cancelled', "Status is 'cancelled'" );
125
    ok( $second_hold->completed, 'Hold marked as comleted' );
126
121
    $nb_of_holds =
127
    $nb_of_holds =
122
      Koha::Holds->search( { biblionumber => $item->biblionumber } )->count;
128
      Koha::Holds->search( { biblio_id => $item->biblionumber, completed => 0 } )->count;
123
    is( $nb_of_holds, 2,
129
    is( $nb_of_holds, 2,
124
        'a hold has been cancelled, there should have only 2 holds placed on this biblio record'
130
        'a hold has been cancelled, there should have only 2 (not completed) holds placed on this biblio record'
125
    );
131
    );
126
132
127
    # discard_changes to refetch
133
    # discard_changes to refetch
Lines 164-170 subtest 'cancel' => sub { Link Here
164
    };
170
    };
165
171
166
    subtest 'waiting hold' => sub {
172
    subtest 'waiting hold' => sub {
167
        plan tests => 1;
173
        plan tests => 2;
168
        my $patron = $builder->build_object({ class => 'Koha::Patrons' });
174
        my $patron = $builder->build_object({ class => 'Koha::Patrons' });
169
        my $reserve_id = C4::Reserves::AddReserve(
175
        my $reserve_id = C4::Reserves::AddReserve(
170
            {
176
            {
Lines 174-185 subtest 'cancel' => sub { Link Here
174
                priority       => 1,
180
                priority       => 1,
175
                title          => "title for fee",
181
                title          => "title for fee",
176
                itemnumber     => $item->itemnumber,
182
                itemnumber     => $item->itemnumber,
177
                found          => 'W',
183
                status         => 'W',
178
            }
184
            }
179
        );
185
        );
180
        Koha::Holds->find( $reserve_id )->cancel;
186
        my $hold = Koha::Holds->find( $reserve_id );
181
        my $hold_old = Koha::Old::Holds->find( $reserve_id );
187
        $hold->cancel->discard_changes;
182
        is( $hold_old->found, 'W', 'The found column should have been kept and a hold is cancelled' );
188
        is( $hold->status, 'cancelled', 'The found column should have been kept and a hold is cancelled' );
189
        ok( $hold->completed, 'Hold is marked as completed' );
183
    };
190
    };
184
191
185
    subtest 'HoldsLog' => sub {
192
    subtest 'HoldsLog' => sub {
Lines 206-255 subtest 'cancel' => sub { Link Here
206
        $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'HOLDS', action => 'CANCEL', object => $reserve_id } )->count;
213
        $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'HOLDS', action => 'CANCEL', object => $reserve_id } )->count;
207
        is( $number_of_logs, 1, 'With HoldsLog, Koha::Hold->cancel should have logged' );
214
        is( $number_of_logs, 1, 'With HoldsLog, Koha::Hold->cancel should have logged' );
208
    };
215
    };
209
210
    subtest 'rollback' => sub {
211
        plan tests => 3;
212
        my $patron_category = $builder->build_object(
213
            {
214
                class => 'Koha::Patron::Categories',
215
                value => { reservefee => 0 }
216
            }
217
        );
218
        my $patron = $builder->build_object(
219
            {
220
                class => 'Koha::Patrons',
221
                value => { categorycode => $patron_category->categorycode }
222
            }
223
        );
224
        my $hold_info = {
225
            branchcode     => $library->branchcode,
226
            borrowernumber => $patron->borrowernumber,
227
            biblionumber   => $item->biblionumber,
228
            priority       => 1,
229
            title          => "title for fee",
230
            itemnumber     => $item->itemnumber,
231
        };
232
233
        t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelayCharge',42 );
234
        my $reserve_id = C4::Reserves::AddReserve($hold_info);
235
        my $hold       = Koha::Holds->find($reserve_id);
236
237
        # Add a row with the same id to make the cancel fails
238
        Koha::Old::Hold->new( $hold->unblessed )->store;
239
240
        warning_like {
241
            eval { $hold->cancel( { charge_cancel_fee => 1 } ) };
242
        }
243
        qr{.*DBD::mysql::st execute failed: Duplicate entry.*},
244
          'DBD should have raised an error about dup primary key';
245
246
        $hold = Koha::Holds->find($reserve_id);
247
        is( ref($hold), 'Koha::Hold', 'The hold should not have been deleted' );
248
        is( $patron->account->balance, 0,
249
'If the hold has not been cancelled, the patron should not have been charged'
250
        );
251
    };
252
253
};
216
};
254
217
255
$schema->storage->txn_rollback;
218
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Koha/Items.t (-6 / +6 lines)
Lines 109-122 subtest 'holds' => sub { Link Here
109
    });
109
    });
110
    $nb_of_items++;
110
    $nb_of_items++;
111
    is($item->holds->count, 0, "Nothing returned if no holds");
111
    is($item->holds->count, 0, "Nothing returned if no holds");
112
    my $hold1 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'T' }});
112
    my $hold1 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'in_transit', completed => 0 }});
113
    my $hold2 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'W' }});
113
    my $hold2 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'waiting', completed => 0 }});
114
    my $hold3 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'W' }});
114
    my $hold3 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'waiting', completed => 0 }});
115
115
116
    is($item->holds()->count,3,"Three holds found");
116
    is($item->holds()->count,3,"Three holds found");
117
    is($item->holds({found => 'W'})->count,2,"Two waiting holds found");
117
    is($item->holds({status => 'waiting'})->count,2,"Two waiting holds found");
118
    is_deeply($item->holds({found => 'T'})->next->unblessed,$hold1,"Found transit holds matches the hold");
118
    is_deeply($item->holds({status => 'in_transit'})->next->unblessed,$hold1,"Found transit holds matches the hold");
119
    is($item->holds({found => undef})->count, 0,"Nothing returned if no matching holds");
119
    is($item->holds({status => 'placed'})->count, 0,"Nothing returned if no matching holds");
120
};
120
};
121
121
122
subtest 'biblio' => sub {
122
subtest 'biblio' => sub {
(-)a/t/db_dependent/Koha/Object.t (-2 / +2 lines)
Lines 264-270 subtest "to_api() tests" => sub { Link Here
264
264
265
    my $biblio = $builder->build_sample_biblio();
265
    my $biblio = $builder->build_sample_biblio();
266
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
266
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
267
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { itemnumber => $item->itemnumber } });
267
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { item_id => $item->itemnumber, completed => 0 } });
268
268
269
    my $embeds = { 'items' => {} };
269
    my $embeds = { 'items' => {} };
270
270
Lines 289-295 subtest "to_api() tests" => sub { Link Here
289
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
289
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
290
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
290
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
291
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
291
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
292
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->reserve_id, 'Hold matches');
292
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->id, 'Hold matches');
293
    is_deeply($biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root');
293
    is_deeply($biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root');
294
294
295
    my $hold_api = $hold->to_api(
295
    my $hold_api = $hold->to_api(
(-)a/t/db_dependent/Koha/Objects.t (-3 / +3 lines)
Lines 310-316 subtest "to_api() tests" => sub { Link Here
310
    my $hold_1   = $builder->build_object(
310
    my $hold_1   = $builder->build_object(
311
        {
311
        {
312
            class => 'Koha::Holds',
312
            class => 'Koha::Holds',
313
            value => { itemnumber => $item_1->itemnumber }
313
            value => { item_id => $item_1->itemnumber, completed => 0 }
314
        }
314
        }
315
    );
315
    );
316
316
Lines 319-325 subtest "to_api() tests" => sub { Link Here
319
    my $hold_2   = $builder->build_object(
319
    my $hold_2   = $builder->build_object(
320
        {
320
        {
321
            class => 'Koha::Holds',
321
            class => 'Koha::Holds',
322
            value => { itemnumber => $item_2->itemnumber }
322
            value => { item_id => $item_2->itemnumber, completed => 0 }
323
        }
323
        }
324
    );
324
    );
325
325
Lines 363-369 subtest "to_api() tests" => sub { Link Here
363
        ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
363
        ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
364
        is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches');
364
        is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches');
365
        ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
365
        ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
366
        is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->reserve_id, 'Hold matches');
366
        is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->id, 'Hold matches');
367
367
368
        $i++;
368
        $i++;
369
    }
369
    }
(-)a/t/db_dependent/Koha/Patrons.t (-8 / +8 lines)
Lines 480-487 subtest "delete" => sub { Link Here
480
    my $patron           = $builder->build( { source => 'Borrower' } );
480
    my $patron           = $builder->build( { source => 'Borrower' } );
481
    my $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} );
481
    my $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} );
482
    my $hold             = $builder->build(
482
    my $hold             = $builder->build(
483
        {   source => 'Reserve',
483
        {   source => 'Hold',
484
            value  => { borrowernumber => $patron->{borrowernumber} }
484
            value  => { patron_id => $patron->{borrowernumber}, completed => 0 }
485
        }
485
        }
486
    );
486
    );
487
    my $list = $builder->build(
487
    my $list = $builder->build(
Lines 496-504 subtest "delete" => sub { Link Here
496
496
497
    is( Koha::Patrons->find( $patron->{borrowernumber} ), undef, 'Koha::Patron->delete should have deleted the patron' );
497
    is( Koha::Patrons->find( $patron->{borrowernumber} ), undef, 'Koha::Patron->delete should have deleted the patron' );
498
498
499
    is (Koha::Old::Holds->search( { reserve_id => $hold->{ reserve_id } } )->count, 1, q|Koha::Patron->delete should have cancelled patron's holds| );
499
    is (Koha::Holds->search( { id => $hold->{id}, status => 'cancelled' } )->count, 1, q|Koha::Patron->delete should have cancelled patron's holds| );
500
500
501
    is( Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have cancelled patron's holds 2| );
501
    is( Koha::Holds->search( { patron_id => $patron->{borrowernumber}, completed => 0 } )->count, 0, q|Koha::Patron->delete should have cancelled patron's holds 2| );
502
502
503
    is( Koha::Virtualshelves->search( { owner => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have deleted patron's lists| );
503
    is( Koha::Virtualshelves->search( { owner => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have deleted patron's lists| );
504
504
Lines 1033-1040 subtest 'holds and old_holds' => sub { Link Here
1033
    is( $holds->count, 2, 'There should be 2 holds placed by this patron' );
1033
    is( $holds->count, 2, 'There should be 2 holds placed by this patron' );
1034
1034
1035
    my $old_holds = $patron->old_holds;
1035
    my $old_holds = $patron->old_holds;
1036
    is( ref($old_holds), 'Koha::Old::Holds',
1036
    is( ref($old_holds), 'Koha::Holds',
1037
        'Koha::Patron->old_holds should return a Koha::Old::Holds objects' );
1037
        'Koha::Patron->old_holds should return a Koha::Holds objects' );
1038
    is( $old_holds->count, 0, 'There should not be any old holds yet');
1038
    is( $old_holds->count, 0, 'There should not be any old holds yet');
1039
1039
1040
    my $hold = $holds->next;
1040
    my $hold = $holds->next;
Lines 1683-1689 subtest 'BorrowersLog tests' => sub { Link Here
1683
$schema->storage->txn_rollback;
1683
$schema->storage->txn_rollback;
1684
1684
1685
subtest 'Test Koha::Patrons::merge' => sub {
1685
subtest 'Test Koha::Patrons::merge' => sub {
1686
    plan tests => 110;
1686
    plan tests => 106;
1687
1687
1688
    my $schema = Koha::Database->new()->schema();
1688
    my $schema = Koha::Database->new()->schema();
1689
1689
Lines 1966-1972 subtest 'lock' => sub { Link Here
1966
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
1966
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
1967
    my $hold = $builder->build_object({
1967
    my $hold = $builder->build_object({
1968
        class => 'Koha::Holds',
1968
        class => 'Koha::Holds',
1969
        value => { borrowernumber => $patron1->borrowernumber },
1969
        value => { patron_id => $patron1->borrowernumber, completed => 0 },
1970
    });
1970
    });
1971
1971
1972
    t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 3 );
1972
    t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 3 );
(-)a/t/db_dependent/Koha/REST/Plugin/Objects.t (-1 / +1 lines)
Lines 234-240 subtest 'objects.search helper, with path parameters and _match' => sub { Link Here
234
    $builder->build_object(
234
    $builder->build_object(
235
        {
235
        {
236
            class => "Koha::Holds",
236
            class => "Koha::Holds",
237
            value => { borrowernumber => $patron->borrowernumber }
237
            value => { patron_id => $patron->borrowernumber, completed => 0 }
238
        }
238
        }
239
    );
239
    );
240
240
(-)a/t/db_dependent/Koha/Z3950Responder/Session.t (-1 / +1 lines)
Lines 32-38 subtest 'add_item_status' => sub { Link Here
32
    });
32
    });
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('952');
34
    my $item_field_1 = scalar $item_marc_1->field('952');
35
    $builder->build({ source => 'Reserve', value=> { itemnumber => $item_1->{itemnumber} } });
35
    $builder->build({ source => 'Hold', value=> { item_id => $item_1->{itemnumber}, completed => 0 } });
36
    $builder->build({ source => 'Branchtransfer', value=> { itemnumber => $item_1->{itemnumber}, datearrived => undef } });
36
    $builder->build({ source => 'Branchtransfer', value=> { itemnumber => $item_1->{itemnumber}, datearrived => undef } });
37
    ## END FIRST ITEM ##
37
    ## END FIRST ITEM ##
38
38
(-)a/t/db_dependent/Koha/Z3950Responder/Session2.t (-1 / +1 lines)
Lines 56-62 subtest 'add_item_status' => sub { Link Here
56
    });
56
    });
57
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->{biblionumber}, $item_1->{itemnumber} );
57
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->{biblionumber}, $item_1->{itemnumber} );
58
    my $item_field_1 = scalar $item_marc_1->field('952');
58
    my $item_field_1 = scalar $item_marc_1->field('952');
59
    $builder->build({ source => 'Reserve', value=> { itemnumber => $item_1->{itemnumber} } });
59
    $builder->build({ source => 'Hold', value=> { item_id => $item_1->{itemnumber}, completed => 0 } });
60
    $builder->build({ source => 'Branchtransfer', value=> { itemnumber => $item_1->{itemnumber}, datearrived => undef } });
60
    $builder->build({ source => 'Branchtransfer', value=> { itemnumber => $item_1->{itemnumber}, datearrived => undef } });
61
    ## END FIRST ITEM ##
61
    ## END FIRST ITEM ##
62
62
(-)a/t/db_dependent/Letters/TemplateToolkit.t (-8 / +11 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 190-196 $prepared_letter = GetPreparedLetter( Link Here
190
        module      => 'test',
190
        module      => 'test',
191
        letter_code => 'TEST_HOLD',
191
        letter_code => 'TEST_HOLD',
192
        tables      => {
192
        tables      => {
193
            reserves => { borrowernumber => $patron->{borrowernumber}, biblionumber => $item->biblionumber },
193
            holds => {
194
                patron_id => $patron->{borrowernumber},
195
                biblio_id => $item->biblionumber
196
            },
194
        },
197
        },
195
    )
198
    )
196
);
199
);
Lines 202-214 eval { Link Here
202
            module      => 'test',
205
            module      => 'test',
203
            letter_code => 'TEST_HOLD',
206
            letter_code => 'TEST_HOLD',
204
            tables      => {
207
            tables      => {
205
                reserves => [ $patron->{borrowernumber}, $item->biblionumber ],
208
                holds => [ $patron->{borrowernumber}, $item->biblionumber ],
206
            },
209
            },
207
        )
210
        )
208
    )
211
    )
209
};
212
};
210
my $croak = $@;
213
my $croak = $@;
211
like( $croak, qr{^Multiple foreign keys \(table reserves\) should be passed using an hashref.*}, "GetPreparedLetter should not be called with arrayref for multiple FK" );
214
like( $croak, qr{^Multiple foreign keys \(table holds\) should be passed using an hashref.*}, "GetPreparedLetter should not be called with arrayref for multiple FK" );
212
215
213
# Bug 16942
216
# Bug 16942
214
$prepared_letter = GetPreparedLetter(
217
$prepared_letter = GetPreparedLetter(
Lines 220-227 $prepared_letter = GetPreparedLetter( Link Here
220
            'borrowers'   => $patron,
223
            'borrowers'   => $patron,
221
            'biblio'      => $item->biblionumber,
224
            'biblio'      => $item->biblionumber,
222
            'biblioitems' => $item->biblioitemnumber,
225
            'biblioitems' => $item->biblioitemnumber,
223
            'reserves'    => $hold->unblessed,
226
            'holds'        => $hold->unblessed,
224
            'items'       => $hold->itemnumber,
227
            'items'       => $hold->item_id,
225
        }
228
        }
226
    )
229
    )
227
);
230
);
Lines 529-535 You have [% count %] items due Link Here
529
                biblionumber   => $biblio1->{biblionumber},
532
                biblionumber   => $biblio1->{biblionumber},
530
                notes          => "a note",
533
                notes          => "a note",
531
                itemnumber     => $item1->{itemnumber},
534
                itemnumber     => $item1->{itemnumber},
532
                found          => 'W'
535
                found          => 'waiting'
533
            }
536
            }
534
        );
537
        );
535
        C4::Reserves::AddReserve(
538
        C4::Reserves::AddReserve(
(-)a/t/db_dependent/Reserves.t (-37 / +45 lines)
Lines 125-131 my ($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber, $barcod Link Here
125
125
126
is($status, "Reserved", "CheckReserves Test 1");
126
is($status, "Reserved", "CheckReserves Test 1");
127
127
128
ok(exists($reserve->{reserve_id}), 'CheckReserves() include reserve_id in its response');
128
ok(exists($reserve->{id}), 'CheckReserves() include reserve_id in its response');
129
129
130
($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber);
130
($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber);
131
is($status, "Reserved", "CheckReserves Test 2");
131
is($status, "Reserved", "CheckReserves Test 2");
Lines 269-282 ModReserveAffect($itemnum_cpl, $requesters{$branch_3}, 0); Link Here
269
269
270
# Now it should have different priorities.
270
# Now it should have different priorities.
271
my $biblio = Koha::Biblios->find( $bibnum2 );
271
my $biblio = Koha::Biblios->find( $bibnum2 );
272
my $holds = $biblio->holds({}, { order_by => 'reserve_id' });;
272
my $holds = $biblio->holds({}, { order_by => 'id' });;
273
is($holds->next->priority, 0, 'Item is correctly waiting');
273
is($holds->next->priority, 0, 'Item is correctly waiting');
274
is($holds->next->priority, 1, 'Item is correctly priority 1');
274
is($holds->next->priority, 1, 'Item is correctly priority 1');
275
is($holds->next->priority, 2, 'Item is correctly priority 2');
275
is($holds->next->priority, 2, 'Item is correctly priority 2');
276
276
277
my @reserves = Koha::Holds->search({ borrowernumber => $requesters{$branch_3} })->waiting();
277
my @reserves = Koha::Holds->search({ patron_id => $requesters{$branch_3} })->waiting();
278
is( @reserves, 1, 'GetWaiting got only the waiting reserve' );
278
is( @reserves, 1, 'GetWaiting got only the waiting reserve' );
279
is( $reserves[0]->borrowernumber(), $requesters{$branch_3}, 'GetWaiting got the reserve for the correct borrower' );
279
is( $reserves[0]->patron_id(), $requesters{$branch_3}, 'GetWaiting got the reserve for the correct borrower' );
280
280
281
281
282
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum2));
282
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum2));
Lines 314-320 my $messages; Link Here
314
# the one placed by the CPL patron, as the other two patron's hold
314
# the one placed by the CPL patron, as the other two patron's hold
315
# requests cannot be filled by that item per policy.
315
# requests cannot be filled by that item per policy.
316
(undef, $messages, undef, undef) = AddReturn('bug10272_CPL', $branch_2);
316
(undef, $messages, undef, undef) = AddReturn('bug10272_CPL', $branch_2);
317
is( $messages->{ResFound}->{borrowernumber},
317
is( $messages->{ResFound}->{patron_id},
318
    $requesters{$branch_1},
318
    $requesters{$branch_1},
319
    'restrictive library\'s items only fill requests by own patrons (bug 10272)');
319
    'restrictive library\'s items only fill requests by own patrons (bug 10272)');
320
320
Lines 326-339 is( $messages->{ResFound}->{borrowernumber}, Link Here
326
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', '' );
326
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', '' );
327
327
328
(undef, $messages, undef, undef) = AddReturn('bug10272_FPL', $branch_2);
328
(undef, $messages, undef, undef) = AddReturn('bug10272_FPL', $branch_2);
329
is( $messages->{ResFound}->{borrowernumber},
329
is( $messages->{ResFound}->{patron_id},
330
    $requesters{$branch_3},
330
    $requesters{$branch_3},
331
    'for generous library, its items fill first hold request in line (bug 10272)');
331
    'for generous library, its items fill first hold request in line (bug 10272)');
332
332
333
$biblio = Koha::Biblios->find( $biblionumber );
333
$biblio = Koha::Biblios->find( $biblionumber );
334
$holds = $biblio->holds;
334
$holds = $biblio->holds;
335
is($holds->count, 1, "Only one reserves for this biblio");
335
is($holds->count, 1, "Only one reserves for this biblio");
336
my $reserve_id = $holds->next->reserve_id;
336
my $reserve_id = $holds->next->id;
337
337
338
# Tests for bug 9761 (ConfirmFutureHolds): new CheckReserves lookahead parameter, and corresponding change in AddReturn
338
# Tests for bug 9761 (ConfirmFutureHolds): new CheckReserves lookahead parameter, and corresponding change in AddReturn
339
# Note that CheckReserve uses its lookahead parameter and does not check ConfirmFutureHolds pref (it should be passed if needed like AddReturn does)
339
# Note that CheckReserve uses its lookahead parameter and does not check ConfirmFutureHolds pref (it should be passed if needed like AddReturn does)
Lines 406-412 is($new_count, $hold_notice_count + 1, 'patron not notified a second time (bug 1 Link Here
406
t::lib::Mocks::mock_preference('IndependentBranches', 0);
406
t::lib::Mocks::mock_preference('IndependentBranches', 0);
407
$item = Koha::Items->find($item->itemnumber);
407
$item = Koha::Items->find($item->itemnumber);
408
is(
408
is(
409
    $item->safe_delete,
409
    $item->safe_to_delete,
410
    'book_reserved',
410
    'book_reserved',
411
    'item that is captured to fill a hold cannot be deleted',
411
    'item that is captured to fill a hold cannot be deleted',
412
);
412
);
Lines 434-440 AddReserve( Link Here
434
434
435
$holds = $item->current_holds;
435
$holds = $item->current_holds;
436
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
436
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
437
my $future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
437
my $future_holds = $holds->search({ placing_date => { '>' => $dtf->format_date( dt_from_string ) } } );
438
is( $future_holds->count, 0, 'current_holds does not return a future next available hold');
438
is( $future_holds->count, 0, 'current_holds does not return a future next available hold');
439
# 9788b: current_holds does not return future item level hold
439
# 9788b: current_holds does not return future item level hold
440
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
440
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
Lines 448-458 AddReserve( Link Here
448
        itemnumber       => $item->itemnumber,
448
        itemnumber       => $item->itemnumber,
449
    }
449
    }
450
); #item level hold
450
); #item level hold
451
$future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
451
$future_holds = $holds->search({ placing_date => { '>' => $dtf->format_date( dt_from_string ) } } );
452
is( $future_holds->count, 0, 'current_holds does not return a future item level hold' );
452
is( $future_holds->count, 0, 'current_holds does not return a future item level hold' );
453
# 9788c: current_holds returns future wait (confirmed future hold)
453
# 9788c: current_holds returns future wait (confirmed future hold)
454
ModReserveAffect( $item->itemnumber,  $requesters{$branch_1} , 0); #confirm hold
454
ModReserveAffect( $item->itemnumber,  $requesters{$branch_1} , 0); #confirm hold
455
$future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
455
$future_holds = $holds->search({ placing_date => { '>' => $dtf->format_date( dt_from_string ) } } );
456
is( $future_holds->count, 1, 'current_holds returns a future wait (confirmed future hold)' );
456
is( $future_holds->count, 1, 'current_holds returns a future wait (confirmed future hold)' );
457
# End of tests for bug 9788
457
# End of tests for bug 9788
458
458
Lines 546-562 is( Link Here
546
    'CanReserveBeCanceledFromOpac should return undef if called without borrowernumber'
546
    'CanReserveBeCanceledFromOpac should return undef if called without borrowernumber'
547
);
547
);
548
548
549
my $cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
549
my $cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
550
is($cancancel, 1, 'Can user cancel its own reserve');
550
is($cancancel, 1, 'Can user cancel its own reserve');
551
551
552
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_2});
552
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_2});
553
is($cancancel, 0, 'Other user cant cancel reserve');
553
is($cancancel, 0, 'Other user cant cancel reserve');
554
554
555
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 1);
555
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 1);
556
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
556
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
557
is($cancancel, 0, 'Reserve in transfer status cant be canceled');
557
is($cancancel, 0, 'Reserve in transfer status cant be canceled');
558
558
559
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
559
$dbh->do('DELETE FROM holds', undef, ($bibnum));
560
AddReserve(
560
AddReserve(
561
    {
561
    {
562
        branchcode     => $branch_1,
562
        branchcode     => $branch_1,
Lines 568-574 AddReserve( Link Here
568
(undef, $canres, undef) = CheckReserves($item->itemnumber);
568
(undef, $canres, undef) = CheckReserves($item->itemnumber);
569
569
570
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 0);
570
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 0);
571
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
571
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
572
is($cancancel, 0, 'Reserve in waiting status cant be canceled');
572
is($cancancel, 0, 'Reserve in waiting status cant be canceled');
573
573
574
# End of tests for bug 12876
574
# End of tests for bug 12876
Lines 636-642 Koha::CirculationRules->set_rules( Link Here
636
636
637
# tests for MoveReserve in relation to ConfirmFutureHolds (BZ 14526)
637
# tests for MoveReserve in relation to ConfirmFutureHolds (BZ 14526)
638
#   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
639
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
639
$dbh->do('DELETE FROM holds');
640
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 0);
640
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 0);
641
t::lib::Mocks::mock_preference('AllowHoldDateInFuture', 1);
641
t::lib::Mocks::mock_preference('AllowHoldDateInFuture', 1);
642
AddReserve(
642
AddReserve(
Lines 657-663 AddReserve( Link Here
657
        borrowernumber => $borrowernumber,
657
        borrowernumber => $borrowernumber,
658
        biblionumber   => $bibnum,
658
        biblionumber   => $bibnum,
659
        priority       => 1,
659
        priority       => 1,
660
        found          => 'W',
660
        found          => 'waiting',
661
    }
661
    }
662
);
662
);
663
MoveReserve( $item->itemnumber, $borrowernumber );
663
MoveReserve( $item->itemnumber, $borrowernumber );
Lines 831-843 subtest 'ReservesNeedReturns' => sub { Link Here
831
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 1); # Test with feature disabled
831
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 1); # Test with feature disabled
832
    my $hold = place_item_hold( $patron, $item, $library, $priority );
832
    my $hold = place_item_hold( $patron, $item, $library, $priority );
833
    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' );
834
    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' );
835
    $hold->delete;
835
    $hold->delete;
836
836
837
    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'
838
    $hold = place_item_hold( $patron, $item, $library, $priority );
838
    $hold = place_item_hold( $patron, $item, $library, $priority );
839
    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' );
840
    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' );
841
    $hold->delete;
841
    $hold->delete;
842
842
843
    $item->onloan('2010-01-01')->store;
843
    $item->onloan('2010-01-01')->store;
Lines 853-863 subtest 'ReservesNeedReturns' => sub { Link Here
853
    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
854
    $hold = place_item_hold( $patron, $item, $library, $priority );
854
    $hold = place_item_hold( $patron, $item, $library, $priority );
855
    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' );
856
    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' );
857
    $hold->delete;
857
    $hold->delete;
858
858
859
    my $hold_1 = place_item_hold( $patron, $item, $library, $priority );
859
    my $hold_1 = place_item_hold( $patron, $item, $library, $priority );
860
    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' );
861
    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' );
862
    $hold = place_item_hold( $patron_2, $item, $library, $priority );
862
    $hold = place_item_hold( $patron_2, $item, $library, $priority );
863
    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 873-893 subtest 'ReservesNeedReturns' => sub { Link Here
873
    });
873
    });
874
    $item->damaged(0)->store;
874
    $item->damaged(0)->store;
875
    $hold = place_item_hold( $patron, $item, $library, $priority );
875
    $hold = place_item_hold( $patron, $item, $library, $priority );
876
    is( $hold->found, undef, 'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
876
    is( $hold->status, 'placed', 'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
877
    is( $hold->priority, 1,  'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
877
    is( $hold->priority, 1,  'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
878
    $hold->delete;
878
    $hold->delete;
879
    $transfer->delete;
879
    $transfer->delete;
880
880
881
    $hold = place_item_hold( $patron, $item, $library, $priority );
881
    $hold = place_item_hold( $patron, $item, $library, $priority );
882
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
882
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
883
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
883
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
884
    $hold_1 = place_item_hold( $patron, $item, $library, $priority );
884
    $hold_1 = place_item_hold( $patron, $item, $library, $priority );
885
    is( $hold_1->priority, 1, 'If ReservesNeedReturns is 0 but item has a hold priority is 1' );
885
    is( $hold_1->priority, 1, 'If ReservesNeedReturns is 0 but item has a hold priority is 1' );
886
    $hold_1->suspend(1)->store; # We suspend the hold
886
    $hold_1->suspended(1)->store; # We suspend the hold
887
    $hold->delete; # Delete the waiting hold
887
    $hold->delete; # Delete the waiting hold
888
    $hold = place_item_hold( $patron, $item, $library, $priority );
888
    $hold = place_item_hold( $patron, $item, $library, $priority );
889
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and other hold(s) suspended, priority must have been set to 0' );
889
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and other hold(s) suspended, priority must have been set to 0' );
890
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and other  hold(s) suspended, found must have been set waiting' );
890
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and other  hold(s) suspended, found must have been set waiting' );
891
891
892
892
893
893
Lines 944-950 subtest 'reserves.item_level_hold' => sub { Link Here
944
        );
944
        );
945
945
946
        my $hold = Koha::Holds->find($reserve_id);
946
        my $hold = Koha::Holds->find($reserve_id);
947
        is( $hold->item_level_hold, 1, 'item_level_hold should be set when AddReserve is called with a specific item' );
947
        is( $hold->item_level, 1, 'item_level should be set when AddReserve is called with a specific item' );
948
948
949
        # Mark it waiting
949
        # Mark it waiting
950
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 1 );
950
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 1 );
Lines 955-961 subtest 'reserves.item_level_hold' => sub { Link Here
955
955
956
        $hold = Koha::Holds->find($reserve_id);
956
        $hold = Koha::Holds->find($reserve_id);
957
957
958
        is( $hold->itemnumber, $item->itemnumber, 'Itemnumber should not be removed when the waiting status is revert' );
958
        is( $hold->item_id, $item->itemnumber, 'Itemnumber should not be removed when the waiting status is revert' );
959
959
960
        $hold->delete;    # cleanup
960
        $hold->delete;    # cleanup
961
    };
961
    };
Lines 972-990 subtest 'reserves.item_level_hold' => sub { Link Here
972
        );
972
        );
973
973
974
        my $hold = Koha::Holds->find($reserve_id);
974
        my $hold = Koha::Holds->find($reserve_id);
975
        is( $hold->item_level_hold, 0, 'item_level_hold should not be set when AddReserve is called without a specific item' );
975
        is( $hold->item_level, 0, 'item_level should not be set when AddReserve is called without a specific item' );
976
976
977
        # Mark it waiting
977
        # Mark it waiting
978
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 1 );
978
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 1 );
979
979
980
        $hold = Koha::Holds->find($reserve_id);
980
        $hold = Koha::Holds->find($reserve_id);
981
        is( $hold->itemnumber, $item->itemnumber, 'Itemnumber should be set on hold confirmation' );
981
        is( $hold->item_id, $item->itemnumber, 'Itemnumber should be set on hold confirmation' );
982
982
983
        # Revert the waiting status
983
        # Revert the waiting status
984
        C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
984
        C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
985
985
986
        $hold = Koha::Holds->find($reserve_id);
986
        $hold = Koha::Holds->find($reserve_id);
987
        is( $hold->itemnumber, undef, 'Itemnumber should be removed when the waiting status is revert' );
987
        is( $hold->item_id, undef, 'Itemnumber should be removed when the waiting status is revert' );
988
988
989
        $hold->delete;
989
        $hold->delete;
990
    };
990
    };
Lines 1022-1037 subtest 'MoveReserve additional test' => sub { Link Here
1022
            itemnumber     => $item_1->itemnumber,
1022
            itemnumber     => $item_1->itemnumber,
1023
        }
1023
        }
1024
    );
1024
    );
1025
    is($patron_1->holds->next()->reserve_id, $reserve_1, "The 1st patron has a hold");
1025
    is($patron_1->holds->next()->id, $reserve_1, "The 1st patron has a hold");
1026
    is($patron_2->holds->next()->reserve_id, $reserve_2, "The 2nd patron has a hold");
1026
    is($patron_2->holds->next()->id, $reserve_2, "The 2nd patron has a hold");
1027
1027
1028
    # Fake the holds queue
1028
    # Fake the holds queue
1029
    $dbh->do(q{INSERT INTO hold_fill_targets VALUES (?, ?, ?, ?, ?)},undef,($patron_1->borrowernumber,$biblio->biblionumber,$item_1->itemnumber,$item_1->homebranch,0));
1029
    $dbh->do(
1030
        q{INSERT INTO hold_fill_targets VALUES (?, ?, ?, ?, ?)},
1031
        undef,
1032
        (
1033
            $patron_1->borrowernumber, $biblio->biblionumber,
1034
            $item_1->itemnumber,       $item_1->homebranch,
1035
            0
1036
        )
1037
    );
1030
1038
1031
    # The 2nd hold should be filed even if the item is preselected for the first hold
1039
    # The 2nd hold should be filed even if the item is preselected for the first hold
1032
    MoveReserve($item_1->itemnumber,$patron_2->borrowernumber);
1040
    MoveReserve($item_1->itemnumber,$patron_2->borrowernumber);
1033
    is($patron_2->holds->count, 0, "The 2nd patrons no longer has a hold");
1041
    is($patron_2->holds({ completed => 0 })->count, 0, "The 2nd patrons no longer has a hold");
1034
    is($patron_2->old_holds->next()->reserve_id, $reserve_2, "The 2nd patrons hold was filled and moved to old holds");
1042
    is($patron_2->holds({ completed => 1 })->next()->id, $reserve_2, "The 2nd patrons hold was filled and moved to old holds");
1035
1043
1036
};
1044
};
1037
1045
(-)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
            completion_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
            completion_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
                    completion_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
                    completion_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 (-88 / +109 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
                placing_date    => $reserve_reservedate,
41
            cancellationdate => undef,
41
                expiration_date => $reserve1_expirationdate,
42
            priority => 0,
42
                completion_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
                placing_date    => $reserve_reservedate,
60
            cancellationdate => undef,
63
                expiration_date => $reserve2_expirationdate,
61
            priority => 0,
64
                completion_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
                placing_date      => $reserve_reservedate,
76
            branchcode => 'LIB1',
84
                expiration_date   => $reserve2_expirationdate,
77
            cancellationdate => undef,
85
                pickup_library_id => 'LIB1',
78
            priority => 0,
86
                completion_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 121-165 subtest 'Test handling of waiting reserves by CancelExpiredReserves' => sub { Link Here
121
    my $expdate = dt_from_string->add( days => -2 );
131
    my $expdate = dt_from_string->add( days => -2 );
122
    my $notexpdate = dt_from_string->add( days => 2 );
132
    my $notexpdate = dt_from_string->add( days => 2 );
123
133
124
    my $hold1 = Koha::Hold->new({
134
    my $hold1 = Koha::Hold->new(
125
        branchcode => $branchcode,
135
        {
126
        borrowernumber => $borrowernumber,
136
            pickup_library_id => $branchcode,
127
        biblionumber => $bibnum,
137
            patron_id         => $borrowernumber,
128
        priority => 1,
138
            biblio_id         => $bibnum,
129
        reservedate => $resdate,
139
            priority          => 1,
130
        expirationdate => $notexpdate,
140
            placing_date      => $resdate,
131
        found => undef,
141
            expiration_date   => $notexpdate,
132
    })->store;
142
            status            => 'placed',
133
143
        }
134
    my $hold2 = Koha::Hold->new({
144
    )->store;
135
        branchcode => $branchcode,
145
136
        borrowernumber => $borrowernumber,
146
    my $hold2 = Koha::Hold->new(
137
        biblionumber => $bibnum,
147
        {
138
        priority => 2,
148
            pickup_library_id => $branchcode,
139
        reservedate => $resdate,
149
            patron_id         => $borrowernumber,
140
        expirationdate => $expdate,
150
            biblio_id         => $bibnum,
141
        found => undef,
151
            priority          => 2,
142
    })->store;
152
            placing_date      => $resdate,
143
153
            expiration_date   => $expdate,
144
    my $hold3 = Koha::Hold->new({
154
            status            => 'placed',
145
        branchcode => $branchcode,
155
        }
146
        borrowernumber => $borrowernumber,
156
    )->store;
147
        biblionumber => $bibnum,
157
148
        itemnumber => $itemnumber,
158
    my $hold3 = Koha::Hold->new(
149
        priority => 0,
159
        {
150
        reservedate => $resdate,
160
            pickup_library_id => $branchcode,
151
        expirationdate => $expdate,
161
            patron_id         => $borrowernumber,
152
        found => 'W',
162
            biblio_id         => $bibnum,
153
    })->store;
163
            item_id           => $itemnumber,
164
            priority          => 0,
165
            placing_date      => $resdate,
166
            expiration_date   => $expdate,
167
            status            => 'waiting',
168
        }
169
    )->store;
154
170
155
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
171
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
156
    CancelExpiredReserves();
172
    CancelExpiredReserves();
157
    my $count1 = Koha::Holds->search->count;
173
    my $count1 = Koha::Holds->search({ completed => 0 })->count;
158
    is( $count1, 2, 'Only the non-waiting expired holds should be cancelled');
174
    is( $count1, 2, 'Only the non-waiting expired holds should be cancelled');
159
175
160
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
176
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
161
    CancelExpiredReserves();
177
    CancelExpiredReserves();
162
    my $count2 = Koha::Holds->search->count;
178
    my $count2 = Koha::Holds->search({ completed => 0 })->count;
163
    is( $count2, 1, 'Also the waiting expired hold should be cancelled now');
179
    is( $count2, 1, 'Also the waiting expired hold should be cancelled now');
164
180
165
};
181
};
Lines 171-203 subtest 'Test handling of in transit reserves by CancelExpiredReserves' => sub { Link Here
171
187
172
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
188
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
173
    my $expdate = dt_from_string->add( days => -2 );
189
    my $expdate = dt_from_string->add( days => -2 );
174
    my $reserve = $builder->build({
190
    my $reserve = $builder->build_object({
175
        source => 'Reserve',
191
        class => 'Koha::Holds',
176
        value  => {
192
        value  => {
177
            expirationdate => '2018-01-01',
193
            expiration_date      => '2018-01-01',
178
            found => 'T',
194
            status               => 'in_transit',
179
            cancellationdate => undef,
195
            suspended            => 0,
180
            suspend => 0,
196
            completed            => 0,
181
            suspend_until => undef
197
            cancellation_date    => undef,
198
            suspended_until_date => undef,
182
        }
199
        }
183
    });
200
    });
184
    my $count = Koha::Holds->search->count;
201
202
    my $active = Koha::Holds->search({ completed => 0 });
203
    my $count = $active->count;
204
185
    CancelExpiredReserves();
205
    CancelExpiredReserves();
186
    is(Koha::Holds->search->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay set");
206
    is($active->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay set");
187
207
188
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
208
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
189
    my $reserve2 = $builder->build({
209
    my $reserve2 = $builder->build_object({
190
        source => 'Reserve',
210
        class => 'Koha::Holds',
191
        value  => {
211
        value  => {
192
            expirationdate => '2018-01-01',
212
            expiration_date      => '2018-01-01',
193
            found => 'T',
213
            status               => 'in_transit',
194
            cancellationdate => undef,
214
            cancellation_date    => undef,
195
            suspend => 0,
215
            suspended            => 0,
196
            suspend_until => undef
216
            suspended_until_date => undef,
217
            completed            => 0,
197
        }
218
        }
198
    });
219
    });
199
    CancelExpiredReserves();
220
    CancelExpiredReserves();
200
    is(Koha::Holds->search->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay unset");
221
    is($active->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay unset");
201
222
202
};
223
};
203
224
(-)a/t/db_dependent/Reserves/GetReserveFee.t (-7 / +7 lines)
Lines 126-144 subtest 'Integration with AddReserve' => sub { Link Here
126
        plan tests => 3;
126
        plan tests => 3;
127
127
128
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
128
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
129
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->{biblionumber} );
129
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
130
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
130
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
131
        addreserve( $patron1->{borrowernumber} );
131
        addreserve( $patron1->{borrowernumber} );
132
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - No fee charged for patron 1 if not issued' );
132
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - No fee charged for patron 1 if not issued' );
133
133
134
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_placed');
134
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_placed');
135
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->{biblionumber} );
135
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
136
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
136
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
137
        addreserve( $patron1->{borrowernumber} );
137
        addreserve( $patron1->{borrowernumber} );
138
        is( acctlines( $patron1->{borrowernumber} ), 1, 'any_time_is_placed - Patron should be always charged' );
138
        is( acctlines( $patron1->{borrowernumber} ), 1, 'any_time_is_placed - Patron should be always charged' );
139
139
140
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_collected');
140
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_collected');
141
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->{biblionumber} );
141
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
142
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
142
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
143
        addreserve( $patron1->{borrowernumber} );
143
        addreserve( $patron1->{borrowernumber} );
144
        is( acctlines( $patron1->{borrowernumber} ), 0, 'any_time_is_collected - Patron should not be charged when placing a hold' );
144
        is( acctlines( $patron1->{borrowernumber} ), 0, 'any_time_is_collected - Patron should not be charged when placing a hold' );
Lines 150-161 subtest 'Integration with AddReserve' => sub { Link Here
150
        C4::Circulation::AddIssue( $patron2, $item1->{barcode}, '2015-12-31', 0, undef, 0, {} );
150
        C4::Circulation::AddIssue( $patron2, $item1->{barcode}, '2015-12-31', 0, undef, 0, {} );
151
151
152
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
152
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
153
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->{biblionumber} );
153
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?",     undef, $biblio->{biblionumber} );
154
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
154
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
155
        addreserve( $patron1->{borrowernumber} );
155
        addreserve( $patron1->{borrowernumber} );
156
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - Patron should not be charged if items are not all checked out' );
156
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - Patron should not be charged if items are not all checked out' );
157
157
158
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->{biblionumber} );
158
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
159
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
159
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
160
        addreserve( $patron3->{borrowernumber} );
160
        addreserve( $patron3->{borrowernumber} );
161
        addreserve( $patron1->{borrowernumber} );
161
        addreserve( $patron1->{borrowernumber} );
Lines 163-169 subtest 'Integration with AddReserve' => sub { Link Here
163
        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' );
163
        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' );
164
164
165
        C4::Circulation::AddIssue( $patron3, $item2->{barcode}, '2015-12-31', 0, undef, 0, {} );
165
        C4::Circulation::AddIssue( $patron3, $item2->{barcode}, '2015-12-31', 0, undef, 0, {} );
166
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->{biblionumber} );
166
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
167
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
167
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
168
        addreserve( $patron1->{borrowernumber} );
168
        addreserve( $patron1->{borrowernumber} );
169
        is( acctlines( $patron1->{borrowernumber} ), 1, 'not_always - Patron should be charged if all items are checked out' );
169
        is( acctlines( $patron1->{borrowernumber} ), 1, 'not_always - Patron should be charged if all items are checked out' );
Lines 174-180 subtest 'Integration with AddIssue' => sub { Link Here
174
    plan tests => 5;
174
    plan tests => 5;
175
175
176
    $dbh->do( "DELETE FROM issues       WHERE borrowernumber = ?", undef, $patron1->{borrowernumber} );
176
    $dbh->do( "DELETE FROM issues       WHERE borrowernumber = ?", undef, $patron1->{borrowernumber} );
177
    $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->{biblionumber} );
177
    $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
178
    $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
178
    $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
179
179
180
    t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
180
    t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
(-)a/t/db_dependent/Reserves/MultiplePerRecord.t (-9 / +9 lines)
Lines 247-271 is( $rule->{holds_per_record}, 5, 'Got holds_per_record Link Here
247
247
248
Koha::CirculationRules->delete();
248
Koha::CirculationRules->delete();
249
249
250
my $holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
250
my $holds = Koha::Holds->search( { patron_id => $patron->{borrowernumber} } );
251
is( $holds->forced_hold_level, undef, "No holds does not force an item or record level hold" );
251
is( $holds->forced_hold_level, undef, "No holds does not force an item or record level hold" );
252
252
253
# Test Koha::Holds::forced_hold_level
253
# Test Koha::Holds::forced_hold_level
254
my $hold = Koha::Hold->new({
254
my $hold = Koha::Hold->new({
255
    borrowernumber => $patron->{borrowernumber},
255
    patron_id => $patron->{borrowernumber},
256
    reservedate => '1981-06-10',
256
    placing_date => '1981-06-10',
257
    biblionumber => $biblio->{biblionumber},
257
    biblio_id => $biblio->{biblionumber},
258
    branchcode => $library->{branchcode},
258
    pickup_library_id => $library->{branchcode},
259
    priority => 1,
259
    priority => 1,
260
})->store();
260
})->store();
261
261
262
$holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
262
$holds = Koha::Holds->search( { patron_id => $patron->{borrowernumber} } );
263
is( $holds->forced_hold_level, 'record', "Record level hold forces record level holds" );
263
is( $holds->forced_hold_level, 'record', "Record level hold forces record level holds" );
264
264
265
$hold->itemnumber( $item1->{itemnumber} );
265
$hold->item_id( $item1->{itemnumber} );
266
$hold->store();
266
$hold->store();
267
267
268
$holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
268
$holds = Koha::Holds->search( { patron_id => $patron->{borrowernumber} } );
269
is( $holds->forced_hold_level, 'item', "Item level hold forces item level holds" );
269
is( $holds->forced_hold_level, 'item', "Item level hold forces item level holds" );
270
270
271
$hold->delete();
271
$hold->delete();
Lines 310-316 ok( $hold_id, 'Second hold was placed' ); Link Here
310
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
310
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
311
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
311
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
312
312
313
Koha::Holds->find($hold_id)->found("W")->store;
313
Koha::Holds->find($hold_id)->set_waiting();
314
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
314
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
315
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
315
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
316
316
(-)a/t/db_dependent/Reserves/ReserveSlip.t (-11 / +12 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 83-106 my $item2 = $builder->build( Link Here
83
83
84
my $hold1 = Koha::Hold->new(
84
my $hold1 = Koha::Hold->new(
85
    {
85
    {
86
        biblionumber   => $biblio->{biblionumber},
86
        biblio_id         => $biblio->{biblionumber},
87
        itemnumber     => $item1->{itemnumber},
87
        item_id           => $item1->{itemnumber},
88
        waitingdate    => '2000-01-01',
88
        waiting_date      => '2000-01-01',
89
        borrowernumber => $patron->{borrowernumber},
89
        patron_id         => $patron->{borrowernumber},
90
        branchcode     => $library->{branchcode},
90
        pickup_library_id => $library->{branchcode},
91
    }
91
    }
92
)->store;
92
)->store;
93
93
94
my $hold2 = Koha::Hold->new(
94
my $hold2 = Koha::Hold->new(
95
    {
95
    {
96
        biblionumber   => $biblio->{biblionumber},
96
        biblio_id         => $biblio->{biblionumber},
97
        itemnumber     => $item2->{itemnumber},
97
        item_id           => $item2->{itemnumber},
98
        waitingdate    => '2000-01-01',
98
        waiting_date      => '2000-01-01',
99
        borrowernumber => $patron->{borrowernumber},
99
        patron_id         => $patron->{borrowernumber},
100
        branchcode     => $library->{branchcode},
100
        pickup_library_id => $library->{branchcode},
101
    }
101
    }
102
)->store;
102
)->store;
103
103
104
104
my $letter = $builder->build(
105
my $letter = $builder->build(
105
    {
106
    {
106
        source => 'Letter',
107
        source => 'Letter',
(-)a/t/db_dependent/TestBuilder.t (-5 / +6 lines)
Lines 248-258 subtest 'Test build with NULL values' => sub { Link Here
248
    is( $info->{is_nullable} && $item && !defined( $item->{barcode} ), 1,
248
    is( $info->{is_nullable} && $item && !defined( $item->{barcode} ), 1,
249
        'Barcode can be NULL' );
249
        'Barcode can be NULL' );
250
    # Nullable FK
250
    # Nullable FK
251
    $params = { source => 'Reserve', value  => { itemnumber => undef }};
251
    $params = { source => 'Hold', value  => { item_id => undef }};
252
    my $reserve = $builder->build( $params );
252
    my $hold = $builder->build( $params );
253
    $info = $schema->source( 'Reserve' )->column_info( 'itemnumber' );
253
    $info = $schema->source( 'Hold' )->column_info( 'item_id' );
254
    is( $reserve && $info->{is_nullable} && $info->{is_foreign_key} &&
254
    is( $hold && $info->{is_nullable} && $info->{is_foreign_key} &&
255
        !defined( $reserve->{itemnumber} ), 1, 'Nullable FK' );
255
        !defined( $hold->{item_id} ), 1, 'Nullable FK' );
256
};
256
};
257
257
258
258
Lines 394-399 subtest 'build_object() tests' => sub { Link Here
394
            $module =~ s|^.*/(Koha.*)\.pm$|$1|;
394
            $module =~ s|^.*/(Koha.*)\.pm$|$1|;
395
            $module =~ s|/|::|g;
395
            $module =~ s|/|::|g;
396
            next if $module eq 'Koha::Objects';
396
            next if $module eq 'Koha::Objects';
397
            next if $module eq 'Koha::Old::Holds'; #This is a view now
397
            eval "require $module";
398
            eval "require $module";
398
            my $object = $builder->build_object( { class => $module } );
399
            my $object = $builder->build_object( { class => $module } );
399
            is( ref($object), $module->object_class, "Testing $module" );
400
            is( ref($object), $module->object_class, "Testing $module" );
(-)a/t/db_dependent/XSLT.t (-4 / +5 lines)
Lines 96-105 subtest 'buildKohaItemsNamespace status tests' => sub { Link Here
96
    like($xml,qr{<status>In transit</status>},"In-transit status takes precedence over Damaged");
96
    like($xml,qr{<status>In transit</status>},"In-transit status takes precedence over Damaged");
97
97
98
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
98
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
99
        biblionumber => $item->biblionumber,
99
        biblio_id => $item->biblionumber,
100
        itemnumber   => $item->itemnumber,
100
        item_id   => $item->itemnumber,
101
        found        => 'W',
101
        status    => 'waiting',
102
        priority     => 0,
102
        priority  => 0,
103
        completed => 0,
103
        }
104
        }
104
    });
105
    });
105
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
106
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
(-)a/t/db_dependent/api/v1/holds.t (-13 / +13 lines)
Lines 114-120 my $biblio_2 = $builder->build_sample_biblio; Link Here
114
my $item_2   = $builder->build_sample_item({ biblionumber => $biblio_2->biblionumber, itype => $itemtype });
114
my $item_2   = $builder->build_sample_item({ biblionumber => $biblio_2->biblionumber, itype => $itemtype });
115
115
116
my $dbh = C4::Context->dbh;
116
my $dbh = C4::Context->dbh;
117
$dbh->do('DELETE FROM reserves');
117
$dbh->do('DELETE FROM holds');
118
Koha::CirculationRules->search()->delete();
118
Koha::CirculationRules->search()->delete();
119
Koha::CirculationRules->set_rules(
119
Koha::CirculationRules->set_rules(
120
    {
120
    {
Lines 162-168 my $post_data = { Link Here
162
};
162
};
163
my $put_data = {
163
my $put_data = {
164
    priority => 2,
164
    priority => 2,
165
    suspended_until => output_pref({ dt => $suspended_until, dateformat => 'rfc3339' }),
165
    suspended_until_date => output_pref({ dt => $suspended_until, dateformat => 'rfc3339' }),
166
};
166
};
167
167
168
subtest "Test endpoints without authentication" => sub {
168
subtest "Test endpoints without authentication" => sub {
Lines 219-225 subtest "Test endpoints with permission" => sub { Link Here
219
    $t->put_ok( "//$userid_1:$password@/api/v1/holds/$reserve_id" => json => $put_data )
219
    $t->put_ok( "//$userid_1:$password@/api/v1/holds/$reserve_id" => json => $put_data )
220
      ->status_is(200)
220
      ->status_is(200)
221
      ->json_is( '/hold_id', $reserve_id )
221
      ->json_is( '/hold_id', $reserve_id )
222
      ->json_is( '/suspended_until', $expected_suspended_until )
222
      ->json_is( '/suspended_until_date', $expected_suspended_until )
223
      ->json_is( '/priority', 2 )
223
      ->json_is( '/priority', 2 )
224
      ->json_is( '/pickup_library_id', $branchcode );
224
      ->json_is( '/pickup_library_id', $branchcode );
225
225
Lines 227-241 subtest "Test endpoints with permission" => sub { Link Here
227
    $t->put_ok( "//$userid_1:$password@/api/v1/holds/$reserve_id" => json => { pickup_library_id => $branchcode2 } )
227
    $t->put_ok( "//$userid_1:$password@/api/v1/holds/$reserve_id" => json => { pickup_library_id => $branchcode2 } )
228
      ->status_is(200)
228
      ->status_is(200)
229
      ->json_is( '/hold_id', $reserve_id )
229
      ->json_is( '/hold_id', $reserve_id )
230
      ->json_is( '/suspended_until', $expected_suspended_until )
230
      ->json_is( '/suspended_until_date', $expected_suspended_until )
231
      ->json_is( '/priority', 2 )
231
      ->json_is( '/priority', 2 )
232
      ->json_is( '/pickup_library_id', $branchcode2 );
232
      ->json_is( '/pickup_library_id', $branchcode2 );
233
233
234
    # Reset suspended_until, everything else should remain
234
    # Reset suspended_until, everything else should remain
235
    $t->put_ok( "//$userid_1:$password@/api/v1/holds/$reserve_id" => json => { suspended_until => undef } )
235
    $t->put_ok( "//$userid_1:$password@/api/v1/holds/$reserve_id" => json => { suspended_until_date => undef } )
236
      ->status_is(200)
236
      ->status_is(200)
237
      ->json_is( '/hold_id', $reserve_id )
237
      ->json_is( '/hold_id', $reserve_id )
238
      ->json_is( '/suspended_until', undef )
238
      ->json_is( '/suspended_until_date', undef )
239
      ->json_is( '/priority', 2 )
239
      ->json_is( '/priority', 2 )
240
      ->json_is( '/pickup_library_id', $branchcode2 );
240
      ->json_is( '/pickup_library_id', $branchcode2 );
241
241
Lines 267-272 subtest "Test endpoints with permission" => sub { Link Here
267
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
267
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
268
      ->status_is(201)
268
      ->status_is(201)
269
      ->json_has('/hold_id');
269
      ->json_has('/hold_id');
270
270
    # Get id from response
271
    # Get id from response
271
    $reserve_id = $t->tx->res->json->{hold_id};
272
    $reserve_id = $t->tx->res->json->{hold_id};
272
273
Lines 329-335 subtest 'test AllowHoldDateInFuture' => sub { Link Here
329
        item_id => int($item_1->itemnumber),
330
        item_id => int($item_1->itemnumber),
330
        pickup_library_id => $branchcode,
331
        pickup_library_id => $branchcode,
331
        expiration_date => output_pref({ dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 }),
332
        expiration_date => output_pref({ dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 }),
332
        hold_date => output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }),
333
        placing_date => output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }),
333
        priority => 2,
334
        priority => 2,
334
    };
335
    };
335
336
Lines 343-349 subtest 'test AllowHoldDateInFuture' => sub { Link Here
343
344
344
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
345
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
345
      ->status_is(201)
346
      ->status_is(201)
346
      ->json_is('/hold_date', output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }));
347
      ->json_is('/placing_date', output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }));
347
};
348
};
348
349
349
subtest 'test AllowHoldPolicyOverride' => sub {
350
subtest 'test AllowHoldPolicyOverride' => sub {
Lines 395-401 subtest 'suspend and resume tests' => sub { Link Here
395
396
396
    my $hold = $builder->build_object(
397
    my $hold = $builder->build_object(
397
        {   class => 'Koha::Holds',
398
        {   class => 'Koha::Holds',
398
            value => { suspend => 0, suspend_until => undef, waitingdate => undef, found => undef }
399
            value => { suspended => 0, suspended_until_date => undef, waiting_date => undef, status => 'placed', completed => 0 }
399
        }
400
        }
400
    );
401
    );
401
402
Lines 422-428 subtest 'suspend and resume tests' => sub { Link Here
422
    $t->json_is(
423
    $t->json_is(
423
      '/end_date',
424
      '/end_date',
424
      output_pref({
425
      output_pref({
425
        dt         => dt_from_string( $hold->suspend_until ),
426
        dt         => dt_from_string( $hold->suspended_until_date ),
426
        dateformat => 'rfc3339',
427
        dateformat => 'rfc3339',
427
        dateonly   => 1
428
        dateonly   => 1
428
      }),
429
      }),
Lines 455-467 subtest 'suspend and resume tests' => sub { Link Here
455
456
456
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
457
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
457
      ->status_is( 400, 'Cannot suspend waiting hold' )
458
      ->status_is( 400, 'Cannot suspend waiting hold' )
458
      ->json_is( '/error', 'Found hold cannot be suspended. Status=W' );
459
      ->json_is( '/error', 'Found hold cannot be suspended. Status=waiting' );
459
460
460
    $hold->set_waiting(1)->discard_changes;
461
    $hold->set_waiting(1)->discard_changes;
461
462
462
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
463
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
463
      ->status_is( 400, 'Cannot suspend waiting hold' )
464
      ->status_is( 400, 'Cannot suspend waiting hold' )
464
      ->json_is( '/error', 'Found hold cannot be suspended. Status=T' );
465
      ->json_is( '/error', 'Found hold cannot be suspended. Status=in_transit' );
465
466
466
    $schema->storage->txn_rollback;
467
    $schema->storage->txn_rollback;
467
};
468
};
468
- 

Return to bug 25260