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

(-)a/C4/Circulation.pm (-4 / +8 lines)
Lines 1273-1279 sub checkHighHolds { Link Here
1273
        due_date    => undef,
1273
        due_date    => undef,
1274
    };
1274
    };
1275
1275
1276
    my $holds = Koha::Holds->search( { biblionumber => $item->{'biblionumber'} } );
1276
    my $holds = Koha::Holds->search( { biblio_id => $item->{'biblionumber'} } );
1277
1277
1278
    if ( $holds->count() ) {
1278
    if ( $holds->count() ) {
1279
        $return_data->{outstanding} = $holds->count();
1279
        $return_data->{outstanding} = $holds->count();
Lines 2850-2857 sub CanBookBeRenewed { Link Here
2850
    # If next hold is non priority, then check if any hold with priority (non_priority = 0) exists for the same biblionumber.
2850
    # If next hold is non priority, then check if any hold with priority (non_priority = 0) exists for the same biblionumber.
2851
    if ( $resfound && $resrec->{non_priority} ) {
2851
    if ( $resfound && $resrec->{non_priority} ) {
2852
        $resfound = Koha::Holds->search(
2852
        $resfound = Koha::Holds->search(
2853
            { biblionumber => $resrec->{biblionumber}, non_priority => 0 } )
2853
            {
2854
          ->count > 0;
2854
                biblio_id    => $resrec->{biblionumber},
2855
                non_priority => 0,
2856
                completed    => 0
2857
            }
2858
        )->count > 0;
2855
    }
2859
    }
2856
2860
2857
2861
Lines 2863-2869 sub CanBookBeRenewed { Link Here
2863
    {
2867
    {
2864
        my $schema = Koha::Database->new()->schema();
2868
        my $schema = Koha::Database->new()->schema();
2865
2869
2866
        my $item_holds = $schema->resultset('Reserve')->search( { itemnumber => $itemnumber, found => undef } )->count();
2870
        my $item_holds = $schema->resultset('Reserve')->search( { item_id => $itemnumber, status => 'placed' } )->count();
2867
        if ($item_holds) {
2871
        if ($item_holds) {
2868
            # There is an item level hold on this item, no other item can fill the hold
2872
            # There is an item level hold on this item, no other item can fill the hold
2869
            $resfound = 1;
2873
            $resfound = 1;
(-)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 (-260 / +254 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
use Koha::Plugins;
46
use Koha::Plugins;
49
47
Lines 186-192 sub AddReserve { Link Here
186
    my $notes          = $params->{notes};
184
    my $notes          = $params->{notes};
187
    my $title          = $params->{title};
185
    my $title          = $params->{title};
188
    my $checkitem      = $params->{itemnumber};
186
    my $checkitem      = $params->{itemnumber};
189
    my $found          = $params->{found};
187
    my $found          = $params->{found} // 'placed';
190
    my $itemtype       = $params->{itemtype};
188
    my $itemtype       = $params->{itemtype};
191
    my $non_priority   = $params->{non_priority};
189
    my $non_priority   = $params->{non_priority};
192
190
Lines 217-223 sub AddReserve { Link Here
217
            && !$item->current_holds->count )
215
            && !$item->current_holds->count )
218
        {
216
        {
219
            $priority = 0;
217
            $priority = 0;
220
            $found = 'W';
218
            $found = 'waiting';
221
        }
219
        }
222
    }
220
    }
223
221
Lines 230-236 sub AddReserve { Link Here
230
    my $waitingdate;
228
    my $waitingdate;
231
229
232
    # If the reserv had the waiting status, we had the value of the resdate
230
    # If the reserv had the waiting status, we had the value of the resdate
233
    if ( $found && $found eq 'W' ) {
231
    if ( $found and $found eq 'waiting' ) {
234
        $waitingdate = $resdate;
232
        $waitingdate = $resdate;
235
    }
233
    }
236
234
Lines 240-261 sub AddReserve { Link Here
240
    # updates take place here
238
    # updates take place here
241
    my $hold = Koha::Hold->new(
239
    my $hold = Koha::Hold->new(
242
        {
240
        {
243
            borrowernumber => $borrowernumber,
241
            patron_id      => $borrowernumber,
244
            biblionumber   => $biblionumber,
242
            biblio_id      => $biblionumber,
245
            reservedate    => $resdate,
243
            created_date   => $resdate,
246
            branchcode     => $branch,
244
            pickup_library_id => $branch,
247
            priority       => $priority,
245
            priority       => $priority,
248
            reservenotes   => $notes,
246
            notes          => $notes,
249
            itemnumber     => $checkitem,
247
            item_id        => $checkitem,
250
            found          => $found,
248
            waiting_date   => $waitingdate,
251
            waitingdate    => $waitingdate,
249
            expiration_date => $expdate,
252
            expirationdate => $expdate,
250
            item_type      => $itemtype,
253
            itemtype       => $itemtype,
251
            item_level     => $checkitem ? 1 : 0,
254
            item_level_hold => $checkitem ? 1 : 0,
255
            non_priority   => $non_priority ? 1 : 0,
252
            non_priority   => $non_priority ? 1 : 0,
256
        }
253
        }
257
    )->store();
254
    )->store();
258
    $hold->set_waiting() if $found && $found eq 'W';
255
    $hold->set_waiting() if $found eq 'waiting';
259
256
260
    logaction( 'HOLDS', 'CREATE', $hold->id, Dumper($hold->unblessed) )
257
    logaction( 'HOLDS', 'CREATE', $hold->id, Dumper($hold->unblessed) )
261
        if C4::Context->preference('HoldsLog');
258
        if C4::Context->preference('HoldsLog');
Lines 391-397 sub CanItemBeReserved { Link Here
391
388
392
    # Check that the patron doesn't have an item level hold on this item already
389
    # Check that the patron doesn't have an item level hold on this item already
393
    return { status =>'itemAlreadyOnHold' }
390
    return { status =>'itemAlreadyOnHold' }
394
      if Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count();
391
      if Koha::Holds->search( { patron_id => $borrowernumber, item_id => $itemnumber, completed => 0 } )->count();
395
392
396
    # Check that patron have not checked out this biblio (if AllowHoldsOnPatronsPossessions set)
393
    # Check that patron have not checked out this biblio (if AllowHoldsOnPatronsPossessions set)
397
    if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions')
394
    if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions')
Lines 403-417 sub CanItemBeReserved { Link Here
403
400
404
    my $querycount = q{
401
    my $querycount = q{
405
        SELECT count(*) AS count
402
        SELECT count(*) AS count
406
          FROM reserves
403
          FROM holds
407
     LEFT JOIN items USING (itemnumber)
404
     LEFT JOIN items ON (holds.item_id=items.itemnumber)
408
     LEFT JOIN biblioitems ON (reserves.biblionumber=biblioitems.biblionumber)
405
     LEFT JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
409
     LEFT JOIN borrowers USING (borrowernumber)
406
     LEFT JOIN borrowers ON (holds.patron_id=borrowers.borrowernumber)
410
         WHERE borrowernumber = ?
407
         WHERE completed = 0 and borrowernumber = ?
411
    };
408
    };
412
409
413
    my $branchcode  = "";
410
    my $branchcode  = "";
414
    my $branchfield = "reserves.branchcode";
411
    my $branchfield = "holds.pickup_library_id";
415
412
416
    if ( $controlbranch eq "ItemHomeLibrary" ) {
413
    if ( $controlbranch eq "ItemHomeLibrary" ) {
417
        $branchfield = "items.homebranch";
414
        $branchfield = "items.homebranch";
Lines 448-457 sub CanItemBeReserved { Link Here
448
    my $holds_per_day    = $rights->{holds_per_day};
445
    my $holds_per_day    = $rights->{holds_per_day};
449
446
450
    my $search_params = {
447
    my $search_params = {
451
        borrowernumber => $borrowernumber,
448
        patron_id => $borrowernumber,
452
        biblionumber   => $item->biblionumber,
449
        biblio_id => $item->biblionumber,
450
        completed => 0,
453
    };
451
    };
454
    $search_params->{found} = undef if $params->{ignore_found_holds};
452
    $search_params->{status} = 'placed' if $params->{ignore_found_holds};
455
453
456
    my $holds = Koha::Holds->search($search_params);
454
    my $holds = Koha::Holds->search($search_params);
457
    if (   defined $holds_per_record && $holds_per_record ne ''
455
    if (   defined $holds_per_record && $holds_per_record ne ''
Lines 460-467 sub CanItemBeReserved { Link Here
460
    }
458
    }
461
459
462
    my $today_holds = Koha::Holds->search({
460
    my $today_holds = Koha::Holds->search({
463
        borrowernumber => $borrowernumber,
461
        patron_id    => $borrowernumber,
464
        reservedate    => dt_from_string->date
462
        created_date => dt_from_string->date,
463
        completed    => 0
465
    });
464
    });
466
465
467
    if (   defined $holds_per_day && $holds_per_day ne ''
466
    if (   defined $holds_per_day && $holds_per_day ne ''
Lines 513-519 sub CanItemBeReserved { Link Here
513
    if ( $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
512
    if ( $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
514
        my $total_holds_count = Koha::Holds->search(
513
        my $total_holds_count = Koha::Holds->search(
515
            {
514
            {
516
                borrowernumber => $borrower->{borrowernumber}
515
                patron_id => $borrower->{borrowernumber},
516
                completed => 0
517
            }
517
            }
518
        )->count();
518
        )->count();
519
519
Lines 591-600 sub CanReserveBeCanceledFromOpac { Link Here
591
    my ($reserve_id, $borrowernumber) = @_;
591
    my ($reserve_id, $borrowernumber) = @_;
592
592
593
    return unless $reserve_id and $borrowernumber;
593
    return unless $reserve_id and $borrowernumber;
594
    my $reserve = Koha::Holds->find($reserve_id);
594
    my $hold = Koha::Holds->find($reserve_id);
595
595
596
    return 0 unless $reserve->borrowernumber == $borrowernumber;
596
    return 0 unless $hold->patron_id == $borrowernumber;
597
    return $reserve->is_cancelable_from_opac;
597
    return $hold->is_cancelable_from_opac;
598
}
598
}
599
599
600
=head2 GetOtherReserves
600
=head2 GetOtherReserves
Lines 612-630 sub GetOtherReserves { Link Here
612
    my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber);
612
    my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber);
613
    if ($checkreserves) {
613
    if ($checkreserves) {
614
        my $item = Koha::Items->find($itemnumber);
614
        my $item = Koha::Items->find($itemnumber);
615
        if ( $item->holdingbranch ne $checkreserves->{'branchcode'} ) {
615
        if ( $item->holdingbranch ne $checkreserves->{pickup_library_id} ) {
616
            $messages->{'transfert'} = $checkreserves->{'branchcode'};
616
            $messages->{'transfert'} = $checkreserves->{pickup_library_id};
617
            #minus priorities of others reservs
617
            #minus priorities of others reservs
618
            ModReserveMinusPriority(
618
            ModReserveMinusPriority(
619
                $itemnumber,
619
                $itemnumber,
620
                $checkreserves->{'reserve_id'},
620
                $checkreserves->{id},
621
            );
621
            );
622
622
623
            #launch the subroutine dotransfer
623
            #launch the subroutine dotransfer
624
            C4::Items::ModItemTransfer(
624
            C4::Items::ModItemTransfer(
625
                $itemnumber,
625
                $itemnumber,
626
                $item->holdingbranch,
626
                $item->holdingbranch,
627
                $checkreserves->{'branchcode'},
627
                $checkreserves->{pickup_library_id},
628
                'Reserve'
628
                'Reserve'
629
              ),
629
              ),
630
              ;
630
              ;
Lines 635-643 sub GetOtherReserves { Link Here
635
            $messages->{'waiting'} = 1;
635
            $messages->{'waiting'} = 1;
636
            ModReserveMinusPriority(
636
            ModReserveMinusPriority(
637
                $itemnumber,
637
                $itemnumber,
638
                $checkreserves->{'reserve_id'},
638
                $checkreserves->{id},
639
            );
639
            );
640
            ModReserveStatus($itemnumber,'W');
640
            ModReserveStatus($itemnumber,'waiting');
641
        }
641
        }
642
642
643
        $nextreservinfo = $checkreserves;
643
        $nextreservinfo = $checkreserves;
Lines 728-752 If several reserves exist, the reserve with the lower priority is given. Link Here
728
## multiple reserves for that bib can have the itemnumber set
728
## multiple reserves for that bib can have the itemnumber set
729
## the sub is only used once in the codebase.
729
## the sub is only used once in the codebase.
730
sub GetReserveStatus {
730
sub GetReserveStatus {
731
    my ($itemnumber) = @_;
731
    my ($item_id) = @_;
732
732
733
    my $dbh = C4::Context->dbh;
733
    my $holds_rs = Koha::Holds->search({ item_id => $item_id, completed => 0 }, { order_by => 'priority' });
734
734
735
    my ($sth, $found, $priority);
735
    if ( $holds_rs->count > 0 ) {
736
    if ( $itemnumber ) {
736
        # They are sorted by priority, pick the first one
737
        $sth = $dbh->prepare("SELECT found, priority FROM reserves WHERE itemnumber = ? order by priority LIMIT 1");
737
        my $hold = $holds_rs->next;
738
        $sth->execute($itemnumber);
739
        ($found, $priority) = $sth->fetchrow_array;
740
    }
741
738
742
    if(defined $found) {
739
        return 'Waiting'    if $hold->is_waiting and $hold->priority == 0;
743
        return 'Waiting'  if $found eq 'W' and $priority == 0;
740
        return 'Processing' if $hold->is_in_processing;
744
        return 'Processing'  if $found eq 'P';
741
        return 'Finished'   if $hold->status eq 'fulfilled';
745
        return 'Finished' if $found eq 'F';
742
        return 'Reserved'   if $hold->priority > 0;
746
    }
743
    }
747
744
748
    return 'Reserved' if defined $priority && $priority > 0;
749
750
    return ''; # empty string here will remove need for checking undef, or less log lines
745
    return ''; # empty string here will remove need for checking undef, or less log lines
751
}
746
}
752
747
Lines 785-791 sub CheckReserves { Link Here
785
    my $sth;
780
    my $sth;
786
    my $select;
781
    my $select;
787
    if (C4::Context->preference('item-level_itypes')){
782
    if (C4::Context->preference('item-level_itypes')){
788
	$select = "
783
    $select = "
789
           SELECT items.biblionumber,
784
           SELECT items.biblionumber,
790
           items.biblioitemnumber,
785
           items.biblioitemnumber,
791
           itemtypes.notforloan,
786
           itemtypes.notforloan,
Lines 800-806 sub CheckReserves { Link Here
800
        ";
795
        ";
801
    }
796
    }
802
    else {
797
    else {
803
	$select = "
798
    $select = "
804
           SELECT items.biblionumber,
799
           SELECT items.biblionumber,
805
           items.biblioitemnumber,
800
           items.biblioitemnumber,
806
           itemtypes.notforloan,
801
           itemtypes.notforloan,
Lines 853-862 sub CheckReserves { Link Here
853
848
854
        my $priority = 10000000;
849
        my $priority = 10000000;
855
        foreach my $res (@reserves) {
850
        foreach my $res (@reserves) {
856
            if ( $res->{'itemnumber'} && $res->{'itemnumber'} == $itemnumber && $res->{'priority'} == 0) {
851
            if ( $res->{item_id} && $res->{item_id} == $itemnumber && $res->{priority} == 0) {
857
                if ($res->{'found'} eq 'W') {
852
                if ($res->{status} eq 'waiting') {
858
                    return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
853
                    return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
859
                } elsif ($res->{'found'} eq 'P') {
854
                } elsif ($res->{'status'} eq 'processing') {
860
                    return ( "Processing", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
855
                    return ( "Processing", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
861
                 } else {
856
                 } else {
862
                    return ( "Reserved", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
857
                    return ( "Reserved", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
Lines 867-873 sub CheckReserves { Link Here
867
                my $local_hold_match;
862
                my $local_hold_match;
868
863
869
                if ($LocalHoldsPriority) {
864
                if ($LocalHoldsPriority) {
870
                    $patron = Koha::Patrons->find( $res->{borrowernumber} );
865
                    $patron = Koha::Patrons->find( $res->{patron_id} );
871
                    $item = Koha::Items->find($itemnumber);
866
                    $item = Koha::Items->find($itemnumber);
872
867
873
                    unless ($item->exclude_from_local_holds_priority || $patron->category->exclude_from_local_holds_priority) {
868
                    unless ($item->exclude_from_local_holds_priority || $patron->category->exclude_from_local_holds_priority) {
Lines 875-881 sub CheckReserves { Link Here
875
                            $item->$LocalHoldsPriorityItemControl;
870
                            $item->$LocalHoldsPriorityItemControl;
876
                        my $local_holds_priority_patron_branchcode =
871
                        my $local_holds_priority_patron_branchcode =
877
                            ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
872
                            ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
878
                            ? $res->{branchcode}
873
                            ? $res->{pickup_library_id}
879
                            : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )
874
                            : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )
880
                            ? $patron->branchcode
875
                            ? $patron->branchcode
881
                            : undef;
876
                            : undef;
Lines 886-895 sub CheckReserves { Link Here
886
                }
881
                }
887
882
888
                # See if this item is more important than what we've got so far
883
                # See if this item is more important than what we've got so far
889
                if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
884
                if ( ( $res->{priority} && $res->{priority} < $priority ) || $local_hold_match ) {
890
                    $item ||= Koha::Items->find($itemnumber);
885
                    $item ||= Koha::Items->find($itemnumber);
891
                    next if $res->{itemtype} && $res->{itemtype} ne $item->effective_itemtype;
886
                    next if $res->{item_type} && $res->{item_type} ne $item->effective_itemtype;
892
                    $patron ||= Koha::Patrons->find( $res->{borrowernumber} );
887
                    $patron ||= Koha::Patrons->find( $res->{patron_id} );
893
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
888
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
894
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
889
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
895
                    next if ($branchitemrule->{'holdallowed'} == 0);
890
                    next if ($branchitemrule->{'holdallowed'} == 0);
Lines 897-906 sub CheckReserves { Link Here
897
                    my $library = Koha::Libraries->find({branchcode=>$item->homebranch});
892
                    my $library = Koha::Libraries->find({branchcode=>$item->homebranch});
898
                    next if (($branchitemrule->{'holdallowed'} == 3) && (!$library->validate_hold_sibling({branchcode => $patron->branchcode}) ));
893
                    next if (($branchitemrule->{'holdallowed'} == 3) && (!$library->validate_hold_sibling({branchcode => $patron->branchcode}) ));
899
                    my $hold_fulfillment_policy = $branchitemrule->{hold_fulfillment_policy};
894
                    my $hold_fulfillment_policy = $branchitemrule->{hold_fulfillment_policy};
900
                    next if ( ($hold_fulfillment_policy eq 'holdgroup') && (!$library->validate_hold_sibling({branchcode => $res->{branchcode}})) );
895
                    next if ( ($hold_fulfillment_policy eq 'holdgroup') && (!$library->validate_hold_sibling({branchcode => $res->{pickup_library_id}})) );
901
                    next if ( ($hold_fulfillment_policy eq 'homebranch') && ($res->{branchcode} ne $item->$hold_fulfillment_policy) );
896
                    next if ( ($hold_fulfillment_policy eq 'homebranch') && ($res->{pickup_library_id} ne $item->$hold_fulfillment_policy) );
902
                    next if ( ($hold_fulfillment_policy eq 'holdingbranch') && ($res->{branchcode} ne $item->$hold_fulfillment_policy) );
897
                    next if ( ($hold_fulfillment_policy eq 'holdingbranch') && ($res->{pickup_library_id} ne $item->$hold_fulfillment_policy) );
903
                    next unless $item->can_be_transferred( { to => Koha::Libraries->find( $res->{branchcode} ) } );
898
                    next unless $item->can_be_transferred( { to => Koha::Libraries->find( $res->{pickup_library_id} ) } );
904
                    $priority = $res->{'priority'};
899
                    $priority = $res->{'priority'};
905
                    $highest  = $res;
900
                    $highest  = $res;
906
                    last if $local_hold_match;
901
                    last if $local_hold_match;
Lines 934-953 sub CancelExpiredReserves { Link Here
934
    my $expireWaiting = C4::Context->preference('ExpireReservesMaxPickUpDelay');
929
    my $expireWaiting = C4::Context->preference('ExpireReservesMaxPickUpDelay');
935
930
936
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
931
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
937
    my $params = { expirationdate => { '<', $dtf->format_date($today) } };
932
    my $params = { expiration_date => { '<', $dtf->format_date($today) } };
938
    $params->{found} = [ { '!=', 'W' }, undef ]  unless $expireWaiting;
933
    $params->{status} = [ { '!=', 'waiting' }, undef ]  unless $expireWaiting;
939
934
940
    # FIXME To move to Koha::Holds->search_expired (?)
935
    # FIXME To move to Koha::Holds->search_expired (?)
941
    my $holds = Koha::Holds->search( $params );
936
    my $holds = Koha::Holds->search( $params );
942
937
943
    while ( my $hold = $holds->next ) {
938
    while ( my $hold = $holds->next ) {
944
        my $calendar = Koha::Calendar->new( branchcode => $hold->branchcode );
939
        my $calendar = Koha::Calendar->new( branchcode => $hold->pickup_library_id );
945
940
946
        next if !$cancel_on_holidays && $calendar->is_holiday( $today );
941
        next if !$cancel_on_holidays && $calendar->is_holiday( $today );
947
942
948
        my $cancel_params = {};
943
        my $cancel_params = {};
949
        $cancel_params->{cancellation_reason} = $cancellation_reason if defined($cancellation_reason);
944
        $cancel_params->{cancellation_reason} = $cancellation_reason if defined($cancellation_reason);
950
        if ( defined($hold->found) && $hold->found eq 'W' ) {
945
        if ( $hold->is_waiting ) {
951
            $cancel_params->{charge_cancel_fee} = 1;
946
            $cancel_params->{charge_cancel_fee} = 1;
952
        }
947
        }
953
        $hold->cancel( $cancel_params );
948
        $hold->cancel( $cancel_params );
Lines 958-971 sub CancelExpiredReserves { Link Here
958
953
959
  AutoUnsuspendReserves();
954
  AutoUnsuspendReserves();
960
955
961
Unsuspends all suspended reserves with a suspend_until date from before today.
956
Unsuspends all suspended reserves with a suspended_until date from before today.
962
957
963
=cut
958
=cut
964
959
965
sub AutoUnsuspendReserves {
960
sub AutoUnsuspendReserves {
966
    my $today = dt_from_string();
961
    my $today = dt_from_string();
967
962
968
    my @holds = Koha::Holds->search( { suspend_until => { '<=' => $today->ymd() } } );
963
    my @holds = Koha::Holds->search( { suspended_until_date => { '<=' => $today->ymd() } } );
969
964
970
    map { $_->resume() } @holds;
965
    map { $_->resume() } @holds;
971
}
966
}
Lines 1025-1034 sub ModReserve { Link Here
1025
1020
1026
    my $hold;
1021
    my $hold;
1027
    unless ( $reserve_id ) {
1022
    unless ( $reserve_id ) {
1028
        my $holds = Koha::Holds->search({ biblionumber => $biblionumber, borrowernumber => $borrowernumber, itemnumber => $itemnumber });
1023
        my $holds = Koha::Holds->search({ biblio_id => $biblionumber, patron_id => $borrowernumber, item_id => $itemnumber });
1029
        return unless $holds->count; # FIXME Should raise an exception
1024
        return unless $holds->count; # FIXME Should raise an exception
1030
        $hold = $holds->next;
1025
        $hold = $holds->next;
1031
        $reserve_id = $hold->reserve_id;
1026
        $reserve_id = $hold->id;
1032
    }
1027
    }
1033
1028
1034
    $hold ||= Koha::Holds->find($reserve_id);
1029
    $hold ||= Koha::Holds->find($reserve_id);
Lines 1037-1057 sub ModReserve { Link Here
1037
        $hold->cancel({ cancellation_reason => $cancellation_reason });
1032
        $hold->cancel({ cancellation_reason => $cancellation_reason });
1038
    }
1033
    }
1039
    elsif ($rank =~ /^\d+/ and $rank > 0) {
1034
    elsif ($rank =~ /^\d+/ and $rank > 0) {
1040
        logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
1035
        logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->unblessed) )
1041
            if C4::Context->preference('HoldsLog');
1036
            if C4::Context->preference('HoldsLog');
1042
1037
1043
        my $properties = {
1038
        my $properties = {
1044
            priority    => $rank,
1039
            priority     => $rank,
1045
            branchcode  => $branchcode,
1040
            pickup_library_id => $branchcode,
1046
            itemnumber  => $itemnumber,
1041
            item_id      => $itemnumber,
1047
            found       => undef,
1042
            status       => 'placed',
1048
            waitingdate => undef
1043
            waiting_date => undef
1049
        };
1044
        };
1050
        if (exists $params->{reservedate}) {
1045
        if (exists $params->{reservedate}) {
1051
            $properties->{reservedate} = $params->{reservedate} || undef;
1046
            $properties->{created_date} = $params->{reservedate} || undef;
1052
        }
1047
        }
1053
        if (exists $params->{expirationdate}) {
1048
        if (exists $params->{expirationdate}) {
1054
            $properties->{expirationdate} = $params->{expirationdate} || undef;
1049
            $properties->{expiration_date} = $params->{expirationdate} || undef;
1055
        }
1050
        }
1056
1051
1057
        $hold->set($properties)->store();
1052
        $hold->set($properties)->store();
Lines 1063-1069 sub ModReserve { Link Here
1063
            } else {
1058
            } else {
1064
                # If the hold is suspended leave the hold suspended, but convert it to an indefinite hold.
1059
                # If the hold is suspended leave the hold suspended, but convert it to an indefinite hold.
1065
                # If the hold is not suspended, this does nothing.
1060
                # If the hold is not suspended, this does nothing.
1066
                $hold->set( { suspend_until => undef } )->store();
1061
                $hold->set( { suspended_until_date => undef } )->store();
1067
            }
1062
            }
1068
        }
1063
        }
1069
1064
Lines 1085-1121 whose keys are fields from the reserves table in the Koha database. Link Here
1085
1080
1086
sub ModReserveFill {
1081
sub ModReserveFill {
1087
    my ($res) = @_;
1082
    my ($res) = @_;
1088
    my $reserve_id = $res->{'reserve_id'};
1083
    my $reserve_id = $res->{'id'};
1089
1084
1090
    my $hold = Koha::Holds->find($reserve_id);
1085
    my $hold = Koha::Holds->find($reserve_id);
1091
    # get the priority on this record....
1086
    # get the priority on this record....
1092
    my $priority = $hold->priority;
1087
    my $priority = $hold->priority;
1093
1088
1094
    # update the hold statuses, no need to store it though, we will be deleting it anyway
1089
    # update the hold statuses, no need to store it though, we will be deleting it anyway
1090
    # FIXME: Add Koha::Hold->set_filled and add the correct log
1095
    $hold->set(
1091
    $hold->set(
1096
        {
1092
        {
1097
            found    => 'F',
1093
            status    => 'fulfilled',
1098
            priority => 0,
1094
            priority  => 0,
1095
            completed => 1,
1096
            completed_date => \'NOW()'
1099
        }
1097
        }
1100
    );
1098
    );
1101
1099
1102
    logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
1100
    logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->unblessed) )
1103
        if C4::Context->preference('HoldsLog');
1101
        if C4::Context->preference('HoldsLog');
1104
1102
1105
    # FIXME Must call Koha::Hold->cancel ? => No, should call ->filled and add the correct log
1103
    $hold->store();
1106
    Koha::Old::Hold->new( $hold->unblessed() )->store();
1107
1108
    $hold->delete();
1109
1104
1110
    if ( C4::Context->preference('HoldFeeMode') eq 'any_time_is_collected' ) {
1105
    if ( C4::Context->preference('HoldFeeMode') eq 'any_time_is_collected' ) {
1111
        my $reserve_fee = GetReserveFee( $hold->borrowernumber, $hold->biblionumber );
1106
        my $reserve_fee = GetReserveFee( $hold->patron_id, $hold->biblio_id );
1112
        ChargeReserveFee( $hold->borrowernumber, $reserve_fee, $hold->biblio->title );
1107
        ChargeReserveFee( $hold->patron_id, $reserve_fee, $hold->biblio->title );
1113
    }
1108
    }
1114
1109
1115
    # now fix the priority on the others (if the priority wasn't
1110
    # now fix the priority on the others (if the priority wasn't
1116
    # already sorted!)....
1111
    # already sorted!)....
1117
    unless ( $priority == 0 ) {
1112
    unless ( $priority == 0 ) {
1118
        _FixPriority( { reserve_id => $reserve_id, biblionumber => $hold->biblionumber } );
1113
        _FixPriority( { reserve_id => $reserve_id, biblionumber => $hold->biblio_id } );
1119
    }
1114
    }
1120
}
1115
}
1121
1116
Lines 1137-1143 sub ModReserveStatus { Link Here
1137
    my ($itemnumber, $newstatus) = @_;
1132
    my ($itemnumber, $newstatus) = @_;
1138
    my $dbh = C4::Context->dbh;
1133
    my $dbh = C4::Context->dbh;
1139
1134
1140
    my $query = "UPDATE reserves SET found = ?, waitingdate = NOW() WHERE itemnumber = ? AND found IS NULL AND priority = 0";
1135
    my $query = "UPDATE holds SET status = ?, waiting_date = NOW() WHERE item_id = ? AND status='placed' AND priority = 0";
1141
    my $sth_set = $dbh->prepare($query);
1136
    my $sth_set = $dbh->prepare($query);
1142
    $sth_set->execute( $newstatus, $itemnumber );
1137
    $sth_set->execute( $newstatus, $itemnumber );
1143
1138
Lines 1181-1195 sub ModReserveAffect { Link Here
1181
    # Find hold by id if we have it
1176
    # Find hold by id if we have it
1182
    $hold = Koha::Holds->find( $reserve_id ) if $reserve_id;
1177
    $hold = Koha::Holds->find( $reserve_id ) if $reserve_id;
1183
    # Find item level hold for this item if there is one
1178
    # Find item level hold for this item if there is one
1184
    $hold ||= Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->next();
1179
    $hold ||= Koha::Holds->search( { patron_id => $borrowernumber, item_id => $itemnumber } )->next();
1185
    # Find record level hold if there is no item level hold
1180
    # Find record level hold if there is no item level hold
1186
    $hold ||= Koha::Holds->search( { borrowernumber => $borrowernumber, biblionumber => $biblionumber } )->next();
1181
    $hold ||= Koha::Holds->search( { patron_id => $borrowernumber, biblio_id => $biblionumber } )->next();
1187
1182
1188
    return unless $hold;
1183
    return unless $hold;
1189
1184
1190
    my $already_on_shelf = $hold->found && $hold->found eq 'W';
1185
    my $already_on_shelf = $hold->status eq 'waiting';
1191
1186
1192
    $hold->itemnumber($itemnumber);
1187
    $hold->item_id($itemnumber);
1193
1188
1194
    if ($transferToDo) {
1189
    if ($transferToDo) {
1195
        $hold->set_transfer();
1190
        $hold->set_transfer();
Lines 1199-1205 sub ModReserveAffect { Link Here
1199
        $hold->set_processing();
1194
        $hold->set_processing();
1200
    } else {
1195
    } else {
1201
        $hold->set_waiting($desk_id);
1196
        $hold->set_waiting($desk_id);
1202
        _koha_notify_reserve( $hold->reserve_id ) unless $already_on_shelf;
1197
        _koha_notify_reserve( $hold->id ) unless $already_on_shelf;
1203
        # Complete transfer if one exists
1198
        # Complete transfer if one exists
1204
        my $transfer = $hold->item->get_transfer;
1199
        my $transfer = $hold->item->get_transfer;
1205
        $transfer->receive if $transfer;
1200
        $transfer->receive if $transfer;
Lines 1212-1218 sub ModReserveAffect { Link Here
1212
      CartToShelf( $itemnumber );
1207
      CartToShelf( $itemnumber );
1213
    }
1208
    }
1214
1209
1215
    logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
1210
    logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->unblessed) )
1216
        if C4::Context->preference('HoldsLog');
1211
        if C4::Context->preference('HoldsLog');
1217
1212
1218
    return;
1213
    return;
Lines 1229-1243 function to cancel reserv,check other reserves, and transfer document if it's ne Link Here
1229
sub ModReserveCancelAll {
1224
sub ModReserveCancelAll {
1230
    my $messages;
1225
    my $messages;
1231
    my $nextreservinfo;
1226
    my $nextreservinfo;
1232
    my ( $itemnumber, $borrowernumber, $cancellation_reason ) = @_;
1227
    my ( $item_id, $patron_id, $cancellation_reason ) = @_;
1233
1228
1234
    #step 1 : cancel the reservation
1229
    #step 1 : cancel the reservation
1235
    my $holds = Koha::Holds->search({ itemnumber => $itemnumber, borrowernumber => $borrowernumber });
1230
    my $holds = Koha::Holds->search({ item_id => $item_id, patron_id => $patron_id });
1236
    return unless $holds->count;
1231
    return unless $holds->count;
1237
    $holds->next->cancel({ cancellation_reason => $cancellation_reason });
1232
    $holds->next->cancel({ cancellation_reason => $cancellation_reason });
1238
1233
1239
    #step 2 launch the subroutine of the others reserves
1234
    #step 2 launch the subroutine of the others reserves
1240
    ( $messages, $nextreservinfo ) = GetOtherReserves($itemnumber);
1235
    ( $messages, $nextreservinfo ) = GetOtherReserves($item_id);
1241
1236
1242
    return ( $messages, $nextreservinfo->{borrowernumber} );
1237
    return ( $messages, $nextreservinfo->{borrowernumber} );
1243
}
1238
}
Lines 1251-1267 Reduce the values of queued list Link Here
1251
=cut
1246
=cut
1252
1247
1253
sub ModReserveMinusPriority {
1248
sub ModReserveMinusPriority {
1254
    my ( $itemnumber, $reserve_id ) = @_;
1249
    my ( $item_id, $reserve_id ) = @_;
1255
1250
1256
    #first step update the value of the first person on reserv
1251
    #first step update the value of the first person on reserv
1257
    my $dbh   = C4::Context->dbh;
1252
    my $dbh   = C4::Context->dbh;
1258
    my $query = "
1253
    my $query = "
1259
        UPDATE reserves
1254
        UPDATE holds
1260
        SET    priority = 0 , itemnumber = ?
1255
        SET    priority = 0 , item_id = ?
1261
        WHERE  reserve_id = ?
1256
        WHERE  id = ?
1262
    ";
1257
    ";
1263
    my $sth_upd = $dbh->prepare($query);
1258
    my $sth_upd = $dbh->prepare($query);
1264
    $sth_upd->execute( $itemnumber, $reserve_id );
1259
    $sth_upd->execute( $item_id, $reserve_id );
1265
    # second step update all others reserves
1260
    # second step update all others reserves
1266
    _FixPriority({ reserve_id => $reserve_id, rank => '0' });
1261
    _FixPriority({ reserve_id => $reserve_id, rank => '0' });
1267
}
1262
}
Lines 1405-1412 sub AlterPriority { Link Here
1405
    my $hold = Koha::Holds->find( $reserve_id );
1400
    my $hold = Koha::Holds->find( $reserve_id );
1406
    return unless $hold;
1401
    return unless $hold;
1407
1402
1408
    if ( $hold->cancellationdate ) {
1403
    if ( $hold->completed_date and $hold->status eq 'cancelled' ) {
1409
        warn "I cannot alter the priority for reserve_id $reserve_id, the reserve has been cancelled (" . $hold->cancellationdate . ')';
1404
        warn "I cannot alter the priority for reserve_id $reserve_id, the reserve has been cancelled (" . $hold->completed_date . ')';
1410
        return;
1405
        return;
1411
    }
1406
    }
1412
1407
Lines 1438-1444 sub ToggleLowestPriority { Link Here
1438
1433
1439
    my $dbh = C4::Context->dbh;
1434
    my $dbh = C4::Context->dbh;
1440
1435
1441
    my $sth = $dbh->prepare( "UPDATE reserves SET lowestPriority = NOT lowestPriority WHERE reserve_id = ?");
1436
    my $sth = $dbh->prepare( "UPDATE holds SET lowest_priority = NOT lowest_priority WHERE id = ?");
1442
    $sth->execute( $reserve_id );
1437
    $sth->execute( $reserve_id );
1443
1438
1444
    _FixPriority({ reserve_id => $reserve_id, rank => '999999' });
1439
    _FixPriority({ reserve_id => $reserve_id, rank => '999999' });
Lines 1498-1506 sub SuspendAll { Link Here
1498
    return unless ( $borrowernumber || $biblionumber );
1493
    return unless ( $borrowernumber || $biblionumber );
1499
1494
1500
    my $params;
1495
    my $params;
1501
    $params->{found}          = undef;
1496
    $params->{status} = 'placed';
1502
    $params->{borrowernumber} = $borrowernumber if $borrowernumber;
1497
    $params->{patron_id} = $borrowernumber if $borrowernumber;
1503
    $params->{biblionumber}   = $biblionumber if $biblionumber;
1498
    $params->{biblio_id} = $biblionumber if $biblionumber;
1504
1499
1505
    my @holds = Koha::Holds->search($params);
1500
    my @holds = Koha::Holds->search($params);
1506
1501
Lines 1560-1574 sub _FixPriority { Link Here
1560
    my $hold;
1555
    my $hold;
1561
    if ( $reserve_id ) {
1556
    if ( $reserve_id ) {
1562
        $hold = Koha::Holds->find( $reserve_id );
1557
        $hold = Koha::Holds->find( $reserve_id );
1563
        if (!defined $hold){
1564
            # may have already been checked out and hold fulfilled
1565
            $hold = Koha::Old::Holds->find( $reserve_id );
1566
        }
1567
        return unless $hold;
1558
        return unless $hold;
1568
    }
1559
    }
1569
1560
1570
    unless ( $biblionumber ) { # FIXME This is a very weird API
1561
    unless ( $biblionumber ) { # FIXME This is a very weird API
1571
        $biblionumber = $hold->biblionumber;
1562
        $biblionumber = $hold->biblio_id;
1572
    }
1563
    }
1573
1564
1574
    if ( $rank eq "del" ) { # FIXME will crash if called without $hold
1565
    if ( $rank eq "del" ) { # FIXME will crash if called without $hold
Lines 1578-1587 sub _FixPriority { Link Here
1578
1569
1579
        # make sure priority for waiting or in-transit items is 0
1570
        # make sure priority for waiting or in-transit items is 0
1580
        my $query = "
1571
        my $query = "
1581
            UPDATE reserves
1572
            UPDATE holds
1582
            SET    priority = 0
1573
            SET    priority = 0
1583
            WHERE reserve_id = ?
1574
            WHERE  id = ?
1584
            AND found IN ('W', 'T', 'P')
1575
            AND status IN ('waiting', 'in_transit', 'processing')
1585
        ";
1576
        ";
1586
        my $sth = $dbh->prepare($query);
1577
        my $sth = $dbh->prepare($query);
1587
        $sth->execute( $reserve_id );
1578
        $sth->execute( $reserve_id );
Lines 1590-1599 sub _FixPriority { Link Here
1590
1581
1591
    # get whats left
1582
    # get whats left
1592
    my $query = "
1583
    my $query = "
1593
        SELECT reserve_id, borrowernumber, reservedate
1584
        SELECT id
1594
        FROM   reserves
1585
        FROM   holds
1595
        WHERE  biblionumber   = ?
1586
        WHERE  biblio_id   = ?
1596
          AND  ((found <> 'W' AND found <> 'T' AND found <> 'P') OR found IS NULL)
1587
          AND  completed = 0
1588
          AND  status = 'placed'
1597
        ORDER BY priority ASC
1589
        ORDER BY priority ASC
1598
    ";
1590
    ";
1599
    my $sth = $dbh->prepare($query);
1591
    my $sth = $dbh->prepare($query);
Lines 1607-1613 sub _FixPriority { Link Here
1607
    my $i;
1599
    my $i;
1608
    my $key = -1;    # to allow for 0 to be a valid result
1600
    my $key = -1;    # to allow for 0 to be a valid result
1609
    for ( $i = 0 ; $i < @priority ; $i++ ) {
1601
    for ( $i = 0 ; $i < @priority ; $i++ ) {
1610
        if ( $reserve_id && $reserve_id == $priority[$i]->{'reserve_id'} ) {
1602
        if ( $reserve_id && $reserve_id == $priority[$i]->{'id'} ) {
1611
            $key = $i;    # save the index
1603
            $key = $i;    # save the index
1612
            last;
1604
            last;
1613
        }
1605
        }
Lines 1623-1647 sub _FixPriority { Link Here
1623
1615
1624
    # now fix the priority on those that are left....
1616
    # now fix the priority on those that are left....
1625
    $query = "
1617
    $query = "
1626
        UPDATE reserves
1618
        UPDATE holds
1627
        SET    priority = ?
1619
        SET    priority = ?
1628
        WHERE  reserve_id = ?
1620
        WHERE  id = ?
1629
    ";
1621
    ";
1630
    $sth = $dbh->prepare($query);
1622
    $sth = $dbh->prepare($query);
1631
    for ( my $j = 0 ; $j < @priority ; $j++ ) {
1623
    for ( my $j = 0 ; $j < @priority ; $j++ ) {
1632
        $sth->execute(
1624
        $sth->execute(
1633
            $j + 1,
1625
            $j + 1,
1634
            $priority[$j]->{'reserve_id'}
1626
            $priority[$j]->{'id'}
1635
        );
1627
        );
1636
    }
1628
    }
1637
1629
1638
    $sth = $dbh->prepare( "SELECT reserve_id FROM reserves WHERE lowestPriority = 1 ORDER BY priority" );
1630
    $sth = $dbh->prepare( "SELECT id FROM holds WHERE lowest_priority = 1 ORDER BY priority" );
1639
    $sth->execute();
1631
    $sth->execute();
1640
1632
1641
    unless ( $ignoreSetLowestRank ) {
1633
    unless ( $ignoreSetLowestRank ) {
1642
      while ( my $res = $sth->fetchrow_hashref() ) {
1634
      while ( my $res = $sth->fetchrow_hashref() ) {
1643
        _FixPriority({
1635
        _FixPriority({
1644
            reserve_id => $res->{'reserve_id'},
1636
            reserve_id => $res->{'id'},
1645
            rank => '999999',
1637
            rank => '999999',
1646
            ignoreSetLowestRank => 1
1638
            ignoreSetLowestRank => 1
1647
        });
1639
        });
Lines 1678-1706 sub _Findgroupreserve { Link Here
1678
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1670
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1679
    # check for exact targeted match
1671
    # check for exact targeted match
1680
    my $item_level_target_query = qq{
1672
    my $item_level_target_query = qq{
1681
        SELECT reserves.biblionumber        AS biblionumber,
1673
        SELECT holds.biblio_id         AS biblio_id,
1682
               reserves.borrowernumber      AS borrowernumber,
1674
               holds.patron_id         AS patron_id,
1683
               reserves.reservedate         AS reservedate,
1675
               holds.created_date      AS created_date,
1684
               reserves.branchcode          AS branchcode,
1676
               holds.pickup_library_id AS pickup_library_id,
1685
               reserves.cancellationdate    AS cancellationdate,
1677
               holds.completed_date   AS completed_date,
1686
               reserves.found               AS found,
1678
               holds.status            AS status,
1687
               reserves.reservenotes        AS reservenotes,
1679
               holds.notes             AS notes,
1688
               reserves.priority            AS priority,
1680
               holds.priority          AS priority,
1689
               reserves.timestamp           AS timestamp,
1681
               holds.timestamp         AS timestamp,
1690
               biblioitems.biblioitemnumber AS biblioitemnumber,
1682
               biblioitems.biblioitemnumber AS biblioitemnumber,
1691
               reserves.itemnumber          AS itemnumber,
1683
               holds.item_id           AS item_id,
1692
               reserves.reserve_id          AS reserve_id,
1684
               holds.id                AS id,
1693
               reserves.itemtype            AS itemtype,
1685
               holds.item_type         AS item_type,
1694
               reserves.non_priority        AS non_priority
1686
               holds.non_priority      AS non_priority
1695
        FROM reserves
1687
        FROM holds
1696
        JOIN biblioitems USING (biblionumber)
1688
        JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
1697
        JOIN hold_fill_targets USING (reserve_id)
1689
        JOIN hold_fill_targets ON (
1698
        WHERE found IS NULL
1690
                holds.biblio_id=hold_fill_targets.biblionumber
1691
            AND holds.patron_id=hold_fill_targets.borrowernumber
1692
            AND holds.item_id=hold_fill_targets.itemnumber)
1693
        WHERE status='placed'
1699
        AND priority > 0
1694
        AND priority > 0
1700
        AND item_level_request = 1
1695
        AND completed = 0
1701
        AND hold_fill_targets.itemnumber = ?
1696
        AND item_level = 1
1702
        AND reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1697
        AND item_id = ?
1703
        AND suspend = 0
1698
        AND created_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1699
        AND suspended = 0
1704
        ORDER BY priority
1700
        ORDER BY priority
1705
    };
1701
    };
1706
    my $sth = $dbh->prepare($item_level_target_query);
1702
    my $sth = $dbh->prepare($item_level_target_query);
Lines 1708-1742 sub _Findgroupreserve { Link Here
1708
    my @results;
1704
    my @results;
1709
    if ( my $data = $sth->fetchrow_hashref ) {
1705
    if ( my $data = $sth->fetchrow_hashref ) {
1710
        push( @results, $data )
1706
        push( @results, $data )
1711
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1707
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1712
    }
1708
    }
1713
    return @results if @results;
1709
    return @results if @results;
1714
1710
1715
    # check for title-level targeted match
1711
    # check for title-level targeted match
1716
    my $title_level_target_query = qq{
1712
    my $title_level_target_query = qq{
1717
        SELECT reserves.biblionumber        AS biblionumber,
1713
        SELECT holds.biblio_id         AS biblio_id,
1718
               reserves.borrowernumber      AS borrowernumber,
1714
               holds.patron_id         AS patron_id,
1719
               reserves.reservedate         AS reservedate,
1715
               holds.created_date      AS created_date,
1720
               reserves.branchcode          AS branchcode,
1716
               holds.pickup_library_id AS pickup_library_id,
1721
               reserves.cancellationdate    AS cancellationdate,
1717
               holds.completed_date   AS completed_date,
1722
               reserves.found               AS found,
1718
               holds.status            AS status,
1723
               reserves.reservenotes        AS reservenotes,
1719
               holds.notes             AS notes,
1724
               reserves.priority            AS priority,
1720
               holds.priority          AS priority,
1725
               reserves.timestamp           AS timestamp,
1721
               holds.timestamp         AS timestamp,
1726
               biblioitems.biblioitemnumber AS biblioitemnumber,
1722
               biblioitems.biblioitemnumber AS biblioitemnumber,
1727
               reserves.itemnumber          AS itemnumber,
1723
               holds.item_id           AS item_id,
1728
               reserves.reserve_id          AS reserve_id,
1724
               holds.id                AS id,
1729
               reserves.itemtype            AS itemtype,
1725
               holds.item_type         AS item_type,
1730
               reserves.non_priority        AS non_priority
1726
               holds.non_priority      AS non_priority
1731
        FROM reserves
1727
        FROM holds
1732
        JOIN biblioitems USING (biblionumber)
1728
        JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
1733
        JOIN hold_fill_targets USING (reserve_id)
1729
        JOIN hold_fill_targets ON (
1734
        WHERE found IS NULL
1730
                holds.biblio_id=hold_fill_targets.biblionumber
1731
            AND holds.patron_id=hold_fill_targets.borrowernumber)
1732
        WHERE status='placed'
1735
        AND priority > 0
1733
        AND priority > 0
1736
        AND item_level_request = 0
1734
        AND completed = 0
1735
        AND item_level = 0
1737
        AND hold_fill_targets.itemnumber = ?
1736
        AND hold_fill_targets.itemnumber = ?
1738
        AND reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1737
        AND created_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1739
        AND suspend = 0
1738
        AND suspended = 0
1740
        ORDER BY priority
1739
        ORDER BY priority
1741
    };
1740
    };
1742
    $sth = $dbh->prepare($title_level_target_query);
1741
    $sth = $dbh->prepare($title_level_target_query);
Lines 1744-1773 sub _Findgroupreserve { Link Here
1744
    @results = ();
1743
    @results = ();
1745
    if ( my $data = $sth->fetchrow_hashref ) {
1744
    if ( my $data = $sth->fetchrow_hashref ) {
1746
        push( @results, $data )
1745
        push( @results, $data )
1747
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1746
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1748
    }
1747
    }
1749
    return @results if @results;
1748
    return @results if @results;
1750
1749
1751
    my $query = qq{
1750
    my $query = qq{
1752
        SELECT reserves.biblionumber               AS biblionumber,
1751
        SELECT holds.biblio_id                  AS biblio_id,
1753
               reserves.borrowernumber             AS borrowernumber,
1752
               holds.patron_id                  AS patron_id,
1754
               reserves.reservedate                AS reservedate,
1753
               holds.created_date               AS created_date,
1755
               reserves.waitingdate                AS waitingdate,
1754
               holds.waiting_date               AS waiting_date,
1756
               reserves.branchcode                 AS branchcode,
1755
               holds.pickup_library_id          AS pickup_library_id,
1757
               reserves.cancellationdate           AS cancellationdate,
1756
               holds.completed_date             AS completed_date,
1758
               reserves.found                      AS found,
1757
               holds.status                     AS status,
1759
               reserves.reservenotes               AS reservenotes,
1758
               holds.notes                      AS notes,
1760
               reserves.priority                   AS priority,
1759
               holds.priority                   AS priority,
1761
               reserves.timestamp                  AS timestamp,
1760
               holds.timestamp                  AS timestamp,
1762
               reserves.itemnumber                 AS itemnumber,
1761
               holds.item_id                    AS item_id,
1763
               reserves.reserve_id                 AS reserve_id,
1762
               holds.id                         AS id,
1764
               reserves.itemtype                   AS itemtype,
1763
               holds.item_type                  AS item_type,
1765
               reserves.non_priority        AS non_priority
1764
               holds.non_priority               AS non_priority
1766
        FROM reserves
1765
        FROM holds
1767
        WHERE reserves.biblionumber = ?
1766
        WHERE holds.biblio_id = ?
1768
          AND (reserves.itemnumber IS NULL OR reserves.itemnumber = ?)
1767
          AND (holds.item_id IS NULL OR holds.item_id = ?)
1769
          AND reserves.reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1768
          AND holds.created_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1770
          AND suspend = 0
1769
          AND suspended = 0
1770
          AND completed = 0
1771
          ORDER BY priority
1771
          ORDER BY priority
1772
    };
1772
    };
1773
    $sth = $dbh->prepare($query);
1773
    $sth = $dbh->prepare($query);
Lines 1775-1781 sub _Findgroupreserve { Link Here
1775
    @results = ();
1775
    @results = ();
1776
    while ( my $data = $sth->fetchrow_hashref ) {
1776
    while ( my $data = $sth->fetchrow_hashref ) {
1777
        push( @results, $data )
1777
        push( @results, $data )
1778
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1778
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1779
    }
1779
    }
1780
    return @results;
1780
    return @results;
1781
}
1781
}
Lines 1811-1817 The following tables are availalbe witin the notice: Link Here
1811
sub _koha_notify_reserve {
1811
sub _koha_notify_reserve {
1812
    my $reserve_id = shift;
1812
    my $reserve_id = shift;
1813
    my $hold = Koha::Holds->find($reserve_id);
1813
    my $hold = Koha::Holds->find($reserve_id);
1814
    my $borrowernumber = $hold->borrowernumber;
1814
    my $borrowernumber = $hold->patron_id;
1815
1815
1816
    my $patron = Koha::Patrons->find( $borrowernumber );
1816
    my $patron = Koha::Patrons->find( $borrowernumber );
1817
1817
Lines 1823-1843 sub _koha_notify_reserve { Link Here
1823
            message_name => 'Hold_Filled'
1823
            message_name => 'Hold_Filled'
1824
    } );
1824
    } );
1825
1825
1826
    my $library = Koha::Libraries->find( $hold->branchcode )->unblessed;
1826
    my $library = Koha::Libraries->find( $hold->pickup_library_id )->unblessed;
1827
1827
1828
    my $admin_email_address = $library->{branchemail} || C4::Context->preference('KohaAdminEmailAddress');
1828
    my $admin_email_address = $library->{branchemail} || C4::Context->preference('KohaAdminEmailAddress');
1829
1829
1830
    my %letter_params = (
1830
    my %letter_params = (
1831
        module => 'reserves',
1831
        module => 'reserves',
1832
        branchcode => $hold->branchcode,
1832
        branchcode => $hold->pickup_library_id,
1833
        lang => $patron->lang,
1833
        lang => $patron->lang,
1834
        tables => {
1834
        tables => {
1835
            'branches'       => $library,
1835
            'branches'       => $library,
1836
            'borrowers'      => $patron->unblessed,
1836
            'borrowers'      => $patron->unblessed,
1837
            'biblio'         => $hold->biblionumber,
1837
            'biblio'         => $hold->biblio_id,
1838
            'biblioitems'    => $hold->biblionumber,
1838
            'biblioitems'    => $hold->biblio_id,
1839
            'reserves'       => $hold->unblessed,
1839
            'reserves'       => $hold->unblessed,
1840
            'items'          => $hold->itemnumber,
1840
            'items'          => $hold->item_id,
1841
        },
1841
        },
1842
    );
1842
    );
1843
1843
Lines 1901-1907 sub _ShiftPriorityByDateAndPriority { Link Here
1901
    my ( $biblio, $resdate, $new_priority ) = @_;
1901
    my ( $biblio, $resdate, $new_priority ) = @_;
1902
1902
1903
    my $dbh = C4::Context->dbh;
1903
    my $dbh = C4::Context->dbh;
1904
    my $query = "SELECT priority FROM reserves WHERE biblionumber = ? AND ( reservedate > ? OR priority > ? ) ORDER BY priority ASC LIMIT 1";
1904
    my $query = "SELECT priority FROM holds WHERE biblio_id = ? AND ( created_date > ? OR priority > ? ) AND completed = 0 ORDER BY priority ASC LIMIT 1";
1905
    my $sth = $dbh->prepare( $query );
1905
    my $sth = $dbh->prepare( $query );
1906
    $sth->execute( $biblio, $resdate, $new_priority );
1906
    $sth->execute( $biblio, $resdate, $new_priority );
1907
    my $min_priority = $sth->fetchrow;
1907
    my $min_priority = $sth->fetchrow;
Lines 1909-1928 sub _ShiftPriorityByDateAndPriority { Link Here
1909
    $new_priority = $min_priority if ( $min_priority );
1909
    $new_priority = $min_priority if ( $min_priority );
1910
1910
1911
    # Shift the priority up by one; works in conjunction with the next SQL statement
1911
    # Shift the priority up by one; works in conjunction with the next SQL statement
1912
    $query = "UPDATE reserves
1912
    $query = "UPDATE holds
1913
              SET priority = priority+1
1913
              SET priority = priority+1
1914
              WHERE biblionumber = ?
1914
              WHERE biblio_id = ?
1915
              AND borrowernumber = ?
1915
              AND patron_id = ?
1916
              AND reservedate = ?
1916
              AND created_date = ?
1917
              AND found IS NULL";
1917
              AND status = 'placed'";
1918
    my $sth_update = $dbh->prepare( $query );
1918
    my $sth_update = $dbh->prepare( $query );
1919
1919
1920
    # Select all reserves for the biblio with priority greater than $new_priority, and order greatest to least
1920
    # Select all reserves for the biblio with priority greater than $new_priority, and order greatest to least
1921
    $query = "SELECT borrowernumber, reservedate FROM reserves WHERE priority >= ? AND biblionumber = ? ORDER BY priority DESC";
1921
    $query = "SELECT patron_id, created_date FROM holds WHERE priority >= ? AND biblio_id = ? ORDER BY priority DESC";
1922
    $sth = $dbh->prepare( $query );
1922
    $sth = $dbh->prepare( $query );
1923
    $sth->execute( $new_priority, $biblio );
1923
    $sth->execute( $new_priority, $biblio );
1924
    while ( my $row = $sth->fetchrow_hashref ) {
1924
    while ( my $row = $sth->fetchrow_hashref ) {
1925
	$sth_update->execute( $biblio, $row->{borrowernumber}, $row->{reservedate} );
1925
    $sth_update->execute( $biblio, $row->{patron_id}, $row->{created_date} );
1926
    }
1926
    }
1927
1927
1928
    return $new_priority;  # so the caller knows what priority they wind up receiving
1928
    return $new_priority;  # so the caller knows what priority they wind up receiving
Lines 1946-1954 sub MoveReserve { Link Here
1946
    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
1946
    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
1947
    return unless $res;
1947
    return unless $res;
1948
1948
1949
    my $biblionumber     =  $res->{biblionumber};
1949
    my $biblionumber = $res->{biblio_id};
1950
1950
1951
    if ($res->{borrowernumber} == $borrowernumber) {
1951
    if ($res->{patron_id} == $borrowernumber) {
1952
        ModReserveFill($res);
1952
        ModReserveFill($res);
1953
    }
1953
    }
1954
    else {
1954
    else {
Lines 1957-1964 sub MoveReserve { Link Here
1957
        # Find this item in the reserves
1957
        # Find this item in the reserves
1958
1958
1959
        my $borr_res  = Koha::Holds->search({
1959
        my $borr_res  = Koha::Holds->search({
1960
            borrowernumber => $borrowernumber,
1960
            patron_id => $borrowernumber,
1961
            biblionumber   => $biblionumber,
1961
            biblio_id => $biblionumber,
1962
        },{
1962
        },{
1963
            order_by       => 'priority'
1963
            order_by       => 'priority'
1964
        })->next();
1964
        })->next();
Lines 1972-1978 sub MoveReserve { Link Here
1972
            RevertWaitingStatus({ itemnumber => $itemnumber });
1972
            RevertWaitingStatus({ itemnumber => $itemnumber });
1973
        }
1973
        }
1974
        elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item
1974
        elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item
1975
            my $hold = Koha::Holds->find( $res->{reserve_id} );
1975
            my $hold = Koha::Holds->find( $res->{id} );
1976
            $hold->cancel;
1976
            $hold->cancel;
1977
        }
1977
        }
1978
    }
1978
    }
Lines 1989-2021 This shifts the holds from C<$from_biblio> to C<$to_biblio> and reorders them by Link Here
1989
sub MergeHolds {
1989
sub MergeHolds {
1990
    my ( $dbh, $to_biblio, $from_biblio ) = @_;
1990
    my ( $dbh, $to_biblio, $from_biblio ) = @_;
1991
    my $sth = $dbh->prepare(
1991
    my $sth = $dbh->prepare(
1992
        "SELECT count(*) as reserve_count FROM reserves WHERE biblionumber = ?"
1992
        "SELECT count(*) as reserve_count FROM holds WHERE biblio_id = ? AND completed = 0"
1993
    );
1993
    );
1994
    $sth->execute($from_biblio);
1994
    $sth->execute($from_biblio);
1995
    if ( my $data = $sth->fetchrow_hashref() ) {
1995
    if ( my $data = $sth->fetchrow_hashref() ) {
1996
1996
1997
        # holds exist on old record, if not we don't need to do anything
1997
        # holds exist on old record, if not we don't need to do anything
1998
        $sth = $dbh->prepare(
1998
        $sth = $dbh->prepare(
1999
            "UPDATE reserves SET biblionumber = ? WHERE biblionumber = ?");
1999
            "UPDATE holds SET biblio_id = ? WHERE biblio_id = ?");
2000
        $sth->execute( $to_biblio, $from_biblio );
2000
        $sth->execute( $to_biblio, $from_biblio );
2001
2001
2002
        # Reorder by date
2002
        # Reorder by date
2003
        # don't reorder those already waiting
2003
        # don't reorder those already waiting
2004
2004
2005
        $sth = $dbh->prepare(
2005
        $sth = $dbh->prepare(
2006
"SELECT * FROM reserves WHERE biblionumber = ? AND (found NOT IN ('W', 'T', 'P') OR found is NULL) ORDER BY reservedate ASC"
2006
            "SELECT id FROM holds WHERE biblio_id = ? AND status = 'placed' AND completed = 0 ORDER BY created_date ASC"
2007
        );
2007
        );
2008
        my $upd_sth = $dbh->prepare(
2008
        my $upd_sth = $dbh->prepare(
2009
"UPDATE reserves SET priority = ? WHERE biblionumber = ? AND borrowernumber = ?
2009
            "UPDATE holds SET priority = ? WHERE id = ? "
2010
        AND reservedate = ? AND (itemnumber = ? or itemnumber is NULL) "
2011
        );
2010
        );
2012
        $sth->execute( $to_biblio );
2011
        $sth->execute( $to_biblio );
2013
        my $priority = 1;
2012
        my $priority = 1;
2014
        while ( my $reserve = $sth->fetchrow_hashref() ) {
2013
        while ( my $reserve = $sth->fetchrow_hashref() ) {
2015
            $upd_sth->execute(
2014
            $upd_sth->execute(
2016
                $priority,                    $to_biblio,
2015
                $priority,
2017
                $reserve->{'borrowernumber'}, $reserve->{'reservedate'},
2016
                $reserve->{'id'}
2018
                $reserve->{'itemnumber'}
2019
            );
2017
            );
2020
            $priority++;
2018
            $priority++;
2021
        }
2019
        }
Lines 2038-2073 sub MergeHolds { Link Here
2038
2036
2039
sub RevertWaitingStatus {
2037
sub RevertWaitingStatus {
2040
    my ( $params ) = @_;
2038
    my ( $params ) = @_;
2041
    my $itemnumber = $params->{'itemnumber'};
2039
    my $item_id = $params->{'itemnumber'};
2042
2040
2043
    return unless ( $itemnumber );
2041
    return unless ( $item_id );
2044
2045
    my $dbh = C4::Context->dbh;
2046
2042
2047
    ## Get the waiting reserve we want to revert
2043
    ## Get the waiting reserve we want to revert
2048
    my $hold = Koha::Holds->search(
2044
    my $hold = Koha::Holds->search(
2049
        {
2045
        {
2050
            itemnumber => $itemnumber,
2046
            item_id => $item_id,
2051
            found => { not => undef },
2047
            status => 'waiting',
2052
        }
2048
        }
2053
    )->next;
2049
    )->next;
2054
2050
2055
    ## Increment the priority of all other non-waiting
2051
    ## Increment the priority of all other non-waiting
2056
    ## reserves for this bib record
2052
    ## reserves for this bib record
2057
    my $holds = Koha::Holds->search({ biblionumber => $hold->biblionumber, priority => { '>' => 0 } })
2053
    my $holds = Koha::Holds->search({ biblio_id => $hold->biblio_id, priority => { '>' => 0 } })
2058
                           ->update({ priority => \'priority + 1' }, { no_triggers => 1 });
2054
                           ->update({ priority => \'priority + 1' }, { no_triggers => 1 });
2059
2055
2060
    ## Fix up the currently waiting reserve
2056
    ## Fix up the currently waiting reserve
2061
    $hold->set(
2057
    $hold->set(
2062
        {
2058
        {
2063
            priority    => 1,
2059
            priority     => 1,
2064
            found       => undef,
2060
            status       => 'placed',
2065
            waitingdate => undef,
2061
            waiting_date => undef,
2066
            itemnumber  => $hold->item_level_hold ? $hold->itemnumber : undef,
2062
            item_id      => $hold->item_level ? $hold->item_id : undef,
2067
        }
2063
        }
2068
    )->store();
2064
    )->store();
2069
2065
2070
    _FixPriority( { biblionumber => $hold->biblionumber } );
2066
    _FixPriority( { biblionumber => $hold->biblio_id } );
2071
2067
2072
    return $hold;
2068
    return $hold;
2073
}
2069
}
Lines 2100-2112 available within the slip: Link Here
2100
2096
2101
sub ReserveSlip {
2097
sub ReserveSlip {
2102
    my ($args) = @_;
2098
    my ($args) = @_;
2103
    my $branchcode     = $args->{branchcode};
2099
    my $branchcode = $args->{branchcode};
2104
    my $reserve_id = $args->{reserve_id};
2100
    my $reserve_id = $args->{reserve_id};
2105
2101
2106
    my $hold = Koha::Holds->find($reserve_id);
2102
    my $hold = Koha::Holds->find($reserve_id);
2107
    return unless $hold;
2103
    return unless $hold;
2108
2104
2109
    my $patron = $hold->borrower;
2105
    my $patron = $hold->patron;
2110
    my $reserve = $hold->unblessed;
2106
    my $reserve = $hold->unblessed;
2111
2107
2112
    return  C4::Letters::GetPreparedLetter (
2108
    return  C4::Letters::GetPreparedLetter (
Lines 2116-2126 sub ReserveSlip { Link Here
2116
        lang => $patron->lang,
2112
        lang => $patron->lang,
2117
        tables => {
2113
        tables => {
2118
            'reserves'    => $reserve,
2114
            'reserves'    => $reserve,
2119
            'branches'    => $reserve->{branchcode},
2115
            'branches'    => $reserve->{pickup_library_id},
2120
            'borrowers'   => $reserve->{borrowernumber},
2116
            'borrowers'   => $reserve->{patron_id},
2121
            'biblio'      => $reserve->{biblionumber},
2117
            'biblio'      => $reserve->{biblio_id},
2122
            'biblioitems' => $reserve->{biblionumber},
2118
            'biblioitems' => $reserve->{biblio_id},
2123
            'items'       => $reserve->{itemnumber},
2119
            'items'       => $reserve->{item_id},
2124
        },
2120
        },
2125
    );
2121
    );
2126
}
2122
}
Lines 2174-2190 sub CalculatePriority { Link Here
2174
    my ( $biblionumber, $resdate ) = @_;
2170
    my ( $biblionumber, $resdate ) = @_;
2175
2171
2176
    my $sql = q{
2172
    my $sql = q{
2177
        SELECT COUNT(*) FROM reserves
2173
        SELECT COUNT(*) FROM holds
2178
        WHERE biblionumber = ?
2174
        WHERE biblio_id = ?
2179
        AND   priority > 0
2175
        AND   priority > 0
2180
        AND   (found IS NULL OR found = '')
2176
        AND   status='placed'
2181
    };
2177
    };
2182
    #skip found==W or found==T or found==P (waiting, transit or processing holds)
2178
    #skip status==waiting or status==in_transit or status==processing
2183
    if( $resdate ) {
2179
    if( $resdate ) {
2184
        $sql.= ' AND ( reservedate <= ? )';
2180
        $sql.= ' AND ( created_date <= ? )';
2185
    }
2181
    }
2186
    else {
2182
    else {
2187
        $sql.= ' AND ( reservedate < NOW() )';
2183
        $sql.= ' AND ( created_date < NOW() )';
2188
    }
2184
    }
2189
    my $dbh = C4::Context->dbh();
2185
    my $dbh = C4::Context->dbh();
2190
    my @row = $dbh->selectrow_array(
2186
    my @row = $dbh->selectrow_array(
Lines 2198-2223 sub CalculatePriority { Link Here
2198
2194
2199
=head2 IsItemOnHoldAndFound
2195
=head2 IsItemOnHoldAndFound
2200
2196
2201
    my $bool = IsItemFoundHold( $itemnumber );
2197
    my $bool = IsItemFoundHold( $item_id );
2202
2198
2203
    Returns true if the item is currently on hold
2199
    Returns true if the item is currently on hold
2204
    and that hold has a non-null found status ( W, T, etc. )
2200
    and that hold has a status of in_transit, processing
2201
    or waiting.
2205
2202
2206
=cut
2203
=cut
2207
2204
2208
sub IsItemOnHoldAndFound {
2205
sub IsItemOnHoldAndFound {
2209
    my ($itemnumber) = @_;
2206
    my ($item_id) = @_;
2210
2211
    my $rs = Koha::Database->new()->schema()->resultset('Reserve');
2212
2207
2213
    my $found = $rs->count(
2208
    return Koha::Holds->search(
2214
        {
2209
        {
2215
            itemnumber => $itemnumber,
2210
            item_id   => $item_id,
2216
            found      => { '!=' => undef }
2211
            status    => [ 'in_transit', 'processing', 'waiting' ],
2212
            completed => 0
2217
        }
2213
        }
2218
    );
2214
    )->count;
2219
2220
    return $found;
2221
}
2215
}
2222
2216
2223
=head2 GetMaxPatronHoldsForRecord
2217
=head2 GetMaxPatronHoldsForRecord
(-)a/C4/SIP/ILS/Patron.pm (-2 / +2 lines)
Lines 525-535 sub _get_outstanding_holds { Link Here
525
    my $borrowernumber = shift;
525
    my $borrowernumber = shift;
526
526
527
    my $patron = Koha::Patrons->find( $borrowernumber );
527
    my $patron = Koha::Patrons->find( $borrowernumber );
528
    my $holds = $patron->holds->search( { -or => [ { found => undef }, { found => { '!=' => 'W' } } ] } );
528
    my $holds = $patron->holds->search( { completed => 0, status => {'!=' => 'waiting'} } );
529
    my @holds;
529
    my @holds;
530
    while ( my $hold = $holds->next ) {
530
    while ( my $hold = $holds->next ) {
531
        my $item;
531
        my $item;
532
        if ($hold->itemnumber) {
532
        if ($hold->item_id) {
533
            $item = $hold->item;
533
            $item = $hold->item;
534
        }
534
        }
535
        else {
535
        else {
(-)a/C4/SIP/ILS/Transaction/Hold.pm (-1 / +1 lines)
Lines 86-92 sub drop_hold { Link Here
86
    }
86
    }
87
87
88
    my $item = Koha::Items->find({ barcode => $self->{item}->id });
88
    my $item = Koha::Items->find({ barcode => $self->{item}->id });
89
    my $holds = $item->holds->search({ borrowernumber => $patron->borrowernumber });
89
    my $holds = $item->holds->search({ patron_id => $patron->borrowernumber });
90
90
91
    return $self unless $holds->count;
91
    return $self unless $holds->count;
92
92
(-)a/C4/XSLT.pm (-1 / +1 lines)
Lines 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 299-305 sub current_item_level_holds { Link Here
299
299
300
    return $biblio->current_holds->search(
300
    return $biblio->current_holds->search(
301
        {
301
        {
302
            itemnumber => {
302
            item_id => {
303
                -in => \@item_numbers
303
                -in => \@item_numbers
304
            }
304
            }
305
        }
305
        }
(-)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, created_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/Hold.pm (-3 / +6 lines)
Lines 355-361 sub is_in_processing { Link Here
355
355
356
Returns true if hold is a cancelable hold
356
Returns true if hold is a cancelable hold
357
357
358
Holds may be only canceled if they are not found.
358
Holds may be only canceled if they are not found or completed.
359
359
360
This is used from the OPAC.
360
This is used from the OPAC.
361
361
Lines 364-371 This is used from the OPAC. Link Here
364
sub is_cancelable_from_opac {
364
sub is_cancelable_from_opac {
365
    my ($self) = @_;
365
    my ($self) = @_;
366
366
367
    return 1 unless $self->is_found();
367
    if ( $self->completed or $self->is_found ) {
368
    return 0; # if ->is_in_transit or if ->is_waiting or ->is_in_processing
368
        return 0;
369
    }
370
371
    return 1;
369
}
372
}
370
373
371
=head3 is_at_destination
374
=head3 is_at_destination
(-)a/Koha/Item.pm (-8 / +10 lines)
Lines 274-280 sub safe_to_delete { Link Here
274
274
275
    # check it doesn't have a waiting reserve
275
    # check it doesn't have a waiting reserve
276
    return "book_reserved"
276
    return "book_reserved"
277
      if $self->holds->search( { found => [ 'W', 'T' ] } )->count;
277
      if $self->holds->search( { status => [ 'waiting', 'in_transit' ], completed => 0 } )->count;
278
278
279
    return "linked_analytics"
279
    return "linked_analytics"
280
      if C4::Items::GetAnalyticsCount( $self->itemnumber ) > 0;
280
      if C4::Items::GetAnalyticsCount( $self->itemnumber ) > 0;
Lines 283-289 sub safe_to_delete { Link Here
283
      if $self->biblio->items->count == 1
283
      if $self->biblio->items->count == 1
284
      && $self->biblio->holds->search(
284
      && $self->biblio->holds->search(
285
          {
285
          {
286
              itemnumber => undef,
286
              item_id => undef,
287
          }
287
          }
288
        )->count;
288
        )->count;
289
289
Lines 398-404 Return holds attached to an item, optionally accept a hashref of params to pass Link Here
398
398
399
sub holds {
399
sub holds {
400
    my ( $self,$params ) = @_;
400
    my ( $self,$params ) = @_;
401
    my $holds_rs = $self->_result->reserves->search($params);
401
    $params->{completed} = 0 unless exists $params->{completed};
402
    my $holds_rs = $self->_result->holds->search($params);
402
    return Koha::Holds->_new_from_dbic( $holds_rs );
403
    return Koha::Holds->_new_from_dbic( $holds_rs );
403
}
404
}
404
405
Lines 750-763 sub current_holds { Link Here
750
    my $attributes = { order_by => 'priority' };
751
    my $attributes = { order_by => 'priority' };
751
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
752
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
752
    my $params = {
753
    my $params = {
753
        itemnumber => $self->itemnumber,
754
        item_id => $self->itemnumber,
754
        suspend => 0,
755
        suspended => 0,
755
        -or => [
756
        -or => [
756
            reservedate => { '<=' => $dtf->format_date(dt_from_string) },
757
            created_date => { '<=' => $dtf->format_date(dt_from_string) },
757
            waitingdate => { '!=' => undef },
758
            waiting_date => { '!=' => undef },
758
        ],
759
        ],
760
        completed => 0
759
    };
761
    };
760
    my $hold_rs = $self->_result->reserves->search( $params, $attributes );
762
    my $hold_rs = $self->_result->holds->search( $params, $attributes );
761
    return Koha::Holds->_new_from_dbic($hold_rs);
763
    return Koha::Holds->_new_from_dbic($hold_rs);
762
}
764
}
763
765
(-)a/Koha/Patron.pm (-6 / +6 lines)
Lines 72-80 our $RESULTSET_PATRON_ID_MAPPING = { Link Here
72
    Message              => 'borrowernumber',
72
    Message              => 'borrowernumber',
73
    MessageQueue         => 'borrowernumber',
73
    MessageQueue         => 'borrowernumber',
74
    OldIssue             => 'borrowernumber',
74
    OldIssue             => 'borrowernumber',
75
    OldReserve           => 'borrowernumber',
76
    Rating               => 'borrowernumber',
75
    Rating               => 'borrowernumber',
77
    Reserve              => 'borrowernumber',
76
    Hold                 => 'patron_id',
78
    Review               => 'borrowernumber',
77
    Review               => 'borrowernumber',
79
    SearchHistory        => 'userid',
78
    SearchHistory        => 'userid',
80
    Statistic            => 'borrowernumber',
79
    Statistic            => 'borrowernumber',
Lines 1196-1203 Return all the holds placed by this patron Link Here
1196
=cut
1195
=cut
1197
1196
1198
sub holds {
1197
sub holds {
1199
    my ($self) = @_;
1198
    my ($self, $params) = @_;
1200
    my $holds_rs = $self->_result->reserves->search( {}, { order_by => 'reservedate' } );
1199
    $params->{completed} = 0 unless exists $params->{completed};
1200
    my $holds_rs = $self->_result->holds->search( $params, { order_by => 'created_date' } );
1201
    return Koha::Holds->_new_from_dbic($holds_rs);
1201
    return Koha::Holds->_new_from_dbic($holds_rs);
1202
}
1202
}
1203
1203
Lines 1211-1218 Return all the historical holds for this patron Link Here
1211
1211
1212
sub old_holds {
1212
sub old_holds {
1213
    my ($self) = @_;
1213
    my ($self) = @_;
1214
    my $old_holds_rs = $self->_result->old_reserves->search( {}, { order_by => 'reservedate' } );
1214
    my $old_holds_rs = $self->_result->holds->search( { completed => 1 }, { order_by => 'created_date' } );
1215
    return Koha::Old::Holds->_new_from_dbic($old_holds_rs);
1215
    return Koha::Holds->_new_from_dbic($old_holds_rs);
1216
}
1216
}
1217
1217
1218
=head3 return_claims
1218
=head3 return_claims
(-)a/Koha/REST/V1/Auth.pm (-11 / +9 lines)
Lines 316-325 sub validate_query_parameters { Link Here
316
Allows access to object for its owner.
316
Allows access to object for its owner.
317
317
318
There are endpoints that should allow access for the object owner even if they
318
There are endpoints that should allow access for the object owner even if they
319
do not have the required permission, e.g. access an own reserve. This can be
319
do not have the required permission, e.g. access an own hold. This can be
320
achieved by defining the operation as follows:
320
achieved by defining the operation as follows:
321
321
322
"/holds/{reserve_id}": {
322
"/holds/{hold_id}": {
323
    "get": {
323
    "get": {
324
        ...,
324
        ...,
325
        "x-koha-authorization": {
325
        "x-koha-authorization": {
Lines 383-389 sub check_object_ownership { Link Here
383
        borrowernumber  => \&_object_ownership_by_patron_id,
383
        borrowernumber  => \&_object_ownership_by_patron_id,
384
        patron_id       => \&_object_ownership_by_patron_id,
384
        patron_id       => \&_object_ownership_by_patron_id,
385
        checkout_id     => \&_object_ownership_by_checkout_id,
385
        checkout_id     => \&_object_ownership_by_checkout_id,
386
        reserve_id      => \&_object_ownership_by_reserve_id,
386
        hold_id      => \&_object_ownership_by_hold_id,
387
    };
387
    };
388
388
389
    foreach my $param ( keys %{ $parameters } ) {
389
    foreach my $param ( keys %{ $parameters } ) {
Lines 447-466 sub _object_ownership_by_checkout_id { Link Here
447
            && $user->borrowernumber == $issue->borrowernumber;
447
            && $user->borrowernumber == $issue->borrowernumber;
448
}
448
}
449
449
450
=head3 _object_ownership_by_reserve_id
450
=head3 _object_ownership_by_hold_id
451
451
452
Finds a Koha::Hold-object by C<$reserve_id> and checks if it
452
Finds a Koha::Hold-object by C<$hold_id> and checks if it
453
belongs to C<$user>.
453
belongs to C<$user>.
454
454
455
TODO: Also compare against old_reserves
456
457
=cut
455
=cut
458
456
459
sub _object_ownership_by_reserve_id {
457
sub _object_ownership_by_hold_id {
460
    my ($c, $user, $reserve_id) = @_;
458
    my ($c, $user, $hold_id) = @_;
461
459
462
    my $reserve = Koha::Holds->find($reserve_id);
460
    my $hold = Koha::Holds->find($hold_id);
463
    return $reserve && $user->borrowernumber == $reserve->borrowernumber;
461
    return $hold && $user->borrowernumber == $hold->borrowernumber;
464
}
462
}
465
463
466
=head3 _basic_auth
464
=head3 _basic_auth
(-)a/Koha/REST/V1/Holds.pm (-18 / +20 lines)
Lines 46-52 sub list { Link Here
46
    my $c = shift->openapi->valid_input or return;
46
    my $c = shift->openapi->valid_input or return;
47
47
48
    return try {
48
    return try {
49
        my $holds_set = Koha::Holds->new;
49
        my $holds_set = Koha::Holds->search({completed=>0});
50
        my $holds     = $c->objects->search( $holds_set );
50
        my $holds     = $c->objects->search( $holds_set );
51
        return $c->render( status => 200, openapi => $holds );
51
        return $c->render( status => 200, openapi => $holds );
52
    }
52
    }
Lines 77-86 sub add { Link Here
77
        my $item_type         = $body->{item_type};
77
        my $item_type         = $body->{item_type};
78
        my $expiration_date   = $body->{expiration_date};
78
        my $expiration_date   = $body->{expiration_date};
79
        my $notes             = $body->{notes};
79
        my $notes             = $body->{notes};
80
        my $hold_date         = $body->{hold_date};
80
        my $created_date      = $body->{created_date};
81
        my $non_priority      = $body->{non_priority};
81
        my $non_priority      = $body->{non_priority};
82
82
83
        if(!C4::Context->preference( 'AllowHoldDateInFuture' ) && $hold_date) {
83
        if(!C4::Context->preference( 'AllowHoldDateInFuture' ) && $created_date) {
84
            return $c->render(
84
            return $c->render(
85
                status  => 400,
85
                status  => 400,
86
                openapi => { error => "Hold date in future not allowed" }
86
                openapi => { error => "Hold date in future not allowed" }
Lines 199-205 sub add { Link Here
199
                borrowernumber   => $patron_id,
199
                borrowernumber   => $patron_id,
200
                biblionumber     => $biblio_id,
200
                biblionumber     => $biblio_id,
201
                priority         => $priority,
201
                priority         => $priority,
202
                reservation_date => $hold_date,
202
                reservation_date => $created_date,
203
                expiration_date  => $expiration_date,
203
                expiration_date  => $expiration_date,
204
                notes            => $notes,
204
                notes            => $notes,
205
                title            => $biblio->title,
205
                title            => $biblio->title,
Lines 253-263 sub edit { Link Here
253
253
254
    return try {
254
    return try {
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,
259
            return $c->render(
260
                            openapi => {error => "Hold not found"} );
260
                status  => 404,
261
                openapi => { error => "Hold not found" }
262
            );
261
        }
263
        }
262
264
263
        my $body = $c->req->json;
265
        my $body = $c->req->json;
Lines 277-293 sub edit { Link Here
277
            );
279
            );
278
        }
280
        }
279
281
280
        $pickup_library_id    //= $hold->branchcode;
282
        $pickup_library_id  //= $hold->pickup_library_id;
281
        my $priority          = $body->{priority} // $hold->priority;
283
        my $priority          = $body->{priority} // $hold->priority;
282
        # suspended_until can also be set to undef
284
        # suspended_until can also be set to undef
283
        my $suspended_until   = exists $body->{suspended_until} ? $body->{suspended_until} : $hold->suspend_until;
285
        my $suspended_until   = exists $body->{suspended_until_date} ? $body->{suspended_until_date} : $hold->suspended_until_date;
284
286
285
        my $params = {
287
        my $params = {
286
            reserve_id    => $hold_id,
288
            reserve_id    => $hold_id,
287
            branchcode    => $pickup_library_id,
289
            branchcode    => $pickup_library_id,
288
            rank          => $priority,
290
            rank          => $priority,
289
            suspend_until => $suspended_until ? output_pref(dt_from_string($suspended_until, 'rfc3339')) : '',
291
            suspend_until => $suspended_until ? output_pref(dt_from_string($suspended_until, 'rfc3339')) : '',
290
            itemnumber    => $hold->itemnumber
292
            itemnumber    => $hold->item_id
291
        };
293
        };
292
294
293
        C4::Reserves::ModReserve($params);
295
        C4::Reserves::ModReserve($params);
Lines 313-319 sub delete { Link Here
313
    my $c = shift->openapi->valid_input or return;
315
    my $c = shift->openapi->valid_input or return;
314
316
315
    my $hold_id = $c->validation->param('hold_id');
317
    my $hold_id = $c->validation->param('hold_id');
316
    my $hold    = Koha::Holds->find($hold_id);
318
    my $hold    = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
317
319
318
    unless ($hold) {
320
    unless ($hold) {
319
        return $c->render( status => 404, openapi => { error => "Hold not found." } );
321
        return $c->render( status => 404, openapi => { error => "Hold not found." } );
Lines 342-348 sub suspend { Link Here
342
    my $c = shift->openapi->valid_input or return;
344
    my $c = shift->openapi->valid_input or return;
343
345
344
    my $hold_id  = $c->validation->param('hold_id');
346
    my $hold_id  = $c->validation->param('hold_id');
345
    my $hold     = Koha::Holds->find($hold_id);
347
    my $hold     = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
346
    my $body     = $c->req->json;
348
    my $body     = $c->req->json;
347
    my $end_date = ($body) ? $body->{end_date} : undef;
349
    my $end_date = ($body) ? $body->{end_date} : undef;
348
350
Lines 356-364 sub suspend { Link Here
356
        $hold->discard_changes;
358
        $hold->discard_changes;
357
        $c->res->headers->location( $c->req->url->to_string );
359
        $c->res->headers->location( $c->req->url->to_string );
358
        my $suspend_end_date;
360
        my $suspend_end_date;
359
        if ($hold->suspend_until) {
361
        if ($hold->suspended_until_date) {
360
            $suspend_end_date = output_pref({
362
            $suspend_end_date = output_pref({
361
                dt         => dt_from_string( $hold->suspend_until ),
363
                dt         => dt_from_string( $hold->suspended_until_date ),
362
                dateformat => 'rfc3339',
364
                dateformat => 'rfc3339',
363
                dateonly   => 1
365
                dateonly   => 1
364
                }
366
                }
Lines 390-396 sub resume { Link Here
390
    my $c = shift->openapi->valid_input or return;
392
    my $c = shift->openapi->valid_input or return;
391
393
392
    my $hold_id = $c->validation->param('hold_id');
394
    my $hold_id = $c->validation->param('hold_id');
393
    my $hold    = Koha::Holds->find($hold_id);
395
    my $hold    = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
394
    my $body    = $c->req->json;
396
    my $body    = $c->req->json;
395
397
396
    unless ($hold) {
398
    unless ($hold) {
Lines 416-422 sub update_priority { Link Here
416
    my $c = shift->openapi->valid_input or return;
418
    my $c = shift->openapi->valid_input or return;
417
419
418
    my $hold_id = $c->validation->param('hold_id');
420
    my $hold_id = $c->validation->param('hold_id');
419
    my $hold = Koha::Holds->find($hold_id);
421
    my $hold = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
420
422
421
    unless ($hold) {
423
    unless ($hold) {
422
        return $c->render(
424
        return $c->render(
Lines 464-470 sub pickup_locations { Link Here
464
    return try {
466
    return try {
465
        my $ps_set;
467
        my $ps_set;
466
468
467
        if ( $hold->itemnumber ) {
469
        if ( $hold->item_id ) {
468
            $ps_set = $hold->item->pickup_locations( { patron => $hold->patron } );
470
            $ps_set = $hold->item->pickup_locations( { patron => $hold->patron } );
469
        }
471
        }
470
        else {
472
        else {
(-)a/Koha/Template/Plugin/Biblio.pm (-4 / +7 lines)
Lines 29-39 use Koha::ArticleRequests; Link Here
29
use Koha::ArticleRequest::Status;
29
use Koha::ArticleRequest::Status;
30
30
31
sub HoldsCount {
31
sub HoldsCount {
32
    my ( $self, $biblionumber ) = @_;
32
    my ( $self, $biblio_id ) = @_;
33
34
    my $holds = Koha::Holds->search( { biblionumber => $biblionumber } );
35
33
36
    return $holds->count();
34
    return Koha::Holds->search(
35
        {
36
            biblio_id => $biblio_id,
37
            completed => 0
38
        }
39
    )->count;
37
}
40
}
38
41
39
sub ArticleRequestsActiveCount {
42
sub ArticleRequestsActiveCount {
(-)a/api/v1/swagger/definitions/hold.json (-3 / +11 lines)
Lines 9-15 Link Here
9
      "type": "integer",
9
      "type": "integer",
10
      "description": "Internal patron identifier"
10
      "description": "Internal patron identifier"
11
    },
11
    },
12
    "hold_date": {
12
    "created_date": {
13
      "type": ["string", "null"],
13
      "type": ["string", "null"],
14
      "format": "date",
14
      "format": "date",
15
      "description": "The date the hold was placed"
15
      "description": "The date the hold was placed"
Lines 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 82-87 Link Here
82
    "item_level": {
82
    "item_level": {
83
      "type": "boolean",
83
      "type": "boolean",
84
      "description": "If the hold is placed at item level"
84
      "description": "If the hold is placed at item level"
85
    },
86
    "completed": {
87
      "type": "boolean",
88
      "description": "If it has been completed (i.e. either 'fulfilled' or 'cancelled')"
89
    },
90
    "completed_date": {
91
      "type": ["string", "null"],
92
      "description": "the date this hold was completed (fulfilled or cancelled)"
85
    }
93
    }
86
  }
94
  }
87
}
95
}
(-)a/api/v1/swagger/paths/holds.json (-2 / +2 lines)
Lines 293-303 Link Here
293
                "type": "integer",
293
                "type": "integer",
294
                "minimum": 1
294
                "minimum": 1
295
              },
295
              },
296
              "branchcode": {
296
              "pickup_library_id": {
297
                "description": "Pickup location",
297
                "description": "Pickup location",
298
                "type": "string"
298
                "type": "string"
299
              },
299
              },
300
              "suspend_until": {
300
              "suspend_until_date": {
301
                "description": "Suspend until",
301
                "description": "Suspend until",
302
                "type": "string",
302
                "type": "string",
303
                "format": "date"
303
                "format": "date"
(-)a/circ/circulation.pl (-1 / +1 lines)
Lines 457-463 if (@$barcodes) { Link Here
457
# BUILD HTML
457
# BUILD HTML
458
# show all reserves of this borrower, and the position of the reservation ....
458
# show all reserves of this borrower, and the position of the reservation ....
459
if ($patron) {
459
if ($patron) {
460
    my $holds = Koha::Holds->search( { borrowernumber => $borrowernumber } ); # FIXME must be Koha::Patron->holds
460
    my $holds = Koha::Holds->search( { patron_id => $borrowernumber } ); # FIXME must be Koha::Patron->holds
461
    my $waiting_holds = $holds->waiting;
461
    my $waiting_holds = $holds->waiting;
462
    $template->param(
462
    $template->param(
463
        holds_count  => $holds->count(),
463
        holds_count  => $holds->count(),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/holdshistory.tt (-13 / +19 lines)
Lines 60-102 Link Here
60
          <td>[% INCLUDE 'biblio-title.inc' biblio=hold.biblio link = 1 %]</td>
60
          <td>[% INCLUDE 'biblio-title.inc' biblio=hold.biblio link = 1 %]</td>
61
          <td>[% hold.biblio.author | html %]</td>
61
          <td>[% hold.biblio.author | html %]</td>
62
          <td>[% hold.item.barcode | html %]</td>
62
          <td>[% hold.item.barcode | html %]</td>
63
          <td>[% Branches.GetName( hold.branchcode ) | html %]</td>
63
          <td>[% Branches.GetName( hold.pickup_library_id ) | html %]</td>
64
          <td><span title="[% hold.reservedate | html %]">[% hold.reservedate | $KohaDates %]</span></td>
64
          <td><span title="[% hold.created_date | html %]">[% hold.created_date | $KohaDates %]</span></td>
65
          <td>
65
          <td>
66
              [% IF hold.expirationdate %]
66
              [% IF hold.expiration_date %]
67
                  <span title="[% hold.expirationdate | html %]">[% hold.expirationdate | $KohaDates %]</span>
67
                  <span title="[% hold.expiration_date | html %]">[% hold.expiration_date | $KohaDates %]</span>
68
              [% ELSE %]
68
              [% ELSE %]
69
                  <span title="0000-00-00"></span>
69
                  <span title="0000-00-00"></span>
70
              [% END %]
70
              [% END %]
71
          </td>
71
          </td>
72
          <td>
72
          <td>
73
              [% IF hold.waitingdate %]
73
              [% IF hold.waiting_date %]
74
                  <span title="[% hold.waitingdate | html %]">[% hold.waitingdate | $KohaDates %]</span>
74
                  <span title="[% hold.waiting_date | html %]">[% hold.waiting_date | $KohaDates %]</span>
75
              [% ELSE %]
75
              [% ELSE %]
76
                  <span title="0000-00-00"></span>
76
                  <span title="0000-00-00"></span>
77
              [% END %]
77
              [% END %]
78
          </td>
78
          </td>
79
          <td>
79
          <td>
80
              [% IF hold.cancellationdate %]
80
              [% IF hold.status == 'cancelled' && hold.completed_date %]
81
                  <span title="[% hold.cancellationdate | html %]">[% hold.cancellationdate | $KohaDates %]</span>
81
                  <span title="[% hold.completed_date | html %]">[% hold.completed_date | $KohaDates %]</span>
82
              [% ELSE %]
82
              [% ELSE %]
83
                  <span title="0000-00-00"></span>
83
                  <span title="0000-00-00"></span>
84
              [% END %]
84
              [% END %]
85
          </td>
85
          </td>
86
          [% IF show_itemtype_column %]
86
          [% IF show_itemtype_column %]
87
            <td>
87
            <td>
88
              [% IF hold.itemtype %]
88
              [% IF hold.item_type %]
89
                  [% ItemTypes.GetDescription( hold.itemtype ) | html %]
89
                  [% ItemTypes.GetDescription( hold.item_type ) | html %]
90
              [% ELSE %]
90
              [% ELSE %]
91
                  <span>Any item type</span>
91
                  <span>Any item type</span>
92
              [% END %]
92
              [% END %]
93
            </td>
93
            </td>
94
          [% END %]
94
          [% END %]
95
          <td>
95
          <td>
96
          [% IF hold.found == 'F' %]
96
          [% IF    hold.status == 'fulfilled' %]
97
              Fulfilled
97
              Fulfilled
98
          [% ELSIF hold.cancellationdate %]
98
          [% ELSIF hold.status == 'cancelled' %]
99
              Cancelled
99
              Cancelled
100
<<<<<<< HEAD
100
                [% IF hold.cancellation_reason %]
101
                [% IF hold.cancellation_reason %]
101
                    ([% AuthorisedValues.GetByCode('HOLD_CANCELLATION', hold.cancellation_reason) | html %])
102
                    ([% AuthorisedValues.GetByCode('HOLD_CANCELLATION', hold.cancellation_reason) | html %])
102
                [% END %]
103
                [% END %]
Lines 105-112 Link Here
105
          [% ELSIF hold.found == 'P' %]
106
          [% ELSIF hold.found == 'P' %]
106
              Processing
107
              Processing
107
          [% ELSIF hold.found == 'T' %]
108
          [% ELSIF hold.found == 'T' %]
109
=======
110
          [% ELSIF hold.status == 'waiting' %]
111
              Waiting
112
          [% ELSIF hold.status == 'in_transit' %]
113
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
108
              In transit
114
              In transit
109
          [% ELSE %]
115
          [% ELSIF hold.status == 'placed' %]
110
              Pending
116
              Pending
111
          [% END %]
117
          [% END %]
112
          </td>
118
          </td>
(-)a/members/holdshistory.pl (-11 / +1 lines)
Lines 54-60 unless ( $patron ) { Link Here
54
}
54
}
55
55
56
my $holds;
56
my $holds;
57
my $old_holds;
58
57
59
if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){
58
if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){
60
    # use of 'eq' in the above comparison is intentional -- the
59
    # use of 'eq' in the above comparison is intentional -- the
Lines 62-82 if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){ Link Here
62
    $template->param( is_anonymous => 1 );
61
    $template->param( is_anonymous => 1 );
63
} else {
62
} else {
64
    $holds = $patron->holds;
63
    $holds = $patron->holds;
65
    $old_holds = $patron->old_holds;
66
67
    while (my $hold = $holds->next) {
68
        push @all_holds, $hold;
69
    }
70
71
    while (my $hold = $old_holds->next) {
72
        push @all_holds, $hold;
73
    }
74
}
64
}
75
65
76
$template->param(
66
$template->param(
77
    holdshistoryview => 1,
67
    holdshistoryview => 1,
78
    patron           => $patron,
68
    patron           => $patron,
79
    holds            => \@all_holds,
69
    holds            => $holds
80
);
70
);
81
71
82
output_html_with_http_headers $input, $cookie, $template->output;
72
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/reserve/request.pl (-19 / +54 lines)
Lines 330-338 foreach my $biblionumber (@biblionumbers) { Link Here
330
        # the patron places must be item level
330
        # the patron places must be item level
331
        my $holds = Koha::Holds->search(
331
        my $holds = Koha::Holds->search(
332
            {
332
            {
333
                borrowernumber => $patron->borrowernumber,
333
                patron_id => $patron->borrowernumber,
334
                biblionumber   => $biblionumber,
334
                biblio_id => $biblionumber,
335
                found          => undef,
335
                status    => 'placed',
336
            }
336
            }
337
        );
337
        );
338
        $force_hold_level = $holds->forced_hold_level();
338
        $force_hold_level = $holds->forced_hold_level();
Lines 349-355 foreach my $biblionumber (@biblionumbers) { Link Here
349
    }
349
    }
350
350
351
351
352
    my $count = Koha::Holds->search( { biblionumber => $biblionumber } )->count();
352
    my $count = Koha::Holds->search(
353
        {
354
            biblio_id => $biblionumber,
355
            completed => 0
356
        }
357
    )->count();
353
    my $totalcount = $count;
358
    my $totalcount = $count;
354
359
355
    # FIXME think @optionloop, is maybe obsolete, or  must be switchable by a systeme preference fixed rank or not
360
    # FIXME think @optionloop, is maybe obsolete, or  must be switchable by a systeme preference fixed rank or not
Lines 494-506 foreach my $biblionumber (@biblionumbers) { Link Here
494
            my $item_object = Koha::Items->find( $itemnumber );
499
            my $item_object = Koha::Items->find( $itemnumber );
495
            my $holds = $item_object->current_holds;
500
            my $holds = $item_object->current_holds;
496
            if ( my $first_hold = $holds->next ) {
501
            if ( my $first_hold = $holds->next ) {
497
                my $p = Koha::Patrons->find( $first_hold->borrowernumber );
502
                my $p = Koha::Patrons->find( $first_hold->patron_id );
498
503
499
                $item->{backgroundcolor} = 'reserved';
504
                $item->{backgroundcolor} = 'reserved';
500
                $item->{reservedate}     = output_pref({ dt => dt_from_string( $first_hold->reservedate ), dateonly => 1 }); # FIXME Should be formatted in the template
505
                $item->{reservedate}     = output_pref({ dt => dt_from_string( $first_hold->created_date ), dateonly => 1 }); # FIXME Should be formatted in the template
501
                $item->{ReservedFor}     = $p;
506
                $item->{ReservedFor}     = $p;
502
                $item->{ExpectedAtLibrary}     = $first_hold->branchcode;
507
                $item->{ExpectedAtLibrary}     = $first_hold->pickup_library_id;
503
                $item->{waitingdate} = $first_hold->waitingdate;
508
                $item->{waitingdate} = $first_hold->waiting_date;
504
            }
509
            }
505
510
506
            # Management of the notforloan document
511
            # Management of the notforloan document
Lines 629-635 foreach my $biblionumber (@biblionumbers) { Link Here
629
634
630
    # existingreserves building
635
    # existingreserves building
631
    my @reserveloop;
636
    my @reserveloop;
632
    my @reserves = Koha::Holds->search( { biblionumber => $biblionumber }, { order_by => 'priority' } );
637
    my @reserves = Koha::Holds->search(
638
        {
639
            biblio_id => $biblionumber,
640
            completed => 0
641
        },
642
        { order_by => 'priority' }
643
    );
633
    foreach my $res (
644
    foreach my $res (
634
        sort {
645
        sort {
635
            my $a_found = $a->found() || '';
646
            my $a_found = $a->found() || '';
Lines 655-665 foreach my $biblionumber (@biblionumbers) { Link Here
655
            $reserve{'holdingbranch'} = $res->item()->holdingbranch();
666
            $reserve{'holdingbranch'} = $res->item()->holdingbranch();
656
            $reserve{'biblionumber'}  = $res->item()->biblionumber();
667
            $reserve{'biblionumber'}  = $res->item()->biblionumber();
657
            $reserve{'barcodenumber'} = $res->item()->barcode();
668
            $reserve{'barcodenumber'} = $res->item()->barcode();
658
            $reserve{'wbrcode'}       = $res->branchcode();
669
            $reserve{'wbrcode'}       = $res->pickup_library_id;
659
            $reserve{'itemnumber'}    = $res->itemnumber();
670
            $reserve{'itemnumber'}    = $res->item_id;
660
            $reserve{'wbrname'}       = $res->branch()->branchname();
671
            $reserve{'wbrname'}       = $res->branch()->branchname();
672
<<<<<<< HEAD
661
            $reserve{'atdestination'} = $res->is_at_destination();
673
            $reserve{'atdestination'} = $res->is_at_destination();
662
            $reserve{'desk_name'}     = ( $res->desk() ) ? $res->desk()->desk_name() : '' ;
674
            $reserve{'desk_name'}     = ( $res->desk() ) ? $res->desk()->desk_name() : '' ;
675
=======
676
677
            if ( $reserve{'holdingbranch'} eq $reserve{'wbrcode'} ) {
678
679
                # Just because the holdingbranch matches the reserve branch doesn't mean the item
680
                # has arrived at the destination, check for an open transfer for the item as well
681
                my ( $transfertwhen, $transfertfrom, $transferto ) =
682
                  C4::Circulation::GetTransfers( $res->item_id );
683
                if ( not $transferto or $transferto ne $res->pickup_library_id ) {
684
                    $reserve{'atdestination'} = 1;
685
                }
686
            }
687
688
            # set found to 1 if reserve is waiting for patron pickup
689
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
663
            $reserve{'found'}     = $res->is_found();
690
            $reserve{'found'}     = $res->is_found();
664
            $reserve{'inprocessing'} = $res->is_in_processing();
691
            $reserve{'inprocessing'} = $res->is_in_processing();
665
            $reserve{'intransit'} = $res->is_in_transit();
692
            $reserve{'intransit'} = $res->is_in_transit();
Lines 672-695 foreach my $biblionumber (@biblionumbers) { Link Here
672
            }
699
            }
673
        }
700
        }
674
701
675
        $reserve{'expirationdate'} = $res->expirationdate;
702
        $reserve{'expirationdate'} = $res->expiration_date;
676
        $reserve{'date'}           = $res->reservedate;
703
        $reserve{'date'}           = $res->created_date;
677
        $reserve{'borrowernumber'} = $res->borrowernumber();
704
        $reserve{'borrowernumber'} = $res->patron_id;
678
        $reserve{'biblionumber'}   = $res->biblionumber();
705
        $reserve{'biblionumber'}   = $res->biblio_id;
679
        $reserve{'patron'}         = $res->borrower;
706
        $reserve{'patron'}         = $res->borrower;
680
        $reserve{'notes'}          = $res->reservenotes();
707
        $reserve{'notes'}          = $res->notes;
681
        $reserve{'waiting_date'}   = $res->waitingdate();
708
        $reserve{'waiting_date'}   = $res->waiting_date;
682
        $reserve{'ccode'}          = $res->item() ? $res->item()->ccode() : undef;
709
        $reserve{'ccode'}          = $res->item() ? $res->item()->ccode() : undef;
683
        $reserve{'barcode'}        = $res->item() ? $res->item()->barcode() : undef;
710
        $reserve{'barcode'}        = $res->item() ? $res->item()->barcode() : undef;
684
        $reserve{'priority'}       = $res->priority();
711
        $reserve{'priority'}       = $res->priority;
685
        $reserve{'lowestPriority'} = $res->lowestPriority();
712
        $reserve{'lowestPriority'} = $res->lowest_priority;
686
        $reserve{'optionloop'}     = \@optionloop;
713
        $reserve{'optionloop'}     = \@optionloop;
714
<<<<<<< HEAD
687
        $reserve{'suspend'}        = $res->suspend();
715
        $reserve{'suspend'}        = $res->suspend();
688
        $reserve{'suspend_until'}  = $res->suspend_until();
716
        $reserve{'suspend_until'}  = $res->suspend_until();
689
        $reserve{'reserve_id'}     = $res->reserve_id();
717
        $reserve{'reserve_id'}     = $res->reserve_id();
690
        $reserve{itemtype}         = $res->itemtype();
718
        $reserve{itemtype}         = $res->itemtype();
691
        $reserve{branchcode}       = $res->branchcode();
719
        $reserve{branchcode}       = $res->branchcode();
692
        $reserve{non_priority}     = $res->non_priority();
720
        $reserve{non_priority}     = $res->non_priority();
721
=======
722
        $reserve{'suspend'}        = $res->suspended;
723
        $reserve{'suspend_until'}  = $res->suspended_until_date;
724
        $reserve{'reserve_id'}     = $res->id;
725
        $reserve{itemtype}         = $res->item_type;
726
        $reserve{branchcode}       = $res->pickup_library_id;
727
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
693
        $reserve{object}           = $res;
728
        $reserve{object}           = $res;
694
729
695
        push( @reserveloop, \%reserve );
730
        push( @reserveloop, \%reserve );
(-)a/t/Koha/REST/Plugin/Query.t (-2 / +2 lines)
Lines 108-114 get '/dbic_merge_sorting_date' => sub { Link Here
108
    $attributes = $c->dbic_merge_sorting(
108
    $attributes = $c->dbic_merge_sorting(
109
        {
109
        {
110
            attributes => $attributes,
110
            attributes => $attributes,
111
            params     => { _match => 'exact', _order_by => [ '-hold_date' ] },
111
            params     => { _match => 'exact', _order_by => [ '-created_date' ] },
112
            result_set => $result_set
112
            result_set => $result_set
113
        }
113
        }
114
    );
114
    );
Lines 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 => 'created_date' }
335
        ]
335
        ]
336
      );
336
      );
337
337
(-)a/t/db_dependent/Circulation.t (-33 / +38 lines)
Lines 421-427 subtest "CanBookBeRenewed tests" => sub { Link Here
421
    my $expdate        = undef;
421
    my $expdate        = undef;
422
    my $notes          = '';
422
    my $notes          = '';
423
    my $checkitem      = undef;
423
    my $checkitem      = undef;
424
    my $found          = undef;
424
    my $found          = 'placed';
425
425
426
    my $issue = AddIssue( $renewing_borrower, $item_1->barcode);
426
    my $issue = AddIssue( $renewing_borrower, $item_1->barcode);
427
    my $datedue = dt_from_string( $issue->date_due() );
427
    my $datedue = dt_from_string( $issue->date_due() );
Lines 449-456 subtest "CanBookBeRenewed tests" => sub { Link Here
449
            reservation_date => $resdate,
449
            reservation_date => $resdate,
450
            expiration_date  => $expdate,
450
            expiration_date  => $expdate,
451
            notes            => $notes,
451
            notes            => $notes,
452
            itemnumber       => $checkitem,
452
            itemnumber       => $checkitem
453
            found            => $found,
454
        }
453
        }
455
    );
454
    );
456
455
Lines 480-510 subtest "CanBookBeRenewed tests" => sub { Link Here
480
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
479
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
481
480
482
    # Now let's add an item level hold, we should no longer be able to renew the item
481
    # Now let's add an item level hold, we should no longer be able to renew the item
483
    my $hold = Koha::Database->new()->schema()->resultset('Reserve')->create(
482
    my $hold = Koha::Hold->new(
484
        {
483
        {
485
            borrowernumber => $hold_waiting_borrowernumber,
484
            patron_id   => $hold_waiting_borrowernumber,
486
            biblionumber   => $biblio->biblionumber,
485
            biblio_id   => $biblio->biblionumber,
487
            itemnumber     => $item_1->itemnumber,
486
            item_id     => $item_1->itemnumber,
488
            branchcode     => $branch,
487
            pickup_library_id => $branch,
489
            priority       => 3,
488
            priority    => 3,
490
        }
489
        }
491
    );
490
    )->store;
492
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
491
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
493
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
492
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
494
    $hold->delete();
493
    $hold->delete();
495
494
496
    # 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
495
    # 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
497
    # be able to renew these items
496
    # be able to renew these items
498
    $hold = Koha::Database->new()->schema()->resultset('Reserve')->create(
497
    $hold = Koha::Hold->new(
499
        {
498
        {
500
            borrowernumber => $hold_waiting_borrowernumber,
499
            patron_id => $hold_waiting_borrowernumber,
501
            biblionumber   => $biblio->biblionumber,
500
            biblio_id   => $biblio->biblionumber,
502
            itemnumber     => $item_3->itemnumber,
501
            item_id     => $item_3->itemnumber,
503
            branchcode     => $branch,
502
            pickup_library_id     => $branch,
504
            priority       => 0,
503
            priority       => 0,
505
            found          => 'W'
504
            status          => 'waiting'
506
        }
505
        }
507
    );
506
    )->store;
508
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
507
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
509
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
508
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
510
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
509
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
Lines 519-533 subtest "CanBookBeRenewed tests" => sub { Link Here
519
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
518
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
520
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
519
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
521
520
522
    my $reserveid = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $reserving_borrowernumber })->next->reserve_id;
521
    my $reserveid = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $reserving_borrowernumber })->next->id;
523
    my $reserving_borrower = Koha::Patrons->find( $reserving_borrowernumber )->unblessed;
522
    my $reserving_borrower = Koha::Patrons->find( $reserving_borrowernumber )->unblessed;
524
    AddIssue($reserving_borrower, $item_3->barcode);
523
    AddIssue($reserving_borrower, $item_3->barcode);
525
    my $reserve = $dbh->selectrow_hashref(
524
    my $reserve = $dbh->selectrow_hashref(
526
        'SELECT * FROM old_reserves WHERE reserve_id = ?',
525
        'SELECT * FROM holds WHERE id = ? AND completed = 1',
527
        { Slice => {} },
526
        { Slice => {} },
528
        $reserveid
527
        $reserveid
529
    );
528
    );
530
    is($reserve->{found}, 'F', 'hold marked completed when checking out item that fills it');
529
    is($reserve->{status}, 'fulfilled', 'hold marked completed when checking out item that fills it');
531
530
532
    # Item-level hold, renewal test
531
    # Item-level hold, renewal test
533
    AddReserve(
532
    AddReserve(
Lines 686-692 subtest "CanBookBeRenewed tests" => sub { Link Here
686
    $fines = Koha::Account::Lines->search( { borrowernumber => $renewing_borrower->{borrowernumber}, itemnumber => $item_7->itemnumber } );
685
    $fines = Koha::Account::Lines->search( { borrowernumber => $renewing_borrower->{borrowernumber}, itemnumber => $item_7->itemnumber } );
687
    $fines->delete();
686
    $fines->delete();
688
687
689
    $hold = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $reserving_borrowernumber })->next;
688
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','blockitem');
689
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_6->itemnumber);
690
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is not overdue');
691
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_7->itemnumber);
692
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is overdue');
693
694
    $hold = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $reserving_borrowernumber })->next;
690
    $hold->cancel;
695
    $hold->cancel;
691
696
692
    # Bug 14101
697
    # Bug 14101
Lines 3361-3367 subtest 'Set waiting flag' => sub { Link Here
3361
    my ( $res, $rr ) = AddReturn( $item->barcode, $library_1->{branchcode} );
3366
    my ( $res, $rr ) = AddReturn( $item->barcode, $library_1->{branchcode} );
3362
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3367
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3363
    my $hold = Koha::Holds->find( $reserve_id );
3368
    my $hold = Koha::Holds->find( $reserve_id );
3364
    is( $hold->found, 'T', 'Hold is in transit' );
3369
    is( $hold->status, 'in_transit', 'Hold is in transit' );
3365
3370
3366
    my ( $status ) = CheckReserves($item->itemnumber);
3371
    my ( $status ) = CheckReserves($item->itemnumber);
3367
    is( $status, 'Reserved', 'Hold is not waiting yet');
3372
    is( $status, 'Reserved', 'Hold is not waiting yet');
Lines 3371-3377 subtest 'Set waiting flag' => sub { Link Here
3371
    AddReturn( $item->barcode, $library_2->{branchcode} );
3376
    AddReturn( $item->barcode, $library_2->{branchcode} );
3372
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3377
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3373
    $hold = Koha::Holds->find( $reserve_id );
3378
    $hold = Koha::Holds->find( $reserve_id );
3374
    is( $hold->found, 'W', 'Hold is waiting' );
3379
    is( $hold->status, 'waiting', 'Hold is waiting' );
3375
    ( $status ) = CheckReserves($item->itemnumber);
3380
    ( $status ) = CheckReserves($item->itemnumber);
3376
    is( $status, 'Waiting', 'Now the hold is waiting');
3381
    is( $status, 'Waiting', 'Now the hold is waiting');
3377
3382
Lines 3379-3390 subtest 'Set waiting flag' => sub { Link Here
3379
    set_userenv( $library_1 );
3384
    set_userenv( $library_1 );
3380
    (undef, my $messages, undef, undef ) = AddReturn ( $item->barcode, $library_1->{branchcode} );
3385
    (undef, my $messages, undef, undef ) = AddReturn ( $item->barcode, $library_1->{branchcode} );
3381
    $hold = Koha::Holds->find( $reserve_id );
3386
    $hold = Koha::Holds->find( $reserve_id );
3382
    is( $hold->found, undef, 'Hold is no longer marked waiting' );
3387
    is( $hold->status, 'placed', 'Hold is no longer marked waiting' );
3383
    is( $hold->priority, 1,  "Hold is now priority one again");
3388
    is( $hold->priority, 1,  "Hold is now priority one again");
3384
    is( $hold->waitingdate, undef, "Hold no longer has a waiting date");
3389
    is( $hold->waiting_date, undef, "Hold no longer has a waiting date");
3385
    is( $hold->itemnumber, $item->itemnumber, "Hold has retained its' itemnumber");
3390
    is( $hold->item_id, $item->itemnumber, "Hold has retained its' itemnumber");
3386
    is( $messages->{ResFound}->{ResFound}, "Reserved", "Hold is still returned");
3391
    is( $messages->{ResFound}->{ResFound}, "Reserved", "Hold is still returned");
3387
    is( $messages->{ResFound}->{found}, undef, "Hold is no longer marked found in return message");
3392
    is( $messages->{ResFound}->{status}, 'placed', "Hold is no longer marked found in return message");
3388
    is( $messages->{ResFound}->{priority}, 1, "Hold is priority 1 in return message");
3393
    is( $messages->{ResFound}->{priority}, 1, "Hold is priority 1 in return message");
3389
};
3394
};
3390
3395
Lines 3423-3429 subtest 'Cancel transfers on lost items' => sub { Link Here
3423
        trigger   => 'Reserve',
3428
        trigger   => 'Reserve',
3424
    });
3429
    });
3425
    my $hold = Koha::Holds->find( $reserve_id );
3430
    my $hold = Koha::Holds->find( $reserve_id );
3426
    is( $hold->found, 'T', 'Hold is in transit' );
3431
    is( $hold->status, 'in_transit', 'Hold is in transit' );
3427
3432
3428
    #Check transfer exists and the items holding branch is the transfer destination branch before marking it as lost
3433
    #Check transfer exists and the items holding branch is the transfer destination branch before marking it as lost
3429
    my ($datesent,$frombranch,$tobranch) = GetTransfers($item->itemnumber);
3434
    my ($datesent,$frombranch,$tobranch) = GetTransfers($item->itemnumber);
Lines 4225-4237 subtest 'Filling a hold should cancel existing transfer' => sub { Link Here
4225
        biblionumber   => $item->biblionumber,
4230
        biblionumber   => $item->biblionumber,
4226
        itemnumber     => $item->itemnumber
4231
        itemnumber     => $item->itemnumber
4227
    });
4232
    });
4228
    my $reserves = Koha::Holds->search({ itemnumber => $item->itemnumber });
4233
    my $reserves = Koha::Holds->search({ item_id => $item->itemnumber });
4229
    is( $reserves->count, 1, "Reserve is placed");
4234
    is( $reserves->count, 1, "Reserve is placed");
4230
    ( undef, $message ) = AddReturn( $item->barcode, $libraryA->branchcode, undef, undef );
4235
    ( undef, $message ) = AddReturn( $item->barcode, $libraryA->branchcode, undef, undef );
4231
    my $reserve = $reserves->next;
4236
    my $reserve = $reserves->next;
4232
    ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 0, $reserve->reserve_id );
4237
    ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 0, $reserve->id );
4233
    $reserve->discard_changes;
4238
    $reserve->discard_changes;
4234
    ok( $reserve->found eq 'W', "Reserve is marked waiting" );
4239
    ok( $reserve->status eq 'waiting', "Reserve is marked waiting" );
4235
    is( Koha::Item::Transfers->search({ itemnumber => $item->itemnumber, datearrived => undef })->count, 0, "No outstanding transfers when hold is waiting");
4240
    is( Koha::Item::Transfers->search({ itemnumber => $item->itemnumber, datearrived => undef })->count, 0, "No outstanding transfers when hold is waiting");
4236
};
4241
};
4237
4242
Lines 4688-4694 subtest 'Checkout should correctly terminate a transfer' => sub { Link Here
4688
    GetOtherReserves( $item->itemnumber )
4693
    GetOtherReserves( $item->itemnumber )
4689
      ;    # To put the Reason, it's what does returns.pl...
4694
      ;    # To put the Reason, it's what does returns.pl...
4690
    my $hold = Koha::Holds->find($reserve_id);
4695
    my $hold = Koha::Holds->find($reserve_id);
4691
    is( $hold->found, 'T', 'Hold is in transit' );
4696
    is( $hold->status, 'in_transit', 'Hold is in transit' );
4692
    my $transfer = $item->get_transfer;
4697
    my $transfer = $item->get_transfer;
4693
    is( $transfer->frombranch, $library_1->branchcode );
4698
    is( $transfer->frombranch, $library_1->branchcode );
4694
    is( $transfer->tobranch,   $library_2->branchcode );
4699
    is( $transfer->tobranch,   $library_2->branchcode );
Lines 4699-4705 subtest 'Checkout should correctly terminate a transfer' => sub { Link Here
4699
    $transfer = $transfer->get_from_storage;
4704
    $transfer = $transfer->get_from_storage;
4700
    isnt( $transfer->datearrived, undef );
4705
    isnt( $transfer->datearrived, undef );
4701
    $hold = $hold->get_from_storage;
4706
    $hold = $hold->get_from_storage;
4702
    is( $hold->found, undef, 'Hold is waiting' );
4707
    is( $hold->status, 'placed', 'Hold is waiting' );
4703
    is( $hold->priority, 1, );
4708
    is( $hold->priority, 1, );
4704
};
4709
};
4705
4710
(-)a/t/db_dependent/Circulation/issue.t (-3 / +2 lines)
Lines 68-75 $dbh->do(q|DELETE FROM borrowers|); Link Here
68
$dbh->do(q|DELETE FROM categories|);
68
$dbh->do(q|DELETE FROM categories|);
69
$dbh->do(q|DELETE FROM accountlines|);
69
$dbh->do(q|DELETE FROM accountlines|);
70
$dbh->do(q|DELETE FROM circulation_rules|);
70
$dbh->do(q|DELETE FROM circulation_rules|);
71
$dbh->do(q|DELETE FROM reserves|);
71
$dbh->do(q|DELETE FROM holds|);
72
$dbh->do(q|DELETE FROM old_reserves|);
73
$dbh->do(q|DELETE FROM statistics|);
72
$dbh->do(q|DELETE FROM statistics|);
74
73
75
# Generate sample datas
74
# Generate sample datas
Lines 484-490 my $reserve_id = AddReserve( Link Here
484
ok( $reserve_id, 'The reserve should have been inserted' );
483
ok( $reserve_id, 'The reserve should have been inserted' );
485
AddIssue( $borrower_2, $barcode_1, dt_from_string, 'cancel' );
484
AddIssue( $borrower_2, $barcode_1, dt_from_string, 'cancel' );
486
my $hold = Koha::Holds->find( $reserve_id );
485
my $hold = Koha::Holds->find( $reserve_id );
487
is( $hold, undef, 'The reserve should have been correctly cancelled' );
486
is( $hold->status, 'cancelled', 'The reserve should have been correctly cancelled' );
488
487
489
# Unseen rewnewals
488
# Unseen rewnewals
490
t::lib::Mocks::mock_preference('UnseenRenewals', 1);
489
t::lib::Mocks::mock_preference('UnseenRenewals', 1);
(-)a/t/db_dependent/DecreaseLoanHighHolds.t (-6 / +6 lines)
Lines 88-96 for my $i ( 0 .. 5 ) { Link Here
88
    my $patron = $patrons[$i];
88
    my $patron = $patrons[$i];
89
    my $hold   = Koha::Hold->new(
89
    my $hold   = Koha::Hold->new(
90
        {
90
        {
91
            borrowernumber => $patron->id,
91
            patron_id => $patron->id,
92
            biblionumber   => $biblio->id,
92
            biblio_id   => $biblio->id,
93
            branchcode     => $library->{branchcode},
93
            pickup_library_id     => $library->{branchcode},
94
        }
94
        }
95
    )->store();
95
    )->store();
96
}
96
}
Lines 169-177 for my $i ( 5 .. 10 ) { Link Here
169
    my $patron = $patrons[$i];
169
    my $patron = $patrons[$i];
170
    my $hold   = Koha::Hold->new(
170
    my $hold   = Koha::Hold->new(
171
        {
171
        {
172
            borrowernumber => $patron->id,
172
            patron_id         => $patron->id,
173
            biblionumber   => $biblio->id,
173
            biblio_id         => $biblio->id,
174
            branchcode     => $library->{branchcode},
174
            pickup_library_id => $library->{branchcode},
175
        }
175
        }
176
    )->store();
176
    )->store();
177
}
177
}
(-)a/t/db_dependent/Hold.t (-47 / +60 lines)
Lines 66-78 $item->store(); Link Here
66
66
67
my $hold = Koha::Hold->new(
67
my $hold = Koha::Hold->new(
68
    {
68
    {
69
        biblionumber   => $biblionumber,
69
        biblio_id      => $biblionumber,
70
        itemnumber     => $item->id(),
70
        item_id        => $item->id(),
71
        reservedate    => '2017-01-01',
71
        created_date   => '2017-01-01',
72
        waitingdate    => '2000-01-01',
72
        waiting_date   => '2000-01-01',
73
        borrowernumber => $borrower->{borrowernumber},
73
        patron_id      => $borrower->{borrowernumber},
74
        branchcode     => $branches[1]->{branchcode},
74
        pickup_library_id => $branches[1]->{branchcode},
75
        suspend        => 0,
75
        suspended      => 0,
76
        status         => 'placed'
76
    }
77
    }
77
);
78
);
78
$hold->store();
79
$hold->store();
Lines 83-104 my $today = dt_from_string; Link Here
83
is( $hold->age(), $today->delta_days( dt_from_string( '2017-01-01' ) )->in_units( 'days')  , "Age of hold is days from reservedate to now if calendar ignored");
84
is( $hold->age(), $today->delta_days( dt_from_string( '2017-01-01' ) )->in_units( 'days')  , "Age of hold is days from reservedate to now if calendar ignored");
84
is( $hold->age(1), $today->delta_days( dt_from_string( '2017-01-01' ) )->in_units( 'days' ) - 1 , "Age of hold is days from reservedate to now minus 1 if calendar used");
85
is( $hold->age(1), $today->delta_days( dt_from_string( '2017-01-01' ) )->in_units( 'days' ) - 1 , "Age of hold is days from reservedate to now minus 1 if calendar used");
85
86
86
is( $hold->suspend, 0, "Hold is not suspended" );
87
is( $hold->suspended, 0, "Hold is not suspended" );
87
$hold->suspend_hold();
88
$hold->suspend_hold();
88
is( $hold->suspend, 1, "Hold is suspended" );
89
is( $hold->suspended, 1, "Hold is suspended" );
89
$hold->resume();
90
$hold->resume();
90
is( $hold->suspend, 0, "Hold is not suspended" );
91
is( $hold->suspended, 0, "Hold is not suspended" );
91
my $dt = dt_from_string();
92
my $dt = dt_from_string();
92
$hold->suspend_hold( $dt );
93
$hold->suspend_hold( $dt );
93
$dt->truncate( to => 'day' );
94
$dt->truncate( to => 'day' );
94
is( $hold->suspend, 1, "Hold is suspended" );
95
is( $hold->suspended, 1, "Hold is suspended" );
95
is( $hold->suspend_until, "$dt", "Hold is suspended with a date, truncation takes place automatically" );
96
is( $hold->suspended_until_date, "$dt", "Hold is suspended with a date, truncation takes place automatically" );
96
$hold->suspend_hold;
97
$hold->suspend_hold;
97
is( $hold->suspend, 1, "Hold is suspended" );
98
is( $hold->suspended, 1, "Hold is suspended" );
98
is( $hold->suspend_until, undef, "Hold is suspended without a date" );
99
is( $hold->suspended_until_date, undef, "Hold is suspended without a date" );
99
$hold->resume();
100
$hold->resume();
100
is( $hold->suspend, 0, "Hold is not suspended" );
101
is( $hold->suspended, 0, "Hold is not suspended" );
101
is( $hold->suspend_until, undef, "Hold no longer has suspend_until date" );
102
is( $hold->suspended_until_date, undef, "Hold no longer has suspend_until date" );
102
103
103
$item = $hold->item();
104
$item = $hold->item();
104
105
Lines 107-143 ok( $hold_borrower, 'Got hold borrower' ); Link Here
107
is( $hold_borrower->borrowernumber(), $borrower->{borrowernumber}, 'Hold borrower matches correct borrower' );
108
is( $hold_borrower->borrowernumber(), $borrower->{borrowernumber}, 'Hold borrower matches correct borrower' );
108
109
109
t::lib::Mocks::mock_preference( 'ReservesMaxPickUpDelay', '5' );
110
t::lib::Mocks::mock_preference( 'ReservesMaxPickUpDelay', '5' );
110
$hold->found('T');
111
$hold->status('in_transit');
111
isnt( $hold->is_waiting, 1, 'The hold is not waiting (T)' );
112
isnt( $hold->is_waiting, 1, 'The hold is not waiting (T)' );
112
is( $hold->is_found, 1, 'The hold is found');
113
is( $hold->is_found, 1, 'The hold is found');
113
is( $hold->is_in_transit, 1, 'The hold is in transit' );
114
is( $hold->is_in_transit, 1, 'The hold is in transit' );
114
115
115
$hold->found('P');
116
$hold->status('processing');
116
is( $hold->is_found, 1, 'The hold is found');
117
is( $hold->is_found, 1, 'The hold is found');
117
is( $hold->is_in_processing, 1, 'The hold is in processing' );
118
is( $hold->is_in_processing, 1, 'The hold is in processing' );
118
119
119
$hold->found(q{});
120
$hold->status('placed');
120
isnt( $hold->is_waiting, 1, 'The hold is not waiting (W)' );
121
isnt( $hold->is_waiting, 1, 'The hold is not waiting (W)' );
121
is( $hold->is_found, 0, 'The hold is not found' );
122
is( $hold->is_found, 0, 'The hold is not found' );
122
ok( !$hold->is_in_transit, 'The hold is not in transit' );
123
ok( !$hold->is_in_transit, 'The hold is not in transit' );
123
ok( !$hold->is_in_processing, 'The hold is not in processing' );
124
ok( !$hold->is_in_processing, 'The hold is not in processing' );
124
125
125
# Test method is_cancelable_from_opac
126
# Test method is_cancelable_from_opac
126
$hold->found(undef);
127
$hold->status('placed');
127
is( $hold->is_cancelable_from_opac, 1, "Unfound hold is cancelable" );
128
is( $hold->is_cancelable_from_opac, 1, "Unfound hold is cancelable" );
128
$hold->found('W');
129
$hold->status('waiting');
129
is( $hold->is_cancelable_from_opac, 0, "Waiting hold is not cancelable" );
130
is( $hold->is_cancelable_from_opac, 0, "Waiting hold is not cancelable" );
130
$hold->found('T');
131
$hold->status('in_transit');
131
is( $hold->is_cancelable_from_opac, 0, "In transit hold is not cancelable" );
132
is( $hold->is_cancelable_from_opac, 0, "In transit hold is not cancelable" );
132
$hold->found('P');
133
$hold->status('processing');
133
is( $hold->is_cancelable_from_opac, 0, "In processing hold is not cancelable" );
134
is( $hold->is_cancelable_from_opac, 0, "In processing hold is not cancelable" );
134
135
135
# Test method is_at_destination
136
# Test method is_at_destination
136
$hold->found(undef);
137
$hold->status('placed');
137
ok( !$hold->is_at_destination(), "Unfound hold cannot be at destination" );
138
ok( !$hold->is_at_destination(), "Unfound hold cannot be at destination" );
138
$hold->found('T');
139
$hold->status('in_transit');
139
ok( !$hold->is_at_destination(), "In transit hold cannot be at destination" );
140
ok( !$hold->is_at_destination(), "In transit hold cannot be at destination" );
140
$hold->found('W');
141
$hold->status('waiting');
141
ok( !$hold->is_at_destination(), "Waiting hold where hold branchcode is not the same as the item's holdingbranch is not at destination" );
142
ok( !$hold->is_at_destination(), "Waiting hold where hold branchcode is not the same as the item's holdingbranch is not at destination" );
142
$item->holdingbranch( $branches[1]->{branchcode} );
143
$item->holdingbranch( $branches[1]->{branchcode} );
143
ok( $hold->is_at_destination(), "Waiting hold where hold branchcode is the same as the item's holdingbranch is at destination" );
144
ok( $hold->is_at_destination(), "Waiting hold where hold branchcode is the same as the item's holdingbranch is at destination" );
Lines 153-183 subtest "delete() tests" => sub { Link Here
153
    # Disable logging
154
    # Disable logging
154
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
155
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
155
156
156
    my $hold = $builder->build({ source => 'Reserve' });
157
    my $hold    = $builder->build_object({ class => 'Koha::Holds' });
158
    my $hold_id = $hold->id;
159
    my $deleted = $hold->delete;
157
160
158
    my $hold_object = Koha::Holds->find( $hold->{ reserve_id } );
159
    my $deleted = $hold_object->delete;
160
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return the Koha::Hold object if the hold has been correctly deleted' );
161
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return the Koha::Hold object if the hold has been correctly deleted' );
161
    is( Koha::Holds->search({ reserve_id => $hold->{ reserve_id } })->count, 0,
162
    is( Koha::Holds->search({ id => $hold_id })->count, 0,
162
        "Koha::Hold->delete should have deleted the hold" );
163
        "Koha::Hold->delete should have deleted the hold" );
163
164
164
    my $number_of_logs = $schema->resultset('ActionLog')->search(
165
    my $number_of_logs = $schema->resultset('ActionLog')->search(
165
            { module => 'HOLDS', action => 'DELETE', object => $hold->{ reserve_id } } )->count;
166
            { module => 'HOLDS', action => 'DELETE', object => $hold_id } )->count;
166
    is( $number_of_logs, 0, 'With HoldsLogs, Koha::Hold->delete shouldn\'t have been logged' );
167
    is( $number_of_logs, 0, 'With HoldsLogs, Koha::Hold->delete shouldn\'t have been logged' );
167
168
168
    # Enable logging
169
    # Enable logging
169
    t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
170
    t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
170
171
171
    $hold = $builder->build({ source => 'Reserve' });
172
    $hold    = $builder->build_object({ class => 'Koha::Holds' });
173
    $hold_id = $hold->id;
174
    $deleted = $hold->delete;
172
175
173
    $hold_object = Koha::Holds->find( $hold->{ reserve_id } );
174
    $deleted = $hold_object->delete;
175
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return a Koha::Hold object if the hold has been correctly deleted' );
176
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return a Koha::Hold object if the hold has been correctly deleted' );
176
    is( Koha::Holds->search({ reserve_id => $hold->{ reserve_id } })->count, 0,
177
    is( Koha::Holds->search({ id => $hold_id })->count, 0,
177
        "Koha::Hold->delete should have deleted the hold" );
178
        "Koha::Hold->delete should have deleted the hold" );
178
179
179
    $number_of_logs = $schema->resultset('ActionLog')->search(
180
    $number_of_logs = $schema->resultset('ActionLog')->search(
180
            { module => 'HOLDS', action => 'DELETE', object => $hold->{ reserve_id } } )->count;
181
            { module => 'HOLDS', action => 'DELETE', object => $hold_id } )->count;
181
    is( $number_of_logs, 1, 'With HoldsLogs, Koha::Hold->delete should have been logged' );
182
    is( $number_of_logs, 1, 'With HoldsLogs, Koha::Hold->delete should have been logged' );
182
183
183
    $schema->storage->txn_rollback();
184
    $schema->storage->txn_rollback();
Lines 193-200 subtest 'suspend() tests' => sub { Link Here
193
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
194
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
194
195
195
    my $hold = $builder->build_object(
196
    my $hold = $builder->build_object(
196
        {   class => 'Koha::Holds',
197
        {
197
            value => { found => undef, suspend => 0, suspend_until => undef, waitingdate => undef }
198
            class => 'Koha::Holds',
199
            value => {
200
                status               => 'placed',
201
                suspended            => 0,
202
                suspended_until_date => undef,
203
                waiting_date         => undef
204
            }
198
        }
205
        }
199
    );
206
    );
200
207
Lines 203-209 subtest 'suspend() tests' => sub { Link Here
203
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
210
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
204
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
211
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
205
    ok( $suspended->is_suspended, 'The hold is suspended' );
212
    ok( $suspended->is_suspended, 'The hold is suspended' );
206
    is( $suspended->suspend_until, undef, 'It is an indefinite suspension' );
213
    is( $suspended->suspended_until_date, undef, 'It is an indefinite suspension' );
207
214
208
    # resume the hold
215
    # resume the hold
209
    $suspended->resume;
216
    $suspended->resume;
Lines 215-221 subtest 'suspend() tests' => sub { Link Here
215
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
222
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
216
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
223
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
217
    ok( $suspended->is_suspended, 'The hold is suspended' );
224
    ok( $suspended->is_suspended, 'The hold is suspended' );
218
    is( $suspended->suspend_until, $date->truncate( to => 'day' ), 'It is an indefinite suspension' );
225
    is( $suspended->suspended_until_date, $date->truncate( to => 'day' ), 'It is an indefinite suspension' );
219
226
220
    # resume the hold
227
    # resume the hold
221
    $suspended->resume;
228
    $suspended->resume;
Lines 228-234 subtest 'suspend() tests' => sub { Link Here
228
        'Koha::Exceptions::Hold::CannotSuspendFound',
235
        'Koha::Exceptions::Hold::CannotSuspendFound',
229
        'Exception is thrown when a found hold is tried to suspend';
236
        'Exception is thrown when a found hold is tried to suspend';
230
237
231
    is( $@->status, 'W', 'Exception gets the \'status\' parameter set correctly' );
238
    is( $@->status, 'waiting', 'Exception gets the \'status\' parameter set correctly' );
232
239
233
    # set hold found=T
240
    # set hold found=T
234
    $hold->set_transfer;
241
    $hold->set_transfer;
Lines 237-243 subtest 'suspend() tests' => sub { Link Here
237
        'Koha::Exceptions::Hold::CannotSuspendFound',
244
        'Koha::Exceptions::Hold::CannotSuspendFound',
238
        'Exception is thrown when a found hold is tried to suspend';
245
        'Exception is thrown when a found hold is tried to suspend';
239
246
240
    is( $@->status, 'T', 'Exception gets the \'status\' parameter set correctly' );
247
    is( $@->status, 'in_transit', 'Exception gets the \'status\' parameter set correctly' );
241
248
242
    # set hold found=T
249
    # set hold found=T
243
    $hold->set_processing();
250
    $hold->set_processing();
Lines 252-258 subtest 'suspend() tests' => sub { Link Here
252
    $holds_module->mock( 'is_found', 1 );
259
    $holds_module->mock( 'is_found', 1 );
253
260
254
    # bad data case
261
    # bad data case
255
    $hold->found('X');
262
    $hold->status('cancelled');
256
    throws_ok
263
    throws_ok
257
        { $hold->suspend_hold }
264
        { $hold->suspend_hold }
258
        'Koha::Exceptions::Hold::CannotSuspendFound',
265
        'Koha::Exceptions::Hold::CannotSuspendFound',
Lines 260-267 subtest 'suspend() tests' => sub { Link Here
260
267
261
    is( $@->error, 'Unhandled data exception on found hold (id='
268
    is( $@->error, 'Unhandled data exception on found hold (id='
262
                    . $hold->id
269
                    . $hold->id
263
                    . ', found='
270
                    . ', status='
264
                    . $hold->found
271
                    . $hold->status
265
                    . ')' , 'Exception gets the \'status\' parameter set correctly' );
272
                    . ')' , 'Exception gets the \'status\' parameter set correctly' );
266
273
267
    $holds_module->unmock( 'is_found' );
274
    $holds_module->unmock( 'is_found' );
Lines 273-280 subtest 'suspend() tests' => sub { Link Here
273
            { module => 'HOLDS', action => 'SUSPEND', object => $hold->id } )->count;
280
            { module => 'HOLDS', action => 'SUSPEND', object => $hold->id } )->count;
274
281
275
    $hold = $builder->build_object(
282
    $hold = $builder->build_object(
276
        {   class => 'Koha::Holds',
283
        {
277
            value => { suspend => 0, suspend_until => undef, waitingdate => undef, found => undef }
284
            class => 'Koha::Holds',
285
            value => {
286
                suspended            => 0,
287
                suspended_until_date => undef,
288
                waiting_date         => undef,
289
                status               => 'placed'
290
            }
278
        }
291
        }
279
    );
292
    );
280
293
(-)a/t/db_dependent/Holds.t (-42 / +40 lines)
Lines 48-54 my $category = $builder->build({ source => 'Category' }); Link Here
48
my $borrowers_count = 5;
48
my $borrowers_count = 5;
49
49
50
$dbh->do('DELETE FROM itemtypes');
50
$dbh->do('DELETE FROM itemtypes');
51
$dbh->do('DELETE FROM reserves');
51
$dbh->do('DELETE FROM holds');
52
$dbh->do('DELETE FROM circulation_rules');
52
$dbh->do('DELETE FROM circulation_rules');
53
my $insert_sth = $dbh->prepare('INSERT INTO itemtypes (itemtype) VALUES (?)');
53
my $insert_sth = $dbh->prepare('INSERT INTO itemtypes (itemtype) VALUES (?)');
54
$insert_sth->execute('CAN');
54
$insert_sth->execute('CAN');
Lines 98-107 is( $holds->next->priority, 5, "Reserve 5 has a priority of 5" ); Link Here
98
my $item = Koha::Items->find( $itemnumber );
98
my $item = Koha::Items->find( $itemnumber );
99
$holds = $item->current_holds;
99
$holds = $item->current_holds;
100
my $first_hold = $holds->next;
100
my $first_hold = $holds->next;
101
my $reservedate = $first_hold->reservedate;
101
my $reservedate = $first_hold->created_date;
102
my $borrowernumber = $first_hold->borrowernumber;
102
my $borrowernumber = $first_hold->patron_id;
103
my $branch_1code = $first_hold->branchcode;
103
my $branch_1code = $first_hold->pickup_library_id;
104
my $reserve_id = $first_hold->reserve_id;
104
my $reserve_id = $first_hold->id;
105
is( $reservedate, output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 }), "holds_placed_today should return a valid reserve date");
105
is( $reservedate, output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 }), "holds_placed_today should return a valid reserve date");
106
is( $borrowernumber, $borrowernumbers[0], "holds_placed_today should return a valid borrowernumber");
106
is( $borrowernumber, $borrowernumbers[0], "holds_placed_today should return a valid borrowernumber");
107
is( $branch_1code, $branch_1, "holds_placed_today should return a valid branchcode");
107
is( $branch_1code, $branch_1, "holds_placed_today should return a valid branchcode");
Lines 118-138 ok( $hold_item == $hold->item(), "item method returns stashed item" ); Link Here
118
my $hold_branch = $hold->branch();
118
my $hold_branch = $hold->branch();
119
ok( $hold_branch, "Got branch using branch() method" );
119
ok( $hold_branch, "Got branch using branch() method" );
120
ok( $hold_branch == $hold->branch(), "branch method returns stashed branch" );
120
ok( $hold_branch == $hold->branch(), "branch method returns stashed branch" );
121
my $hold_found = $hold->found();
121
my $hold_found = $hold->status();
122
$hold->set({ found => 'W'})->store();
122
$hold->set({ status => 'waiting' })->store();
123
is( Koha::Holds->waiting()->count(), 1, "Koha::Holds->waiting returns waiting holds" );
123
is( Koha::Holds->waiting()->count(), 1, "Koha::Holds->waiting returns waiting holds" );
124
is( Koha::Holds->unfilled()->count(), 4, "Koha::Holds->unfilled returns unfilled holds" );
124
is( Koha::Holds->unfilled()->count(), 4, "Koha::Holds->unfilled returns unfilled holds" );
125
125
126
my $patron = Koha::Patrons->find( $borrowernumbers[0] );
126
my $patron = Koha::Patrons->find( $borrowernumbers[0] );
127
$holds = $patron->holds;
127
$holds = $patron->holds;
128
is( $holds->next->borrowernumber, $borrowernumbers[0], "Test Koha::Patron->holds");
128
is( $holds->next->patron_id, $borrowernumbers[0], "Test Koha::Patron->holds");
129
129
130
130
131
$holds = $item->current_holds;
131
$holds = $item->current_holds;
132
$first_hold = $holds->next;
132
$first_hold = $holds->next;
133
$borrowernumber = $first_hold->borrowernumber;
133
$borrowernumber = $first_hold->patron_id;
134
$branch_1code = $first_hold->branchcode;
134
$branch_1code = $first_hold->pickup_library_id;
135
$reserve_id = $first_hold->reserve_id;
135
$reserve_id = $first_hold->id;
136
136
137
ModReserve({
137
ModReserve({
138
    reserve_id    => $reserve_id,
138
    reserve_id    => $reserve_id,
Lines 144-151 ModReserve({ Link Here
144
144
145
$hold = Koha::Holds->find( $reserve_id );
145
$hold = Koha::Holds->find( $reserve_id );
146
ok( $hold->priority eq '4', "Test ModReserve, priority changed correctly" );
146
ok( $hold->priority eq '4', "Test ModReserve, priority changed correctly" );
147
ok( $hold->suspend, "Test ModReserve, suspend hold" );
147
ok( $hold->suspended, "Test ModReserve, suspend hold" );
148
is( $hold->suspend_until, '2013-01-01 00:00:00', "Test ModReserve, suspend until date" );
148
is( $hold->suspended_until_date, '2013-01-01 00:00:00', "Test ModReserve, suspend until date" );
149
149
150
ModReserve({ # call without reserve_id
150
ModReserve({ # call without reserve_id
151
    rank          => '3',
151
    rank          => '3',
Lines 158-172 ok( $hold->priority eq '3', "Test ModReserve, priority changed correctly" ); Link Here
158
158
159
ToggleSuspend( $reserve_id );
159
ToggleSuspend( $reserve_id );
160
$hold = Koha::Holds->find( $reserve_id );
160
$hold = Koha::Holds->find( $reserve_id );
161
ok( ! $hold->suspend, "Test ToggleSuspend(), no date" );
161
ok( ! $hold->suspended, "Test ToggleSuspend(), no date" );
162
162
163
ToggleSuspend( $reserve_id, '2012-01-01' );
163
ToggleSuspend( $reserve_id, '2012-01-01' );
164
$hold = Koha::Holds->find( $reserve_id );
164
$hold = Koha::Holds->find( $reserve_id );
165
is( $hold->suspend_until, '2012-01-01 00:00:00', "Test ToggleSuspend(), with date" );
165
is( $hold->suspended_until_date, '2012-01-01 00:00:00', "Test ToggleSuspend(), with date" );
166
166
167
AutoUnsuspendReserves();
167
AutoUnsuspendReserves();
168
$hold = Koha::Holds->find( $reserve_id );
168
$hold = Koha::Holds->find( $reserve_id );
169
ok( ! $hold->suspend, "Test AutoUnsuspendReserves()" );
169
ok( ! $hold->suspended, "Test AutoUnsuspendReserves()" );
170
170
171
SuspendAll(
171
SuspendAll(
172
    borrowernumber => $borrowernumber,
172
    borrowernumber => $borrowernumber,
Lines 175-182 SuspendAll( Link Here
175
    suspend_until => '2012-01-01',
175
    suspend_until => '2012-01-01',
176
);
176
);
177
$hold = Koha::Holds->find( $reserve_id );
177
$hold = Koha::Holds->find( $reserve_id );
178
is( $hold->suspend, 1, "Test SuspendAll()" );
178
is( $hold->suspended, 1, "Test SuspendAll()" );
179
is( $hold->suspend_until, '2012-01-01 00:00:00', "Test SuspendAll(), with date" );
179
is( $hold->suspended_until_date, '2012-01-01 00:00:00', "Test SuspendAll(), with date" );
180
180
181
SuspendAll(
181
SuspendAll(
182
    borrowernumber => $borrowernumber,
182
    borrowernumber => $borrowernumber,
Lines 184-191 SuspendAll( Link Here
184
    suspend => 0,
184
    suspend => 0,
185
);
185
);
186
$hold = Koha::Holds->find( $reserve_id );
186
$hold = Koha::Holds->find( $reserve_id );
187
is( $hold->suspend, 0, "Test resuming with SuspendAll()" );
187
is( $hold->suspended, 0, "Test resuming with SuspendAll()" );
188
is( $hold->suspend_until, undef, "Test resuming with SuspendAll(), should have no suspend until date" );
188
is( $hold->suspended_until_date, undef, "Test resuming with SuspendAll(), should have no suspend until date" );
189
189
190
# Add a new hold for the borrower whose hold we canceled earlier, this time at the bib level
190
# Add a new hold for the borrower whose hold we canceled earlier, this time at the bib level
191
    AddReserve(
191
    AddReserve(
Lines 198-223 is( $hold->suspend_until, undef, "Test resuming with SuspendAll(), should have n Link Here
198
198
199
$patron = Koha::Patrons->find( $borrowernumber );
199
$patron = Koha::Patrons->find( $borrowernumber );
200
$holds = $patron->holds;
200
$holds = $patron->holds;
201
my $reserveid = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $borrowernumbers[0] })->next->reserve_id;
201
my $reserveid = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $borrowernumbers[0] })->next->id;
202
ModReserveMinusPriority( $itemnumber, $reserveid );
202
ModReserveMinusPriority( $itemnumber, $reserveid );
203
$holds = $patron->holds;
203
$holds = $patron->holds;
204
is( $holds->search({ itemnumber => $itemnumber })->count, 1, "Test ModReserveMinusPriority()" );
204
is( $holds->search({ item_id => $itemnumber })->count, 1, "Test ModReserveMinusPriority()" );
205
205
206
$holds = $biblio->holds;
206
$holds = $biblio->holds;
207
$hold = $holds->next;
207
$hold = $holds->next;
208
AlterPriority( 'top', $hold->reserve_id, undef, 2, 1, 6 );
208
AlterPriority( 'top', $hold->id, undef, 2, 1, 6 );
209
$hold = Koha::Holds->find( $reserveid );
209
$hold = Koha::Holds->find( $reserveid );
210
is( $hold->priority, '1', "Test AlterPriority(), move to top" );
210
is( $hold->priority, '1', "Test AlterPriority(), move to top" );
211
211
212
AlterPriority( 'down', $hold->reserve_id, undef, 2, 1, 6 );
212
AlterPriority( 'down', $hold->id, undef, 2, 1, 6 );
213
$hold = Koha::Holds->find( $reserveid );
213
$hold = Koha::Holds->find( $reserveid );
214
is( $hold->priority, '2', "Test AlterPriority(), move down" );
214
is( $hold->priority, '2', "Test AlterPriority(), move down" );
215
215
216
AlterPriority( 'up', $hold->reserve_id, 1, 3, 1, 6 );
216
AlterPriority( 'up', $hold->id, 1, 3, 1, 6 );
217
$hold = Koha::Holds->find( $reserveid );
217
$hold = Koha::Holds->find( $reserveid );
218
is( $hold->priority, '1', "Test AlterPriority(), move up" );
218
is( $hold->priority, '1', "Test AlterPriority(), move up" );
219
219
220
AlterPriority( 'bottom', $hold->reserve_id, undef, 2, 1, 6 );
220
AlterPriority( 'bottom', $hold->id, undef, 2, 1, 6 );
221
$hold = Koha::Holds->find( $reserveid );
221
$hold = Koha::Holds->find( $reserveid );
222
is( $hold->priority, '6', "Test AlterPriority(), move to bottom" );
222
is( $hold->priority, '6', "Test AlterPriority(), move to bottom" );
223
223
Lines 317-323 ok( Link Here
317
        }
317
        }
318
    );
318
    );
319
319
320
    my $hhh = Koha::Holds->search({ biblionumber => $biblio->biblionumber });
320
    my $hhh = Koha::Holds->search({ biblio_id => $biblio->biblionumber });
321
    my $hold3 = Koha::Holds->find( $reserveid3 );
321
    my $hold3 = Koha::Holds->find( $reserveid3 );
322
    is( $hold3->priority, 3, "The 3rd hold should have a priority set to 3" );
322
    is( $hold3->priority, 3, "The 3rd hold should have a priority set to 3" );
323
    ModReserve({ reserve_id => $reserveid1, rank => 'del' });
323
    ModReserve({ reserve_id => $reserveid1, rank => 'del' });
Lines 332-340 ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold can be trapped for damag Link Here
332
332
333
$hold = Koha::Hold->new(
333
$hold = Koha::Hold->new(
334
    {
334
    {
335
        borrowernumber => $borrowernumbers[0],
335
        patron_id => $borrowernumbers[0],
336
        itemnumber     => $itemnumber,
336
        item_id   => $itemnumber,
337
        biblionumber   => $biblio->biblionumber,
337
        biblio_id => $biblio->biblionumber,
338
    }
338
    }
339
)->store();
339
)->store();
340
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber )->{status},
340
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber )->{status},
Lines 349-365 ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for d Link Here
349
# Items that are not for loan, but holdable should not be trapped until they are available for loan
349
# Items that are not for loan, but holdable should not be trapped until they are available for loan
350
t::lib::Mocks::mock_preference( 'TrapHoldsOnOrder', 0 );
350
t::lib::Mocks::mock_preference( 'TrapHoldsOnOrder', 0 );
351
Koha::Items->find($itemnumber)->damaged(0)->notforloan(-1)->store;
351
Koha::Items->find($itemnumber)->damaged(0)->notforloan(-1)->store;
352
Koha::Holds->search({ biblionumber => $biblio->id })->delete();
352
Koha::Holds->search({ biblio_id => $biblio->id })->delete();
353
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber)->{status}, 'OK', "Patron can place hold on item that is not for loan but holdable ( notforloan < 0 )" );
353
is( CanItemBeReserved( $borrowernumbers[0], $itemnumber)->{status}, 'OK', "Patron can place hold on item that is not for loan but holdable ( notforloan < 0 )" );
354
$hold = Koha::Hold->new(
354
$hold = Koha::Hold->new(
355
    {
355
    {
356
        borrowernumber => $borrowernumbers[0],
356
        patron_id         => $borrowernumbers[0],
357
        itemnumber     => $itemnumber,
357
        item_id           => $itemnumber,
358
        biblionumber   => $biblio->biblionumber,
358
        biblio_id         => $biblio->biblionumber,
359
        found          => undef,
359
        priority          => 1,
360
        priority       => 1,
360
        pickup_library_id => $branch_1,
361
        reservedate    => dt_from_string,
362
        branchcode     => $branch_1,
363
    }
361
    }
364
)->store();
362
)->store();
365
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for item that is not for loan but holdable ( notforloan < 0 )" );
363
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for item that is not for loan but holdable ( notforloan < 0 )" );
Lines 458-464 is(CanItemBeReserved($borrowernumbers[0], $itemnumber)->{status}, 'OK', Link Here
458
t::lib::Mocks::mock_preference( 'item-level_itypes',     1 );
456
t::lib::Mocks::mock_preference( 'item-level_itypes',     1 );
459
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
457
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
460
458
461
$dbh->do('DELETE FROM reserves');
459
$dbh->do('DELETE FROM holds');
462
$dbh->do('DELETE FROM issues');
460
$dbh->do('DELETE FROM issues');
463
$dbh->do('DELETE FROM items');
461
$dbh->do('DELETE FROM items');
464
$dbh->do('DELETE FROM biblio');
462
$dbh->do('DELETE FROM biblio');
Lines 502-508 t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' ); Link Here
502
subtest 'Test max_holds per library/patron category' => sub {
500
subtest 'Test max_holds per library/patron category' => sub {
503
    plan tests => 6;
501
    plan tests => 6;
504
502
505
    $dbh->do('DELETE FROM reserves');
503
    $dbh->do('DELETE FROM holds');
506
504
507
    $biblio = $builder->build_sample_biblio;
505
    $biblio = $builder->build_sample_biblio;
508
    $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
506
    $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
Lines 530-536 subtest 'Test max_holds per library/patron category' => sub { Link Here
530
    }
528
    }
531
529
532
    my $count =
530
    my $count =
533
      Koha::Holds->search( { borrowernumber => $borrowernumbers[0] } )->count();
531
      Koha::Holds->search( { patron_id => $borrowernumbers[0] } )->count();
534
    is( $count, 3, 'Patron now has 3 holds' );
532
    is( $count, 3, 'Patron now has 3 holds' );
535
533
536
    my $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
534
    my $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
Lines 715-721 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
715
    # Update last hold so reservedate is in the past, so 2 holds, but different day
713
    # Update last hold so reservedate is in the past, so 2 holds, but different day
716
    $hold = Koha::Holds->find($res_id);
714
    $hold = Koha::Holds->find($res_id);
717
    my $yesterday = dt_from_string() - DateTime::Duration->new( days => 1 );
715
    my $yesterday = dt_from_string() - DateTime::Duration->new( days => 1 );
718
    $hold->reservedate($yesterday)->store;
716
    $hold->created_date($yesterday)->store;
719
717
720
    is_deeply(
718
    is_deeply(
721
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
719
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
(-)a/t/db_dependent/Holds/DisallowHoldIfItemsAvailable.t (-3 / +3 lines)
Lines 290-299 my $itemtype2 = $builder->build( Link Here
290
my $item3 = $builder->build_sample_item( { itype => $itemtype2 } );
290
my $item3 = $builder->build_sample_item( { itype => $itemtype2 } );
291
291
292
my $hold = $builder->build(
292
my $hold = $builder->build(
293
    {   source => 'Reserve',
293
    {   source => 'Hold',
294
        value  => {
294
        value  => {
295
            itemnumber => $item3->itemnumber,
295
            item_id => $item3->itemnumber,
296
            found      => 'T'
296
            status  => 'in_transit'
297
        }
297
        }
298
    }
298
    }
299
);
299
);
(-)a/t/db_dependent/Holds/HoldItemtypeLimit.t (-1 / +1 lines)
Lines 57-63 my $right_itemtype = $itemtype1->{itemtype}; Link Here
57
my $wrong_itemtype = $itemtype2->{itemtype};
57
my $wrong_itemtype = $itemtype2->{itemtype};
58
my $borrowernumber = $borrower->{borrowernumber};
58
my $borrowernumber = $borrower->{borrowernumber};
59
my $branchcode = $library->{branchcode};
59
my $branchcode = $library->{branchcode};
60
$dbh->do("DELETE FROM reserves");
60
$dbh->do("DELETE FROM holds");
61
$dbh->do("DELETE FROM issues");
61
$dbh->do("DELETE FROM issues");
62
$dbh->do("DELETE FROM items");
62
$dbh->do("DELETE FROM items");
63
$dbh->do("DELETE FROM biblio");
63
$dbh->do("DELETE FROM biblio");
(-)a/t/db_dependent/Holds/LocalHoldsPriority.t (-6 / +6 lines)
Lines 85-113 my ($status, $reserve, $all_reserves); Link Here
85
85
86
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 0 );
86
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 0 );
87
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
87
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
88
ok( $reserve->{borrowernumber} eq $borrowernumbers[0], "Received expected results with LocalHoldsPriority disabled" );
88
ok( $reserve->{patron_id} eq $borrowernumbers[0], "Received expected results with LocalHoldsPriority disabled" );
89
89
90
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
90
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
91
91
92
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
92
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
93
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
93
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
94
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
94
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
95
ok( $reserve->{borrowernumber} eq $borrowernumbers[2], "Received expected results with PickupLibrary/homebranch" );
95
ok( $reserve->{patron_id} eq $borrowernumbers[2], "Received expected results with PickupLibrary/homebranch" );
96
96
97
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
97
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
98
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
98
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
99
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
99
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
100
ok( $reserve->{borrowernumber} eq $borrowernumbers[1], "Received expected results with PickupLibrary/holdingbranch" );
100
ok( $reserve->{patron_id} eq $borrowernumbers[1], "Received expected results with PickupLibrary/holdingbranch" );
101
101
102
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
102
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
103
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
103
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
104
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
104
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
105
ok( $reserve->{borrowernumber} eq $borrowernumbers[2], "Received expected results with HomeLibrary/holdingbranch" );
105
ok( $reserve->{patron_id} eq $borrowernumbers[2], "Received expected results with HomeLibrary/holdingbranch" );
106
106
107
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
107
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
108
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
108
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
109
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
109
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
110
ok( $reserve->{borrowernumber} eq $borrowernumbers[3], "Received expected results with HomeLibrary/homebranch" );
110
ok( $reserve->{patron_id} eq $borrowernumbers[3], "Received expected results with HomeLibrary/homebranch" );
111
111
112
$schema->storage->txn_rollback;
112
$schema->storage->txn_rollback;
113
113
Lines 208-211 subtest "exclude from local holds" => sub { Link Here
208
    is($reserve->{borrowernumber}, $patron_nex_l2->borrowernumber, "Patron from other library is next checkout because item is excluded");
208
    is($reserve->{borrowernumber}, $patron_nex_l2->borrowernumber, "Patron from other library is next checkout because item is excluded");
209
209
210
    $schema->storage->txn_rollback;
210
    $schema->storage->txn_rollback;
211
};
211
};
(-)a/t/db_dependent/Holds/RevertWaitingStatus.t (-2 / +1 lines)
Lines 34-41 $schema->storage->txn_begin; Link Here
34
my $builder = t::lib::TestBuilder->new;
34
my $builder = t::lib::TestBuilder->new;
35
my $dbh = C4::Context->dbh;
35
my $dbh = C4::Context->dbh;
36
36
37
$dbh->do("DELETE FROM reserves");
37
$dbh->do("DELETE FROM holds");
38
$dbh->do("DELETE FROM old_reserves");
39
38
40
my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
39
my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
41
my $itemtype = $builder->build(
40
my $itemtype = $builder->build(
(-)a/t/db_dependent/Holds/WaitingReserves.t (-46 / +50 lines)
Lines 18-24 $schema->storage->txn_begin; Link Here
18
my $dbh = C4::Context->dbh;
18
my $dbh = C4::Context->dbh;
19
$dbh->do(q{DELETE FROM special_holidays});
19
$dbh->do(q{DELETE FROM special_holidays});
20
$dbh->do(q{DELETE FROM repeatable_holidays});
20
$dbh->do(q{DELETE FROM repeatable_holidays});
21
$dbh->do("DELETE FROM reserves");
21
$dbh->do(q{DELETE FROM holds});
22
22
23
my $builder = t::lib::TestBuilder->new();
23
my $builder = t::lib::TestBuilder->new();
24
24
Lines 77-92 $reserve1_reservedate->subtract(days => 20); Link Here
77
my $reserve1_expirationdate = $today->clone;
77
my $reserve1_expirationdate = $today->clone;
78
$reserve1_expirationdate->add(days => 6);
78
$reserve1_expirationdate->add(days => 6);
79
79
80
my $reserve1 = $builder->build({
80
my $r = $builder->build_object({
81
    source => 'Reserve',
81
    class => 'Koha::Holds',
82
    value => {
82
    value => {
83
        borrowernumber => $patron1->{borrowernumber},
83
        patron_id => $patron1->{borrowernumber},
84
        reservedate => $reserve1_reservedate->ymd,
84
        created_date => $reserve1_reservedate->ymd,
85
        expirationdate => undef,
85
        expiration_date => undef,
86
        biblionumber => $biblio->biblionumber,
86
        biblio_id => $biblio->biblionumber,
87
        branchcode => 'LIB1',
87
        pickup_library_id => 'LIB1',
88
        priority => 1,
88
        priority => 1,
89
        found => '',
89
        status => 'placed',
90
        completed => 0
90
    },
91
    },
91
});
92
});
92
93
Lines 94-137 t::lib::Mocks::mock_preference('ExpireReservesMaxPickUpDelay', 1); Link Here
94
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 6);
95
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 6);
95
96
96
ModReserveAffect( $item1->itemnumber, $patron1->{borrowernumber});
97
ModReserveAffect( $item1->itemnumber, $patron1->{borrowernumber});
97
my $r = Koha::Holds->find($reserve1->{reserve_id});
98
$r->discard_changes;
98
99
99
is($r->waitingdate, $today->ymd, 'Waiting date should be set to today' );
100
is($r->waiting_date, $today->ymd, 'Waiting date should be set to today' );
100
is($r->expirationdate, $reserve1_expirationdate->ymd, 'Expiration date should be set to today + 6' );
101
is($r->expiration_date, $reserve1_expirationdate->ymd, 'Expiration date should be set to today + 6' );
101
is($r->found, 'W', 'Reserve status is now "waiting"' );
102
is($r->status, 'waiting', 'Reserve status is now "waiting"' );
102
is($r->priority, 0, 'Priority should be 0' );
103
is($r->priority, 0, 'Priority should be 0' );
103
is($r->itemnumber, $item1->itemnumber, 'Item number should be set correctly' );
104
is($r->item_id, $item1->itemnumber, 'Item number should be set correctly' );
104
105
105
my $reserve2 = $builder->build({
106
my $r2 = $builder->build_object({
106
    source => 'Reserve',
107
    class => 'Koha::Holds',
107
    value => {
108
    value => {
108
        borrowernumber => $patron2->{borrowernumber},
109
        patron_id => $patron2->{borrowernumber},
109
        reservedate => $reserve1_reservedate->ymd,
110
        created_date => $reserve1_reservedate->ymd,
110
        expirationdate => undef,
111
        expiration_date => undef,
111
        biblionumber => $biblio2->biblionumber,
112
        biblio_id => $biblio2->biblionumber,
112
        branchcode => 'LIB1',
113
        pickup_library_id => 'LIB1',
113
        priority => 1,
114
        priority => 1,
114
        found => '',
115
        status => 'placed',
116
        completed => 0
115
    },
117
    },
116
});
118
});
117
119
118
ModReserveAffect( $item2->itemnumber, $patron2->{borrowernumber}, 1);
120
ModReserveAffect( $item2->itemnumber, $patron2->{borrowernumber}, 1);
119
my $r2 = Koha::Holds->find($reserve2->{reserve_id});
121
$r2->discard_changes;
120
122
121
is($r2->found, 'T', '2nd reserve - Reserve status is now "To transfer"' );
123
is($r2->status, 'in_transit', '2nd reserve - Reserve status is now "To transfer"' );
122
is($r2->priority, 0, '2nd reserve - Priority should be 0' );
124
is($r2->priority, 0, '2nd reserve - Priority should be 0' );
123
is($r2->itemnumber, $item2->itemnumber, '2nd reserve - Item number should be set correctly' );
125
is($r2->item_id, $item2->itemnumber, '2nd reserve - Item number should be set correctly' );
124
126
125
my $reserve3 = $builder->build({
127
my $r3 = $builder->build_object({
126
    source => 'Reserve',
128
    class => 'Koha::Holds',
127
    value => {
129
    value => {
128
        borrowernumber => $patron2->{borrowernumber},
130
        patron_id => $patron2->{borrowernumber},
129
        reservedate => $reserve1_reservedate->ymd,
131
        created_date => $reserve1_reservedate->ymd,
130
        expirationdate => undef,
132
        expiration_date => undef,
131
        biblionumber => $biblio3->biblionumber,
133
        biblio_id => $biblio3->biblionumber,
132
        branchcode => 'LIB1',
134
        pickup_library_id => 'LIB1',
133
        priority => 1,
135
        priority => 1,
134
        found => '',
136
        status => 'placed',
137
        completed => 0
135
    },
138
    },
136
});
139
});
137
140
Lines 174-202 ModReserveAffect( $item3->itemnumber, $patron2->{borrowernumber}); Link Here
174
my $expected_expiration = $today->clone;
177
my $expected_expiration = $today->clone;
175
$expected_expiration->add(days => 8);
178
$expected_expiration->add(days => 8);
176
179
177
my $r3 = Koha::Holds->find($reserve3->{reserve_id});
180
$r3->discard_changes;
178
is($r3->expirationdate, $expected_expiration->ymd, 'Expiration date should be set to today + 7' );
181
is($r3->expiration_date, $expected_expiration->ymd, 'Expiration date should be set to today + 7' );
179
182
180
my $reserve4_reservedate = $today->clone;
183
my $reserve4_reservedate = $today->clone;
181
my $requested_expiredate = $today->clone()->add(days => 6);
184
my $requested_expiredate = $today->clone()->add(days => 6);
182
185
183
my $reserve4 = $builder->build({
186
my $r4 = $builder->build_object({
184
    source => 'Reserve',
187
    class => 'Koha::Holds',
185
    value => {
188
    value => {
186
        borrowernumber => $patron2->{borrowernumber},
189
        patron_id => $patron2->{borrowernumber},
187
        reservedate => $reserve4_reservedate->ymd,
190
        created_date => $reserve4_reservedate->ymd,
188
        expirationdate => $requested_expiredate->ymd,
191
        expiration_date => $requested_expiredate->ymd,
189
        biblionumber => $biblio4->biblionumber,
192
        biblio_id => $biblio4->biblionumber,
190
        branchcode => 'LIB1',
193
        pickup_library_id => 'LIB1',
191
        priority => 1,
194
        priority => 1,
192
        found => '',
195
        status => 'placed',
196
        completed => 0
193
    },
197
    },
194
});
198
});
195
199
196
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 10);
200
t::lib::Mocks::mock_preference('ReservesMaxPickUpDelay', 10);
197
ModReserveAffect( $item4->itemnumber, $patron2->{borrowernumber}, 0, $reserve4->{reserve_id});
201
ModReserveAffect( $item4->itemnumber, $patron2->{borrowernumber}, 0, $r4->id );
198
202
199
my $r4 = Koha::Holds->find($reserve4->{reserve_id});
203
$r4->discard_changes;
200
is($r4->expirationdate, $requested_expiredate->ymd, 'Requested expiration date should be kept' );
204
is($r4->expiration_date, $requested_expiredate->ymd, 'Requested expiration date should be kept' );
201
205
202
$schema->storage->txn_rollback;
206
$schema->storage->txn_rollback;
(-)a/t/db_dependent/HoldsQueue.t (-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 created_date = DATE_SUB( created_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 288-301 $items_insert_sth->execute( $barcode + 0, $branchcodes[0], $branchcodes[0] ); Link Here
288
$items_insert_sth->execute( $barcode + 1, $branchcodes[1], $branchcodes[1] );
288
$items_insert_sth->execute( $barcode + 1, $branchcodes[1], $branchcodes[1] );
289
$items_insert_sth->execute( $barcode + 2, $branchcodes[1], $branchcodes[1] );
289
$items_insert_sth->execute( $barcode + 2, $branchcodes[1], $branchcodes[1] );
290
290
291
$dbh->do("DELETE FROM reserves");
291
$dbh->do("DELETE FROM holds");
292
my $sth = $dbh->prepare(q{
292
my $sth = $dbh->prepare(q{
293
    INSERT INTO reserves (
293
    INSERT INTO holds (
294
        borrowernumber,
294
        patron_id,
295
        biblionumber,
295
        biblio_id,
296
        branchcode,
296
        pickup_library_id,
297
        priority,
297
        priority,
298
        reservedate
298
        created_date
299
    ) VALUES ( ?,?,?,?, CURRENT_DATE() )
299
    ) VALUES ( ?,?,?,?, CURRENT_DATE() )
300
});
300
});
301
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
301
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
Lines 383-389 $dbh->do("DELETE FROM issues"); Link Here
383
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
383
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
384
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
384
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
385
C4::Context->clear_syspref_cache();
385
C4::Context->clear_syspref_cache();
386
$dbh->do("DELETE FROM reserves");
386
$dbh->do("DELETE FROM holds");
387
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
387
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
388
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
388
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
389
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
389
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
Lines 401-407 t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary') Link Here
401
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
401
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
402
t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '1' );
402
t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '1' );
403
C4::Context->clear_syspref_cache();
403
C4::Context->clear_syspref_cache();
404
$dbh->do("DELETE FROM reserves");
404
$dbh->do("DELETE FROM holds");
405
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
405
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
406
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[1], 2 );
406
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[1], 2 );
407
407
Lines 443-449 t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '0' ); Link Here
443
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
443
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
444
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
444
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
445
C4::Context->clear_syspref_cache();
445
C4::Context->clear_syspref_cache();
446
$dbh->do("DELETE FROM reserves");
446
$dbh->do("DELETE FROM holds");
447
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
447
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
448
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
448
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
449
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
449
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
Lines 460-466 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue givi Link Here
460
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
460
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
461
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
461
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
462
C4::Context->clear_syspref_cache();
462
C4::Context->clear_syspref_cache();
463
$dbh->do("DELETE FROM reserves");
463
$dbh->do("DELETE FROM holds");
464
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
464
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
465
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
465
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
466
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
466
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
Lines 477-483 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue givi Link Here
477
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
477
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
478
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
478
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
479
C4::Context->clear_syspref_cache();
479
C4::Context->clear_syspref_cache();
480
$dbh->do("DELETE FROM reserves");
480
$dbh->do("DELETE FROM holds");
481
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
481
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
482
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
482
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
483
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
483
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
Lines 500-506 $borrowernumber = $borrower3->{borrowernumber}; Link Here
500
my $library_A = $library1->{branchcode};
500
my $library_A = $library1->{branchcode};
501
my $library_B = $library2->{branchcode};
501
my $library_B = $library2->{branchcode};
502
my $library_C = $borrower3->{branchcode};
502
my $library_C = $borrower3->{branchcode};
503
$dbh->do("DELETE FROM reserves");
503
$dbh->do("DELETE FROM holds");
504
$dbh->do("DELETE FROM issues");
504
$dbh->do("DELETE FROM issues");
505
$dbh->do("DELETE FROM items");
505
$dbh->do("DELETE FROM items");
506
$dbh->do("DELETE FROM biblio");
506
$dbh->do("DELETE FROM biblio");
Lines 565-571 $itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } Link Here
565
$borrowernumber = $borrower2->{borrowernumber};
565
$borrowernumber = $borrower2->{borrowernumber};
566
$library_A = $library1->{branchcode};
566
$library_A = $library1->{branchcode};
567
$library_B = $library2->{branchcode};
567
$library_B = $library2->{branchcode};
568
$dbh->do("DELETE FROM reserves");
568
$dbh->do("DELETE FROM holds");
569
$dbh->do("DELETE FROM issues");
569
$dbh->do("DELETE FROM issues");
570
$dbh->do("DELETE FROM items");
570
$dbh->do("DELETE FROM items");
571
$dbh->do("DELETE FROM biblio");
571
$dbh->do("DELETE FROM biblio");
Lines 618-624 $borrowernumber = $borrower3->{borrowernumber}; Link Here
618
$library_A = $library1->{branchcode};
618
$library_A = $library1->{branchcode};
619
$library_B = $library2->{branchcode};
619
$library_B = $library2->{branchcode};
620
$library_C = $library3->{branchcode};
620
$library_C = $library3->{branchcode};
621
$dbh->do("DELETE FROM reserves");
621
$dbh->do("DELETE FROM holds");
622
$dbh->do("DELETE FROM issues");
622
$dbh->do("DELETE FROM issues");
623
$dbh->do("DELETE FROM items");
623
$dbh->do("DELETE FROM items");
624
$dbh->do("DELETE FROM biblio");
624
$dbh->do("DELETE FROM biblio");
Lines 828-834 my $wrong_itemtype = $builder->build({ source => 'Itemtype', value => { notforlo Link Here
828
my $right_itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
828
my $right_itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
829
$borrowernumber = $borrower3->{borrowernumber};
829
$borrowernumber = $borrower3->{borrowernumber};
830
my $branchcode = $library1->{branchcode};
830
my $branchcode = $library1->{branchcode};
831
$dbh->do("DELETE FROM reserves");
831
$dbh->do("DELETE FROM holds");
832
$dbh->do("DELETE FROM issues");
832
$dbh->do("DELETE FROM issues");
833
$dbh->do("DELETE FROM items");
833
$dbh->do("DELETE FROM items");
834
$dbh->do("DELETE FROM biblio");
834
$dbh->do("DELETE FROM biblio");
Lines 1204-1210 subtest "Test Local Holds Priority - Ensure no duplicate requests in holds queue Link Here
1204
1204
1205
    $dbh->do("DELETE FROM tmp_holdsqueue");
1205
    $dbh->do("DELETE FROM tmp_holdsqueue");
1206
    $dbh->do("DELETE FROM hold_fill_targets");
1206
    $dbh->do("DELETE FROM hold_fill_targets");
1207
    $dbh->do("DELETE FROM reserves");
1207
    $dbh->do("DELETE FROM holds");
1208
    $dbh->do("DELETE FROM circulation_rules");
1208
    $dbh->do("DELETE FROM circulation_rules");
1209
    Koha::Biblios->delete();
1209
    Koha::Biblios->delete();
1210
1210
(-)a/t/db_dependent/ILSDI_Services.t (-16 / +17 lines)
Lines 326-336 subtest 'Holds test' => sub { Link Here
326
    $item->damaged(0)->store;
326
    $item->damaged(0)->store;
327
327
328
    my $hold = $builder->build({
328
    my $hold = $builder->build({
329
        source => 'Reserve',
329
        source => 'Hold',
330
        value => {
330
        value => {
331
            borrowernumber => $patron->{borrowernumber},
331
            patron_id => $patron->{borrowernumber},
332
            biblionumber => $item->biblionumber,
332
            biblio_id => $item->biblionumber,
333
            itemnumber => $item->itemnumber
333
            item_id   => $item->itemnumber,
334
            completed => 0
334
        }
335
        }
335
    });
336
    });
336
337
Lines 533-547 subtest 'Holds test for branch transfer limits' => sub { Link Here
533
534
534
    $reply = C4::ILSDI::Services::HoldItem( $query );
535
    $reply = C4::ILSDI::Services::HoldItem( $query );
535
    is( $reply->{code}, undef, "Item hold, Item can be transferred" );
536
    is( $reply->{code}, undef, "Item hold, Item can be transferred" );
536
    my $hold = Koha::Holds->search({ itemnumber => $item->itemnumber, borrowernumber => $patron->{borrowernumber} })->next;
537
    my $hold = Koha::Holds->search({ item_id => $item->itemnumber, patron_id => $patron->{borrowernumber} })->next;
537
    is( $hold->branchcode, $pickup_branch->{branchcode}, 'The library id is correctly set' );
538
    is( $hold->pickup_library_id, $pickup_branch->{branchcode}, 'The library id is correctly set' );
538
539
539
    Koha::Holds->search()->delete();
540
    Koha::Holds->search()->delete();
540
541
541
    $reply = C4::ILSDI::Services::HoldTitle( $query );
542
    $reply = C4::ILSDI::Services::HoldTitle( $query );
542
    is( $reply->{code}, undef, "Record hold, Item con be transferred" );
543
    is( $reply->{code}, undef, "Record hold, Item con be transferred" );
543
    $hold = Koha::Holds->search({ biblionumber => $item->biblionumber, borrowernumber => $patron->{borrowernumber} })->next;
544
    $hold = Koha::Holds->search({ biblio_id => $item->biblionumber, patron_id => $patron->{borrowernumber} })->next;
544
    is( $hold->branchcode, $pickup_branch->{branchcode}, 'The library id is correctly set' );
545
    is( $hold->pickup_library_id, $pickup_branch->{branchcode}, 'The library id is correctly set' );
545
546
546
    $schema->storage->txn_rollback;
547
    $schema->storage->txn_rollback;
547
};
548
};
Lines 587-605 subtest 'Holds test with start_date and end_date' => sub { Link Here
587
588
588
    my $reply = C4::ILSDI::Services::HoldItem( $query );
589
    my $reply = C4::ILSDI::Services::HoldItem( $query );
589
    is ($reply->{pickup_location}, $pickup_library->branchname, "Item hold with date parameters was placed");
590
    is ($reply->{pickup_location}, $pickup_library->branchname, "Item hold with date parameters was placed");
590
    my $hold = Koha::Holds->search({ biblionumber => $item->biblionumber})->next();
591
    my $hold = Koha::Holds->search({ biblio_id => $item->biblionumber})->next();
591
    is( $hold->biblionumber, $item->biblionumber, "correct biblionumber");
592
    is( $hold->biblio_id, $item->biblionumber, "correct biblionumber");
592
    is( $hold->reservedate, '2020-03-20', "Item hold has correct start date" );
593
    is( $hold->created_date, '2020-03-20', "Item hold has correct start date" );
593
    is( $hold->expirationdate, '2020-04-22', "Item hold has correct end date" );
594
    is( $hold->expiration_date, '2020-04-22', "Item hold has correct end date" );
594
595
595
    $hold->delete();
596
    $hold->delete();
596
597
597
    $reply = C4::ILSDI::Services::HoldTitle( $query );
598
    $reply = C4::ILSDI::Services::HoldTitle( $query );
598
    is ($reply->{pickup_location}, $pickup_library->branchname, "Record hold with date parameters was placed");
599
    is ($reply->{pickup_location}, $pickup_library->branchname, "Record hold with date parameters was placed");
599
    $hold = Koha::Holds->search({ biblionumber => $item->biblionumber})->next();
600
    $hold = Koha::Holds->search({ biblio_id => $item->biblionumber})->next();
600
    is( $hold->biblionumber, $item->biblionumber, "correct biblionumber");
601
    is( $hold->biblio_id, $item->biblionumber, "correct biblionumber");
601
    is( $hold->reservedate, '2020-03-20', "Record hold has correct start date" );
602
    is( $hold->created_date, '2020-03-20', "Record hold has correct start date" );
602
    is( $hold->expirationdate, '2020-04-22', "Record hold has correct end date" );
603
    is( $hold->expiration_date, '2020-04-22', "Record hold has correct end date" );
603
604
604
    $schema->storage->txn_rollback;
605
    $schema->storage->txn_rollback;
605
};
606
};
(-)a/t/db_dependent/Items/GetItemsForInventory.t (-1 / +1 lines)
Lines 112-118 subtest 'Skip items with waiting holds' => sub { Link Here
112
            biblionumber   => $item_1->biblionumber,
112
            biblionumber   => $item_1->biblionumber,
113
            priority       => 1,
113
            priority       => 1,
114
            itemnumber     => $item_1->itemnumber,
114
            itemnumber     => $item_1->itemnumber,
115
            found          => 'W'
115
            found          => 'waiting'
116
        }
116
        }
117
    );
117
    );
118
    C4::Reserves::AddReserve(
118
    C4::Reserves::AddReserve(
(-)a/t/db_dependent/Items/MoveItemFromBiblio.t (-12 / +12 lines)
Lines 43-60 my $item3 = $builder->build_sample_item( Link Here
43
43
44
44
45
my $bib_level_hold_not_to_move = $builder->build(
45
my $bib_level_hold_not_to_move = $builder->build(
46
    {   source => 'Reserve',
46
    {   source => 'Hold',
47
        value  => { biblionumber => $from_biblio->biblionumber, },
47
        value  => { biblio_id => $from_biblio->biblionumber, },
48
    }
48
    }
49
);
49
);
50
my $item_level_hold_not_to_move = $builder->build(
50
my $item_level_hold_not_to_move = $builder->build(
51
    {   source => 'Reserve',
51
    {   source => 'Hold',
52
        value  => { biblionumber => $from_biblio->biblionumber, itemnumber => $item1->itemnumber },
52
        value  => { biblio_id => $from_biblio->biblionumber, item_id => $item1->itemnumber },
53
    }
53
    }
54
);
54
);
55
my $item_level_hold_to_move = $builder->build(
55
my $item_level_hold_to_move = $builder->build(
56
    {   source => 'Reserve',
56
    {   source => 'Hold',
57
        value  => { biblionumber => $from_biblio->biblionumber, itemnumber => $item2->itemnumber },
57
        value  => { biblio_id => $from_biblio->biblionumber, item_id => $item2->itemnumber },
58
    }
58
    }
59
);
59
);
60
60
Lines 73-85 is( $get_item2->biblionumber, $to_biblio->biblionumber, 'The item2 should have b Link Here
73
my $get_item3 = Koha::Items->find( $item3->itemnumber );
73
my $get_item3 = Koha::Items->find( $item3->itemnumber );
74
is( $get_item3->biblionumber, $to_biblio->biblionumber, 'The item3 should not have been moved' );
74
is( $get_item3->biblionumber, $to_biblio->biblionumber, 'The item3 should not have been moved' );
75
75
76
my $get_bib_level_hold    = Koha::Holds->find( $bib_level_hold_not_to_move->{reserve_id} );
76
my $get_bib_level_hold    = Koha::Holds->find( $bib_level_hold_not_to_move->{id} );
77
my $get_item_level_hold_1 = Koha::Holds->find( $item_level_hold_not_to_move->{reserve_id} );
77
my $get_item_level_hold_1 = Koha::Holds->find( $item_level_hold_not_to_move->{id} );
78
my $get_item_level_hold_2 = Koha::Holds->find( $item_level_hold_to_move->{reserve_id} );
78
my $get_item_level_hold_2 = Koha::Holds->find( $item_level_hold_to_move->{id} );
79
79
80
is( $get_bib_level_hold->biblionumber,    $from_biblio->biblionumber, 'MoveItemFromBiblio should not have moved the biblio-level hold' );
80
is( $get_bib_level_hold->biblio_id,    $from_biblio->biblionumber, 'MoveItemFromBiblio should not have moved the biblio-level hold' );
81
is( $get_item_level_hold_1->biblionumber, $from_biblio->biblionumber, 'MoveItemFromBiblio should not have moved the item-level hold placed on item 1' );
81
is( $get_item_level_hold_1->biblio_id, $from_biblio->biblionumber, 'MoveItemFromBiblio should not have moved the item-level hold placed on item 1' );
82
is( $get_item_level_hold_2->biblionumber, $to_biblio->biblionumber,   'MoveItemFromBiblio should have moved the item-level hold placed on item 2' );
82
is( $get_item_level_hold_2->biblio_id, $to_biblio->biblionumber,   'MoveItemFromBiblio should have moved the item-level hold placed on item 2' );
83
83
84
$schema->storage->txn_rollback;
84
$schema->storage->txn_rollback;
85
85
(-)a/t/db_dependent/Koha/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 95-119 subtest 'holds + current_holds' => sub { Link Here
95
};
95
};
96
96
97
subtest 'waiting_or_in_transit' => sub {
97
subtest 'waiting_or_in_transit' => sub {
98
98
    plan tests => 4;
99
    plan tests => 4;
100
99
    my $item = $builder->build_sample_item;
101
    my $item = $builder->build_sample_item;
100
    my $reserve = $builder->build({
102
    my $hold = $builder->build_object({
101
        source => 'Reserve',
103
        class => 'Koha::Holds',
102
        value => {
104
        value => {
103
            biblionumber => $item->biblionumber,
105
            biblio_id => $item->biblionumber,
104
            found => undef
105
        }
106
        }
106
    });
107
    });
107
108
108
    $reserve = Koha::Holds->find($reserve->{reserve_id});
109
    $biblio = $item->biblio;
109
    $biblio = $item->biblio;
110
110
111
    is($biblio->has_items_waiting_or_intransit, 0, 'Item is neither waiting nor in transit');
111
    is($biblio->has_items_waiting_or_intransit, 0, 'Item is neither waiting nor in transit');
112
112
113
    $reserve->found('W')->store;
113
    $hold->set_waiting();
114
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is waiting');
114
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is waiting');
115
115
116
    $reserve->found('T')->store;
116
    $hold->set_transfer();
117
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is in transit');
117
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is in transit');
118
118
119
    my $transfer = $builder->build({
119
    my $transfer = $builder->build({
Lines 125-131 subtest 'waiting_or_in_transit' => sub { Link Here
125
        }
125
        }
126
    });
126
    });
127
    my $t = Koha::Database->new()->schema()->resultset( 'Branchtransfer' )->find($transfer->{branchtransfer_id});
127
    my $t = Koha::Database->new()->schema()->resultset( 'Branchtransfer' )->find($transfer->{branchtransfer_id});
128
    $reserve->found(undef)->store;
128
    $hold->status('placed')->store;
129
    is($biblio->has_items_waiting_or_intransit, 1, 'Item has transfer');
129
    is($biblio->has_items_waiting_or_intransit, 1, 'Item has transfer');
130
};
130
};
131
131
(-)a/t/db_dependent/Koha/Club/Hold.t (-1 / +1 lines)
Lines 131-137 subtest 'add' => sub { Link Here
131
131
132
    my $hold = Koha::Holds->find($patron_hold->hold_id);
132
    my $hold = Koha::Holds->find($patron_hold->hold_id);
133
133
134
    is($patron_hold->patron_id, $hold->borrowernumber, 'Patron must be the same');
134
    is($patron_hold->patron_id, $hold->patron_id, 'Patron must be the same');
135
135
136
    $schema->storage->txn_rollback;
136
    $schema->storage->txn_rollback;
137
}
137
}
(-)a/t/db_dependent/Koha/Holds.t (-56 / +19 lines)
Lines 61-67 subtest 'DB constraints' => sub { Link Here
61
};
61
};
62
62
63
subtest 'cancel' => sub {
63
subtest 'cancel' => sub {
64
    plan tests => 12;
64
65
    plan tests => 13;
66
65
    my $biblioitem = $builder->build_object( { class => 'Koha::Biblioitems' } );
67
    my $biblioitem = $builder->build_object( { class => 'Koha::Biblioitems' } );
66
    my $library    = $builder->build_object( { class => 'Koha::Libraries' } );
68
    my $library    = $builder->build_object( { class => 'Koha::Libraries' } );
67
    my $itemtype   = $builder->build_object( { class => 'Koha::ItemTypes', value => { rentalcharge => 0 } } );
69
    my $itemtype   = $builder->build_object( { class => 'Koha::ItemTypes', value => { rentalcharge => 0 } } );
Lines 102-108 subtest 'cancel' => sub { Link Here
102
104
103
    # There are 3 holds on this records
105
    # There are 3 holds on this records
104
    my $nb_of_holds =
106
    my $nb_of_holds =
105
      Koha::Holds->search( { biblionumber => $item->biblionumber } )->count;
107
      Koha::Holds->search( { biblio_id => $item->biblionumber } )->count;
106
    is( $nb_of_holds, 3,
108
    is( $nb_of_holds, 3,
107
        'There should have 3 holds placed on this biblio record' );
109
        'There should have 3 holds placed on this biblio record' );
108
    my $first_hold  = $holds[0];
110
    my $first_hold  = $holds[0];
Lines 116-129 subtest 'cancel' => sub { Link Here
116
    # Remove the second hold, only 2 should still exist in DB and priorities must have been updated
118
    # Remove the second hold, only 2 should still exist in DB and priorities must have been updated
117
    my $is_cancelled = $second_hold->cancel;
119
    my $is_cancelled = $second_hold->cancel;
118
    is( ref($is_cancelled), 'Koha::Hold',
120
    is( ref($is_cancelled), 'Koha::Hold',
119
        'Koha::Hold->cancel should return the Koha::Hold (?)' )
121
        'Koha::Hold->cancel should return the Koha::Hold (?)' );
122
    $second_hold->discard_changes;
120
      ;    # This is can reconsidered
123
      ;    # This is can reconsidered
121
    is( $second_hold->in_storage, 0,
124
    is( $second_hold->in_storage, 1,
122
        'The hold has been cancelled and does not longer exist in DB' );
125
        'The hold has been cancelled and still exists on the DB' );
126
    is( $second_hold->status, 'cancelled', "Status is 'cancelled'" );
127
    ok( $second_hold->completed, 'Hold marked as comleted' );
128
123
    $nb_of_holds =
129
    $nb_of_holds =
124
      Koha::Holds->search( { biblionumber => $item->biblionumber } )->count;
130
      Koha::Holds->search( { biblio_id => $item->biblionumber, completed => 0 } )->count;
125
    is( $nb_of_holds, 2,
131
    is( $nb_of_holds, 2,
126
        'a hold has been cancelled, there should have only 2 holds placed on this biblio record'
132
        'a hold has been cancelled, there should have only 2 (not completed) holds placed on this biblio record'
127
    );
133
    );
128
134
129
    # discard_changes to refetch
135
    # discard_changes to refetch
Lines 166-172 subtest 'cancel' => sub { Link Here
166
    };
172
    };
167
173
168
    subtest 'waiting hold' => sub {
174
    subtest 'waiting hold' => sub {
169
        plan tests => 1;
175
        plan tests => 2;
170
        my $patron = $builder->build_object({ class => 'Koha::Patrons' });
176
        my $patron = $builder->build_object({ class => 'Koha::Patrons' });
171
        my $reserve_id = C4::Reserves::AddReserve(
177
        my $reserve_id = C4::Reserves::AddReserve(
172
            {
178
            {
Lines 176-187 subtest 'cancel' => sub { Link Here
176
                priority       => 1,
182
                priority       => 1,
177
                title          => "title for fee",
183
                title          => "title for fee",
178
                itemnumber     => $item->itemnumber,
184
                itemnumber     => $item->itemnumber,
179
                found          => 'W',
185
                status         => 'W',
180
            }
186
            }
181
        );
187
        );
182
        Koha::Holds->find( $reserve_id )->cancel;
188
        my $hold = Koha::Holds->find( $reserve_id );
183
        my $hold_old = Koha::Old::Holds->find( $reserve_id );
189
        $hold->cancel->discard_changes;
184
        is( $hold_old->found, 'W', 'The found column should have been kept and a hold is cancelled' );
190
        is( $hold->status, 'cancelled', 'The found column should have been kept and a hold is cancelled' );
191
        ok( $hold->completed, 'Hold is marked as completed' );
185
    };
192
    };
186
193
187
    subtest 'HoldsLog' => sub {
194
    subtest 'HoldsLog' => sub {
Lines 208-257 subtest 'cancel' => sub { Link Here
208
        $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'HOLDS', action => 'CANCEL', object => $reserve_id } )->count;
215
        $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'HOLDS', action => 'CANCEL', object => $reserve_id } )->count;
209
        is( $number_of_logs, 1, 'With HoldsLog, Koha::Hold->cancel should have logged' );
216
        is( $number_of_logs, 1, 'With HoldsLog, Koha::Hold->cancel should have logged' );
210
    };
217
    };
211
212
    subtest 'rollback' => sub {
213
        plan tests => 3;
214
        my $patron_category = $builder->build_object(
215
            {
216
                class => 'Koha::Patron::Categories',
217
                value => { reservefee => 0 }
218
            }
219
        );
220
        my $patron = $builder->build_object(
221
            {
222
                class => 'Koha::Patrons',
223
                value => { categorycode => $patron_category->categorycode }
224
            }
225
        );
226
        my $hold_info = {
227
            branchcode     => $library->branchcode,
228
            borrowernumber => $patron->borrowernumber,
229
            biblionumber   => $item->biblionumber,
230
            priority       => 1,
231
            title          => "title for fee",
232
            itemnumber     => $item->itemnumber,
233
        };
234
235
        t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelayCharge',42 );
236
        my $reserve_id = C4::Reserves::AddReserve($hold_info);
237
        my $hold       = Koha::Holds->find($reserve_id);
238
239
        # Add a row with the same id to make the cancel fails
240
        Koha::Old::Hold->new( $hold->unblessed )->store;
241
242
        warning_like {
243
            eval { $hold->cancel( { charge_cancel_fee => 1 } ) };
244
        }
245
        qr{.*DBD::mysql::st execute failed: Duplicate entry.*},
246
          'DBD should have raised an error about dup primary key';
247
248
        $hold = Koha::Holds->find($reserve_id);
249
        is( ref($hold), 'Koha::Hold', 'The hold should not have been deleted' );
250
        is( $patron->account->balance, 0,
251
'If the hold has not been cancelled, the patron should not have been charged'
252
        );
253
    };
254
255
};
218
};
256
219
257
subtest 'cancel with reason' => sub {
220
subtest 'cancel with reason' => sub {
(-)a/t/db_dependent/Koha/Items.t (-6 / +6 lines)
Lines 1267-1280 subtest 'holds' => sub { Link Here
1267
        biblionumber => $biblio->biblionumber,
1267
        biblionumber => $biblio->biblionumber,
1268
    });
1268
    });
1269
    is($item->holds->count, 0, "Nothing returned if no holds");
1269
    is($item->holds->count, 0, "Nothing returned if no holds");
1270
    my $hold1 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'T' }});
1270
    my $hold1 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'in_transit', completed => 0 }});
1271
    my $hold2 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'W' }});
1271
    my $hold2 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'waiting', completed => 0 }});
1272
    my $hold3 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'W' }});
1272
    my $hold3 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'waiting', completed => 0 }});
1273
1273
1274
    is($item->holds()->count,3,"Three holds found");
1274
    is($item->holds()->count,3,"Three holds found");
1275
    is($item->holds({found => 'W'})->count,2,"Two waiting holds found");
1275
    is($item->holds({status => 'waiting'})->count,2,"Two waiting holds found");
1276
    is_deeply($item->holds({found => 'T'})->next->unblessed,$hold1,"Found transit holds matches the hold");
1276
    is_deeply($item->holds({status => 'in_transit'})->next->unblessed,$hold1,"Found transit holds matches the hold");
1277
    is($item->holds({found => undef})->count, 0,"Nothing returned if no matching holds");
1277
    is($item->holds({status => 'placed'})->count, 0,"Nothing returned if no matching holds");
1278
};
1278
};
1279
1279
1280
subtest 'biblio' => sub {
1280
subtest 'biblio' => sub {
(-)a/t/db_dependent/Koha/Object.t (-2 / +2 lines)
Lines 272-278 subtest "to_api() tests" => sub { Link Here
272
272
273
    my $biblio = $builder->build_sample_biblio();
273
    my $biblio = $builder->build_sample_biblio();
274
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
274
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
275
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { itemnumber => $item->itemnumber } });
275
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { item_id => $item->itemnumber, completed => 0 } });
276
276
277
    my $embeds = { 'items' => {} };
277
    my $embeds = { 'items' => {} };
278
278
Lines 297-303 subtest "to_api() tests" => sub { Link Here
297
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
297
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
298
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
298
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
299
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
299
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
300
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->reserve_id, 'Hold matches');
300
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->id, 'Hold matches');
301
    is_deeply($biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root');
301
    is_deeply($biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root');
302
302
303
    my $hold_api = $hold->to_api(
303
    my $hold_api = $hold->to_api(
(-)a/t/db_dependent/Koha/Objects.t (-3 / +3 lines)
Lines 338-344 subtest "to_api() tests" => sub { Link Here
338
    my $hold_1   = $builder->build_object(
338
    my $hold_1   = $builder->build_object(
339
        {
339
        {
340
            class => 'Koha::Holds',
340
            class => 'Koha::Holds',
341
            value => { itemnumber => $item_1->itemnumber }
341
            value => { item_id => $item_1->itemnumber, completed => 0 }
342
        }
342
        }
343
    );
343
    );
344
344
Lines 347-353 subtest "to_api() tests" => sub { Link Here
347
    my $hold_2   = $builder->build_object(
347
    my $hold_2   = $builder->build_object(
348
        {
348
        {
349
            class => 'Koha::Holds',
349
            class => 'Koha::Holds',
350
            value => { itemnumber => $item_2->itemnumber }
350
            value => { item_id => $item_2->itemnumber, completed => 0 }
351
        }
351
        }
352
    );
352
    );
353
353
Lines 391-397 subtest "to_api() tests" => sub { Link Here
391
        ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
391
        ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
392
        is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches');
392
        is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches');
393
        ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
393
        ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
394
        is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->reserve_id, 'Hold matches');
394
        is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->id, 'Hold matches');
395
395
396
        $i++;
396
        $i++;
397
    }
397
    }
(-)a/t/db_dependent/Koha/Patrons.t (-8 / +8 lines)
Lines 468-475 subtest "delete" => sub { Link Here
468
    my $patron           = $builder->build( { source => 'Borrower' } );
468
    my $patron           = $builder->build( { source => 'Borrower' } );
469
    my $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} );
469
    my $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} );
470
    my $hold             = $builder->build(
470
    my $hold             = $builder->build(
471
        {   source => 'Reserve',
471
        {   source => 'Hold',
472
            value  => { borrowernumber => $patron->{borrowernumber} }
472
            value  => { patron_id => $patron->{borrowernumber}, completed => 0 }
473
        }
473
        }
474
    );
474
    );
475
    my $list = $builder->build(
475
    my $list = $builder->build(
Lines 484-492 subtest "delete" => sub { Link Here
484
484
485
    is( Koha::Patrons->find( $patron->{borrowernumber} ), undef, 'Koha::Patron->delete should have deleted the patron' );
485
    is( Koha::Patrons->find( $patron->{borrowernumber} ), undef, 'Koha::Patron->delete should have deleted the patron' );
486
486
487
    is (Koha::Old::Holds->search( { reserve_id => $hold->{ reserve_id } } )->count, 1, q|Koha::Patron->delete should have cancelled patron's holds| );
487
    is (Koha::Holds->search( { id => $hold->{id}, status => 'cancelled' } )->count, 1, q|Koha::Patron->delete should have cancelled patron's holds| );
488
488
489
    is( Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have cancelled patron's holds 2| );
489
    is( Koha::Holds->search( { patron_id => $patron->{borrowernumber}, completed => 0 } )->count, 0, q|Koha::Patron->delete should have cancelled patron's holds 2| );
490
490
491
    is( Koha::Virtualshelves->search( { owner => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have deleted patron's lists| );
491
    is( Koha::Virtualshelves->search( { owner => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have deleted patron's lists| );
492
492
Lines 992-999 subtest 'holds and old_holds' => sub { Link Here
992
    is( $holds->count, 2, 'There should be 2 holds placed by this patron' );
992
    is( $holds->count, 2, 'There should be 2 holds placed by this patron' );
993
993
994
    my $old_holds = $patron->old_holds;
994
    my $old_holds = $patron->old_holds;
995
    is( ref($old_holds), 'Koha::Old::Holds',
995
    is( ref($old_holds), 'Koha::Holds',
996
        'Koha::Patron->old_holds should return a Koha::Old::Holds objects' );
996
        'Koha::Patron->old_holds should return a Koha::Holds objects' );
997
    is( $old_holds->count, 0, 'There should not be any old holds yet');
997
    is( $old_holds->count, 0, 'There should not be any old holds yet');
998
998
999
    my $hold = $holds->next;
999
    my $hold = $holds->next;
Lines 1605-1611 subtest 'BorrowersLog tests' => sub { Link Here
1605
$schema->storage->txn_rollback;
1605
$schema->storage->txn_rollback;
1606
1606
1607
subtest 'Test Koha::Patrons::merge' => sub {
1607
subtest 'Test Koha::Patrons::merge' => sub {
1608
    plan tests => 113;
1608
    plan tests => 109;
1609
1609
1610
    my $schema = Koha::Database->new()->schema();
1610
    my $schema = Koha::Database->new()->schema();
1611
1611
Lines 1903-1909 subtest 'lock' => sub { Link Here
1903
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
1903
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
1904
    my $hold = $builder->build_object({
1904
    my $hold = $builder->build_object({
1905
        class => 'Koha::Holds',
1905
        class => 'Koha::Holds',
1906
        value => { borrowernumber => $patron1->borrowernumber },
1906
        value => { patron_id => $patron1->borrowernumber, completed => 0 },
1907
    });
1907
    });
1908
1908
1909
    t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 3 );
1909
    t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 3 );
(-)a/t/db_dependent/Koha/Z3950Responder/Session.t (-1 / +1 lines)
Lines 32-38 subtest 'add_item_status' => sub { Link Here
32
    my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField( "items.itemnumber" );
32
    my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField( "items.itemnumber" );
33
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
33
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
34
    my $item_field_1 = scalar $item_marc_1->field($itemtag);
34
    my $item_field_1 = scalar $item_marc_1->field($itemtag);
35
    $builder->build({ source => 'Reserve', value=> { itemnumber => $item_1->itemnumber } });
35
    $builder->build({ source => 'Hold', value=> { item_id => $item_1->itemnumber } });
36
    $builder->build(
36
    $builder->build(
37
        {
37
        {
38
            source => 'Branchtransfer',
38
            source => 'Branchtransfer',
(-)a/t/db_dependent/Koha/Z3950Responder/Session2.t (-1 / +1 lines)
Lines 55-61 subtest 'add_item_status' => sub { Link Here
55
    );
55
    );
56
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
56
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
57
    my $item_field_1 = scalar $item_marc_1->field('952');
57
    my $item_field_1 = scalar $item_marc_1->field('952');
58
    $builder->build({ source => 'Reserve', value=> { itemnumber => $item_1->itemnumber } });
58
    $builder->build({ source => 'Hold', value=> { item_id => $item_1->itemnumber } });
59
    $builder->build(
59
    $builder->build(
60
        {
60
        {
61
            source => 'Branchtransfer',
61
            source => 'Branchtransfer',
(-)a/t/db_dependent/Letters/TemplateToolkit.t (-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 197-208 $prepared_letter = GetPreparedLetter( Link Here
197
        module      => 'test',
197
        module      => 'test',
198
        letter_code => 'TEST_HOLD',
198
        letter_code => 'TEST_HOLD',
199
        tables      => {
199
        tables      => {
200
            reserves => { borrowernumber => $patron->{borrowernumber}, biblionumber => $item->biblionumber },
200
            holds => {
201
                patron_id => $patron->{borrowernumber},
202
                biblio_id => $item->biblionumber
203
            },
201
        },
204
        },
202
    )
205
    )
203
);
206
);
204
is( $prepared_letter->{content}, $hold->id(), 'Hold object used correctly for content' );
207
is( $prepared_letter->{content}, $hold->id(), 'Hold object used correctly for content' );
205
is( $prepared_letter->{title}, $hold->borrowernumber, 'Hold object used correctly for title' );
208
is( $prepared_letter->{title}, $hold->patron_id, 'Hold object used correctly for title' );
206
209
207
eval {
210
eval {
208
    $prepared_letter = GetPreparedLetter(
211
    $prepared_letter = GetPreparedLetter(
Lines 210-222 eval { Link Here
210
            module      => 'test',
213
            module      => 'test',
211
            letter_code => 'TEST_HOLD',
214
            letter_code => 'TEST_HOLD',
212
            tables      => {
215
            tables      => {
213
                reserves => [ $patron->{borrowernumber}, $item->biblionumber ],
216
                holds => [ $patron->{borrowernumber}, $item->biblionumber ],
214
            },
217
            },
215
        )
218
        )
216
    )
219
    )
217
};
220
};
218
my $croak = $@;
221
my $croak = $@;
219
like( $croak, qr{^Multiple foreign keys \(table reserves\) should be passed using an hashref.*}, "GetPreparedLetter should not be called with arrayref for multiple FK" );
222
like( $croak, qr{^Multiple foreign keys \(table holds\) should be passed using an hashref.*}, "GetPreparedLetter should not be called with arrayref for multiple FK" );
220
223
221
# Bug 16942
224
# Bug 16942
222
$prepared_letter = GetPreparedLetter(
225
$prepared_letter = GetPreparedLetter(
Lines 228-235 $prepared_letter = GetPreparedLetter( Link Here
228
            'borrowers'   => $patron,
231
            'borrowers'   => $patron,
229
            'biblio'      => $item->biblionumber,
232
            'biblio'      => $item->biblionumber,
230
            'biblioitems' => $item->biblioitemnumber,
233
            'biblioitems' => $item->biblioitemnumber,
231
            'reserves'    => $hold->unblessed,
234
            'holds'        => $hold->unblessed,
232
            'items'       => $hold->itemnumber,
235
            'items'       => $hold->item_id,
233
        }
236
        }
234
    )
237
    )
235
);
238
);
(-)a/t/db_dependent/Reserves.t (-72 / +61 lines)
Lines 122-128 my ($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber, $barcod Link Here
122
122
123
is($status, "Reserved", "CheckReserves Test 1");
123
is($status, "Reserved", "CheckReserves Test 1");
124
124
125
ok(exists($reserve->{reserve_id}), 'CheckReserves() include reserve_id in its response');
125
ok(exists($reserve->{id}), 'CheckReserves() include reserve_id in its response');
126
126
127
($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber);
127
($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber);
128
is($status, "Reserved", "CheckReserves Test 2");
128
is($status, "Reserved", "CheckReserves Test 2");
Lines 266-279 ModReserveAffect($itemnum_cpl, $requesters{$branch_3}, 0); Link Here
266
266
267
# Now it should have different priorities.
267
# Now it should have different priorities.
268
my $biblio = Koha::Biblios->find( $bibnum2 );
268
my $biblio = Koha::Biblios->find( $bibnum2 );
269
my $holds = $biblio->holds({}, { order_by => 'reserve_id' });;
269
my $holds = $biblio->holds({}, { order_by => 'id' });;
270
is($holds->next->priority, 0, 'Item is correctly waiting');
270
is($holds->next->priority, 0, 'Item is correctly waiting');
271
is($holds->next->priority, 1, 'Item is correctly priority 1');
271
is($holds->next->priority, 1, 'Item is correctly priority 1');
272
is($holds->next->priority, 2, 'Item is correctly priority 2');
272
is($holds->next->priority, 2, 'Item is correctly priority 2');
273
273
274
my @reserves = Koha::Holds->search({ borrowernumber => $requesters{$branch_3} })->waiting();
274
my @reserves = Koha::Holds->search({ patron_id => $requesters{$branch_3} })->waiting();
275
is( @reserves, 1, 'GetWaiting got only the waiting reserve' );
275
is( @reserves, 1, 'GetWaiting got only the waiting reserve' );
276
is( $reserves[0]->borrowernumber(), $requesters{$branch_3}, 'GetWaiting got the reserve for the correct borrower' );
276
is( $reserves[0]->patron_id(), $requesters{$branch_3}, 'GetWaiting got the reserve for the correct borrower' );
277
277
278
278
279
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum2));
279
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum2));
Lines 311-317 my $messages; Link Here
311
# the one placed by the CPL patron, as the other two patron's hold
311
# the one placed by the CPL patron, as the other two patron's hold
312
# requests cannot be filled by that item per policy.
312
# requests cannot be filled by that item per policy.
313
(undef, $messages, undef, undef) = AddReturn('bug10272_CPL', $branch_2);
313
(undef, $messages, undef, undef) = AddReturn('bug10272_CPL', $branch_2);
314
is( $messages->{ResFound}->{borrowernumber},
314
is( $messages->{ResFound}->{patron_id},
315
    $requesters{$branch_1},
315
    $requesters{$branch_1},
316
    'restrictive library\'s items only fill requests by own patrons (bug 10272)');
316
    'restrictive library\'s items only fill requests by own patrons (bug 10272)');
317
317
Lines 323-341 is( $messages->{ResFound}->{borrowernumber}, Link Here
323
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', '' );
323
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', '' );
324
324
325
(undef, $messages, undef, undef) = AddReturn('bug10272_FPL', $branch_2);
325
(undef, $messages, undef, undef) = AddReturn('bug10272_FPL', $branch_2);
326
is( $messages->{ResFound}->{borrowernumber},
326
is( $messages->{ResFound}->{patron_id},
327
    $requesters{$branch_3},
327
    $requesters{$branch_3},
328
    'for generous library, its items fill first hold request in line (bug 10272)');
328
    'for generous library, its items fill first hold request in line (bug 10272)');
329
329
330
$biblio = Koha::Biblios->find( $biblionumber );
330
$biblio = Koha::Biblios->find( $biblionumber );
331
$holds = $biblio->holds;
331
$holds = $biblio->holds;
332
is($holds->count, 1, "Only one reserves for this biblio");
332
is($holds->count, 1, "Only one reserves for this biblio");
333
$holds->next->reserve_id;
334
333
335
# Tests for bug 9761 (ConfirmFutureHolds): new CheckReserves lookahead parameter, and corresponding change in AddReturn
334
# Tests for bug 9761 (ConfirmFutureHolds): new CheckReserves lookahead parameter, and corresponding change in AddReturn
336
# Note that CheckReserve uses its lookahead parameter and does not check ConfirmFutureHolds pref (it should be passed if needed like AddReturn does)
335
# Note that CheckReserve uses its lookahead parameter and does not check ConfirmFutureHolds pref (it should be passed if needed like AddReturn does)
337
# Test 9761a: Add a reserve without date, CheckReserve should return it
336
# Test 9761a: Add a reserve without date, CheckReserve should return it
338
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
337
$dbh->do("DELETE FROM holds WHERE biblio_id=?",undef,($bibnum));
339
AddReserve(
338
AddReserve(
340
    {
339
    {
341
        branchcode     => $branch_1,
340
        branchcode     => $branch_1,
Lines 403-409 is($new_count, $hold_notice_count + 1, 'patron not notified a second time (bug 1 Link Here
403
t::lib::Mocks::mock_preference('IndependentBranches', 0);
402
t::lib::Mocks::mock_preference('IndependentBranches', 0);
404
$item = Koha::Items->find($item->itemnumber);
403
$item = Koha::Items->find($item->itemnumber);
405
is(
404
is(
406
    $item->safe_delete,
405
    $item->safe_to_delete,
407
    'book_reserved',
406
    'book_reserved',
408
    'item that is captured to fill a hold cannot be deleted',
407
    'item that is captured to fill a hold cannot be deleted',
409
);
408
);
Lines 431-437 AddReserve( Link Here
431
430
432
$holds = $item->current_holds;
431
$holds = $item->current_holds;
433
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
432
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
434
my $future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
433
my $future_holds = $holds->search({ created_date => { '>' => $dtf->format_date( dt_from_string ) } } );
435
is( $future_holds->count, 0, 'current_holds does not return a future next available hold');
434
is( $future_holds->count, 0, 'current_holds does not return a future next available hold');
436
# 9788b: current_holds does not return future item level hold
435
# 9788b: current_holds does not return future item level hold
437
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
436
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
Lines 445-455 AddReserve( Link Here
445
        itemnumber       => $item->itemnumber,
444
        itemnumber       => $item->itemnumber,
446
    }
445
    }
447
); #item level hold
446
); #item level hold
448
$future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
447
$future_holds = $holds->search({ created_date => { '>' => $dtf->format_date( dt_from_string ) } } );
449
is( $future_holds->count, 0, 'current_holds does not return a future item level hold' );
448
is( $future_holds->count, 0, 'current_holds does not return a future item level hold' );
450
# 9788c: current_holds returns future wait (confirmed future hold)
449
# 9788c: current_holds returns future wait (confirmed future hold)
451
ModReserveAffect( $item->itemnumber,  $requesters{$branch_1} , 0); #confirm hold
450
ModReserveAffect( $item->itemnumber,  $requesters{$branch_1} , 0); #confirm hold
452
$future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
451
$future_holds = $holds->search({ created_date => { '>' => $dtf->format_date( dt_from_string ) } } );
453
is( $future_holds->count, 1, 'current_holds returns a future wait (confirmed future hold)' );
452
is( $future_holds->count, 1, 'current_holds returns a future wait (confirmed future hold)' );
454
# End of tests for bug 9788
453
# End of tests for bug 9788
455
454
Lines 543-559 is( Link Here
543
    'CanReserveBeCanceledFromOpac should return undef if called without borrowernumber'
542
    'CanReserveBeCanceledFromOpac should return undef if called without borrowernumber'
544
);
543
);
545
544
546
my $cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
545
my $cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
547
is($cancancel, 1, 'Can user cancel its own reserve');
546
is($cancancel, 1, 'Can user cancel its own reserve');
548
547
549
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_2});
548
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_2});
550
is($cancancel, 0, 'Other user cant cancel reserve');
549
is($cancancel, 0, 'Other user cant cancel reserve');
551
550
552
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 1);
551
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 1);
553
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
552
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
554
is($cancancel, 0, 'Reserve in transfer status cant be canceled');
553
is($cancancel, 0, 'Reserve in transfer status cant be canceled');
555
554
556
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
555
$dbh->do('DELETE FROM holds', undef, ($bibnum));
557
AddReserve(
556
AddReserve(
558
    {
557
    {
559
        branchcode     => $branch_1,
558
        branchcode     => $branch_1,
Lines 565-571 AddReserve( Link Here
565
(undef, $canres, undef) = CheckReserves($item->itemnumber);
564
(undef, $canres, undef) = CheckReserves($item->itemnumber);
566
565
567
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 0);
566
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 0);
568
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
567
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
569
is($cancancel, 0, 'Reserve in waiting status cant be canceled');
568
is($cancancel, 0, 'Reserve in waiting status cant be canceled');
570
569
571
# End of tests for bug 12876
570
# End of tests for bug 12876
Lines 633-639 Koha::CirculationRules->set_rules( Link Here
633
632
634
# tests for MoveReserve in relation to ConfirmFutureHolds (BZ 14526)
633
# tests for MoveReserve in relation to ConfirmFutureHolds (BZ 14526)
635
#   hold from A pos 1, today, no fut holds: MoveReserve should fill it
634
#   hold from A pos 1, today, no fut holds: MoveReserve should fill it
636
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
635
$dbh->do('DELETE FROM holds');
637
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 0);
636
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 0);
638
t::lib::Mocks::mock_preference('AllowHoldDateInFuture', 1);
637
t::lib::Mocks::mock_preference('AllowHoldDateInFuture', 1);
639
AddReserve(
638
AddReserve(
Lines 654-660 AddReserve( Link Here
654
        borrowernumber => $borrowernumber,
653
        borrowernumber => $borrowernumber,
655
        biblionumber   => $bibnum,
654
        biblionumber   => $bibnum,
656
        priority       => 1,
655
        priority       => 1,
657
        found          => 'W',
656
        found          => 'waiting',
658
    }
657
    }
659
);
658
);
660
MoveReserve( $item->itemnumber, $borrowernumber );
659
MoveReserve( $item->itemnumber, $borrowernumber );
Lines 828-840 subtest 'ReservesNeedReturns' => sub { Link Here
828
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 1); # Test with feature disabled
827
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 1); # Test with feature disabled
829
    my $hold = place_item_hold( $patron, $item, $library, $priority );
828
    my $hold = place_item_hold( $patron, $item, $library, $priority );
830
    is( $hold->priority, $priority, 'If ReservesNeedReturns is 1, priority must not have been set to changed' );
829
    is( $hold->priority, $priority, 'If ReservesNeedReturns is 1, priority must not have been set to changed' );
831
    is( $hold->found, undef, 'If ReservesNeedReturns is 1, found must not have been set waiting' );
830
    is( $hold->status, 'placed', 'If ReservesNeedReturns is 1, status must not have been set waiting' );
832
    $hold->delete;
831
    $hold->delete;
833
832
834
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 0); # '0' means 'Automatically mark a hold as found and waiting'
833
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 0); # '0' means 'Automatically mark a hold as status and waiting'
835
    $hold = place_item_hold( $patron, $item, $library, $priority );
834
    $hold = place_item_hold( $patron, $item, $library, $priority );
836
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
835
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
837
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
836
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and no other status, status must have been set waiting' );
838
    $hold->delete;
837
    $hold->delete;
839
838
840
    $item->onloan('2010-01-01')->store;
839
    $item->onloan('2010-01-01')->store;
Lines 850-860 subtest 'ReservesNeedReturns' => sub { Link Here
850
    t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1); # '0' means damaged holds not allowed
849
    t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1); # '0' means damaged holds not allowed
851
    $hold = place_item_hold( $patron, $item, $library, $priority );
850
    $hold = place_item_hold( $patron, $item, $library, $priority );
852
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and damaged holds allowed, priority must have been set to 0' );
851
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and damaged holds allowed, priority must have been set to 0' );
853
    is( $hold->found,  'W', 'If ReservesNeedReturns is 0 and damaged holds allowed, found must have been set waiting' );
852
    is( $hold->status,  'waiting', 'If ReservesNeedReturns is 0 and damaged holds allowed, status must have been set waiting' );
854
    $hold->delete;
853
    $hold->delete;
855
854
856
    my $hold_1 = place_item_hold( $patron, $item, $library, $priority );
855
    my $hold_1 = place_item_hold( $patron, $item, $library, $priority );
857
    is( $hold_1->found,  'W', 'First hold on item is set to waiting with ReservesNeedReturns set to 0' );
856
    is( $hold_1->status,  'waiting', 'First hold on item is set to waiting with ReservesNeedReturns set to 0' );
858
    is( $hold_1->priority, 0, 'First hold on item is set to waiting with ReservesNeedReturns set to 0' );
857
    is( $hold_1->priority, 0, 'First hold on item is set to waiting with ReservesNeedReturns set to 0' );
859
    $hold = place_item_hold( $patron_2, $item, $library, $priority );
858
    $hold = place_item_hold( $patron_2, $item, $library, $priority );
860
    is( $hold->priority, 1, 'If ReservesNeedReturns is 0 but item already on hold priority must be set to 1' );
859
    is( $hold->priority, 1, 'If ReservesNeedReturns is 0 but item already on hold priority must be set to 1' );
Lines 871-891 subtest 'ReservesNeedReturns' => sub { Link Here
871
    });
870
    });
872
    $item->damaged(0)->store;
871
    $item->damaged(0)->store;
873
    $hold = place_item_hold( $patron, $item, $library, $priority );
872
    $hold = place_item_hold( $patron, $item, $library, $priority );
874
    is( $hold->found, undef, 'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
873
    is( $hold->status, 'placed', 'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
875
    is( $hold->priority, 1,  'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
874
    is( $hold->priority, 1,  'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
876
    $hold->delete;
875
    $hold->delete;
877
    $transfer->delete;
876
    $transfer->delete;
878
877
879
    $hold = place_item_hold( $patron, $item, $library, $priority );
878
    $hold = place_item_hold( $patron, $item, $library, $priority );
880
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
879
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
881
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
880
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
882
    $hold_1 = place_item_hold( $patron, $item, $library, $priority );
881
    $hold_1 = place_item_hold( $patron, $item, $library, $priority );
883
    is( $hold_1->priority, 1, 'If ReservesNeedReturns is 0 but item has a hold priority is 1' );
882
    is( $hold_1->priority, 1, 'If ReservesNeedReturns is 0 but item has a hold priority is 1' );
884
    $hold_1->suspend(1)->store; # We suspend the hold
883
    $hold_1->suspended(1)->store; # We suspend the hold
885
    $hold->delete; # Delete the waiting hold
884
    $hold->delete; # Delete the waiting hold
886
    $hold = place_item_hold( $patron, $item, $library, $priority );
885
    $hold = place_item_hold( $patron, $item, $library, $priority );
887
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and other hold(s) suspended, priority must have been set to 0' );
886
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and other hold(s) suspended, priority must have been set to 0' );
888
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and other  hold(s) suspended, found must have been set waiting' );
887
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and other  hold(s) suspended, found must have been set waiting' );
889
888
890
889
891
890
Lines 931-936 subtest 'reserves.item_level_hold' => sub { Link Here
931
930
932
    subtest 'item level hold' => sub {
931
    subtest 'item level hold' => sub {
933
        plan tests => 2;
932
        plan tests => 2;
933
934
        $schema->storage->txn_begin;
935
934
        my $reserve_id = AddReserve(
936
        my $reserve_id = AddReserve(
935
            {
937
            {
936
                branchcode     => $item->homebranch,
938
                branchcode     => $item->homebranch,
Lines 942-961 subtest 'reserves.item_level_hold' => sub { Link Here
942
        );
944
        );
943
945
944
        my $hold = Koha::Holds->find($reserve_id);
946
        my $hold = Koha::Holds->find($reserve_id);
945
        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' );
946
948
947
        # Mark it waiting
949
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber );
948
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 1 );
949
950
950
        # Revert the waiting status
951
        # Revert the waiting status
951
        C4::Reserves::RevertWaitingStatus(
952
        C4::Reserves::RevertWaitingStatus(
952
            { itemnumber => $item->itemnumber } );
953
            { itemnumber => $item->itemnumber } );
953
954
954
        $hold = Koha::Holds->find($reserve_id);
955
        $hold->discard_changes;
955
956
956
        is( $hold->itemnumber, $item->itemnumber, 'Itemnumber should not be removed when the waiting status is revert' );
957
        is( $hold->item_id, $item->itemnumber, 'Itemnumber should not be removed when the waiting status is revert' );
957
958
958
        $hold->delete;    # cleanup
959
        $schema->storage->txn_rollback;
959
    };
960
    };
960
961
961
    subtest 'biblio level hold' => sub {
962
    subtest 'biblio level hold' => sub {
Lines 970-988 subtest 'reserves.item_level_hold' => sub { Link Here
970
        );
971
        );
971
972
972
        my $hold = Koha::Holds->find($reserve_id);
973
        my $hold = Koha::Holds->find($reserve_id);
973
        is( $hold->item_level_hold, 0, 'item_level_hold should not be set when AddReserve is called without a specific item' );
974
        is( $hold->item_level, 0, 'item_level should not be set when AddReserve is called without a specific item' );
974
975
975
        # Mark it waiting
976
        # Mark it waiting
976
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 1 );
977
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber );
977
978
978
        $hold = Koha::Holds->find($reserve_id);
979
        $hold = Koha::Holds->find($reserve_id);
979
        is( $hold->itemnumber, $item->itemnumber, 'Itemnumber should be set on hold confirmation' );
980
        is( $hold->item_id, $item->itemnumber, 'Itemnumber should be set on hold confirmation' );
980
981
981
        # Revert the waiting status
982
        # Revert the waiting status
982
        C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
983
        C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
983
984
984
        $hold = Koha::Holds->find($reserve_id);
985
        $hold = Koha::Holds->find($reserve_id);
985
        is( $hold->itemnumber, undef, 'Itemnumber should be removed when the waiting status is revert' );
986
        is( $hold->item_id, undef, 'Itemnumber should be removed when the waiting status is revert' );
986
987
987
        $hold->delete;
988
        $hold->delete;
988
    };
989
    };
Lines 1020-1035 subtest 'MoveReserve additional test' => sub { Link Here
1020
            itemnumber     => $item_1->itemnumber,
1021
            itemnumber     => $item_1->itemnumber,
1021
        }
1022
        }
1022
    );
1023
    );
1023
    is($patron_1->holds->next()->reserve_id, $reserve_1, "The 1st patron has a hold");
1024
    is($patron_1->holds->next()->id, $reserve_1, "The 1st patron has a hold");
1024
    is($patron_2->holds->next()->reserve_id, $reserve_2, "The 2nd patron has a hold");
1025
    is($patron_2->holds->next()->id, $reserve_2, "The 2nd patron has a hold");
1025
1026
1026
    # Fake the holds queue
1027
    # Fake the holds queue
1027
    $dbh->do(q{INSERT INTO hold_fill_targets VALUES (?, ?, ?, ?, ?,?)},undef,($patron_1->borrowernumber,$biblio->biblionumber,$item_1->itemnumber,$item_1->homebranch,0,$reserve_1));
1028
    $dbh->do(q{INSERT INTO hold_fill_targets VALUES (?, ?, ?, ?, ?,?)},undef,($patron_1->borrowernumber,$biblio->biblionumber,$item_1->itemnumber,$item_1->homebranch,0,$reserve_1));
1028
1029
1029
    # The 2nd hold should be filed even if the item is preselected for the first hold
1030
    # The 2nd hold should be filed even if the item is preselected for the first hold
1030
    MoveReserve($item_1->itemnumber,$patron_2->borrowernumber);
1031
    MoveReserve($item_1->itemnumber,$patron_2->borrowernumber);
1031
    is($patron_2->holds->count, 0, "The 2nd patrons no longer has a hold");
1032
    is($patron_2->holds({ completed => 0 })->count, 0, "The 2nd patrons no longer has a hold");
1032
    is($patron_2->old_holds->next()->reserve_id, $reserve_2, "The 2nd patrons hold was filled and moved to old holds");
1033
    is($patron_2->holds({ completed => 1 })->next()->id, $reserve_2, "The 2nd patrons hold was filled and moved to old holds");
1033
1034
1034
};
1035
};
1035
1036
Lines 1085-1102 subtest 'CheckReserves additional test' => sub { Link Here
1085
        {
1086
        {
1086
            class => "Koha::Holds",
1087
            class => "Koha::Holds",
1087
            value => {
1088
            value => {
1088
                found            => undef,
1089
                priority         => 1,
1089
                priority         => 1,
1090
                itemnumber       => undef,
1090
                item_id          => undef,
1091
                biblionumber     => $item->biblionumber,
1091
                biblio_id        => $item->biblionumber,
1092
                waitingdate      => undef,
1092
                item_level       => 0,
1093
                cancellationdate => undef,
1093
                lowest_priority  => 0,
1094
                item_level_hold  => 0,
1094
                expiration_date  => undef,
1095
                lowestPriority   => 0,
1096
                expirationdate   => undef,
1097
                suspend_until    => undef,
1098
                suspend          => 0,
1099
                itemtype         => undef,
1100
            }
1095
            }
1101
        }
1096
        }
1102
    );
1097
    );
Lines 1104-1122 subtest 'CheckReserves additional test' => sub { Link Here
1104
        {
1099
        {
1105
            class => "Koha::Holds",
1100
            class => "Koha::Holds",
1106
            value => {
1101
            value => {
1107
                found            => undef,
1108
                priority         => 2,
1102
                priority         => 2,
1109
                biblionumber     => $item->biblionumber,
1103
                item_id          => $item->biblionumber,
1110
                borrowernumber   => $reserve1->borrowernumber,
1104
                patron_id        => $reserve1->patron_id,
1111
                itemnumber       => undef,
1105
                item_id          => undef,
1112
                waitingdate      => undef,
1106
                suspended_until  => undef,
1113
                cancellationdate => undef,
1107
                suspended        => 0,
1114
                item_level_hold  => 0,
1108
                item_type       => undef,
1115
                lowestPriority   => 0,
1116
                expirationdate   => undef,
1117
                suspend_until    => undef,
1118
                suspend          => 0,
1119
                itemtype         => undef,
1120
            }
1109
            }
1121
        }
1110
        }
1122
    );
1111
    );
Lines 1125-1132 subtest 'CheckReserves additional test' => sub { Link Here
1125
        {
1114
        {
1126
            source => 'TmpHoldsqueue',
1115
            source => 'TmpHoldsqueue',
1127
            value  => {
1116
            value  => {
1128
                borrowernumber => $reserve1->borrowernumber,
1117
                borrowernumber => $reserve1->patron_id,
1129
                biblionumber   => $reserve1->biblionumber,
1118
                biblionumber   => $reserve1->biblio_id,
1130
            }
1119
            }
1131
        }
1120
        }
1132
    );
1121
    );
Lines 1134-1155 subtest 'CheckReserves additional test' => sub { Link Here
1134
        {
1123
        {
1135
            source => 'HoldFillTarget',
1124
            source => 'HoldFillTarget',
1136
            value  => {
1125
            value  => {
1137
                borrowernumber     => $reserve1->borrowernumber,
1126
                borrowernumber     => $reserve1->patron_id,
1138
                biblionumber       => $reserve1->biblionumber,
1127
                biblionumber       => $reserve1->biblio_id,
1139
                itemnumber         => $item->itemnumber,
1128
                itemnumber         => $item->itemnumber,
1140
                item_level_request => 0,
1129
                item_level_request => 0,
1141
            }
1130
            }
1142
        }
1131
        }
1143
    );
1132
    );
1144
1133
1145
    ModReserveAffect( $item->itemnumber, $reserve1->borrowernumber, 1,
1134
    ModReserveAffect( $item->itemnumber, $reserve1->patron_id, 1,
1146
        $reserve1->reserve_id );
1135
        $reserve1->id );
1147
    my ( $status, $matched_reserve, $possible_reserves ) =
1136
    my ( $status, $matched_reserve, $possible_reserves ) =
1148
      CheckReserves( $item->itemnumber );
1137
      CheckReserves( $item->itemnumber );
1149
1138
1150
    is( $status, 'Reserved', "We found a reserve" );
1139
    is( $status, 'Reserved', "We found a reserve" );
1151
    is( $matched_reserve->{reserve_id},
1140
    is( $matched_reserve->{reserve_id},
1152
        $reserve1->reserve_id, "We got the Transit reserve" );
1141
        $reserve1->id, "We got the Transit reserve" );
1153
    is( scalar @$possible_reserves, 2, 'We do get both reserves' );
1142
    is( scalar @$possible_reserves, 2, 'We do get both reserves' );
1154
};
1143
};
1155
1144
(-)a/t/db_dependent/Reserves/AutoUnsuspendReserves.t (-16 / +16 lines)
Lines 43-52 subtest 'AutoUnsuspendReserves test' => sub { Link Here
43
    my $hold_1 = $builder->build_object({
43
    my $hold_1 = $builder->build_object({
44
        class => 'Koha::Holds',
44
        class => 'Koha::Holds',
45
        value => {
45
        value => {
46
            expirationdate => undef,
46
            expiration_date => undef,
47
            cancellationdate => undef,
47
            completed_date  => undef,
48
            priority => 5,
48
            priority => 5,
49
            found => undef,
49
            status => 'placed',
50
        },
50
        },
51
    });
51
    });
52
52
Lines 56-65 subtest 'AutoUnsuspendReserves test' => sub { Link Here
56
    my $hold_2 = $builder->build_object({
56
    my $hold_2 = $builder->build_object({
57
        class => 'Koha::Holds',
57
        class => 'Koha::Holds',
58
        value => {
58
        value => {
59
            expirationdate => undef,
59
            expiration_date => undef,
60
            cancellationdate => undef,
60
            completed_date  => undef,
61
            priority => 6,
61
            priority => 6,
62
            found => undef,
62
            status => 'placed',
63
        },
63
        },
64
    });
64
    });
65
65
Lines 84-94 subtest 'AutoUnsuspendReserves test' => sub { Link Here
84
        my $hold_3 = $builder->build_object(
84
        my $hold_3 = $builder->build_object(
85
            {   class => 'Koha::Holds',
85
            {   class => 'Koha::Holds',
86
                value => {
86
                value => {
87
                    expirationdate   => undef,
87
                    expiration_date   => undef,
88
                    cancellationdate => undef,
88
                    completed_date    => undef,
89
                    priority         => 5,
89
                    priority          => 5,
90
                    found            => undef,
90
                    status            => 'placed',
91
                    suspend_until    => undef,
91
                    suspended_until_date => undef,
92
                }
92
                }
93
            }
93
            }
94
        );
94
        );
Lines 121-130 subtest 'AutoUnsuspendReserves test' => sub { Link Here
121
        my $hold_4 = $builder->build_object(
121
        my $hold_4 = $builder->build_object(
122
            {   class => 'Koha::Holds',
122
            {   class => 'Koha::Holds',
123
                value => {
123
                value => {
124
                    expirationdate   => undef,
124
                    expiration_date   => undef,
125
                    cancellationdate => undef,
125
                    completed_date    => undef,
126
                    priority         => 5,
126
                    priority          => 5,
127
                    found            => undef
127
                    status            => 'placed'
128
                }
128
                }
129
            }
129
            }
130
        );
130
        );
Lines 137-143 subtest 'AutoUnsuspendReserves test' => sub { Link Here
137
        AutoUnsuspendReserves();
137
        AutoUnsuspendReserves();
138
138
139
        $hold_4->discard_changes;
139
        $hold_4->discard_changes;
140
        ok(!defined($hold_4->suspend_until), 'Hold suspended until today should be unsuspended.');
140
        ok(!defined($hold_4->suspended_until_date), 'Hold suspended until today should be unsuspended.');
141
141
142
        my $new_logs_count = $schema->resultset('ActionLog')
142
        my $new_logs_count = $schema->resultset('ActionLog')
143
            ->search( { module => 'HOLDS', action => 'RESUME' } )->count;
143
            ->search( { module => 'HOLDS', action => 'RESUME' } )->count;
(-)a/t/db_dependent/Reserves/CancelExpiredReserves.t (-58 / +112 lines)
Lines 16-22 my $schema = Koha::Database->new->schema; Link Here
16
$schema->storage->txn_begin;
16
$schema->storage->txn_begin;
17
17
18
subtest 'CancelExpiredReserves tests incl. holidays' => sub {
18
subtest 'CancelExpiredReserves tests incl. holidays' => sub {
19
    plan tests => 4;
19
    plan tests => 6;
20
20
21
    my $builder = t::lib::TestBuilder->new();
21
    my $builder = t::lib::TestBuilder->new();
22
22
Lines 33-84 subtest 'CancelExpiredReserves tests incl. holidays' => sub { Link Here
33
    $reserve1_expirationdate->add(days => 1);
33
    $reserve1_expirationdate->add(days => 1);
34
34
35
    # Reserve not expired
35
    # Reserve not expired
36
    my $reserve1 = $builder->build({
36
    my $reserve1 = $builder->build_object(
37
        source => 'Reserve',
37
        {
38
        value => {
38
            class => 'Koha::Holds',
39
            reservedate => $reserve_reservedate,
39
            value => {
40
            expirationdate => $reserve1_expirationdate,
40
                created_date    => $reserve_reservedate,
41
            cancellationdate => undef,
41
                expiration_date => $reserve1_expirationdate,
42
            priority => 0,
42
                completed_date  => undef,
43
            found => 'W',
43
                priority        => 0,
44
        },
44
                status          => 'waiting',
45
    });
45
                completed       => 0,
46
            },
47
        }
48
    );
46
49
47
    CancelExpiredReserves();
50
    CancelExpiredReserves();
48
    my $r1 = Koha::Holds->find($reserve1->{reserve_id});
51
    my $r1 = Koha::Holds->find($reserve1->id);
49
    ok($r1, 'Reserve 1 should not be canceled.');
52
    ok($r1, 'Reserve 1 should not be canceled.');
50
53
51
    my $reserve2_expirationdate = $today->clone;
54
    my $reserve2_expirationdate = $today->clone;
52
    $reserve2_expirationdate->subtract(days => 1);
55
    $reserve2_expirationdate->subtract(days => 1);
53
56
54
    # Reserve expired
57
    # Reserve expired
55
    my $reserve2 = $builder->build({
58
    my $reserve2 = $builder->build_object(
56
        source => 'Reserve',
59
        {
57
        value => {
60
            class => 'Koha::Holds',
58
            reservedate => $reserve_reservedate,
61
            value => {
59
            expirationdate => $reserve2_expirationdate,
62
                created_date    => $reserve_reservedate,
60
            cancellationdate => undef,
63
                expiration_date => $reserve2_expirationdate,
61
            priority => 0,
64
                completed_date  => undef,
62
            found => 'W',
65
                priority        => 0,
63
        },
66
                status          => 'waiting',
64
    });
67
                completed       => 0,
68
            },
69
        }
70
    );
65
71
66
    CancelExpiredReserves();
72
    CancelExpiredReserves();
67
    my $r2 = Koha::Holds->find($reserve2->{reserve_id});
73
    my $r2 = Koha::Holds->find($reserve2->id);
68
    is($r2, undef,'reserve 2 should be canceled.');
74
    is(ref($r2), 'Koha::Hold', 'reserve 2 is still there.');
75
    is($r2->status, 'cancelled', 'reserve 2 should be canceled.');
76
    is($r2->completed, 1, 'reserve 2 should be completed.');
69
77
70
    # Reserve expired on holiday
78
    # Reserve expired on holiday
71
    my $reserve3 = $builder->build({
79
    my $reserve3 = $builder->build_object(
72
        source => 'Reserve',
80
        {
73
        value => {
81
            class => 'Koha::Holds',
74
            reservedate => $reserve_reservedate,
82
            value => {
75
            expirationdate => $reserve2_expirationdate,
83
                created_date      => $reserve_reservedate,
76
            branchcode => 'LIB1',
84
                expiration_date   => $reserve2_expirationdate,
77
            cancellationdate => undef,
85
                pickup_library_id => 'LIB1',
78
            priority => 0,
86
                completed_date    => undef,
79
            found => 'W',
87
                priority          => 0,
80
        },
88
                status            => 'waiting',
81
    });
89
            },
90
        }
91
    );
82
92
83
    Koha::Caches->get_instance()->flush_all();
93
    Koha::Caches->get_instance()->flush_all();
84
    my $holiday = $builder->build({
94
    my $holiday = $builder->build({
Lines 94-106 subtest 'CancelExpiredReserves tests incl. holidays' => sub { Link Here
94
    });
104
    });
95
105
96
    CancelExpiredReserves();
106
    CancelExpiredReserves();
97
    my $r3 = Koha::Holds->find($reserve3->{reserve_id});
107
    $reserve3->discard_changes;
98
    ok($r3,'Reserve 3 should not be canceled.');
108
    is($reserve3->status, 'waiting','Reserve 3 should not be canceled.');
99
109
100
    t::lib::Mocks::mock_preference('ExpireReservesOnHolidays', 1);
110
    t::lib::Mocks::mock_preference('ExpireReservesOnHolidays', 1);
101
    CancelExpiredReserves();
111
    CancelExpiredReserves();
102
    $r3 = Koha::Holds->find($reserve3->{reserve_id});
112
    $reserve3->discard_changes;
103
    is($r3, undef,'Reserve 3 should be canceled.');
113
    is($reserve3->status, 'cancelled', 'Reserve 3 should be cancelled.');
104
};
114
};
105
115
106
subtest 'Test handling of waiting reserves by CancelExpiredReserves' => sub {
116
subtest 'Test handling of waiting reserves by CancelExpiredReserves' => sub {
Lines 119-124 subtest 'Test handling of waiting reserves by CancelExpiredReserves' => sub { Link Here
119
    my $expdate = dt_from_string->add( days => -2 );
129
    my $expdate = dt_from_string->add( days => -2 );
120
    my $notexpdate = dt_from_string->add( days => 2 );
130
    my $notexpdate = dt_from_string->add( days => 2 );
121
131
132
<<<<<<< HEAD
122
    my $hold1 = Koha::Hold->new({
133
    my $hold1 = Koha::Hold->new({
123
        branchcode => $branchcode,
134
        branchcode => $branchcode,
124
        borrowernumber => $borrowernumber,
135
        borrowernumber => $borrowernumber,
Lines 149-163 subtest 'Test handling of waiting reserves by CancelExpiredReserves' => sub { Link Here
149
        expirationdate => $expdate,
160
        expirationdate => $expdate,
150
        found => 'W',
161
        found => 'W',
151
    })->store;
162
    })->store;
163
=======
164
    my $hold1 = Koha::Hold->new(
165
        {
166
            pickup_library_id => $branchcode,
167
            patron_id         => $borrowernumber,
168
            biblio_id         => $bibnum,
169
            priority          => 1,
170
            created_date      => $resdate,
171
            expiration_date   => $notexpdate,
172
            status            => 'placed',
173
        }
174
    )->store;
175
176
    my $hold2 = Koha::Hold->new(
177
        {
178
            pickup_library_id => $branchcode,
179
            patron_id         => $borrowernumber,
180
            biblio_id         => $bibnum,
181
            priority          => 2,
182
            created_date      => $resdate,
183
            expiration_date   => $expdate,
184
            status            => 'placed',
185
        }
186
    )->store;
187
188
    my $hold3 = Koha::Hold->new(
189
        {
190
            pickup_library_id => $branchcode,
191
            patron_id         => $borrowernumber,
192
            biblio_id         => $bibnum,
193
            item_id           => $itemnumber,
194
            priority          => 0,
195
            created_date      => $resdate,
196
            expiration_date   => $expdate,
197
            status            => 'waiting',
198
        }
199
    )->store;
200
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
152
201
153
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
202
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
154
    CancelExpiredReserves();
203
    CancelExpiredReserves();
155
    my $count1 = Koha::Holds->search->count;
204
    my $count1 = Koha::Holds->search({ completed => 0 })->count;
156
    is( $count1, 2, 'Only the non-waiting expired holds should be cancelled');
205
    is( $count1, 2, 'Only the non-waiting expired holds should be cancelled');
157
206
158
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
207
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
159
    CancelExpiredReserves();
208
    CancelExpiredReserves();
160
    my $count2 = Koha::Holds->search->count;
209
    my $count2 = Koha::Holds->search({ completed => 0 })->count;
161
    is( $count2, 1, 'Also the waiting expired hold should be cancelled now');
210
    is( $count2, 1, 'Also the waiting expired hold should be cancelled now');
162
211
163
};
212
};
Lines 169-201 subtest 'Test handling of in transit reserves by CancelExpiredReserves' => sub { Link Here
169
218
170
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
219
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
171
    my $expdate = dt_from_string->add( days => -2 );
220
    my $expdate = dt_from_string->add( days => -2 );
172
    my $reserve = $builder->build({
221
    my $reserve = $builder->build_object({
173
        source => 'Reserve',
222
        class => 'Koha::Holds',
174
        value  => {
223
        value  => {
175
            expirationdate => '2018-01-01',
224
            expiration_date      => '2018-01-01',
176
            found => 'T',
225
            status               => 'in_transit',
177
            cancellationdate => undef,
226
            suspended            => 0,
178
            suspend => 0,
227
            completed            => 0,
179
            suspend_until => undef
228
            cancellation_date    => undef,
229
            suspended_until_date => undef,
180
        }
230
        }
181
    });
231
    });
182
    my $count = Koha::Holds->search->count;
232
233
    my $active = Koha::Holds->search({ completed => 0 });
234
    my $count = $active->count;
235
183
    CancelExpiredReserves();
236
    CancelExpiredReserves();
184
    is(Koha::Holds->search->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay set");
237
    is($active->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay set");
185
238
186
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
239
    t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 0 );
187
    my $reserve2 = $builder->build({
240
    my $reserve2 = $builder->build_object({
188
        source => 'Reserve',
241
        class => 'Koha::Holds',
189
        value  => {
242
        value  => {
190
            expirationdate => '2018-01-01',
243
            expiration_date      => '2018-01-01',
191
            found => 'T',
244
            status               => 'in_transit',
192
            cancellationdate => undef,
245
            cancellation_date    => undef,
193
            suspend => 0,
246
            suspended            => 0,
194
            suspend_until => undef
247
            suspended_until_date => undef,
248
            completed            => 0,
195
        }
249
        }
196
    });
250
    });
197
    CancelExpiredReserves();
251
    CancelExpiredReserves();
198
    is(Koha::Holds->search->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay unset");
252
    is($active->count, $count-1, "Transit hold is cancelled if ExpireReservesMaxPickUpDelay unset");
199
253
200
};
254
};
201
255
(-)a/t/db_dependent/Reserves/GetReserveFee.t (+29 lines)
Lines 119-137 subtest 'Integration with AddReserve' => sub { Link Here
119
        plan tests => 3;
119
        plan tests => 3;
120
120
121
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
121
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
122
<<<<<<< HEAD
122
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
123
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
124
=======
125
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
126
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
123
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
127
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
124
        addreserve( $patron1->{borrowernumber} );
128
        addreserve( $patron1->{borrowernumber} );
125
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - No fee charged for patron 1 if not issued' );
129
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - No fee charged for patron 1 if not issued' );
126
130
127
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_placed');
131
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_placed');
132
<<<<<<< HEAD
128
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
133
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
134
=======
135
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
136
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
129
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
137
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
130
        addreserve( $patron1->{borrowernumber} );
138
        addreserve( $patron1->{borrowernumber} );
131
        is( acctlines( $patron1->{borrowernumber} ), 1, 'any_time_is_placed - Patron should be always charged' );
139
        is( acctlines( $patron1->{borrowernumber} ), 1, 'any_time_is_placed - Patron should be always charged' );
132
140
133
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_collected');
141
        t::lib::Mocks::mock_preference('HoldFeeMode', 'any_time_is_collected');
142
<<<<<<< HEAD
134
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
143
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
144
=======
145
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
146
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
135
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
147
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
136
        addreserve( $patron1->{borrowernumber} );
148
        addreserve( $patron1->{borrowernumber} );
137
        is( acctlines( $patron1->{borrowernumber} ), 0, 'any_time_is_collected - Patron should not be charged when placing a hold' );
149
        is( acctlines( $patron1->{borrowernumber} ), 0, 'any_time_is_collected - Patron should not be charged when placing a hold' );
Lines 143-162 subtest 'Integration with AddReserve' => sub { Link Here
143
        C4::Circulation::AddIssue( $patron2, $item1->barcode, '2015-12-31', 0, undef, 0, {} );
155
        C4::Circulation::AddIssue( $patron2, $item1->barcode, '2015-12-31', 0, undef, 0, {} );
144
156
145
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
157
        t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
158
<<<<<<< HEAD
146
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
159
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
160
=======
161
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?",     undef, $biblio->{biblionumber} );
162
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
147
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
163
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
148
        addreserve( $patron1->{borrowernumber} );
164
        addreserve( $patron1->{borrowernumber} );
149
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - Patron should not be charged if items are not all checked out' );
165
        is( acctlines( $patron1->{borrowernumber} ), 0, 'not_always - Patron should not be charged if items are not all checked out' );
150
166
167
<<<<<<< HEAD
151
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
168
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
169
=======
170
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
171
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
152
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
172
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
153
        addreserve( $patron3->{borrowernumber} );
173
        addreserve( $patron3->{borrowernumber} );
154
        addreserve( $patron1->{borrowernumber} );
174
        addreserve( $patron1->{borrowernumber} );
155
        # FIXME Are we sure it's the expected behavior?
175
        # FIXME Are we sure it's the expected behavior?
156
        is( acctlines( $patron1->{borrowernumber} ), 1, 'not_always - Patron should be charged if all the items are not checked out and at least 1 hold is already placed' );
176
        is( acctlines( $patron1->{borrowernumber} ), 1, 'not_always - Patron should be charged if all the items are not checked out and at least 1 hold is already placed' );
157
177
178
<<<<<<< HEAD
158
        C4::Circulation::AddIssue( $patron3, $item2->barcode, '2015-12-31', 0, undef, 0, {} );
179
        C4::Circulation::AddIssue( $patron3, $item2->barcode, '2015-12-31', 0, undef, 0, {} );
159
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
180
        $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
181
=======
182
        C4::Circulation::AddIssue( $patron3, $item2->{barcode}, '2015-12-31', 0, undef, 0, {} );
183
        $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
184
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
160
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
185
        $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
161
        addreserve( $patron1->{borrowernumber} );
186
        addreserve( $patron1->{borrowernumber} );
162
        is( acctlines( $patron1->{borrowernumber} ), 1, 'not_always - Patron should be charged if all items are checked out' );
187
        is( acctlines( $patron1->{borrowernumber} ), 1, 'not_always - Patron should be charged if all items are checked out' );
Lines 167-173 subtest 'Integration with AddIssue' => sub { Link Here
167
    plan tests => 5;
192
    plan tests => 5;
168
193
169
    $dbh->do( "DELETE FROM issues       WHERE borrowernumber = ?", undef, $patron1->{borrowernumber} );
194
    $dbh->do( "DELETE FROM issues       WHERE borrowernumber = ?", undef, $patron1->{borrowernumber} );
195
<<<<<<< HEAD
170
    $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
196
    $dbh->do( "DELETE FROM reserves     WHERE biblionumber=?", undef, $biblio->biblionumber );
197
=======
198
    $dbh->do( "DELETE FROM holds        WHERE biblio_id=?", undef, $biblio->{biblionumber} );
199
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
171
    $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
200
    $dbh->do( "DELETE FROM accountlines WHERE borrowernumber=?", undef, $patron1->{borrowernumber} );
172
201
173
    t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
202
    t::lib::Mocks::mock_preference('HoldFeeMode', 'not_always');
(-)a/t/db_dependent/Reserves/MultiplePerRecord.t (-3 / +19 lines)
Lines 184-208 is( $max, 9, 'GetMaxPatronHoldsForRecord returns max of 9 because Library specif Link Here
184
184
185
Koha::CirculationRules->delete();
185
Koha::CirculationRules->delete();
186
186
187
my $holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
187
my $holds = Koha::Holds->search( { patron_id => $patron->{borrowernumber} } );
188
is( $holds->forced_hold_level, undef, "No holds does not force an item or record level hold" );
188
is( $holds->forced_hold_level, undef, "No holds does not force an item or record level hold" );
189
189
190
# Test Koha::Holds::forced_hold_level
190
# Test Koha::Holds::forced_hold_level
191
my $hold = Koha::Hold->new({
191
my $hold = Koha::Hold->new({
192
<<<<<<< HEAD
192
    borrowernumber => $patron->{borrowernumber},
193
    borrowernumber => $patron->{borrowernumber},
193
    reservedate => '1981-06-10',
194
    reservedate => '1981-06-10',
194
    biblionumber => $biblio->biblionumber,
195
    biblionumber => $biblio->biblionumber,
195
    branchcode => $library->{branchcode},
196
    branchcode => $library->{branchcode},
197
=======
198
    patron_id => $patron->{borrowernumber},
199
    created_date => '1981-06-10',
200
    biblio_id => $biblio->{biblionumber},
201
    pickup_library_id => $library->{branchcode},
202
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
196
    priority => 1,
203
    priority => 1,
197
})->store();
204
})->store();
198
205
199
$holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
206
$holds = Koha::Holds->search( { patron_id => $patron->{borrowernumber} } );
200
is( $holds->forced_hold_level, 'record', "Record level hold forces record level holds" );
207
is( $holds->forced_hold_level, 'record', "Record level hold forces record level holds" );
201
208
209
<<<<<<< HEAD
202
$hold->itemnumber( $item1->itemnumber );
210
$hold->itemnumber( $item1->itemnumber );
211
=======
212
$hold->item_id( $item1->{itemnumber} );
213
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
203
$hold->store();
214
$hold->store();
204
215
205
$holds = Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } );
216
$holds = Koha::Holds->search( { patron_id => $patron->{borrowernumber} } );
206
is( $holds->forced_hold_level, 'item', "Item level hold forces item level holds" );
217
is( $holds->forced_hold_level, 'item', "Item level hold forces item level holds" );
207
218
208
$hold->delete();
219
$hold->delete();
Lines 247-254 ok( $hold_id, 'Second hold was placed' ); Link Here
247
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->biblionumber);
258
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->biblionumber);
248
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
259
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
249
260
261
<<<<<<< HEAD
250
Koha::Holds->find($hold_id)->found("W")->store;
262
Koha::Holds->find($hold_id)->found("W")->store;
251
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->biblionumber);
263
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->biblionumber);
264
=======
265
Koha::Holds->find($hold_id)->set_waiting();
266
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->{biblionumber});
267
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
252
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
268
is( $can->{status}, 'tooManyHoldsForThisRecord', 'Third hold exceeds limit of holds per record' );
253
269
254
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->biblionumber, undef, { ignore_found_holds => 1 });
270
$can = CanBookBeReserved($patron->{borrowernumber}, $biblio->biblionumber, undef, { ignore_found_holds => 1 });
(-)a/t/db_dependent/Reserves/ReserveSlip.t (-1 / +18 lines)
Lines 31-37 $schema->storage->txn_begin; Link Here
31
31
32
my $dbh = C4::Context->dbh;
32
my $dbh = C4::Context->dbh;
33
$dbh->do(q|DELETE FROM letter|);
33
$dbh->do(q|DELETE FROM letter|);
34
$dbh->do(q|DELETE FROM reserves|);
34
$dbh->do(q|DELETE FROM holds|);
35
35
36
my $builder = t::lib::TestBuilder->new();
36
my $builder = t::lib::TestBuilder->new();
37
my $library = $builder->build(
37
my $library = $builder->build(
Lines 66-89 my $item2 = $builder->build_sample_item( Link Here
66
66
67
my $hold1 = Koha::Hold->new(
67
my $hold1 = Koha::Hold->new(
68
    {
68
    {
69
<<<<<<< HEAD
69
        biblionumber   => $biblio->biblionumber,
70
        biblionumber   => $biblio->biblionumber,
70
        itemnumber     => $item1->itemnumber,
71
        itemnumber     => $item1->itemnumber,
71
        waitingdate    => '2000-01-01',
72
        waitingdate    => '2000-01-01',
72
        borrowernumber => $patron->{borrowernumber},
73
        borrowernumber => $patron->{borrowernumber},
73
        branchcode     => $library->{branchcode},
74
        branchcode     => $library->{branchcode},
75
=======
76
        biblio_id         => $biblio->{biblionumber},
77
        item_id           => $item1->{itemnumber},
78
        waiting_date      => '2000-01-01',
79
        patron_id         => $patron->{borrowernumber},
80
        pickup_library_id => $library->{branchcode},
81
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
74
    }
82
    }
75
)->store;
83
)->store;
76
84
77
my $hold2 = Koha::Hold->new(
85
my $hold2 = Koha::Hold->new(
78
    {
86
    {
87
<<<<<<< HEAD
79
        biblionumber   => $biblio->biblionumber,
88
        biblionumber   => $biblio->biblionumber,
80
        itemnumber     => $item2->itemnumber,
89
        itemnumber     => $item2->itemnumber,
81
        waitingdate    => '2000-01-01',
90
        waitingdate    => '2000-01-01',
82
        borrowernumber => $patron->{borrowernumber},
91
        borrowernumber => $patron->{borrowernumber},
83
        branchcode     => $library->{branchcode},
92
        branchcode     => $library->{branchcode},
93
=======
94
        biblio_id         => $biblio->{biblionumber},
95
        item_id           => $item2->{itemnumber},
96
        waiting_date      => '2000-01-01',
97
        patron_id         => $patron->{borrowernumber},
98
        pickup_library_id => $library->{branchcode},
99
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
84
    }
100
    }
85
)->store;
101
)->store;
86
102
103
87
my $letter = $builder->build(
104
my $letter = $builder->build(
88
    {
105
    {
89
        source => 'Letter',
106
        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 97-106 subtest 'buildKohaItemsNamespace status tests' => sub { Link Here
97
    like($xml,qr{<status>In transit</status>},"In-transit status takes precedence over Damaged");
97
    like($xml,qr{<status>In transit</status>},"In-transit status takes precedence over Damaged");
98
98
99
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
99
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
100
        biblionumber => $item->biblionumber,
100
        biblio_id => $item->biblionumber,
101
        itemnumber   => $item->itemnumber,
101
        item_id   => $item->itemnumber,
102
        found        => 'W',
102
        status    => 'waiting',
103
        priority     => 0,
103
        priority  => 0,
104
        completed => 0,
104
        }
105
        }
105
    });
106
    });
106
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
107
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
(-)a/t/db_dependent/api/v1/holds.t (-35 / +44 lines)
Lines 164-170 my $post_data = { Link Here
164
};
164
};
165
my $put_data = {
165
my $put_data = {
166
    priority => 2,
166
    priority => 2,
167
    suspended_until => output_pref({ dt => $suspended_until, dateformat => 'rfc3339' }),
167
    suspended_until_date => output_pref({ dt => $suspended_until, dateformat => 'rfc3339' }),
168
};
168
};
169
169
170
subtest "Test endpoints without authentication" => sub {
170
subtest "Test endpoints without authentication" => sub {
Lines 331-337 subtest 'test AllowHoldDateInFuture' => sub { Link Here
331
        item_id => int($item_1->itemnumber),
331
        item_id => int($item_1->itemnumber),
332
        pickup_library_id => $branchcode,
332
        pickup_library_id => $branchcode,
333
        expiration_date => output_pref({ dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 }),
333
        expiration_date => output_pref({ dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 }),
334
        hold_date => output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }),
334
        created_date => output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }),
335
        priority => 2,
335
        priority => 2,
336
    };
336
    };
337
337
Lines 351-357 subtest 'test AllowHoldDateInFuture' => sub { Link Here
351
351
352
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
352
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
353
      ->status_is(201)
353
      ->status_is(201)
354
      ->json_is('/hold_date', output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }));
354
      ->json_is('/created_date', output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }));
355
};
355
};
356
356
357
subtest 'test AllowHoldPolicyOverride' => sub {
357
subtest 'test AllowHoldPolicyOverride' => sub {
Lines 416-422 subtest 'suspend and resume tests' => sub { Link Here
416
416
417
    my $hold = $builder->build_object(
417
    my $hold = $builder->build_object(
418
        {   class => 'Koha::Holds',
418
        {   class => 'Koha::Holds',
419
            value => { suspend => 0, suspend_until => undef, waitingdate => undef, found => undef }
419
            value => {
420
                suspended    => 0,
421
                waiting_date => undef,
422
                suspended_until_date => undef,
423
                completed => 0
424
            }
420
        }
425
        }
421
    );
426
    );
422
427
Lines 427-433 subtest 'suspend and resume tests' => sub { Link Here
427
    $hold->discard_changes;    # refresh object
432
    $hold->discard_changes;    # refresh object
428
433
429
    ok( $hold->is_suspended, 'Hold is suspended' );
434
    ok( $hold->is_suspended, 'Hold is suspended' );
430
    $t->json_is('/end_date', undef, 'Hold suspension has no end date');
435
    $t->json_is('/suspended_until_date', undef, 'Hold suspension has no end date');
431
436
432
    my $end_date = output_pref({
437
    my $end_date = output_pref({
433
      dt         => dt_from_string( undef ),
438
      dt         => dt_from_string( undef ),
Lines 443-449 subtest 'suspend and resume tests' => sub { Link Here
443
    $t->json_is(
448
    $t->json_is(
444
      '/end_date',
449
      '/end_date',
445
      output_pref({
450
      output_pref({
446
        dt         => dt_from_string( $hold->suspend_until ),
451
        dt         => dt_from_string( $hold->suspended_until_date ),
447
        dateformat => 'rfc3339',
452
        dateformat => 'rfc3339',
448
        dateonly   => 1
453
        dateonly   => 1
449
      }),
454
      }),
Lines 476-488 subtest 'suspend and resume tests' => sub { Link Here
476
481
477
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
482
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
478
      ->status_is( 400, 'Cannot suspend waiting hold' )
483
      ->status_is( 400, 'Cannot suspend waiting hold' )
479
      ->json_is( '/error', 'Found hold cannot be suspended. Status=W' );
484
      ->json_is( '/error', 'Found hold cannot be suspended. Status=waiting' );
480
485
481
    $hold->set_transfer->discard_changes;
486
    $hold->set_transfer->discard_changes;
482
487
483
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
488
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
484
      ->status_is( 400, 'Cannot suspend hold on transfer' )
489
      ->status_is( 400, 'Cannot suspend hold on transfer' )
485
      ->json_is( '/error', 'Found hold cannot be suspended. Status=T' );
490
      ->json_is( '/error', 'Found hold cannot be suspended. Status=in_transit' );
486
491
487
    $schema->storage->txn_rollback;
492
    $schema->storage->txn_rollback;
488
};
493
};
Lines 769-788 subtest 'pickup_locations() tests' => sub { Link Here
769
        {
774
        {
770
            class => 'Koha::Holds',
775
            class => 'Koha::Holds',
771
            value => {
776
            value => {
772
                itemnumber     => undef,
777
                item_id   => undef,
773
                biblionumber   => $item->biblionumber,
778
                biblio_id => $item->biblionumber,
774
                borrowernumber => $patron->borrowernumber
779
                patron_id => $patron->borrowernumber,
780
                completed => 0,
775
            }
781
            }
776
        }
782
        }
777
    );
783
    );
784
778
    # item-level hold
785
    # item-level hold
779
    my $hold_2 = $builder->build_object(
786
    my $hold_2 = $builder->build_object(
780
        {
787
        {
781
            class => 'Koha::Holds',
788
            class => 'Koha::Holds',
782
            value => {
789
            value => {
783
                itemnumber     => $item->itemnumber,
790
                item_id   => $item->itemnumber,
784
                biblionumber   => $item->biblionumber,
791
                biblio_id => $item->biblionumber,
785
                borrowernumber => $patron->borrowernumber
792
                patron_id => $patron->borrowernumber,
793
                completed => 0,
786
            }
794
            }
787
        }
795
        }
788
    );
796
    );
Lines 859-868 subtest 'edit() tests' => sub { Link Here
859
        {
867
        {
860
            class => "Koha::Holds",
868
            class => "Koha::Holds",
861
            value => {
869
            value => {
862
                biblionumber => $biblio->biblionumber,
870
                biblio_id         => $biblio->biblionumber,
863
                branchcode   => $library_3->branchcode,
871
                pickup_library_id => $library_3->branchcode,
864
                itemnumber   => undef,
872
                item_id           => undef,
865
                priority     => 1,
873
                priority          => 1,
874
                completed         => 0,
866
            }
875
            }
867
        }
876
        }
868
    );
877
    );
Lines 877-883 subtest 'edit() tests' => sub { Link Here
877
      ->json_is({ error => 'The supplied pickup location is not valid' });
886
      ->json_is({ error => 'The supplied pickup location is not valid' });
878
887
879
    $biblio_hold->discard_changes;
888
    $biblio_hold->discard_changes;
880
    is( $biblio_hold->branchcode, $library_3->branchcode, 'branchcode remains untouched' );
889
    is( $biblio_hold->pickup_library_id, $library_3->branchcode, 'pickup_library_id remains untouched' );
881
890
882
    $biblio_hold_data->{pickup_library_id} = $library_2->branchcode;
891
    $biblio_hold_data->{pickup_library_id} = $library_2->branchcode;
883
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
892
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
Lines 886-902 subtest 'edit() tests' => sub { Link Here
886
      ->status_is(200);
895
      ->status_is(200);
887
896
888
    $biblio_hold->discard_changes;
897
    $biblio_hold->discard_changes;
889
    is( $biblio_hold->branchcode, $library_2->id, 'Pickup location changed correctly' );
898
    is( $biblio_hold->pickup_library_id, $library_2->id, 'Pickup location changed correctly' );
890
899
891
    # Test item-level holds
900
    # Test item-level holds
892
    my $item_hold = $builder->build_object(
901
    my $item_hold = $builder->build_object(
893
        {
902
        {
894
            class => "Koha::Holds",
903
            class => "Koha::Holds",
895
            value => {
904
            value => {
896
                biblionumber => $biblio->biblionumber,
905
                biblio_id         => $biblio->biblionumber,
897
                branchcode   => $library_3->branchcode,
906
                pickup_library_id => $library_3->branchcode,
898
                itemnumber   => $item->itemnumber,
907
                item_id           => $item->itemnumber,
899
                priority     => 1,
908
                priority          => 1,
909
                completed         => 0,
900
            }
910
            }
901
        }
911
        }
902
    );
912
    );
Lines 911-917 subtest 'edit() tests' => sub { Link Here
911
      ->json_is({ error => 'The supplied pickup location is not valid' });
921
      ->json_is({ error => 'The supplied pickup location is not valid' });
912
922
913
    $item_hold->discard_changes;
923
    $item_hold->discard_changes;
914
    is( $item_hold->branchcode, $library_3->branchcode, 'branchcode remains untouched' );
924
    is( $item_hold->pickup_library_id, $library_3->branchcode, 'branchcode remains untouched' );
915
925
916
    $item_hold_data->{pickup_library_id} = $library_2->branchcode;
926
    $item_hold_data->{pickup_library_id} = $library_2->branchcode;
917
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
927
    $t->put_ok( "//$userid:$password@/api/v1/holds/"
Lines 920-926 subtest 'edit() tests' => sub { Link Here
920
      ->status_is(200);
930
      ->status_is(200);
921
931
922
    $item_hold->discard_changes;
932
    $item_hold->discard_changes;
923
    is( $item_hold->branchcode, $library_2->id, 'Pickup location changed correctly' );
933
    is( $item_hold->pickup_library_id, $library_2->id, 'Pickup location changed correctly' );
924
934
925
    $schema->storage->txn_rollback;
935
    $schema->storage->txn_rollback;
926
};
936
};
Lines 977-986 subtest 'add() tests' => sub { Link Here
977
        {
987
        {
978
            class => "Koha::Holds",
988
            class => "Koha::Holds",
979
            value => {
989
            value => {
980
                biblionumber => $biblio->biblionumber,
990
                biblio_id         => $biblio->biblionumber,
981
                branchcode   => $library_3->branchcode,
991
                pickup_library_id => $library_3->branchcode,
982
                itemnumber   => undef,
992
                item_id           => undef,
983
                priority     => 1,
993
                priority          => 1,
984
            }
994
            }
985
        }
995
        }
986
    );
996
    );
Lines 1003-1012 subtest 'add() tests' => sub { Link Here
1003
        {
1013
        {
1004
            class => "Koha::Holds",
1014
            class => "Koha::Holds",
1005
            value => {
1015
            value => {
1006
                biblionumber => $biblio->biblionumber,
1016
                biblio_id         => $biblio->biblionumber,
1007
                branchcode   => $library_3->branchcode,
1017
                pickup_library_id => $library_3->branchcode,
1008
                itemnumber   => $item->itemnumber,
1018
                item_id           => $item->itemnumber,
1009
                priority     => 1,
1019
                priority          => 1,
1010
            }
1020
            }
1011
        }
1021
        }
1012
    );
1022
    );
1013
- 

Return to bug 25260