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

(-)a/C4/Circulation.pm (-4 / +8 lines)
Lines 1297-1303 sub checkHighHolds { Link Here
1297
        due_date    => undef,
1297
        due_date    => undef,
1298
    };
1298
    };
1299
1299
1300
    my $holds = Koha::Holds->search( { biblionumber => $item->{'biblionumber'} } );
1300
    my $holds = Koha::Holds->search( { biblio_id => $item->{'biblionumber'} } );
1301
1301
1302
    if ( $holds->count() ) {
1302
    if ( $holds->count() ) {
1303
        $return_data->{outstanding} = $holds->count();
1303
        $return_data->{outstanding} = $holds->count();
Lines 2878-2885 sub CanBookBeRenewed { Link Here
2878
    # If next hold is non priority, then check if any hold with priority (non_priority = 0) exists for the same biblionumber.
2878
    # If next hold is non priority, then check if any hold with priority (non_priority = 0) exists for the same biblionumber.
2879
    if ( $resfound && $resrec->{non_priority} ) {
2879
    if ( $resfound && $resrec->{non_priority} ) {
2880
        $resfound = Koha::Holds->search(
2880
        $resfound = Koha::Holds->search(
2881
            { biblionumber => $resrec->{biblionumber}, non_priority => 0 } )
2881
            {
2882
          ->count > 0;
2882
                biblio_id    => $resrec->{biblionumber},
2883
                non_priority => 0,
2884
                completed    => 0
2885
            }
2886
        )->count > 0;
2883
    }
2887
    }
2884
2888
2885
2889
Lines 2889-2895 sub CanBookBeRenewed { Link Here
2889
    if ( $resfound
2893
    if ( $resfound
2890
        && C4::Context->preference('AllowRenewalIfOtherItemsAvailable') )
2894
        && C4::Context->preference('AllowRenewalIfOtherItemsAvailable') )
2891
    {
2895
    {
2892
        my $item_holds = Koha::Holds->search( { itemnumber => $itemnumber, found => undef } )->count();
2896
        my $item_holds = Koha::Holds->search( { item_id => $itemnumber, status => 'placed' } )->count();
2893
        if ($item_holds) {
2897
        if ($item_holds) {
2894
            # There is an item level hold on this item, no other item can fill the hold
2898
            # There is an item level hold on this item, no other item can fill the hold
2895
            $resfound = 1;
2899
            $resfound = 1;
(-)a/C4/Members.pm (-1 / +1 lines)
Lines 233-239 sub patronflags { Link Here
233
        $flags{'ODUES'} = \%flaginfo;
233
        $flags{'ODUES'} = \%flaginfo;
234
    }
234
    }
235
235
236
    my $waiting_holds = $patron->holds->search({ found => 'W' });
236
    my $waiting_holds = $patron->holds->search({ status => 'waiting' });
237
    my $nowaiting = $waiting_holds->count;
237
    my $nowaiting = $waiting_holds->count;
238
    if ( $nowaiting > 0 ) {
238
    if ( $nowaiting > 0 ) {
239
        my %flaginfo;
239
        my %flaginfo;
(-)a/C4/Reserves.pm (-258 / +252 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 394-400 sub CanItemBeReserved { Link Here
394
391
395
    # Check that the patron doesn't have an item level hold on this item already
392
    # Check that the patron doesn't have an item level hold on this item already
396
    return { status =>'itemAlreadyOnHold' }
393
    return { status =>'itemAlreadyOnHold' }
397
      if ( !$params->{ignore_hold_counts} && Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count() );
394
      if ( !$params->{ignore_hold_counts} && Koha::Holds->search( { patron_id => $borrowernumber, item_id => $itemnumber, completed => 0 } )->count() );
398
395
399
    # Check that patron have not checked out this biblio (if AllowHoldsOnPatronsPossessions set)
396
    # Check that patron have not checked out this biblio (if AllowHoldsOnPatronsPossessions set)
400
    if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions')
397
    if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions')
Lines 406-420 sub CanItemBeReserved { Link Here
406
403
407
    my $querycount = q{
404
    my $querycount = q{
408
        SELECT count(*) AS count
405
        SELECT count(*) AS count
409
          FROM reserves
406
          FROM holds
410
     LEFT JOIN items USING (itemnumber)
407
     LEFT JOIN items ON (holds.item_id=items.itemnumber)
411
     LEFT JOIN biblioitems ON (reserves.biblionumber=biblioitems.biblionumber)
408
     LEFT JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
412
     LEFT JOIN borrowers USING (borrowernumber)
409
     LEFT JOIN borrowers ON (holds.patron_id=borrowers.borrowernumber)
413
         WHERE borrowernumber = ?
410
         WHERE completed = 0 and borrowernumber = ?
414
    };
411
    };
415
412
416
    my $branchcode  = "";
413
    my $branchcode  = "";
417
    my $branchfield = "reserves.branchcode";
414
    my $branchfield = "holds.pickup_library_id";
418
415
419
    if ( $controlbranch eq "ItemHomeLibrary" ) {
416
    if ( $controlbranch eq "ItemHomeLibrary" ) {
420
        $branchfield = "items.homebranch";
417
        $branchfield = "items.homebranch";
Lines 451-460 sub CanItemBeReserved { Link Here
451
    my $holds_per_day    = $rights->{holds_per_day};
448
    my $holds_per_day    = $rights->{holds_per_day};
452
449
453
    my $search_params = {
450
    my $search_params = {
454
        borrowernumber => $borrowernumber,
451
        patron_id => $borrowernumber,
455
        biblionumber   => $item->biblionumber,
452
        biblio_id => $item->biblionumber,
453
        completed => 0,
456
    };
454
    };
457
    $search_params->{found} = undef if $params->{ignore_found_holds};
455
    $search_params->{status} = 'placed' if $params->{ignore_found_holds};
458
456
459
    my $holds = Koha::Holds->search($search_params);
457
    my $holds = Koha::Holds->search($search_params);
460
    if (   defined $holds_per_record && $holds_per_record ne '' ){
458
    if (   defined $holds_per_record && $holds_per_record ne '' ){
Lines 467-474 sub CanItemBeReserved { Link Here
467
    }
465
    }
468
466
469
    my $today_holds = Koha::Holds->search({
467
    my $today_holds = Koha::Holds->search({
470
        borrowernumber => $borrowernumber,
468
        patron_id    => $borrowernumber,
471
        reservedate    => dt_from_string->date
469
        created_date => dt_from_string->date,
470
        completed    => 0
472
    });
471
    });
473
472
474
    if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne ''
473
    if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne ''
Lines 524-530 sub CanItemBeReserved { Link Here
524
    if (!$params->{ignore_hold_counts} && $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
523
    if (!$params->{ignore_hold_counts} && $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) {
525
        my $total_holds_count = Koha::Holds->search(
524
        my $total_holds_count = Koha::Holds->search(
526
            {
525
            {
527
                borrowernumber => $borrower->{borrowernumber}
526
                patron_id => $borrower->{borrowernumber},
527
                completed => 0
528
            }
528
            }
529
        )->count();
529
        )->count();
530
530
Lines 602-611 sub CanReserveBeCanceledFromOpac { Link Here
602
    my ($reserve_id, $borrowernumber) = @_;
602
    my ($reserve_id, $borrowernumber) = @_;
603
603
604
    return unless $reserve_id and $borrowernumber;
604
    return unless $reserve_id and $borrowernumber;
605
    my $reserve = Koha::Holds->find($reserve_id);
605
    my $hold = Koha::Holds->find($reserve_id);
606
606
607
    return 0 unless $reserve->borrowernumber == $borrowernumber;
607
    return 0 unless $hold->patron_id == $borrowernumber;
608
    return $reserve->is_cancelable_from_opac;
608
    return $hold->is_cancelable_from_opac;
609
}
609
}
610
610
611
=head2 GetOtherReserves
611
=head2 GetOtherReserves
Lines 623-641 sub GetOtherReserves { Link Here
623
    my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber);
623
    my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber);
624
    if ($checkreserves) {
624
    if ($checkreserves) {
625
        my $item = Koha::Items->find($itemnumber);
625
        my $item = Koha::Items->find($itemnumber);
626
        if ( $item->holdingbranch ne $checkreserves->{'branchcode'} ) {
626
        if ( $item->holdingbranch ne $checkreserves->{pickup_library_id} ) {
627
            $messages->{'transfert'} = $checkreserves->{'branchcode'};
627
            $messages->{'transfert'} = $checkreserves->{pickup_library_id};
628
            #minus priorities of others reservs
628
            #minus priorities of others reservs
629
            ModReserveMinusPriority(
629
            ModReserveMinusPriority(
630
                $itemnumber,
630
                $itemnumber,
631
                $checkreserves->{'reserve_id'},
631
                $checkreserves->{id},
632
            );
632
            );
633
633
634
            #launch the subroutine dotransfer
634
            #launch the subroutine dotransfer
635
            C4::Items::ModItemTransfer(
635
            C4::Items::ModItemTransfer(
636
                $itemnumber,
636
                $itemnumber,
637
                $item->holdingbranch,
637
                $item->holdingbranch,
638
                $checkreserves->{'branchcode'},
638
                $checkreserves->{pickup_library_id},
639
                'Reserve'
639
                'Reserve'
640
              ),
640
              ),
641
              ;
641
              ;
Lines 646-654 sub GetOtherReserves { Link Here
646
            $messages->{'waiting'} = 1;
646
            $messages->{'waiting'} = 1;
647
            ModReserveMinusPriority(
647
            ModReserveMinusPriority(
648
                $itemnumber,
648
                $itemnumber,
649
                $checkreserves->{'reserve_id'},
649
                $checkreserves->{id},
650
            );
650
            );
651
            ModReserveStatus($itemnumber,'W');
651
            ModReserveStatus($itemnumber,'waiting');
652
        }
652
        }
653
653
654
        $nextreservinfo = $checkreserves;
654
        $nextreservinfo = $checkreserves;
Lines 739-763 If several reserves exist, the reserve with the lower priority is given. Link Here
739
## multiple reserves for that bib can have the itemnumber set
739
## multiple reserves for that bib can have the itemnumber set
740
## the sub is only used once in the codebase.
740
## the sub is only used once in the codebase.
741
sub GetReserveStatus {
741
sub GetReserveStatus {
742
    my ($itemnumber) = @_;
742
    my ($item_id) = @_;
743
743
744
    my $dbh = C4::Context->dbh;
744
    my $holds_rs = Koha::Holds->search({ item_id => $item_id, completed => 0 }, { order_by => 'priority' });
745
745
746
    my ($sth, $found, $priority);
746
    if ( $holds_rs->count > 0 ) {
747
    if ( $itemnumber ) {
747
        # They are sorted by priority, pick the first one
748
        $sth = $dbh->prepare("SELECT found, priority FROM reserves WHERE itemnumber = ? order by priority LIMIT 1");
748
        my $hold = $holds_rs->next;
749
        $sth->execute($itemnumber);
750
        ($found, $priority) = $sth->fetchrow_array;
751
    }
752
749
753
    if(defined $found) {
750
        return 'Waiting'    if $hold->is_waiting and $hold->priority == 0;
754
        return 'Waiting'  if $found eq 'W' and $priority == 0;
751
        return 'Processing' if $hold->is_in_processing;
755
        return 'Processing'  if $found eq 'P';
752
        return 'Finished'   if $hold->status eq 'fulfilled';
756
        return 'Finished' if $found eq 'F';
753
        return 'Reserved'   if $hold->priority > 0;
757
    }
754
    }
758
755
759
    return 'Reserved' if defined $priority && $priority > 0;
760
761
    return ''; # empty string here will remove need for checking undef, or less log lines
756
    return ''; # empty string here will remove need for checking undef, or less log lines
762
}
757
}
763
758
Lines 796-802 sub CheckReserves { Link Here
796
    my $sth;
791
    my $sth;
797
    my $select;
792
    my $select;
798
    if (C4::Context->preference('item-level_itypes')){
793
    if (C4::Context->preference('item-level_itypes')){
799
	$select = "
794
    $select = "
800
           SELECT items.biblionumber,
795
           SELECT items.biblionumber,
801
           items.biblioitemnumber,
796
           items.biblioitemnumber,
802
           itemtypes.notforloan,
797
           itemtypes.notforloan,
Lines 811-817 sub CheckReserves { Link Here
811
        ";
806
        ";
812
    }
807
    }
813
    else {
808
    else {
814
	$select = "
809
    $select = "
815
           SELECT items.biblionumber,
810
           SELECT items.biblionumber,
816
           items.biblioitemnumber,
811
           items.biblioitemnumber,
817
           itemtypes.notforloan,
812
           itemtypes.notforloan,
Lines 864-874 sub CheckReserves { Link Here
864
859
865
        my $priority = 10000000;
860
        my $priority = 10000000;
866
        foreach my $res (@reserves) {
861
        foreach my $res (@reserves) {
867
            if ($res->{'found'} && $res->{'found'} eq 'W') {
862
            if ($res->{status} eq 'waiting') {
868
                return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
863
                return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
869
            } elsif ($res->{'found'} && $res->{'found'} eq 'P') {
864
            } elsif ($res->{status} eq 'processing') {
870
                return ( "Processing", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
865
                return ( "Processing", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
871
            } elsif ($res->{'found'} && $res->{'found'} eq 'T') {
866
            } elsif ($res->{status} eq 'in_transit') {
872
                return ( "Transferred", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
867
                return ( "Transferred", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
873
            } else {
868
            } else {
874
                my $patron;
869
                my $patron;
Lines 876-882 sub CheckReserves { Link Here
876
                my $local_hold_match;
871
                my $local_hold_match;
877
872
878
                if ($LocalHoldsPriority) {
873
                if ($LocalHoldsPriority) {
879
                    $patron = Koha::Patrons->find( $res->{borrowernumber} );
874
                    $patron = Koha::Patrons->find( $res->{patron_id} );
880
                    $item = Koha::Items->find($itemnumber);
875
                    $item = Koha::Items->find($itemnumber);
881
876
882
                    unless ($item->exclude_from_local_holds_priority || $patron->category->exclude_from_local_holds_priority) {
877
                    unless ($item->exclude_from_local_holds_priority || $patron->category->exclude_from_local_holds_priority) {
Lines 884-890 sub CheckReserves { Link Here
884
                            $item->$LocalHoldsPriorityItemControl;
879
                            $item->$LocalHoldsPriorityItemControl;
885
                        my $local_holds_priority_patron_branchcode =
880
                        my $local_holds_priority_patron_branchcode =
886
                            ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
881
                            ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
887
                            ? $res->{branchcode}
882
                            ? $res->{pickup_library_id}
888
                            : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )
883
                            : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )
889
                            ? $patron->branchcode
884
                            ? $patron->branchcode
890
                            : undef;
885
                            : undef;
Lines 895-904 sub CheckReserves { Link Here
895
                }
890
                }
896
891
897
                # See if this item is more important than what we've got so far
892
                # See if this item is more important than what we've got so far
898
                if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
893
                if ( ( $res->{priority} && $res->{priority} < $priority ) || $local_hold_match ) {
899
                    $item ||= Koha::Items->find($itemnumber);
894
                    $item ||= Koha::Items->find($itemnumber);
900
                    next if $res->{itemtype} && $res->{itemtype} ne $item->effective_itemtype;
895
                    next if $res->{item_type} && $res->{item_type} ne $item->effective_itemtype;
901
                    $patron ||= Koha::Patrons->find( $res->{borrowernumber} );
896
                    $patron ||= Koha::Patrons->find( $res->{patron_id} );
902
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
897
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
903
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
898
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
904
                    next if ($branchitemrule->{'holdallowed'} eq 'not_allowed');
899
                    next if ($branchitemrule->{'holdallowed'} eq 'not_allowed');
Lines 906-915 sub CheckReserves { Link Here
906
                    my $library = Koha::Libraries->find({branchcode=>$item->homebranch});
901
                    my $library = Koha::Libraries->find({branchcode=>$item->homebranch});
907
                    next if (($branchitemrule->{'holdallowed'} eq 'from_local_hold_group') && (!$library->validate_hold_sibling({branchcode => $patron->branchcode}) ));
902
                    next if (($branchitemrule->{'holdallowed'} eq 'from_local_hold_group') && (!$library->validate_hold_sibling({branchcode => $patron->branchcode}) ));
908
                    my $hold_fulfillment_policy = $branchitemrule->{hold_fulfillment_policy};
903
                    my $hold_fulfillment_policy = $branchitemrule->{hold_fulfillment_policy};
909
                    next if ( ($hold_fulfillment_policy eq 'holdgroup') && (!$library->validate_hold_sibling({branchcode => $res->{branchcode}})) );
904
                    next if ( ($hold_fulfillment_policy eq 'holdgroup') && (!$library->validate_hold_sibling({branchcode => $res->{pickup_library_id}})) );
910
                    next if ( ($hold_fulfillment_policy eq 'homebranch') && ($res->{branchcode} ne $item->$hold_fulfillment_policy) );
905
                    next if ( ($hold_fulfillment_policy eq 'homebranch') && ($res->{pickup_library_id} ne $item->$hold_fulfillment_policy) );
911
                    next if ( ($hold_fulfillment_policy eq 'holdingbranch') && ($res->{branchcode} ne $item->$hold_fulfillment_policy) );
906
                    next if ( ($hold_fulfillment_policy eq 'holdingbranch') && ($res->{pickup_library_id} ne $item->$hold_fulfillment_policy) );
912
                    next unless $item->can_be_transferred( { to => Koha::Libraries->find( $res->{branchcode} ) } );
907
                    next unless $item->can_be_transferred( { to => Koha::Libraries->find( $res->{pickup_library_id} ) } );
913
                    $priority = $res->{'priority'};
908
                    $priority = $res->{'priority'};
914
                    $highest  = $res;
909
                    $highest  = $res;
915
                    last if $local_hold_match;
910
                    last if $local_hold_match;
Lines 943-962 sub CancelExpiredReserves { Link Here
943
    my $expireWaiting = C4::Context->preference('ExpireReservesMaxPickUpDelay');
938
    my $expireWaiting = C4::Context->preference('ExpireReservesMaxPickUpDelay');
944
939
945
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
940
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
946
    my $params = { expirationdate => { '<', $dtf->format_date($today) } };
941
    my $params = { expiration_date => { '<', $dtf->format_date($today) } };
947
    $params->{found} = [ { '!=', 'W' }, undef ]  unless $expireWaiting;
942
    $params->{status} = [ { '!=', 'waiting' }, undef ]  unless $expireWaiting;
948
943
949
    # FIXME To move to Koha::Holds->search_expired (?)
944
    # FIXME To move to Koha::Holds->search_expired (?)
950
    my $holds = Koha::Holds->search( $params );
945
    my $holds = Koha::Holds->search( $params );
951
946
952
    while ( my $hold = $holds->next ) {
947
    while ( my $hold = $holds->next ) {
953
        my $calendar = Koha::Calendar->new( branchcode => $hold->branchcode );
948
        my $calendar = Koha::Calendar->new( branchcode => $hold->pickup_library_id );
954
949
955
        next if !$cancel_on_holidays && $calendar->is_holiday( $today );
950
        next if !$cancel_on_holidays && $calendar->is_holiday( $today );
956
951
957
        my $cancel_params = {};
952
        my $cancel_params = {};
958
        $cancel_params->{cancellation_reason} = $cancellation_reason if defined($cancellation_reason);
953
        $cancel_params->{cancellation_reason} = $cancellation_reason if defined($cancellation_reason);
959
        if ( defined($hold->found) && $hold->found eq 'W' ) {
954
        if ( $hold->is_waiting ) {
960
            $cancel_params->{charge_cancel_fee} = 1;
955
            $cancel_params->{charge_cancel_fee} = 1;
961
        }
956
        }
962
        $hold->cancel( $cancel_params );
957
        $hold->cancel( $cancel_params );
Lines 967-980 sub CancelExpiredReserves { Link Here
967
962
968
  AutoUnsuspendReserves();
963
  AutoUnsuspendReserves();
969
964
970
Unsuspends all suspended reserves with a suspend_until date from before today.
965
Unsuspends all suspended reserves with a suspended_until date from before today.
971
966
972
=cut
967
=cut
973
968
974
sub AutoUnsuspendReserves {
969
sub AutoUnsuspendReserves {
975
    my $today = dt_from_string();
970
    my $today = dt_from_string();
976
971
977
    my @holds = Koha::Holds->search( { suspend_until => { '<=' => $today->ymd() } } );
972
    my @holds = Koha::Holds->search( { suspended_until_date => { '<=' => $today->ymd() } } );
978
973
979
    map { $_->resume() } @holds;
974
    map { $_->resume() } @holds;
980
}
975
}
Lines 1034-1043 sub ModReserve { Link Here
1034
1029
1035
    my $hold;
1030
    my $hold;
1036
    unless ( $reserve_id ) {
1031
    unless ( $reserve_id ) {
1037
        my $holds = Koha::Holds->search({ biblionumber => $biblionumber, borrowernumber => $borrowernumber, itemnumber => $itemnumber });
1032
        my $holds = Koha::Holds->search({ biblio_id => $biblionumber, patron_id => $borrowernumber, item_id => $itemnumber });
1038
        return unless $holds->count; # FIXME Should raise an exception
1033
        return unless $holds->count; # FIXME Should raise an exception
1039
        $hold = $holds->next;
1034
        $hold = $holds->next;
1040
        $reserve_id = $hold->reserve_id;
1035
        $reserve_id = $hold->id;
1041
    }
1036
    }
1042
1037
1043
    $hold ||= Koha::Holds->find($reserve_id);
1038
    $hold ||= Koha::Holds->find($reserve_id);
Lines 1046-1066 sub ModReserve { Link Here
1046
        $hold->cancel({ cancellation_reason => $cancellation_reason });
1041
        $hold->cancel({ cancellation_reason => $cancellation_reason });
1047
    }
1042
    }
1048
    elsif ($rank =~ /^\d+/ and $rank > 0) {
1043
    elsif ($rank =~ /^\d+/ and $rank > 0) {
1049
        logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
1044
        logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->unblessed) )
1050
            if C4::Context->preference('HoldsLog');
1045
            if C4::Context->preference('HoldsLog');
1051
1046
1052
        my $properties = {
1047
        my $properties = {
1053
            priority    => $rank,
1048
            priority     => $rank,
1054
            branchcode  => $branchcode,
1049
            pickup_library_id => $branchcode,
1055
            itemnumber  => $itemnumber,
1050
            item_id      => $itemnumber,
1056
            found       => undef,
1051
            status       => 'placed',
1057
            waitingdate => undef
1052
            waiting_date => undef
1058
        };
1053
        };
1059
        if (exists $params->{reservedate}) {
1054
        if (exists $params->{reservedate}) {
1060
            $properties->{reservedate} = $params->{reservedate} || undef;
1055
            $properties->{created_date} = $params->{reservedate} || undef;
1061
        }
1056
        }
1062
        if (exists $params->{expirationdate}) {
1057
        if (exists $params->{expirationdate}) {
1063
            $properties->{expirationdate} = $params->{expirationdate} || undef;
1058
            $properties->{expiration_date} = $params->{expirationdate} || undef;
1064
        }
1059
        }
1065
1060
1066
        $hold->set($properties)->store();
1061
        $hold->set($properties)->store();
Lines 1072-1078 sub ModReserve { Link Here
1072
            } else {
1067
            } else {
1073
                # If the hold is suspended leave the hold suspended, but convert it to an indefinite hold.
1068
                # If the hold is suspended leave the hold suspended, but convert it to an indefinite hold.
1074
                # If the hold is not suspended, this does nothing.
1069
                # If the hold is not suspended, this does nothing.
1075
                $hold->set( { suspend_until => undef } )->store();
1070
                $hold->set( { suspended_until_date => undef } )->store();
1076
            }
1071
            }
1077
        }
1072
        }
1078
1073
Lines 1094-1130 whose keys are fields from the reserves table in the Koha database. Link Here
1094
1089
1095
sub ModReserveFill {
1090
sub ModReserveFill {
1096
    my ($res) = @_;
1091
    my ($res) = @_;
1097
    my $reserve_id = $res->{'reserve_id'};
1092
    my $reserve_id = $res->{'id'};
1098
1093
1099
    my $hold = Koha::Holds->find($reserve_id);
1094
    my $hold = Koha::Holds->find($reserve_id);
1100
    # get the priority on this record....
1095
    # get the priority on this record....
1101
    my $priority = $hold->priority;
1096
    my $priority = $hold->priority;
1102
1097
1103
    # update the hold statuses, no need to store it though, we will be deleting it anyway
1098
    # update the hold statuses, no need to store it though, we will be deleting it anyway
1099
    # FIXME: Add Koha::Hold->set_filled and add the correct log
1104
    $hold->set(
1100
    $hold->set(
1105
        {
1101
        {
1106
            found    => 'F',
1102
            status    => 'fulfilled',
1107
            priority => 0,
1103
            priority  => 0,
1104
            completed => 1,
1105
            completed_date => \'NOW()'
1108
        }
1106
        }
1109
    );
1107
    );
1110
1108
1111
    logaction( 'HOLDS', 'MODIFY', $hold->reserve_id, Dumper($hold->unblessed) )
1109
    logaction( 'HOLDS', 'MODIFY', $hold->id, Dumper($hold->unblessed) )
1112
        if C4::Context->preference('HoldsLog');
1110
        if C4::Context->preference('HoldsLog');
1113
1111
1114
    # FIXME Must call Koha::Hold->cancel ? => No, should call ->filled and add the correct log
1112
    $hold->store();
1115
    Koha::Old::Hold->new( $hold->unblessed() )->store();
1116
1117
    $hold->delete();
1118
1113
1119
    if ( C4::Context->preference('HoldFeeMode') eq 'any_time_is_collected' ) {
1114
    if ( C4::Context->preference('HoldFeeMode') eq 'any_time_is_collected' ) {
1120
        my $reserve_fee = GetReserveFee( $hold->borrowernumber, $hold->biblionumber );
1115
        my $reserve_fee = GetReserveFee( $hold->patron_id, $hold->biblio_id );
1121
        ChargeReserveFee( $hold->borrowernumber, $reserve_fee, $hold->biblio->title );
1116
        ChargeReserveFee( $hold->patron_id, $reserve_fee, $hold->biblio->title );
1122
    }
1117
    }
1123
1118
1124
    # now fix the priority on the others (if the priority wasn't
1119
    # now fix the priority on the others (if the priority wasn't
1125
    # already sorted!)....
1120
    # already sorted!)....
1126
    unless ( $priority == 0 ) {
1121
    unless ( $priority == 0 ) {
1127
        _FixPriority( { reserve_id => $reserve_id, biblionumber => $hold->biblionumber } );
1122
        _FixPriority( { reserve_id => $reserve_id, biblionumber => $hold->biblio_id } );
1128
    }
1123
    }
1129
}
1124
}
1130
1125
Lines 1146-1152 sub ModReserveStatus { Link Here
1146
    my ($itemnumber, $newstatus) = @_;
1141
    my ($itemnumber, $newstatus) = @_;
1147
    my $dbh = C4::Context->dbh;
1142
    my $dbh = C4::Context->dbh;
1148
1143
1149
    my $query = "UPDATE reserves SET found = ?, waitingdate = NOW() WHERE itemnumber = ? AND found IS NULL AND priority = 0";
1144
    my $query = "UPDATE holds SET status = ?, waiting_date = NOW() WHERE item_id = ? AND status='placed' AND priority = 0";
1150
    my $sth_set = $dbh->prepare($query);
1145
    my $sth_set = $dbh->prepare($query);
1151
    $sth_set->execute( $newstatus, $itemnumber );
1146
    $sth_set->execute( $newstatus, $itemnumber );
1152
1147
Lines 1192-1206 sub ModReserveAffect { Link Here
1192
    # Find hold by id if we have it
1187
    # Find hold by id if we have it
1193
    $hold = Koha::Holds->find( $reserve_id ) if $reserve_id;
1188
    $hold = Koha::Holds->find( $reserve_id ) if $reserve_id;
1194
    # Find item level hold for this item if there is one
1189
    # Find item level hold for this item if there is one
1195
    $hold ||= Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->next();
1190
    $hold ||= Koha::Holds->search( { patron_id => $borrowernumber, item_id => $itemnumber } )->next();
1196
    # Find record level hold if there is no item level hold
1191
    # Find record level hold if there is no item level hold
1197
    $hold ||= Koha::Holds->search( { borrowernumber => $borrowernumber, biblionumber => $biblionumber } )->next();
1192
    $hold ||= Koha::Holds->search( { patron_id => $borrowernumber, biblio_id => $biblionumber } )->next();
1198
1193
1199
    return unless $hold;
1194
    return unless $hold;
1200
1195
1201
    my $already_on_shelf = $hold->found && $hold->found eq 'W';
1196
    my $already_on_shelf = $hold->status eq 'waiting';
1202
1197
1203
    $hold->itemnumber($itemnumber);
1198
    $hold->item_id($itemnumber);
1204
1199
1205
    if ($transferToDo) {
1200
    if ($transferToDo) {
1206
        $hold->set_transfer();
1201
        $hold->set_transfer();
Lines 1253-1267 function to cancel reserv,check other reserves, and transfer document if it's ne Link Here
1253
sub ModReserveCancelAll {
1248
sub ModReserveCancelAll {
1254
    my $messages;
1249
    my $messages;
1255
    my $nextreservinfo;
1250
    my $nextreservinfo;
1256
    my ( $itemnumber, $borrowernumber, $cancellation_reason ) = @_;
1251
    my ( $item_id, $patron_id, $cancellation_reason ) = @_;
1257
1252
1258
    #step 1 : cancel the reservation
1253
    #step 1 : cancel the reservation
1259
    my $holds = Koha::Holds->search({ itemnumber => $itemnumber, borrowernumber => $borrowernumber });
1254
    my $holds = Koha::Holds->search({ item_id => $item_id, patron_id => $patron_id });
1260
    return unless $holds->count;
1255
    return unless $holds->count;
1261
    $holds->next->cancel({ cancellation_reason => $cancellation_reason });
1256
    $holds->next->cancel({ cancellation_reason => $cancellation_reason });
1262
1257
1263
    #step 2 launch the subroutine of the others reserves
1258
    #step 2 launch the subroutine of the others reserves
1264
    ( $messages, $nextreservinfo ) = GetOtherReserves($itemnumber);
1259
    ( $messages, $nextreservinfo ) = GetOtherReserves($item_id);
1265
1260
1266
    return ( $messages, $nextreservinfo->{borrowernumber} );
1261
    return ( $messages, $nextreservinfo->{borrowernumber} );
1267
}
1262
}
Lines 1275-1291 Reduce the values of queued list Link Here
1275
=cut
1270
=cut
1276
1271
1277
sub ModReserveMinusPriority {
1272
sub ModReserveMinusPriority {
1278
    my ( $itemnumber, $reserve_id ) = @_;
1273
    my ( $item_id, $reserve_id ) = @_;
1279
1274
1280
    #first step update the value of the first person on reserv
1275
    #first step update the value of the first person on reserv
1281
    my $dbh   = C4::Context->dbh;
1276
    my $dbh   = C4::Context->dbh;
1282
    my $query = "
1277
    my $query = "
1283
        UPDATE reserves
1278
        UPDATE holds
1284
        SET    priority = 0 , itemnumber = ?
1279
        SET    priority = 0 , item_id = ?
1285
        WHERE  reserve_id = ?
1280
        WHERE  id = ?
1286
    ";
1281
    ";
1287
    my $sth_upd = $dbh->prepare($query);
1282
    my $sth_upd = $dbh->prepare($query);
1288
    $sth_upd->execute( $itemnumber, $reserve_id );
1283
    $sth_upd->execute( $item_id, $reserve_id );
1289
    # second step update all others reserves
1284
    # second step update all others reserves
1290
    _FixPriority({ reserve_id => $reserve_id, rank => '0' });
1285
    _FixPriority({ reserve_id => $reserve_id, rank => '0' });
1291
}
1286
}
Lines 1429-1436 sub AlterPriority { Link Here
1429
    my $hold = Koha::Holds->find( $reserve_id );
1424
    my $hold = Koha::Holds->find( $reserve_id );
1430
    return unless $hold;
1425
    return unless $hold;
1431
1426
1432
    if ( $hold->cancellationdate ) {
1427
    if ( $hold->completed_date and $hold->status eq 'cancelled' ) {
1433
        warn "I cannot alter the priority for reserve_id $reserve_id, the reserve has been cancelled (" . $hold->cancellationdate . ')';
1428
        warn "I cannot alter the priority for reserve_id $reserve_id, the reserve has been cancelled (" . $hold->completed_date . ')';
1434
        return;
1429
        return;
1435
    }
1430
    }
1436
1431
Lines 1462-1468 sub ToggleLowestPriority { Link Here
1462
1457
1463
    my $dbh = C4::Context->dbh;
1458
    my $dbh = C4::Context->dbh;
1464
1459
1465
    my $sth = $dbh->prepare( "UPDATE reserves SET lowestPriority = NOT lowestPriority WHERE reserve_id = ?");
1460
    my $sth = $dbh->prepare( "UPDATE holds SET lowest_priority = NOT lowest_priority WHERE id = ?");
1466
    $sth->execute( $reserve_id );
1461
    $sth->execute( $reserve_id );
1467
1462
1468
    _FixPriority({ reserve_id => $reserve_id, rank => '999999' });
1463
    _FixPriority({ reserve_id => $reserve_id, rank => '999999' });
Lines 1522-1530 sub SuspendAll { Link Here
1522
    return unless ( $borrowernumber || $biblionumber );
1517
    return unless ( $borrowernumber || $biblionumber );
1523
1518
1524
    my $params;
1519
    my $params;
1525
    $params->{found}          = undef;
1520
    $params->{status} = 'placed';
1526
    $params->{borrowernumber} = $borrowernumber if $borrowernumber;
1521
    $params->{patron_id} = $borrowernumber if $borrowernumber;
1527
    $params->{biblionumber}   = $biblionumber if $biblionumber;
1522
    $params->{biblio_id} = $biblionumber if $biblionumber;
1528
1523
1529
    my @holds = Koha::Holds->search($params);
1524
    my @holds = Koha::Holds->search($params);
1530
1525
Lines 1584-1598 sub _FixPriority { Link Here
1584
    my $hold;
1579
    my $hold;
1585
    if ( $reserve_id ) {
1580
    if ( $reserve_id ) {
1586
        $hold = Koha::Holds->find( $reserve_id );
1581
        $hold = Koha::Holds->find( $reserve_id );
1587
        if (!defined $hold){
1588
            # may have already been checked out and hold fulfilled
1589
            $hold = Koha::Old::Holds->find( $reserve_id );
1590
        }
1591
        return unless $hold;
1582
        return unless $hold;
1592
    }
1583
    }
1593
1584
1594
    unless ( $biblionumber ) { # FIXME This is a very weird API
1585
    unless ( $biblionumber ) { # FIXME This is a very weird API
1595
        $biblionumber = $hold->biblionumber;
1586
        $biblionumber = $hold->biblio_id;
1596
    }
1587
    }
1597
1588
1598
    if ( $rank eq "del" ) { # FIXME will crash if called without $hold
1589
    if ( $rank eq "del" ) { # FIXME will crash if called without $hold
Lines 1602-1611 sub _FixPriority { Link Here
1602
1593
1603
        # make sure priority for waiting or in-transit items is 0
1594
        # make sure priority for waiting or in-transit items is 0
1604
        my $query = "
1595
        my $query = "
1605
            UPDATE reserves
1596
            UPDATE holds
1606
            SET    priority = 0
1597
            SET    priority = 0
1607
            WHERE reserve_id = ?
1598
            WHERE  id = ?
1608
            AND found IN ('W', 'T', 'P')
1599
            AND status IN ('waiting', 'in_transit', 'processing')
1609
        ";
1600
        ";
1610
        my $sth = $dbh->prepare($query);
1601
        my $sth = $dbh->prepare($query);
1611
        $sth->execute( $reserve_id );
1602
        $sth->execute( $reserve_id );
Lines 1614-1623 sub _FixPriority { Link Here
1614
1605
1615
    # get whats left
1606
    # get whats left
1616
    my $query = "
1607
    my $query = "
1617
        SELECT reserve_id, borrowernumber, reservedate
1608
        SELECT id
1618
        FROM   reserves
1609
        FROM   holds
1619
        WHERE  biblionumber   = ?
1610
        WHERE  biblio_id   = ?
1620
          AND  ((found <> 'W' AND found <> 'T' AND found <> 'P') OR found IS NULL)
1611
          AND  completed = 0
1612
          AND  status = 'placed'
1621
        ORDER BY priority ASC
1613
        ORDER BY priority ASC
1622
    ";
1614
    ";
1623
    my $sth = $dbh->prepare($query);
1615
    my $sth = $dbh->prepare($query);
Lines 1631-1637 sub _FixPriority { Link Here
1631
    my $i;
1623
    my $i;
1632
    my $key = -1;    # to allow for 0 to be a valid result
1624
    my $key = -1;    # to allow for 0 to be a valid result
1633
    for ( $i = 0 ; $i < @priority ; $i++ ) {
1625
    for ( $i = 0 ; $i < @priority ; $i++ ) {
1634
        if ( $reserve_id && $reserve_id == $priority[$i]->{'reserve_id'} ) {
1626
        if ( $reserve_id && $reserve_id == $priority[$i]->{'id'} ) {
1635
            $key = $i;    # save the index
1627
            $key = $i;    # save the index
1636
            last;
1628
            last;
1637
        }
1629
        }
Lines 1647-1671 sub _FixPriority { Link Here
1647
1639
1648
    # now fix the priority on those that are left....
1640
    # now fix the priority on those that are left....
1649
    $query = "
1641
    $query = "
1650
        UPDATE reserves
1642
        UPDATE holds
1651
        SET    priority = ?
1643
        SET    priority = ?
1652
        WHERE  reserve_id = ?
1644
        WHERE  id = ?
1653
    ";
1645
    ";
1654
    $sth = $dbh->prepare($query);
1646
    $sth = $dbh->prepare($query);
1655
    for ( my $j = 0 ; $j < @priority ; $j++ ) {
1647
    for ( my $j = 0 ; $j < @priority ; $j++ ) {
1656
        $sth->execute(
1648
        $sth->execute(
1657
            $j + 1,
1649
            $j + 1,
1658
            $priority[$j]->{'reserve_id'}
1650
            $priority[$j]->{'id'}
1659
        );
1651
        );
1660
    }
1652
    }
1661
1653
1662
    $sth = $dbh->prepare( "SELECT reserve_id FROM reserves WHERE lowestPriority = 1 ORDER BY priority" );
1654
    $sth = $dbh->prepare( "SELECT id FROM holds WHERE lowest_priority = 1 ORDER BY priority" );
1663
    $sth->execute();
1655
    $sth->execute();
1664
1656
1665
    unless ( $ignoreSetLowestRank ) {
1657
    unless ( $ignoreSetLowestRank ) {
1666
      while ( my $res = $sth->fetchrow_hashref() ) {
1658
      while ( my $res = $sth->fetchrow_hashref() ) {
1667
        _FixPriority({
1659
        _FixPriority({
1668
            reserve_id => $res->{'reserve_id'},
1660
            reserve_id => $res->{'id'},
1669
            rank => '999999',
1661
            rank => '999999',
1670
            ignoreSetLowestRank => 1
1662
            ignoreSetLowestRank => 1
1671
        });
1663
        });
Lines 1702-1730 sub _Findgroupreserve { Link Here
1702
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1694
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1703
    # check for exact targeted match
1695
    # check for exact targeted match
1704
    my $item_level_target_query = qq{
1696
    my $item_level_target_query = qq{
1705
        SELECT reserves.biblionumber        AS biblionumber,
1697
        SELECT holds.biblio_id         AS biblio_id,
1706
               reserves.borrowernumber      AS borrowernumber,
1698
               holds.patron_id         AS patron_id,
1707
               reserves.reservedate         AS reservedate,
1699
               holds.created_date      AS created_date,
1708
               reserves.branchcode          AS branchcode,
1700
               holds.pickup_library_id AS pickup_library_id,
1709
               reserves.cancellationdate    AS cancellationdate,
1701
               holds.completed_date   AS completed_date,
1710
               reserves.found               AS found,
1702
               holds.status            AS status,
1711
               reserves.reservenotes        AS reservenotes,
1703
               holds.notes             AS notes,
1712
               reserves.priority            AS priority,
1704
               holds.priority          AS priority,
1713
               reserves.timestamp           AS timestamp,
1705
               holds.timestamp         AS timestamp,
1714
               biblioitems.biblioitemnumber AS biblioitemnumber,
1706
               biblioitems.biblioitemnumber AS biblioitemnumber,
1715
               reserves.itemnumber          AS itemnumber,
1707
               holds.item_id           AS item_id,
1716
               reserves.reserve_id          AS reserve_id,
1708
               holds.id                AS id,
1717
               reserves.itemtype            AS itemtype,
1709
               holds.item_type         AS item_type,
1718
               reserves.non_priority        AS non_priority
1710
               holds.non_priority      AS non_priority
1719
        FROM reserves
1711
        FROM holds
1720
        JOIN biblioitems USING (biblionumber)
1712
        JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
1721
        JOIN hold_fill_targets USING (reserve_id)
1713
        JOIN hold_fill_targets ON (
1722
        WHERE found IS NULL
1714
                holds.biblio_id=hold_fill_targets.biblionumber
1715
            AND holds.patron_id=hold_fill_targets.borrowernumber
1716
            AND holds.item_id=hold_fill_targets.itemnumber)
1717
        WHERE status='placed'
1723
        AND priority > 0
1718
        AND priority > 0
1724
        AND item_level_request = 1
1719
        AND completed = 0
1725
        AND hold_fill_targets.itemnumber = ?
1720
        AND item_level = 1
1726
        AND reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1721
        AND item_id = ?
1727
        AND suspend = 0
1722
        AND created_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1723
        AND suspended = 0
1728
        ORDER BY priority
1724
        ORDER BY priority
1729
    };
1725
    };
1730
    my $sth = $dbh->prepare($item_level_target_query);
1726
    my $sth = $dbh->prepare($item_level_target_query);
Lines 1732-1766 sub _Findgroupreserve { Link Here
1732
    my @results;
1728
    my @results;
1733
    if ( my $data = $sth->fetchrow_hashref ) {
1729
    if ( my $data = $sth->fetchrow_hashref ) {
1734
        push( @results, $data )
1730
        push( @results, $data )
1735
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1731
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1736
    }
1732
    }
1737
    return @results if @results;
1733
    return @results if @results;
1738
1734
1739
    # check for title-level targeted match
1735
    # check for title-level targeted match
1740
    my $title_level_target_query = qq{
1736
    my $title_level_target_query = qq{
1741
        SELECT reserves.biblionumber        AS biblionumber,
1737
        SELECT holds.biblio_id         AS biblio_id,
1742
               reserves.borrowernumber      AS borrowernumber,
1738
               holds.patron_id         AS patron_id,
1743
               reserves.reservedate         AS reservedate,
1739
               holds.created_date      AS created_date,
1744
               reserves.branchcode          AS branchcode,
1740
               holds.pickup_library_id AS pickup_library_id,
1745
               reserves.cancellationdate    AS cancellationdate,
1741
               holds.completed_date   AS completed_date,
1746
               reserves.found               AS found,
1742
               holds.status            AS status,
1747
               reserves.reservenotes        AS reservenotes,
1743
               holds.notes             AS notes,
1748
               reserves.priority            AS priority,
1744
               holds.priority          AS priority,
1749
               reserves.timestamp           AS timestamp,
1745
               holds.timestamp         AS timestamp,
1750
               biblioitems.biblioitemnumber AS biblioitemnumber,
1746
               biblioitems.biblioitemnumber AS biblioitemnumber,
1751
               reserves.itemnumber          AS itemnumber,
1747
               holds.item_id           AS item_id,
1752
               reserves.reserve_id          AS reserve_id,
1748
               holds.id                AS id,
1753
               reserves.itemtype            AS itemtype,
1749
               holds.item_type         AS item_type,
1754
               reserves.non_priority        AS non_priority
1750
               holds.non_priority      AS non_priority
1755
        FROM reserves
1751
        FROM holds
1756
        JOIN biblioitems USING (biblionumber)
1752
        JOIN biblioitems ON (holds.biblio_id=biblioitems.biblionumber)
1757
        JOIN hold_fill_targets USING (reserve_id)
1753
        JOIN hold_fill_targets ON (
1758
        WHERE found IS NULL
1754
                holds.biblio_id=hold_fill_targets.biblionumber
1755
            AND holds.patron_id=hold_fill_targets.borrowernumber)
1756
        WHERE status='placed'
1759
        AND priority > 0
1757
        AND priority > 0
1760
        AND item_level_request = 0
1758
        AND completed = 0
1759
        AND item_level = 0
1761
        AND hold_fill_targets.itemnumber = ?
1760
        AND hold_fill_targets.itemnumber = ?
1762
        AND reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1761
        AND created_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1763
        AND suspend = 0
1762
        AND suspended = 0
1764
        ORDER BY priority
1763
        ORDER BY priority
1765
    };
1764
    };
1766
    $sth = $dbh->prepare($title_level_target_query);
1765
    $sth = $dbh->prepare($title_level_target_query);
Lines 1768-1797 sub _Findgroupreserve { Link Here
1768
    @results = ();
1767
    @results = ();
1769
    if ( my $data = $sth->fetchrow_hashref ) {
1768
    if ( my $data = $sth->fetchrow_hashref ) {
1770
        push( @results, $data )
1769
        push( @results, $data )
1771
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1770
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1772
    }
1771
    }
1773
    return @results if @results;
1772
    return @results if @results;
1774
1773
1775
    my $query = qq{
1774
    my $query = qq{
1776
        SELECT reserves.biblionumber               AS biblionumber,
1775
        SELECT holds.biblio_id                  AS biblio_id,
1777
               reserves.borrowernumber             AS borrowernumber,
1776
               holds.patron_id                  AS patron_id,
1778
               reserves.reservedate                AS reservedate,
1777
               holds.created_date               AS created_date,
1779
               reserves.waitingdate                AS waitingdate,
1778
               holds.waiting_date               AS waiting_date,
1780
               reserves.branchcode                 AS branchcode,
1779
               holds.pickup_library_id          AS pickup_library_id,
1781
               reserves.cancellationdate           AS cancellationdate,
1780
               holds.completed_date             AS completed_date,
1782
               reserves.found                      AS found,
1781
               holds.status                     AS status,
1783
               reserves.reservenotes               AS reservenotes,
1782
               holds.notes                      AS notes,
1784
               reserves.priority                   AS priority,
1783
               holds.priority                   AS priority,
1785
               reserves.timestamp                  AS timestamp,
1784
               holds.timestamp                  AS timestamp,
1786
               reserves.itemnumber                 AS itemnumber,
1785
               holds.item_id                    AS item_id,
1787
               reserves.reserve_id                 AS reserve_id,
1786
               holds.id                         AS id,
1788
               reserves.itemtype                   AS itemtype,
1787
               holds.item_type                  AS item_type,
1789
               reserves.non_priority        AS non_priority
1788
               holds.non_priority               AS non_priority
1790
        FROM reserves
1789
        FROM holds
1791
        WHERE reserves.biblionumber = ?
1790
        WHERE holds.biblio_id = ?
1792
          AND (reserves.itemnumber IS NULL OR reserves.itemnumber = ?)
1791
          AND (holds.item_id IS NULL OR holds.item_id = ?)
1793
          AND reserves.reservedate <= DATE_ADD(NOW(),INTERVAL ? DAY)
1792
          AND holds.created_date <= DATE_ADD(NOW(),INTERVAL ? DAY)
1794
          AND suspend = 0
1793
          AND suspended = 0
1794
          AND completed = 0
1795
          ORDER BY priority
1795
          ORDER BY priority
1796
    };
1796
    };
1797
    $sth = $dbh->prepare($query);
1797
    $sth = $dbh->prepare($query);
Lines 1799-1805 sub _Findgroupreserve { Link Here
1799
    @results = ();
1799
    @results = ();
1800
    while ( my $data = $sth->fetchrow_hashref ) {
1800
    while ( my $data = $sth->fetchrow_hashref ) {
1801
        push( @results, $data )
1801
        push( @results, $data )
1802
          unless any{ $data->{borrowernumber} eq $_ } @$ignore_borrowers ;
1802
          unless any{ $data->{patron_id} eq $_ } @$ignore_borrowers ;
1803
    }
1803
    }
1804
    return @results;
1804
    return @results;
1805
}
1805
}
Lines 1835-1841 The following tables are availalbe witin the notice: Link Here
1835
sub _koha_notify_reserve {
1835
sub _koha_notify_reserve {
1836
    my $reserve_id = shift;
1836
    my $reserve_id = shift;
1837
    my $hold = Koha::Holds->find($reserve_id);
1837
    my $hold = Koha::Holds->find($reserve_id);
1838
    my $borrowernumber = $hold->borrowernumber;
1838
    my $borrowernumber = $hold->patron_id;
1839
1839
1840
    my $patron = Koha::Patrons->find( $borrowernumber );
1840
    my $patron = Koha::Patrons->find( $borrowernumber );
1841
1841
Lines 1847-1867 sub _koha_notify_reserve { Link Here
1847
            message_name => 'Hold_Filled'
1847
            message_name => 'Hold_Filled'
1848
    } );
1848
    } );
1849
1849
1850
    my $library = Koha::Libraries->find( $hold->branchcode );
1850
    my $library = Koha::Libraries->find( $hold->pickup_library_id );
1851
    my $admin_email_address = $library->from_email_address;
1851
    my $admin_email_address = $library->from_email_address;
1852
    $library = $library->unblessed;
1852
    $library = $library->unblessed;
1853
1853
1854
    my %letter_params = (
1854
    my %letter_params = (
1855
        module => 'reserves',
1855
        module => 'reserves',
1856
        branchcode => $hold->branchcode,
1856
        branchcode => $hold->pickup_library_id,
1857
        lang => $patron->lang,
1857
        lang => $patron->lang,
1858
        tables => {
1858
        tables => {
1859
            'branches'       => $library,
1859
            'branches'       => $library,
1860
            'borrowers'      => $patron->unblessed,
1860
            'borrowers'      => $patron->unblessed,
1861
            'biblio'         => $hold->biblionumber,
1861
            'biblio'         => $hold->biblio_id,
1862
            'biblioitems'    => $hold->biblionumber,
1862
            'biblioitems'    => $hold->biblio_id,
1863
            'reserves'       => $hold->unblessed,
1863
            'reserves'       => $hold->unblessed,
1864
            'items'          => $hold->itemnumber,
1864
            'items'          => $hold->item_id,
1865
        },
1865
        },
1866
    );
1866
    );
1867
1867
Lines 1925-1931 sub _ShiftPriorityByDateAndPriority { Link Here
1925
    my ( $biblio, $resdate, $new_priority ) = @_;
1925
    my ( $biblio, $resdate, $new_priority ) = @_;
1926
1926
1927
    my $dbh = C4::Context->dbh;
1927
    my $dbh = C4::Context->dbh;
1928
    my $query = "SELECT priority FROM reserves WHERE biblionumber = ? AND ( reservedate > ? OR priority > ? ) ORDER BY priority ASC LIMIT 1";
1928
    my $query = "SELECT priority FROM holds WHERE biblio_id = ? AND ( created_date > ? OR priority > ? ) AND completed = 0 ORDER BY priority ASC LIMIT 1";
1929
    my $sth = $dbh->prepare( $query );
1929
    my $sth = $dbh->prepare( $query );
1930
    $sth->execute( $biblio, $resdate, $new_priority );
1930
    $sth->execute( $biblio, $resdate, $new_priority );
1931
    my $min_priority = $sth->fetchrow;
1931
    my $min_priority = $sth->fetchrow;
Lines 1933-1952 sub _ShiftPriorityByDateAndPriority { Link Here
1933
    $new_priority = $min_priority if ( $min_priority );
1933
    $new_priority = $min_priority if ( $min_priority );
1934
1934
1935
    # Shift the priority up by one; works in conjunction with the next SQL statement
1935
    # Shift the priority up by one; works in conjunction with the next SQL statement
1936
    $query = "UPDATE reserves
1936
    $query = "UPDATE holds
1937
              SET priority = priority+1
1937
              SET priority = priority+1
1938
              WHERE biblionumber = ?
1938
              WHERE biblio_id = ?
1939
              AND borrowernumber = ?
1939
              AND patron_id = ?
1940
              AND reservedate = ?
1940
              AND created_date = ?
1941
              AND found IS NULL";
1941
              AND status = 'placed'";
1942
    my $sth_update = $dbh->prepare( $query );
1942
    my $sth_update = $dbh->prepare( $query );
1943
1943
1944
    # Select all reserves for the biblio with priority greater than $new_priority, and order greatest to least
1944
    # Select all reserves for the biblio with priority greater than $new_priority, and order greatest to least
1945
    $query = "SELECT borrowernumber, reservedate FROM reserves WHERE priority >= ? AND biblionumber = ? ORDER BY priority DESC";
1945
    $query = "SELECT patron_id, created_date FROM holds WHERE priority >= ? AND biblio_id = ? ORDER BY priority DESC";
1946
    $sth = $dbh->prepare( $query );
1946
    $sth = $dbh->prepare( $query );
1947
    $sth->execute( $new_priority, $biblio );
1947
    $sth->execute( $new_priority, $biblio );
1948
    while ( my $row = $sth->fetchrow_hashref ) {
1948
    while ( my $row = $sth->fetchrow_hashref ) {
1949
	$sth_update->execute( $biblio, $row->{borrowernumber}, $row->{reservedate} );
1949
    $sth_update->execute( $biblio, $row->{patron_id}, $row->{created_date} );
1950
    }
1950
    }
1951
1951
1952
    return $new_priority;  # so the caller knows what priority they wind up receiving
1952
    return $new_priority;  # so the caller knows what priority they wind up receiving
Lines 1970-1978 sub MoveReserve { Link Here
1970
    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
1970
    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
1971
    return unless $res;
1971
    return unless $res;
1972
1972
1973
    my $biblionumber     =  $res->{biblionumber};
1973
    my $biblionumber = $res->{biblio_id};
1974
1974
1975
    if ($res->{borrowernumber} == $borrowernumber) {
1975
    if ($res->{patron_id} == $borrowernumber) {
1976
        ModReserveFill($res);
1976
        ModReserveFill($res);
1977
    }
1977
    }
1978
    else {
1978
    else {
Lines 1981-1988 sub MoveReserve { Link Here
1981
        # Find this item in the reserves
1981
        # Find this item in the reserves
1982
1982
1983
        my $borr_res  = Koha::Holds->search({
1983
        my $borr_res  = Koha::Holds->search({
1984
            borrowernumber => $borrowernumber,
1984
            patron_id => $borrowernumber,
1985
            biblionumber   => $biblionumber,
1985
            biblio_id => $biblionumber,
1986
        },{
1986
        },{
1987
            order_by       => 'priority'
1987
            order_by       => 'priority'
1988
        })->next();
1988
        })->next();
Lines 1996-2002 sub MoveReserve { Link Here
1996
            RevertWaitingStatus({ itemnumber => $itemnumber });
1996
            RevertWaitingStatus({ itemnumber => $itemnumber });
1997
        }
1997
        }
1998
        elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item
1998
        elsif ( $cancelreserve eq 'cancel' || $cancelreserve ) { # cancel reserves on this item
1999
            my $hold = Koha::Holds->find( $res->{reserve_id} );
1999
            my $hold = Koha::Holds->find( $res->{id} );
2000
            $hold->cancel;
2000
            $hold->cancel;
2001
        }
2001
        }
2002
    }
2002
    }
Lines 2013-2045 This shifts the holds from C<$from_biblio> to C<$to_biblio> and reorders them by Link Here
2013
sub MergeHolds {
2013
sub MergeHolds {
2014
    my ( $dbh, $to_biblio, $from_biblio ) = @_;
2014
    my ( $dbh, $to_biblio, $from_biblio ) = @_;
2015
    my $sth = $dbh->prepare(
2015
    my $sth = $dbh->prepare(
2016
        "SELECT count(*) as reserve_count FROM reserves WHERE biblionumber = ?"
2016
        "SELECT count(*) as reserve_count FROM holds WHERE biblio_id = ? AND completed = 0"
2017
    );
2017
    );
2018
    $sth->execute($from_biblio);
2018
    $sth->execute($from_biblio);
2019
    if ( my $data = $sth->fetchrow_hashref() ) {
2019
    if ( my $data = $sth->fetchrow_hashref() ) {
2020
2020
2021
        # holds exist on old record, if not we don't need to do anything
2021
        # holds exist on old record, if not we don't need to do anything
2022
        $sth = $dbh->prepare(
2022
        $sth = $dbh->prepare(
2023
            "UPDATE reserves SET biblionumber = ? WHERE biblionumber = ?");
2023
            "UPDATE holds SET biblio_id = ? WHERE biblio_id = ?");
2024
        $sth->execute( $to_biblio, $from_biblio );
2024
        $sth->execute( $to_biblio, $from_biblio );
2025
2025
2026
        # Reorder by date
2026
        # Reorder by date
2027
        # don't reorder those already waiting
2027
        # don't reorder those already waiting
2028
2028
2029
        $sth = $dbh->prepare(
2029
        $sth = $dbh->prepare(
2030
"SELECT * FROM reserves WHERE biblionumber = ? AND (found NOT IN ('W', 'T', 'P') OR found is NULL) ORDER BY reservedate ASC"
2030
            "SELECT id FROM holds WHERE biblio_id = ? AND status = 'placed' AND completed = 0 ORDER BY created_date ASC"
2031
        );
2031
        );
2032
        my $upd_sth = $dbh->prepare(
2032
        my $upd_sth = $dbh->prepare(
2033
"UPDATE reserves SET priority = ? WHERE biblionumber = ? AND borrowernumber = ?
2033
            "UPDATE holds SET priority = ? WHERE id = ? "
2034
        AND reservedate = ? AND (itemnumber = ? or itemnumber is NULL) "
2035
        );
2034
        );
2036
        $sth->execute( $to_biblio );
2035
        $sth->execute( $to_biblio );
2037
        my $priority = 1;
2036
        my $priority = 1;
2038
        while ( my $reserve = $sth->fetchrow_hashref() ) {
2037
        while ( my $reserve = $sth->fetchrow_hashref() ) {
2039
            $upd_sth->execute(
2038
            $upd_sth->execute(
2040
                $priority,                    $to_biblio,
2039
                $priority,
2041
                $reserve->{'borrowernumber'}, $reserve->{'reservedate'},
2040
                $reserve->{'id'}
2042
                $reserve->{'itemnumber'}
2043
            );
2041
            );
2044
            $priority++;
2042
            $priority++;
2045
        }
2043
        }
Lines 2062-2097 sub MergeHolds { Link Here
2062
2060
2063
sub RevertWaitingStatus {
2061
sub RevertWaitingStatus {
2064
    my ( $params ) = @_;
2062
    my ( $params ) = @_;
2065
    my $itemnumber = $params->{'itemnumber'};
2063
    my $item_id = $params->{'itemnumber'};
2066
2064
2067
    return unless ( $itemnumber );
2065
    return unless ( $item_id );
2068
2069
    my $dbh = C4::Context->dbh;
2070
2066
2071
    ## Get the waiting reserve we want to revert
2067
    ## Get the waiting reserve we want to revert
2072
    my $hold = Koha::Holds->search(
2068
    my $hold = Koha::Holds->search(
2073
        {
2069
        {
2074
            itemnumber => $itemnumber,
2070
            item_id => $item_id,
2075
            found => { not => undef },
2071
            status => 'waiting',
2076
        }
2072
        }
2077
    )->next;
2073
    )->next;
2078
2074
2079
    ## Increment the priority of all other non-waiting
2075
    ## Increment the priority of all other non-waiting
2080
    ## reserves for this bib record
2076
    ## reserves for this bib record
2081
    my $holds = Koha::Holds->search({ biblionumber => $hold->biblionumber, priority => { '>' => 0 } })
2077
    my $holds = Koha::Holds->search({ biblio_id => $hold->biblio_id, priority => { '>' => 0 } })
2082
                           ->update({ priority => \'priority + 1' }, { no_triggers => 1 });
2078
                           ->update({ priority => \'priority + 1' }, { no_triggers => 1 });
2083
2079
2084
    ## Fix up the currently waiting reserve
2080
    ## Fix up the currently waiting reserve
2085
    $hold->set(
2081
    $hold->set(
2086
        {
2082
        {
2087
            priority    => 1,
2083
            priority     => 1,
2088
            found       => undef,
2084
            status       => 'placed',
2089
            waitingdate => undef,
2085
            waiting_date => undef,
2090
            itemnumber  => $hold->item_level_hold ? $hold->itemnumber : undef,
2086
            item_id      => $hold->item_level ? $hold->item_id : undef,
2091
        }
2087
        }
2092
    )->store();
2088
    )->store();
2093
2089
2094
    _FixPriority( { biblionumber => $hold->biblionumber } );
2090
    _FixPriority( { biblionumber => $hold->biblio_id } );
2095
2091
2096
    return $hold;
2092
    return $hold;
2097
}
2093
}
Lines 2124-2136 available within the slip: Link Here
2124
2120
2125
sub ReserveSlip {
2121
sub ReserveSlip {
2126
    my ($args) = @_;
2122
    my ($args) = @_;
2127
    my $branchcode     = $args->{branchcode};
2123
    my $branchcode = $args->{branchcode};
2128
    my $reserve_id = $args->{reserve_id};
2124
    my $reserve_id = $args->{reserve_id};
2129
2125
2130
    my $hold = Koha::Holds->find($reserve_id);
2126
    my $hold = Koha::Holds->find($reserve_id);
2131
    return unless $hold;
2127
    return unless $hold;
2132
2128
2133
    my $patron = $hold->borrower;
2129
    my $patron = $hold->patron;
2134
    my $reserve = $hold->unblessed;
2130
    my $reserve = $hold->unblessed;
2135
2131
2136
    return  C4::Letters::GetPreparedLetter (
2132
    return  C4::Letters::GetPreparedLetter (
Lines 2140-2150 sub ReserveSlip { Link Here
2140
        lang => $patron->lang,
2136
        lang => $patron->lang,
2141
        tables => {
2137
        tables => {
2142
            'reserves'    => $reserve,
2138
            'reserves'    => $reserve,
2143
            'branches'    => $reserve->{branchcode},
2139
            'branches'    => $reserve->{pickup_library_id},
2144
            'borrowers'   => $reserve->{borrowernumber},
2140
            'borrowers'   => $reserve->{patron_id},
2145
            'biblio'      => $reserve->{biblionumber},
2141
            'biblio'      => $reserve->{biblio_id},
2146
            'biblioitems' => $reserve->{biblionumber},
2142
            'biblioitems' => $reserve->{biblio_id},
2147
            'items'       => $reserve->{itemnumber},
2143
            'items'       => $reserve->{item_id},
2148
        },
2144
        },
2149
    );
2145
    );
2150
}
2146
}
Lines 2198-2214 sub CalculatePriority { Link Here
2198
    my ( $biblionumber, $resdate ) = @_;
2194
    my ( $biblionumber, $resdate ) = @_;
2199
2195
2200
    my $sql = q{
2196
    my $sql = q{
2201
        SELECT COUNT(*) FROM reserves
2197
        SELECT COUNT(*) FROM holds
2202
        WHERE biblionumber = ?
2198
        WHERE biblio_id = ?
2203
        AND   priority > 0
2199
        AND   priority > 0
2204
        AND   (found IS NULL OR found = '')
2200
        AND   status='placed'
2205
    };
2201
    };
2206
    #skip found==W or found==T or found==P (waiting, transit or processing holds)
2202
    #skip status==waiting or status==in_transit or status==processing
2207
    if( $resdate ) {
2203
    if( $resdate ) {
2208
        $sql.= ' AND ( reservedate <= ? )';
2204
        $sql.= ' AND ( created_date <= ? )';
2209
    }
2205
    }
2210
    else {
2206
    else {
2211
        $sql.= ' AND ( reservedate < NOW() )';
2207
        $sql.= ' AND ( created_date < NOW() )';
2212
    }
2208
    }
2213
    my $dbh = C4::Context->dbh();
2209
    my $dbh = C4::Context->dbh();
2214
    my @row = $dbh->selectrow_array(
2210
    my @row = $dbh->selectrow_array(
Lines 2222-2247 sub CalculatePriority { Link Here
2222
2218
2223
=head2 IsItemOnHoldAndFound
2219
=head2 IsItemOnHoldAndFound
2224
2220
2225
    my $bool = IsItemFoundHold( $itemnumber );
2221
    my $bool = IsItemFoundHold( $item_id );
2226
2222
2227
    Returns true if the item is currently on hold
2223
    Returns true if the item is currently on hold
2228
    and that hold has a non-null found status ( W, T, etc. )
2224
    and that hold has a status of in_transit, processing
2225
    or waiting.
2229
2226
2230
=cut
2227
=cut
2231
2228
2232
sub IsItemOnHoldAndFound {
2229
sub IsItemOnHoldAndFound {
2233
    my ($itemnumber) = @_;
2230
    my ($item_id) = @_;
2234
2235
    my $rs = Koha::Database->new()->schema()->resultset('Reserve');
2236
2231
2237
    my $found = $rs->count(
2232
    return Koha::Holds->search(
2238
        {
2233
        {
2239
            itemnumber => $itemnumber,
2234
            item_id   => $item_id,
2240
            found      => { '!=' => undef }
2235
            status    => [ 'in_transit', 'processing', 'waiting' ],
2236
            completed => 0
2241
        }
2237
        }
2242
    );
2238
    )->count;
2243
2244
    return $found;
2245
}
2239
}
2246
2240
2247
=head2 GetMaxPatronHoldsForRecord
2241
=head2 GetMaxPatronHoldsForRecord
(-)a/C4/SIP/ILS/Patron.pm (-2 / +2 lines)
Lines 520-530 sub _get_outstanding_holds { Link Here
520
    my $borrowernumber = shift;
520
    my $borrowernumber = shift;
521
521
522
    my $patron = Koha::Patrons->find( $borrowernumber );
522
    my $patron = Koha::Patrons->find( $borrowernumber );
523
    my $holds = $patron->holds->search( { -or => [ { found => undef }, { found => { '!=' => 'W' } } ] } );
523
    my $holds = $patron->holds->search( { completed => 0, status => {'!=' => 'waiting'} } );
524
    my @holds;
524
    my @holds;
525
    while ( my $hold = $holds->next ) {
525
    while ( my $hold = $holds->next ) {
526
        my $item;
526
        my $item;
527
        if ($hold->itemnumber) {
527
        if ($hold->item_id) {
528
            $item = $hold->item;
528
            $item = $hold->item;
529
        }
529
        }
530
        else {
530
        else {
(-)a/C4/SIP/ILS/Transaction/Hold.pm (-1 / +1 lines)
Lines 86-92 sub drop_hold { Link Here
86
    }
86
    }
87
87
88
    my $item = Koha::Items->find({ barcode => $self->{item}->id });
88
    my $item = Koha::Items->find({ barcode => $self->{item}->id });
89
    my $holds = $item->holds->search({ borrowernumber => $patron->borrowernumber });
89
    my $holds = $item->holds->search({ patron_id => $patron->borrowernumber });
90
90
91
    return $self unless $holds->count;
91
    return $self unless $holds->count;
92
92
(-)a/C4/XSLT.pm (-1 / +1 lines)
Lines 316-322 sub buildKohaItemsNamespace { Link Here
316
        $items_rs = Koha::Items->new;
316
        $items_rs = Koha::Items->new;
317
    }
317
    }
318
318
319
    my $items = $items_rs->search( $query, { prefetch => [ 'branchtransfers', 'reserves' ] } );
319
    my $items = $items_rs->search( $query, { prefetch => [ 'branchtransfers', 'holds' ] } );
320
320
321
    my $shelflocations =
321
    my $shelflocations =
322
      { map { $_->{authorised_value} => $_->{opac_description} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => "", kohafield => 'items.location' } ) };
322
      { map { $_->{authorised_value} => $_->{opac_description} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => "", kohafield => 'items.location' } ) };
(-)a/Koha/Acquisition/Order.pm (-1 / +1 lines)
Lines 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 446-452 return the current holds placed on this record Link Here
446
sub holds {
446
sub holds {
447
    my ( $self, $params, $attributes ) = @_;
447
    my ( $self, $params, $attributes ) = @_;
448
    $attributes->{order_by} = 'priority' unless exists $attributes->{order_by};
448
    $attributes->{order_by} = 'priority' unless exists $attributes->{order_by};
449
    my $hold_rs = $self->_result->reserves->search( $params, $attributes );
449
    $params->{completed} = 0 unless exists $params->{completed};
450
    my $hold_rs = $self->_result->holds->search( $params, $attributes );
450
    return Koha::Holds->_new_from_dbic($hold_rs);
451
    return Koha::Holds->_new_from_dbic($hold_rs);
451
}
452
}
452
453
Lines 463-469 sub current_holds { Link Here
463
    my ($self) = @_;
464
    my ($self) = @_;
464
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
465
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
465
    return $self->holds(
466
    return $self->holds(
466
        { reservedate => { '<=' => $dtf->format_date(dt_from_string) } } );
467
        { completed => 0, created_date => { '<=' => $dtf->format_date(dt_from_string) } } );
467
}
468
}
468
469
469
=head3 biblioitem
470
=head3 biblioitem
Lines 524-531 Tells if this bibliographic record has items waiting or in transit. Link Here
524
sub has_items_waiting_or_intransit {
525
sub has_items_waiting_or_intransit {
525
    my ( $self ) = @_;
526
    my ( $self ) = @_;
526
527
527
    if ( Koha::Holds->search({ biblionumber => $self->id,
528
    if ( Koha::Holds->search({ biblio_id => $self->id,
528
                               found => ['W', 'T'] })->count ) {
529
                               status => ['waiting', 'in_transit'] })->count ) {
529
        return 1;
530
        return 1;
530
    }
531
    }
531
532
(-)a/Koha/Hold.pm (-3 / +6 lines)
Lines 369-375 sub is_in_processing { Link Here
369
369
370
Returns true if hold is a cancelable hold
370
Returns true if hold is a cancelable hold
371
371
372
Holds may be only canceled if they are not found.
372
Holds may be only canceled if they are not found or completed.
373
373
374
This is used from the OPAC.
374
This is used from the OPAC.
375
375
Lines 378-385 This is used from the OPAC. Link Here
378
sub is_cancelable_from_opac {
378
sub is_cancelable_from_opac {
379
    my ($self) = @_;
379
    my ($self) = @_;
380
380
381
    return 1 unless $self->is_found();
381
    if ( $self->completed or $self->is_found ) {
382
    return 0; # if ->is_in_transit or if ->is_waiting or ->is_in_processing
382
        return 0;
383
    }
384
385
    return 1;
383
}
386
}
384
387
385
=head3 is_at_destination
388
=head3 is_at_destination
(-)a/Koha/Item.pm (-8 / +10 lines)
Lines 283-289 sub safe_to_delete { Link Here
283
283
284
    # check it doesn't have a waiting reserve
284
    # check it doesn't have a waiting reserve
285
    return "book_reserved"
285
    return "book_reserved"
286
      if $self->holds->search( { found => [ 'W', 'T' ] } )->count;
286
      if $self->holds->search( { status => [ 'waiting', 'in_transit' ], completed => 0 } )->count;
287
287
288
    return "linked_analytics"
288
    return "linked_analytics"
289
      if C4::Items::GetAnalyticsCount( $self->itemnumber ) > 0;
289
      if C4::Items::GetAnalyticsCount( $self->itemnumber ) > 0;
Lines 292-298 sub safe_to_delete { Link Here
292
      if $self->biblio->items->count == 1
292
      if $self->biblio->items->count == 1
293
      && $self->biblio->holds->search(
293
      && $self->biblio->holds->search(
294
          {
294
          {
295
              itemnumber => undef,
295
              item_id => undef,
296
          }
296
          }
297
        )->count;
297
        )->count;
298
298
Lines 407-413 Return holds attached to an item, optionally accept a hashref of params to pass Link Here
407
407
408
sub holds {
408
sub holds {
409
    my ( $self,$params ) = @_;
409
    my ( $self,$params ) = @_;
410
    my $holds_rs = $self->_result->reserves->search($params);
410
    $params->{completed} = 0 unless exists $params->{completed};
411
    my $holds_rs = $self->_result->holds->search($params);
411
    return Koha::Holds->_new_from_dbic( $holds_rs );
412
    return Koha::Holds->_new_from_dbic( $holds_rs );
412
}
413
}
413
414
Lines 791-804 sub current_holds { Link Here
791
    my $attributes = { order_by => 'priority' };
792
    my $attributes = { order_by => 'priority' };
792
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
793
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
793
    my $params = {
794
    my $params = {
794
        itemnumber => $self->itemnumber,
795
        item_id => $self->itemnumber,
795
        suspend => 0,
796
        suspended => 0,
796
        -or => [
797
        -or => [
797
            reservedate => { '<=' => $dtf->format_date(dt_from_string) },
798
            created_date => { '<=' => $dtf->format_date(dt_from_string) },
798
            waitingdate => { '!=' => undef },
799
            waiting_date => { '!=' => undef },
799
        ],
800
        ],
801
        completed => 0
800
    };
802
    };
801
    my $hold_rs = $self->_result->reserves->search( $params, $attributes );
803
    my $hold_rs = $self->_result->holds->search( $params, $attributes );
802
    return Koha::Holds->_new_from_dbic($hold_rs);
804
    return Koha::Holds->_new_from_dbic($hold_rs);
803
}
805
}
804
806
(-)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 1206-1213 Return all the holds placed by this patron Link Here
1206
=cut
1205
=cut
1207
1206
1208
sub holds {
1207
sub holds {
1209
    my ($self) = @_;
1208
    my ($self, $params) = @_;
1210
    my $holds_rs = $self->_result->reserves->search( {}, { order_by => 'reservedate' } );
1209
    $params->{completed} = 0 unless exists $params->{completed};
1210
    my $holds_rs = $self->_result->holds->search( $params, { order_by => 'created_date' } );
1211
    return Koha::Holds->_new_from_dbic($holds_rs);
1211
    return Koha::Holds->_new_from_dbic($holds_rs);
1212
}
1212
}
1213
1213
Lines 1221-1228 Return all the historical holds for this patron Link Here
1221
1221
1222
sub old_holds {
1222
sub old_holds {
1223
    my ($self) = @_;
1223
    my ($self) = @_;
1224
    my $old_holds_rs = $self->_result->old_reserves->search( {}, { order_by => 'reservedate' } );
1224
    my $old_holds_rs = $self->_result->holds->search( { completed => 1 }, { order_by => 'created_date' } );
1225
    return Koha::Old::Holds->_new_from_dbic($old_holds_rs);
1225
    return Koha::Holds->_new_from_dbic($old_holds_rs);
1226
}
1226
}
1227
1227
1228
=head3 return_claims
1228
=head3 return_claims
(-)a/Koha/REST/V1/Auth.pm (-11 / +9 lines)
Lines 318-327 sub validate_query_parameters { Link Here
318
Allows access to object for its owner.
318
Allows access to object for its owner.
319
319
320
There are endpoints that should allow access for the object owner even if they
320
There are endpoints that should allow access for the object owner even if they
321
do not have the required permission, e.g. access an own reserve. This can be
321
do not have the required permission, e.g. access an own hold. This can be
322
achieved by defining the operation as follows:
322
achieved by defining the operation as follows:
323
323
324
"/holds/{reserve_id}": {
324
"/holds/{hold_id}": {
325
    "get": {
325
    "get": {
326
        ...,
326
        ...,
327
        "x-koha-authorization": {
327
        "x-koha-authorization": {
Lines 385-391 sub check_object_ownership { Link Here
385
        borrowernumber  => \&_object_ownership_by_patron_id,
385
        borrowernumber  => \&_object_ownership_by_patron_id,
386
        patron_id       => \&_object_ownership_by_patron_id,
386
        patron_id       => \&_object_ownership_by_patron_id,
387
        checkout_id     => \&_object_ownership_by_checkout_id,
387
        checkout_id     => \&_object_ownership_by_checkout_id,
388
        reserve_id      => \&_object_ownership_by_reserve_id,
388
        hold_id      => \&_object_ownership_by_hold_id,
389
    };
389
    };
390
390
391
    foreach my $param ( keys %{ $parameters } ) {
391
    foreach my $param ( keys %{ $parameters } ) {
Lines 449-468 sub _object_ownership_by_checkout_id { Link Here
449
            && $user->borrowernumber == $issue->borrowernumber;
449
            && $user->borrowernumber == $issue->borrowernumber;
450
}
450
}
451
451
452
=head3 _object_ownership_by_reserve_id
452
=head3 _object_ownership_by_hold_id
453
453
454
Finds a Koha::Hold-object by C<$reserve_id> and checks if it
454
Finds a Koha::Hold-object by C<$hold_id> and checks if it
455
belongs to C<$user>.
455
belongs to C<$user>.
456
456
457
TODO: Also compare against old_reserves
458
459
=cut
457
=cut
460
458
461
sub _object_ownership_by_reserve_id {
459
sub _object_ownership_by_hold_id {
462
    my ($c, $user, $reserve_id) = @_;
460
    my ($c, $user, $hold_id) = @_;
463
461
464
    my $reserve = Koha::Holds->find($reserve_id);
462
    my $hold = Koha::Holds->find($hold_id);
465
    return $reserve && $user->borrowernumber == $reserve->borrowernumber;
463
    return $hold && $user->borrowernumber == $hold->borrowernumber;
466
}
464
}
467
465
468
=head3 _basic_auth
466
=head3 _basic_auth
(-)a/Koha/REST/V1/Holds.pm (-15 / +15 lines)
Lines 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-89 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
        my $overrides = $c->stash('koha.overrides');
83
        my $overrides = $c->stash('koha.overrides');
84
        my $can_override = $overrides->{any} && C4::Context->preference('AllowHoldPolicyOverride');
84
        my $can_override = $overrides->{any} && C4::Context->preference('AllowHoldPolicyOverride');
85
85
86
        if(!C4::Context->preference( 'AllowHoldDateInFuture' ) && $hold_date) {
86
        if(!C4::Context->preference( 'AllowHoldDateInFuture' ) && $created_date) {
87
            return $c->render(
87
            return $c->render(
88
                status  => 400,
88
                status  => 400,
89
                openapi => { error => "Hold date in future not allowed" }
89
                openapi => { error => "Hold date in future not allowed" }
Lines 195-201 sub add { Link Here
195
                borrowernumber   => $patron_id,
195
                borrowernumber   => $patron_id,
196
                biblionumber     => $biblio_id,
196
                biblionumber     => $biblio_id,
197
                priority         => $priority,
197
                priority         => $priority,
198
                reservation_date => $hold_date,
198
                reservation_date => $created_date,
199
                expiration_date  => $expiration_date,
199
                expiration_date  => $expiration_date,
200
                notes            => $notes,
200
                notes            => $notes,
201
                title            => $biblio->title,
201
                title            => $biblio->title,
Lines 249-255 sub edit { Link Here
249
249
250
    return try {
250
    return try {
251
        my $hold_id = $c->validation->param('hold_id');
251
        my $hold_id = $c->validation->param('hold_id');
252
        my $hold = Koha::Holds->find( $hold_id );
252
        my $hold    = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
253
253
254
        unless ($hold) {
254
        unless ($hold) {
255
            return $c->render(
255
            return $c->render(
Lines 278-294 sub edit { Link Here
278
            );
278
            );
279
        }
279
        }
280
280
281
        $pickup_library_id //= $hold->branchcode;
281
        $pickup_library_id //= $hold->pickup_library_id;
282
        my $priority         = $body->{priority} // $hold->priority;
282
        my $priority         = $body->{priority} // $hold->priority;
283
        # suspended_until can also be set to undef
283
        # suspended_until can also be set to undef
284
        my $suspended_until   = exists $body->{suspended_until} ? $body->{suspended_until} : $hold->suspend_until;
284
        my $suspended_until   = exists $body->{suspended_until_date} ? $body->{suspended_until_date} : $hold->suspended_until_date;
285
285
286
        my $params = {
286
        my $params = {
287
            reserve_id    => $hold_id,
287
            reserve_id    => $hold_id,
288
            branchcode    => $pickup_library_id,
288
            branchcode    => $pickup_library_id,
289
            rank          => $priority,
289
            rank          => $priority,
290
            suspend_until => $suspended_until ? output_pref(dt_from_string($suspended_until, 'rfc3339')) : '',
290
            suspend_until => $suspended_until ? output_pref(dt_from_string($suspended_until, 'rfc3339')) : '',
291
            itemnumber    => $hold->itemnumber
291
            itemnumber    => $hold->item_id
292
        };
292
        };
293
293
294
        C4::Reserves::ModReserve($params);
294
        C4::Reserves::ModReserve($params);
Lines 314-320 sub delete { Link Here
314
    my $c = shift->openapi->valid_input or return;
314
    my $c = shift->openapi->valid_input or return;
315
315
316
    my $hold_id = $c->validation->param('hold_id');
316
    my $hold_id = $c->validation->param('hold_id');
317
    my $hold    = Koha::Holds->find($hold_id);
317
    my $hold    = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
318
318
319
    unless ($hold) {
319
    unless ($hold) {
320
        return $c->render( status => 404, openapi => { error => "Hold not found." } );
320
        return $c->render( status => 404, openapi => { error => "Hold not found." } );
Lines 343-349 sub suspend { Link Here
343
    my $c = shift->openapi->valid_input or return;
343
    my $c = shift->openapi->valid_input or return;
344
344
345
    my $hold_id  = $c->validation->param('hold_id');
345
    my $hold_id  = $c->validation->param('hold_id');
346
    my $hold     = Koha::Holds->find($hold_id);
346
    my $hold     = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
347
    my $body     = $c->req->json;
347
    my $body     = $c->req->json;
348
    my $end_date = ($body) ? $body->{end_date} : undef;
348
    my $end_date = ($body) ? $body->{end_date} : undef;
349
349
Lines 357-365 sub suspend { Link Here
357
        $hold->discard_changes;
357
        $hold->discard_changes;
358
        $c->res->headers->location( $c->req->url->to_string );
358
        $c->res->headers->location( $c->req->url->to_string );
359
        my $suspend_end_date;
359
        my $suspend_end_date;
360
        if ($hold->suspend_until) {
360
        if ($hold->suspended_until_date) {
361
            $suspend_end_date = output_pref({
361
            $suspend_end_date = output_pref({
362
                dt         => dt_from_string( $hold->suspend_until ),
362
                dt         => dt_from_string( $hold->suspended_until_date ),
363
                dateformat => 'rfc3339',
363
                dateformat => 'rfc3339',
364
                dateonly   => 1
364
                dateonly   => 1
365
                }
365
                }
Lines 391-397 sub resume { Link Here
391
    my $c = shift->openapi->valid_input or return;
391
    my $c = shift->openapi->valid_input or return;
392
392
393
    my $hold_id = $c->validation->param('hold_id');
393
    my $hold_id = $c->validation->param('hold_id');
394
    my $hold    = Koha::Holds->find($hold_id);
394
    my $hold    = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
395
    my $body    = $c->req->json;
395
    my $body    = $c->req->json;
396
396
397
    unless ($hold) {
397
    unless ($hold) {
Lines 417-423 sub update_priority { Link Here
417
    my $c = shift->openapi->valid_input or return;
417
    my $c = shift->openapi->valid_input or return;
418
418
419
    my $hold_id = $c->validation->param('hold_id');
419
    my $hold_id = $c->validation->param('hold_id');
420
    my $hold = Koha::Holds->find($hold_id);
420
    my $hold = Koha::Holds->search({id=>$hold_id, completed=>0})->next;
421
421
422
    unless ($hold) {
422
    unless ($hold) {
423
        return $c->render(
423
        return $c->render(
Lines 465-471 sub pickup_locations { Link Here
465
    return try {
465
    return try {
466
        my $ps_set;
466
        my $ps_set;
467
467
468
        if ( $hold->itemnumber ) {
468
        if ( $hold->item_id ) {
469
            $ps_set = $hold->item->pickup_locations( { patron => $hold->patron } );
469
            $ps_set = $hold->item->pickup_locations( { patron => $hold->patron } );
470
        }
470
        }
471
        else {
471
        else {
(-)a/Koha/Template/Plugin/Biblio.pm (-4 / +7 lines)
Lines 29-39 use Koha::ArticleRequests; Link Here
29
use Koha::ArticleRequest::Status;
29
use Koha::ArticleRequest::Status;
30
30
31
sub HoldsCount {
31
sub HoldsCount {
32
    my ( $self, $biblionumber ) = @_;
32
    my ( $self, $biblio_id ) = @_;
33
34
    my $holds = Koha::Holds->search( { biblionumber => $biblionumber } );
35
33
36
    return $holds->count();
34
    return Koha::Holds->search(
35
        {
36
            biblio_id => $biblio_id,
37
            completed => 0
38
        }
39
    )->count;
37
}
40
}
38
41
39
sub ArticleRequestsActiveCount {
42
sub ArticleRequestsActiveCount {
(-)a/api/v1/swagger/definitions/hold.json (-3 / +11 lines)
Lines 9-15 Link Here
9
      "type": "integer",
9
      "type": "integer",
10
      "description": "Internal patron identifier"
10
      "description": "Internal patron identifier"
11
    },
11
    },
12
    "hold_date": {
12
    "created_date": {
13
      "type": ["string", "null"],
13
      "type": ["string", "null"],
14
      "format": "date",
14
      "format": "date",
15
      "description": "The date the hold was placed"
15
      "description": "The date the hold was placed"
Lines 45-51 Link Here
45
    },
45
    },
46
    "status": {
46
    "status": {
47
      "type": ["string", "null"],
47
      "type": ["string", "null"],
48
      "description": "A one letter code defining what the status of the hold is after it has been confirmed"
48
      "description": "the status the hold is ('placed', 'fulfilled', 'waiting', 'in_transit', 'cancelled')"
49
    },
49
    },
50
    "timestamp": {
50
    "timestamp": {
51
      "type": "string",
51
      "type": "string",
Lines 74-80 Link Here
74
      "type": "boolean",
74
      "type": "boolean",
75
      "description": "Controls if the hold is suspended"
75
      "description": "Controls if the hold is suspended"
76
    },
76
    },
77
    "suspended_until": {
77
    "suspended_until_date": {
78
      "type": ["string", "null"],
78
      "type": ["string", "null"],
79
      "format": "date-time",
79
      "format": "date-time",
80
      "description": "Date until which the hold has been suspended"
80
      "description": "Date until which the hold has been suspended"
Lines 90-95 Link Here
90
    "item_level": {
90
    "item_level": {
91
      "type": "boolean",
91
      "type": "boolean",
92
      "description": "If the hold is placed at item level"
92
      "description": "If the hold is placed at item level"
93
    },
94
    "completed": {
95
      "type": "boolean",
96
      "description": "If it has been completed (i.e. either 'fulfilled' or 'cancelled')"
97
    },
98
    "completed_date": {
99
      "type": ["string", "null"],
100
      "description": "the date this hold was completed (fulfilled or cancelled)"
93
    }
101
    }
94
  },
102
  },
95
  "additionalProperties": false
103
  "additionalProperties": false
(-)a/api/v1/swagger/paths/holds.json (-3 / +3 lines)
Lines 99-105 Link Here
99
          "type": "boolean"
99
          "type": "boolean"
100
        },
100
        },
101
        {
101
        {
102
          "name": "suspended_until",
102
          "name": "suspended_until_date",
103
          "in": "query",
103
          "in": "query",
104
          "description": "Suspended until",
104
          "description": "Suspended until",
105
          "type": "string"
105
          "type": "string"
Lines 320-326 Link Here
320
                "description": "Internal library identifier for the pickup library",
320
                "description": "Internal library identifier for the pickup library",
321
                "type": "string"
321
                "type": "string"
322
              },
322
              },
323
              "suspended_until": {
323
              "suspended_until_date": {
324
                "description": "Date until which the hold has been suspended",
324
                "description": "Date until which the hold has been suspended",
325
                "type": "string",
325
                "type": "string",
326
                "format": "date-time"
326
                "format": "date-time"
Lines 407-413 Link Here
407
                "description": "Internal library identifier for the pickup library",
407
                "description": "Internal library identifier for the pickup library",
408
                "type": "string"
408
                "type": "string"
409
              },
409
              },
410
              "suspended_until": {
410
              "suspended_until_date": {
411
                "description": "Date until which the hold has been suspended",
411
                "description": "Date until which the hold has been suspended",
412
                "type": "string",
412
                "type": "string",
413
                "format": "date-time"
413
                "format": "date-time"
(-)a/circ/circulation.pl (-1 / +1 lines)
Lines 454-460 if (@$barcodes) { Link Here
454
# BUILD HTML
454
# BUILD HTML
455
# show all reserves of this borrower, and the position of the reservation ....
455
# show all reserves of this borrower, and the position of the reservation ....
456
if ($patron) {
456
if ($patron) {
457
    my $holds = Koha::Holds->search( { borrowernumber => $borrowernumber } ); # FIXME must be Koha::Patron->holds
457
    my $holds = Koha::Holds->search( { patron_id => $borrowernumber } ); # FIXME must be Koha::Patron->holds
458
    my $waiting_holds = $holds->waiting;
458
    my $waiting_holds = $holds->waiting;
459
    $template->param(
459
    $template->param(
460
        holds_count  => $holds->count(),
460
        holds_count  => $holds->count(),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/holdshistory.tt (-16 / +16 lines)
Lines 74-114 Link Here
74
          <td>[% INCLUDE 'biblio-title.inc' biblio=hold.biblio link = 1 %]</td>
74
          <td>[% INCLUDE 'biblio-title.inc' biblio=hold.biblio link = 1 %]</td>
75
          <td>[% hold.biblio.author | html %]</td>
75
          <td>[% hold.biblio.author | html %]</td>
76
          <td>[% hold.item.barcode | html %]</td>
76
          <td>[% hold.item.barcode | html %]</td>
77
          <td>[% Branches.GetName( hold.branchcode ) | html %]</td>
77
          <td>[% Branches.GetName( hold.pickup_library_id ) | html %]</td>
78
          <td data-order="[% hold.reservedate | html %]">[% hold.reservedate | $KohaDates %]</td>
78
          <td data-order="[% hold.created_date | html %]">[% hold.created_date | $KohaDates %]</td>
79
          <td data-order="[% hold.expirationdate | html %]">
79
          <td data-order="[% hold.expiration_date | html %]">
80
                [% hold.expirationdate | $KohaDates %]
80
                [% hold.expiration_date | $KohaDates %]
81
          </td>
81
          </td>
82
          <td data-order="[% hold.waitingdate | html %]">
82
          <td data-order="[% hold.waiting_date | html %]">
83
                [% hold.waitingdate | $KohaDates %]
83
                [% hold.waiting_date | $KohaDates %]
84
          </td>
84
          </td>
85
          <td data-order="[% hold.cancellationdate | html %]">
85
          <td data-order="[% hold.completed_date | html %]">
86
                [% hold.cancellationdate | $KohaDates %]
86
                [% hold.completed_date | $KohaDates %]
87
          </td>
87
          </td>
88
          [% IF show_itemtype_column %]
88
          [% IF show_itemtype_column %]
89
            <td>
89
            <td>
90
              [% IF hold.itemtype %]
90
              [% IF hold.item_type %]
91
                  [% ItemTypes.GetDescription( hold.itemtype ) | html %]
91
                  [% ItemTypes.GetDescription( hold.item_type ) | html %]
92
              [% ELSE %]
92
              [% ELSE %]
93
                  <span>Any item type</span>
93
                  <span>Any item type</span>
94
              [% END %]
94
              [% END %]
95
            </td>
95
            </td>
96
          [% END %]
96
          [% END %]
97
          <td>
97
          <td>
98
          [% IF hold.found == 'F' %]
98
          [% IF    hold.status == 'fulfilled' %]
99
              Fulfilled
99
              Fulfilled
100
          [% ELSIF hold.cancellationdate %]
100
          [% ELSIF hold.status == 'cancelled' %]
101
              Cancelled
101
              Cancelled
102
                [% IF hold.cancellation_reason %]
102
                [% IF hold.cancellation_reason %]
103
                    ([% AuthorisedValues.GetByCode('HOLD_CANCELLATION', hold.cancellation_reason) | html %])
103
                    ([% AuthorisedValues.GetByCode('HOLD_CANCELLATION', hold.cancellation_reason) | html %])
104
                [% END %]
104
                [% END %]
105
          [% ELSIF hold.found == 'W' %]
105
          [% ELSIF hold.status == 'waiting' %]
106
              Waiting
106
              Waiting
107
          [% ELSIF hold.found == 'P' %]
107
          [% ELSIF hold.status == 'processing' %]
108
              Processing
108
              Processing
109
          [% ELSIF hold.found == 'T' %]
109
          [% ELSIF hold.status == 'in_transit' %]
110
              In transit
110
              In transit
111
          [% ELSE %]
111
          [% ELSIF hold.status == 'placed' %]
112
              Pending
112
              Pending
113
          [% END %]
113
          [% END %]
114
          </td>
114
          </td>
(-)a/members/holdshistory.pl (-11 / +1 lines)
Lines 53-59 unless ( $patron ) { Link Here
53
}
53
}
54
54
55
my $holds;
55
my $holds;
56
my $old_holds;
57
56
58
if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){
57
if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){
59
    # use of 'eq' in the above comparison is intentional -- the
58
    # use of 'eq' in the above comparison is intentional -- the
Lines 61-81 if ( $borrowernumber eq C4::Context->preference('AnonymousPatron') ){ Link Here
61
    $template->param( is_anonymous => 1 );
60
    $template->param( is_anonymous => 1 );
62
} else {
61
} else {
63
    $holds = $patron->holds;
62
    $holds = $patron->holds;
64
    $old_holds = $patron->old_holds;
65
66
    while (my $hold = $holds->next) {
67
        push @all_holds, $hold;
68
    }
69
70
    while (my $hold = $old_holds->next) {
71
        push @all_holds, $hold;
72
    }
73
}
63
}
74
64
75
$template->param(
65
$template->param(
76
    holdshistoryview => 1,
66
    holdshistoryview => 1,
77
    patron           => $patron,
67
    patron           => $patron,
78
    holds            => \@all_holds,
68
    holds            => $holds
79
);
69
);
80
70
81
output_html_with_http_headers $input, $cookie, $template->output;
71
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/reserve/request.pl (-19 / +54 lines)
Lines 349-357 foreach my $biblionumber (@biblionumbers) { Link Here
349
        # the patron places must be item level
349
        # the patron places must be item level
350
        my $holds = Koha::Holds->search(
350
        my $holds = Koha::Holds->search(
351
            {
351
            {
352
                borrowernumber => $patron->borrowernumber,
352
                patron_id => $patron->borrowernumber,
353
                biblionumber   => $biblionumber,
353
                biblio_id => $biblionumber,
354
                found          => undef,
354
                status    => 'placed',
355
            }
355
            }
356
        );
356
        );
357
        $force_hold_level = $holds->forced_hold_level();
357
        $force_hold_level = $holds->forced_hold_level();
Lines 368-374 foreach my $biblionumber (@biblionumbers) { Link Here
368
    }
368
    }
369
369
370
370
371
    my $count = Koha::Holds->search( { biblionumber => $biblionumber } )->count();
371
    my $count = Koha::Holds->search(
372
        {
373
            biblio_id => $biblionumber,
374
            completed => 0
375
        }
376
    )->count();
372
    my $totalcount = $count;
377
    my $totalcount = $count;
373
378
374
    # FIXME think @optionloop, is maybe obsolete, or  must be switchable by a systeme preference fixed rank or not
379
    # FIXME think @optionloop, is maybe obsolete, or  must be switchable by a systeme preference fixed rank or not
Lines 513-525 foreach my $biblionumber (@biblionumbers) { Link Here
513
            my $item_object = Koha::Items->find( $itemnumber );
518
            my $item_object = Koha::Items->find( $itemnumber );
514
            my $holds = $item_object->current_holds;
519
            my $holds = $item_object->current_holds;
515
            if ( my $first_hold = $holds->next ) {
520
            if ( my $first_hold = $holds->next ) {
516
                my $p = Koha::Patrons->find( $first_hold->borrowernumber );
521
                my $p = Koha::Patrons->find( $first_hold->patron_id );
517
522
518
                $item->{backgroundcolor} = 'reserved';
523
                $item->{backgroundcolor} = 'reserved';
519
                $item->{reservedate}     = output_pref({ dt => dt_from_string( $first_hold->reservedate ), dateonly => 1 }); # FIXME Should be formatted in the template
524
                $item->{reservedate}     = output_pref({ dt => dt_from_string( $first_hold->created_date ), dateonly => 1 }); # FIXME Should be formatted in the template
520
                $item->{ReservedFor}     = $p;
525
                $item->{ReservedFor}     = $p;
521
                $item->{ExpectedAtLibrary}     = $first_hold->branchcode;
526
                $item->{ExpectedAtLibrary}     = $first_hold->pickup_library_id;
522
                $item->{waitingdate} = $first_hold->waitingdate;
527
                $item->{waitingdate} = $first_hold->waiting_date;
523
            }
528
            }
524
529
525
            # Management of the notforloan document
530
            # Management of the notforloan document
Lines 647-653 foreach my $biblionumber (@biblionumbers) { Link Here
647
652
648
    # existingreserves building
653
    # existingreserves building
649
    my @reserveloop;
654
    my @reserveloop;
650
    my @reserves = Koha::Holds->search( { biblionumber => $biblionumber }, { order_by => 'priority' } );
655
    my @reserves = Koha::Holds->search(
656
        {
657
            biblio_id => $biblionumber,
658
            completed => 0
659
        },
660
        { order_by => 'priority' }
661
    );
651
    foreach my $res (
662
    foreach my $res (
652
        sort {
663
        sort {
653
            my $a_found = $a->found() || '';
664
            my $a_found = $a->found() || '';
Lines 673-683 foreach my $biblionumber (@biblionumbers) { Link Here
673
            $reserve{'holdingbranch'} = $res->item()->holdingbranch();
684
            $reserve{'holdingbranch'} = $res->item()->holdingbranch();
674
            $reserve{'biblionumber'}  = $res->item()->biblionumber();
685
            $reserve{'biblionumber'}  = $res->item()->biblionumber();
675
            $reserve{'barcodenumber'} = $res->item()->barcode();
686
            $reserve{'barcodenumber'} = $res->item()->barcode();
676
            $reserve{'wbrcode'}       = $res->branchcode();
687
            $reserve{'wbrcode'}       = $res->pickup_library_id;
677
            $reserve{'itemnumber'}    = $res->itemnumber();
688
            $reserve{'itemnumber'}    = $res->item_id;
678
            $reserve{'wbrname'}       = $res->branch()->branchname();
689
            $reserve{'wbrname'}       = $res->branch()->branchname();
690
<<<<<<< HEAD
679
            $reserve{'atdestination'} = $res->is_at_destination();
691
            $reserve{'atdestination'} = $res->is_at_destination();
680
            $reserve{'desk_name'}     = ( $res->desk() ) ? $res->desk()->desk_name() : '' ;
692
            $reserve{'desk_name'}     = ( $res->desk() ) ? $res->desk()->desk_name() : '' ;
693
=======
694
695
            if ( $reserve{'holdingbranch'} eq $reserve{'wbrcode'} ) {
696
697
                # Just because the holdingbranch matches the reserve branch doesn't mean the item
698
                # has arrived at the destination, check for an open transfer for the item as well
699
                my ( $transfertwhen, $transfertfrom, $transferto ) =
700
                  C4::Circulation::GetTransfers( $res->item_id );
701
                if ( not $transferto or $transferto ne $res->pickup_library_id ) {
702
                    $reserve{'atdestination'} = 1;
703
                }
704
            }
705
706
            # set found to 1 if reserve is waiting for patron pickup
707
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
681
            $reserve{'found'}     = $res->is_found();
708
            $reserve{'found'}     = $res->is_found();
682
            $reserve{'inprocessing'} = $res->is_in_processing();
709
            $reserve{'inprocessing'} = $res->is_in_processing();
683
            $reserve{'intransit'} = $res->is_in_transit();
710
            $reserve{'intransit'} = $res->is_in_transit();
Lines 690-713 foreach my $biblionumber (@biblionumbers) { Link Here
690
            }
717
            }
691
        }
718
        }
692
719
693
        $reserve{'expirationdate'} = $res->expirationdate;
720
        $reserve{'expirationdate'} = $res->expiration_date;
694
        $reserve{'date'}           = $res->reservedate;
721
        $reserve{'date'}           = $res->created_date;
695
        $reserve{'borrowernumber'} = $res->borrowernumber();
722
        $reserve{'borrowernumber'} = $res->patron_id;
696
        $reserve{'biblionumber'}   = $res->biblionumber();
723
        $reserve{'biblionumber'}   = $res->biblio_id;
697
        $reserve{'patron'}         = $res->borrower;
724
        $reserve{'patron'}         = $res->borrower;
698
        $reserve{'notes'}          = $res->reservenotes();
725
        $reserve{'notes'}          = $res->notes;
699
        $reserve{'waiting_date'}   = $res->waitingdate();
726
        $reserve{'waiting_date'}   = $res->waiting_date;
700
        $reserve{'ccode'}          = $res->item() ? $res->item()->ccode() : undef;
727
        $reserve{'ccode'}          = $res->item() ? $res->item()->ccode() : undef;
701
        $reserve{'barcode'}        = $res->item() ? $res->item()->barcode() : undef;
728
        $reserve{'barcode'}        = $res->item() ? $res->item()->barcode() : undef;
702
        $reserve{'priority'}       = $res->priority();
729
        $reserve{'priority'}       = $res->priority;
703
        $reserve{'lowestPriority'} = $res->lowestPriority();
730
        $reserve{'lowestPriority'} = $res->lowest_priority;
704
        $reserve{'optionloop'}     = \@optionloop;
731
        $reserve{'optionloop'}     = \@optionloop;
732
<<<<<<< HEAD
705
        $reserve{'suspend'}        = $res->suspend();
733
        $reserve{'suspend'}        = $res->suspend();
706
        $reserve{'suspend_until'}  = $res->suspend_until();
734
        $reserve{'suspend_until'}  = $res->suspend_until();
707
        $reserve{'reserve_id'}     = $res->reserve_id();
735
        $reserve{'reserve_id'}     = $res->reserve_id();
708
        $reserve{itemtype}         = $res->itemtype();
736
        $reserve{itemtype}         = $res->itemtype();
709
        $reserve{branchcode}       = $res->branchcode();
737
        $reserve{branchcode}       = $res->branchcode();
710
        $reserve{non_priority}     = $res->non_priority();
738
        $reserve{non_priority}     = $res->non_priority();
739
=======
740
        $reserve{'suspend'}        = $res->suspended;
741
        $reserve{'suspend_until'}  = $res->suspended_until_date;
742
        $reserve{'reserve_id'}     = $res->id;
743
        $reserve{itemtype}         = $res->item_type;
744
        $reserve{branchcode}       = $res->pickup_library_id;
745
>>>>>>> 324514e305 (Bug 25260: Adapt all the things)
711
        $reserve{object}           = $res;
746
        $reserve{object}           = $res;
712
747
713
        push( @reserveloop, \%reserve );
748
        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 343-349 subtest 'dbic_merge_sorting() tests' => sub { Link Here
343
      ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
343
      ->json_is( '/a' => 'a', 'Existing values are kept (a)' )
344
      ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
344
      ->json_is( '/b' => 'b', 'Existing values are kept (b)' )->json_is(
345
        '/order_by' => [
345
        '/order_by' => [
346
            { -desc => 'reservedate' }
346
            { -desc => 'created_date' }
347
        ]
347
        ]
348
      );
348
      );
349
349
(-)a/t/db_dependent/Circulation.t (-32 / +31 lines)
Lines 507-513 subtest "CanBookBeRenewed tests" => sub { Link Here
507
    my $expdate        = undef;
507
    my $expdate        = undef;
508
    my $notes          = '';
508
    my $notes          = '';
509
    my $checkitem      = undef;
509
    my $checkitem      = undef;
510
    my $found          = undef;
510
    my $found          = 'placed';
511
511
512
    my $issue = AddIssue( $renewing_borrower, $item_1->barcode);
512
    my $issue = AddIssue( $renewing_borrower, $item_1->barcode);
513
    my $datedue = dt_from_string( $issue->date_due() );
513
    my $datedue = dt_from_string( $issue->date_due() );
Lines 535-542 subtest "CanBookBeRenewed tests" => sub { Link Here
535
            reservation_date => $resdate,
535
            reservation_date => $resdate,
536
            expiration_date  => $expdate,
536
            expiration_date  => $expdate,
537
            notes            => $notes,
537
            notes            => $notes,
538
            itemnumber       => $checkitem,
538
            itemnumber       => $checkitem
539
            found            => $found,
540
        }
539
        }
541
    );
540
    );
542
541
Lines 566-596 subtest "CanBookBeRenewed tests" => sub { Link Here
566
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
565
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
567
566
568
    # Now let's add an item level hold, we should no longer be able to renew the item
567
    # Now let's add an item level hold, we should no longer be able to renew the item
569
    my $hold = Koha::Database->new()->schema()->resultset('Reserve')->create(
568
    my $hold = Koha::Hold->new(
570
        {
569
        {
571
            borrowernumber => $hold_waiting_borrowernumber,
570
            patron_id   => $hold_waiting_borrowernumber,
572
            biblionumber   => $biblio->biblionumber,
571
            biblio_id   => $biblio->biblionumber,
573
            itemnumber     => $item_1->itemnumber,
572
            item_id     => $item_1->itemnumber,
574
            branchcode     => $branch,
573
            pickup_library_id => $branch,
575
            priority       => 3,
574
            priority    => 3,
576
        }
575
        }
577
    );
576
    )->store;
578
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
577
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
579
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
578
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
580
    $hold->delete();
579
    $hold->delete();
581
580
582
    # Now let's add a waiting hold on the 3rd item, it's no longer available tp check out by just anyone, so we should no longer
581
    # Now let's add a waiting hold on the 3rd item, it's no longer available tp check out by just anyone, so we should no longer
583
    # be able to renew these items
582
    # be able to renew these items
584
    $hold = Koha::Database->new()->schema()->resultset('Reserve')->create(
583
    $hold = Koha::Hold->new(
585
        {
584
        {
586
            borrowernumber => $hold_waiting_borrowernumber,
585
            patron_id => $hold_waiting_borrowernumber,
587
            biblionumber   => $biblio->biblionumber,
586
            biblio_id   => $biblio->biblionumber,
588
            itemnumber     => $item_3->itemnumber,
587
            item_id     => $item_3->itemnumber,
589
            branchcode     => $branch,
588
            pickup_library_id     => $branch,
590
            priority       => 0,
589
            priority       => 0,
591
            found          => 'W'
590
            status          => 'waiting'
592
        }
591
        }
593
    );
592
    )->store;
594
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
593
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
595
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
594
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
596
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
595
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
Lines 605-619 subtest "CanBookBeRenewed tests" => sub { Link Here
605
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
604
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
606
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
605
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
607
606
608
    my $reserveid = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $reserving_borrowernumber })->next->reserve_id;
607
    my $reserveid = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $reserving_borrowernumber })->next->id;
609
    my $reserving_borrower = Koha::Patrons->find( $reserving_borrowernumber )->unblessed;
608
    my $reserving_borrower = Koha::Patrons->find( $reserving_borrowernumber )->unblessed;
610
    AddIssue($reserving_borrower, $item_3->barcode);
609
    AddIssue($reserving_borrower, $item_3->barcode);
611
    my $reserve = $dbh->selectrow_hashref(
610
    my $reserve = $dbh->selectrow_hashref(
612
        'SELECT * FROM old_reserves WHERE reserve_id = ?',
611
        'SELECT * FROM holds WHERE id = ? AND completed = 1',
613
        { Slice => {} },
612
        { Slice => {} },
614
        $reserveid
613
        $reserveid
615
    );
614
    );
616
    is($reserve->{found}, 'F', 'hold marked completed when checking out item that fills it');
615
    is($reserve->{status}, 'fulfilled', 'hold marked completed when checking out item that fills it');
617
616
618
    # Item-level hold, renewal test
617
    # Item-level hold, renewal test
619
    AddReserve(
618
    AddReserve(
Lines 775-781 subtest "CanBookBeRenewed tests" => sub { Link Here
775
    $fines = Koha::Account::Lines->search( { borrowernumber => $renewing_borrower->{borrowernumber}, itemnumber => $item_7->itemnumber } );
774
    $fines = Koha::Account::Lines->search( { borrowernumber => $renewing_borrower->{borrowernumber}, itemnumber => $item_7->itemnumber } );
776
    $fines->delete();
775
    $fines->delete();
777
776
778
    $hold = Koha::Holds->search({ biblionumber => $biblio->biblionumber, borrowernumber => $reserving_borrowernumber })->next;
777
    $hold = Koha::Holds->search({ biblio_id => $biblio->biblionumber, patron_id => $reserving_borrowernumber })->next;
779
    $hold->cancel;
778
    $hold->cancel;
780
779
781
    # Bug 14101
780
    # Bug 14101
Lines 3450-3456 subtest 'Set waiting flag' => sub { Link Here
3450
    my ( $res, $rr ) = AddReturn( $item->barcode, $library_1->{branchcode} );
3449
    my ( $res, $rr ) = AddReturn( $item->barcode, $library_1->{branchcode} );
3451
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3450
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3452
    my $hold = Koha::Holds->find( $reserve_id );
3451
    my $hold = Koha::Holds->find( $reserve_id );
3453
    is( $hold->found, 'T', 'Hold is in transit' );
3452
    is( $hold->status, 'in_transit', 'Hold is in transit' );
3454
3453
3455
    my ( $status ) = CheckReserves($item->itemnumber);
3454
    my ( $status ) = CheckReserves($item->itemnumber);
3456
    is( $status, 'Transferred', 'Hold is not waiting yet');
3455
    is( $status, 'Transferred', 'Hold is not waiting yet');
Lines 3460-3466 subtest 'Set waiting flag' => sub { Link Here
3460
    AddReturn( $item->barcode, $library_2->{branchcode} );
3459
    AddReturn( $item->barcode, $library_2->{branchcode} );
3461
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3460
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3462
    $hold = Koha::Holds->find( $reserve_id );
3461
    $hold = Koha::Holds->find( $reserve_id );
3463
    is( $hold->found, 'W', 'Hold is waiting' );
3462
    is( $hold->status, 'waiting', 'Hold is waiting' );
3464
    ( $status ) = CheckReserves($item->itemnumber);
3463
    ( $status ) = CheckReserves($item->itemnumber);
3465
    is( $status, 'Waiting', 'Now the hold is waiting');
3464
    is( $status, 'Waiting', 'Now the hold is waiting');
3466
3465
Lines 3468-3479 subtest 'Set waiting flag' => sub { Link Here
3468
    set_userenv( $library_1 );
3467
    set_userenv( $library_1 );
3469
    (undef, my $messages, undef, undef ) = AddReturn ( $item->barcode, $library_1->{branchcode} );
3468
    (undef, my $messages, undef, undef ) = AddReturn ( $item->barcode, $library_1->{branchcode} );
3470
    $hold = Koha::Holds->find( $reserve_id );
3469
    $hold = Koha::Holds->find( $reserve_id );
3471
    is( $hold->found, undef, 'Hold is no longer marked waiting' );
3470
    is( $hold->status, 'placed', 'Hold is no longer marked waiting' );
3472
    is( $hold->priority, 1,  "Hold is now priority one again");
3471
    is( $hold->priority, 1,  "Hold is now priority one again");
3473
    is( $hold->waitingdate, undef, "Hold no longer has a waiting date");
3472
    is( $hold->waiting_date, undef, "Hold no longer has a waiting date");
3474
    is( $hold->itemnumber, $item->itemnumber, "Hold has retained its' itemnumber");
3473
    is( $hold->item_id, $item->itemnumber, "Hold has retained its' itemnumber");
3475
    is( $messages->{ResFound}->{ResFound}, "Reserved", "Hold is still returned");
3474
    is( $messages->{ResFound}->{ResFound}, "Reserved", "Hold is still returned");
3476
    is( $messages->{ResFound}->{found}, undef, "Hold is no longer marked found in return message");
3475
    is( $messages->{ResFound}->{status}, 'placed', "Hold is no longer marked found in return message");
3477
    is( $messages->{ResFound}->{priority}, 1, "Hold is priority 1 in return message");
3476
    is( $messages->{ResFound}->{priority}, 1, "Hold is priority 1 in return message");
3478
};
3477
};
3479
3478
Lines 4331-4343 subtest 'Filling a hold should cancel existing transfer' => sub { Link Here
4331
        biblionumber   => $item->biblionumber,
4330
        biblionumber   => $item->biblionumber,
4332
        itemnumber     => $item->itemnumber
4331
        itemnumber     => $item->itemnumber
4333
    });
4332
    });
4334
    my $reserves = Koha::Holds->search({ itemnumber => $item->itemnumber });
4333
    my $reserves = Koha::Holds->search({ item_id => $item->itemnumber });
4335
    is( $reserves->count, 1, "Reserve is placed");
4334
    is( $reserves->count, 1, "Reserve is placed");
4336
    ( undef, $message ) = AddReturn( $item->barcode, $libraryA->branchcode, undef, undef );
4335
    ( undef, $message ) = AddReturn( $item->barcode, $libraryA->branchcode, undef, undef );
4337
    my $reserve = $reserves->next;
4336
    my $reserve = $reserves->next;
4338
    ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 0, $reserve->reserve_id );
4337
    ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 0, $reserve->id );
4339
    $reserve->discard_changes;
4338
    $reserve->discard_changes;
4340
    ok( $reserve->found eq 'W', "Reserve is marked waiting" );
4339
    ok( $reserve->status eq 'waiting', "Reserve is marked waiting" );
4341
    is( Koha::Item::Transfers->search({ itemnumber => $item->itemnumber, datearrived => undef })->count, 0, "No outstanding transfers when hold is waiting");
4340
    is( Koha::Item::Transfers->search({ itemnumber => $item->itemnumber, datearrived => undef })->count, 0, "No outstanding transfers when hold is waiting");
4342
};
4341
};
4343
4342
Lines 4794-4800 subtest 'Checkout should correctly terminate a transfer' => sub { Link Here
4794
    GetOtherReserves( $item->itemnumber )
4793
    GetOtherReserves( $item->itemnumber )
4795
      ;    # To put the Reason, it's what does returns.pl...
4794
      ;    # To put the Reason, it's what does returns.pl...
4796
    my $hold = Koha::Holds->find($reserve_id);
4795
    my $hold = Koha::Holds->find($reserve_id);
4797
    is( $hold->found, 'T', 'Hold is in transit' );
4796
    is( $hold->status, 'in_transit', 'Hold is in transit' );
4798
    my $transfer = $item->get_transfer;
4797
    my $transfer = $item->get_transfer;
4799
    is( $transfer->frombranch, $library_1->branchcode );
4798
    is( $transfer->frombranch, $library_1->branchcode );
4800
    is( $transfer->tobranch,   $library_2->branchcode );
4799
    is( $transfer->tobranch,   $library_2->branchcode );
Lines 4805-4811 subtest 'Checkout should correctly terminate a transfer' => sub { Link Here
4805
    $transfer = $transfer->get_from_storage;
4804
    $transfer = $transfer->get_from_storage;
4806
    isnt( $transfer->datearrived, undef );
4805
    isnt( $transfer->datearrived, undef );
4807
    $hold = $hold->get_from_storage;
4806
    $hold = $hold->get_from_storage;
4808
    is( $hold->found, undef, 'Hold is waiting' );
4807
    is( $hold->status, 'placed', 'Hold is waiting' );
4809
    is( $hold->priority, 1, );
4808
    is( $hold->priority, 1, );
4810
};
4809
};
4811
4810
(-)a/t/db_dependent/Circulation/issue.t (-3 / +2 lines)
Lines 68-75 $dbh->do(q|DELETE FROM borrowers|); Link Here
68
$dbh->do(q|DELETE FROM categories|);
68
$dbh->do(q|DELETE FROM categories|);
69
$dbh->do(q|DELETE FROM accountlines|);
69
$dbh->do(q|DELETE FROM accountlines|);
70
$dbh->do(q|DELETE FROM circulation_rules|);
70
$dbh->do(q|DELETE FROM circulation_rules|);
71
$dbh->do(q|DELETE FROM reserves|);
71
$dbh->do(q|DELETE FROM holds|);
72
$dbh->do(q|DELETE FROM old_reserves|);
73
$dbh->do(q|DELETE FROM statistics|);
72
$dbh->do(q|DELETE FROM statistics|);
74
73
75
# Generate sample datas
74
# Generate sample datas
Lines 484-490 my $reserve_id = AddReserve( Link Here
484
ok( $reserve_id, 'The reserve should have been inserted' );
483
ok( $reserve_id, 'The reserve should have been inserted' );
485
AddIssue( $borrower_2, $barcode_1, dt_from_string, 'cancel' );
484
AddIssue( $borrower_2, $barcode_1, dt_from_string, 'cancel' );
486
my $hold = Koha::Holds->find( $reserve_id );
485
my $hold = Koha::Holds->find( $reserve_id );
487
is( $hold, undef, 'The reserve should have been correctly cancelled' );
486
is( $hold->status, 'cancelled', 'The reserve should have been correctly cancelled' );
488
487
489
# Unseen rewnewals
488
# Unseen rewnewals
490
t::lib::Mocks::mock_preference('UnseenRenewals', 1);
489
t::lib::Mocks::mock_preference('UnseenRenewals', 1);
(-)a/t/db_dependent/DecreaseLoanHighHolds.t (-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 234-264 subtest "delete() tests" => sub { Link Here
234
    # Disable logging
235
    # Disable logging
235
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
236
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
236
237
237
    my $hold = $builder->build({ source => 'Reserve' });
238
    my $hold    = $builder->build_object({ class => 'Koha::Holds' });
239
    my $hold_id = $hold->id;
240
    my $deleted = $hold->delete;
238
241
239
    my $hold_object = Koha::Holds->find( $hold->{ reserve_id } );
240
    my $deleted = $hold_object->delete;
241
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return the Koha::Hold object if the hold has been correctly deleted' );
242
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return the Koha::Hold object if the hold has been correctly deleted' );
242
    is( Koha::Holds->search({ reserve_id => $hold->{ reserve_id } })->count, 0,
243
    is( Koha::Holds->search({ id => $hold_id })->count, 0,
243
        "Koha::Hold->delete should have deleted the hold" );
244
        "Koha::Hold->delete should have deleted the hold" );
244
245
245
    my $number_of_logs = $schema->resultset('ActionLog')->search(
246
    my $number_of_logs = $schema->resultset('ActionLog')->search(
246
            { module => 'HOLDS', action => 'DELETE', object => $hold->{ reserve_id } } )->count;
247
            { module => 'HOLDS', action => 'DELETE', object => $hold_id } )->count;
247
    is( $number_of_logs, 0, 'With HoldsLogs, Koha::Hold->delete shouldn\'t have been logged' );
248
    is( $number_of_logs, 0, 'With HoldsLogs, Koha::Hold->delete shouldn\'t have been logged' );
248
249
249
    # Enable logging
250
    # Enable logging
250
    t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
251
    t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
251
252
252
    $hold = $builder->build({ source => 'Reserve' });
253
    $hold    = $builder->build_object({ class => 'Koha::Holds' });
254
    $hold_id = $hold->id;
255
    $deleted = $hold->delete;
253
256
254
    $hold_object = Koha::Holds->find( $hold->{ reserve_id } );
255
    $deleted = $hold_object->delete;
256
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return a Koha::Hold object if the hold has been correctly deleted' );
257
    is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return a Koha::Hold object if the hold has been correctly deleted' );
257
    is( Koha::Holds->search({ reserve_id => $hold->{ reserve_id } })->count, 0,
258
    is( Koha::Holds->search({ id => $hold_id })->count, 0,
258
        "Koha::Hold->delete should have deleted the hold" );
259
        "Koha::Hold->delete should have deleted the hold" );
259
260
260
    $number_of_logs = $schema->resultset('ActionLog')->search(
261
    $number_of_logs = $schema->resultset('ActionLog')->search(
261
            { module => 'HOLDS', action => 'DELETE', object => $hold->{ reserve_id } } )->count;
262
            { module => 'HOLDS', action => 'DELETE', object => $hold_id } )->count;
262
    is( $number_of_logs, 1, 'With HoldsLogs, Koha::Hold->delete should have been logged' );
263
    is( $number_of_logs, 1, 'With HoldsLogs, Koha::Hold->delete should have been logged' );
263
264
264
    $schema->storage->txn_rollback();
265
    $schema->storage->txn_rollback();
Lines 274-281 subtest 'suspend() tests' => sub { Link Here
274
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
275
    t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
275
276
276
    my $hold = $builder->build_object(
277
    my $hold = $builder->build_object(
277
        {   class => 'Koha::Holds',
278
        {
278
            value => { found => undef, suspend => 0, suspend_until => undef, waitingdate => undef }
279
            class => 'Koha::Holds',
280
            value => {
281
                status               => 'placed',
282
                suspended            => 0,
283
                suspended_until_date => undef,
284
                waiting_date         => undef
285
            }
279
        }
286
        }
280
    );
287
    );
281
288
Lines 284-290 subtest 'suspend() tests' => sub { Link Here
284
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
291
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
285
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
292
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
286
    ok( $suspended->is_suspended, 'The hold is suspended' );
293
    ok( $suspended->is_suspended, 'The hold is suspended' );
287
    is( $suspended->suspend_until, undef, 'It is an indefinite suspension' );
294
    is( $suspended->suspended_until_date, undef, 'It is an indefinite suspension' );
288
295
289
    # resume the hold
296
    # resume the hold
290
    $suspended->resume;
297
    $suspended->resume;
Lines 296-302 subtest 'suspend() tests' => sub { Link Here
296
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
303
    is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
297
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
304
    is( $suspended->id, $hold->id, 'suspend returns the same object' );
298
    ok( $suspended->is_suspended, 'The hold is suspended' );
305
    ok( $suspended->is_suspended, 'The hold is suspended' );
299
    is( $suspended->suspend_until, $date->truncate( to => 'day' ), 'It is an indefinite suspension' );
306
    is( $suspended->suspended_until_date, $date->truncate( to => 'day' ), 'It is an indefinite suspension' );
300
307
301
    # resume the hold
308
    # resume the hold
302
    $suspended->resume;
309
    $suspended->resume;
Lines 309-315 subtest 'suspend() tests' => sub { Link Here
309
        'Koha::Exceptions::Hold::CannotSuspendFound',
316
        'Koha::Exceptions::Hold::CannotSuspendFound',
310
        'Exception is thrown when a found hold is tried to suspend';
317
        'Exception is thrown when a found hold is tried to suspend';
311
318
312
    is( $@->status, 'W', 'Exception gets the \'status\' parameter set correctly' );
319
    is( $@->status, 'waiting', 'Exception gets the \'status\' parameter set correctly' );
313
320
314
    # set hold found=T
321
    # set hold found=T
315
    $hold->set_transfer;
322
    $hold->set_transfer;
Lines 318-324 subtest 'suspend() tests' => sub { Link Here
318
        'Koha::Exceptions::Hold::CannotSuspendFound',
325
        'Koha::Exceptions::Hold::CannotSuspendFound',
319
        'Exception is thrown when a found hold is tried to suspend';
326
        'Exception is thrown when a found hold is tried to suspend';
320
327
321
    is( $@->status, 'T', 'Exception gets the \'status\' parameter set correctly' );
328
    is( $@->status, 'in_transit', 'Exception gets the \'status\' parameter set correctly' );
322
329
323
    # set hold found=T
330
    # set hold found=T
324
    $hold->set_processing();
331
    $hold->set_processing();
Lines 333-339 subtest 'suspend() tests' => sub { Link Here
333
    $holds_module->mock( 'is_found', 1 );
340
    $holds_module->mock( 'is_found', 1 );
334
341
335
    # bad data case
342
    # bad data case
336
    $hold->found('X');
343
    $hold->status('cancelled');
337
    throws_ok
344
    throws_ok
338
        { $hold->suspend_hold }
345
        { $hold->suspend_hold }
339
        'Koha::Exceptions::Hold::CannotSuspendFound',
346
        'Koha::Exceptions::Hold::CannotSuspendFound',
Lines 341-348 subtest 'suspend() tests' => sub { Link Here
341
348
342
    is( $@->error, 'Unhandled data exception on found hold (id='
349
    is( $@->error, 'Unhandled data exception on found hold (id='
343
                    . $hold->id
350
                    . $hold->id
344
                    . ', found='
351
                    . ', status='
345
                    . $hold->found
352
                    . $hold->status
346
                    . ')' , 'Exception gets the \'status\' parameter set correctly' );
353
                    . ')' , 'Exception gets the \'status\' parameter set correctly' );
347
354
348
    $holds_module->unmock( 'is_found' );
355
    $holds_module->unmock( 'is_found' );
Lines 354-361 subtest 'suspend() tests' => sub { Link Here
354
            { module => 'HOLDS', action => 'SUSPEND', object => $hold->id } )->count;
361
            { module => 'HOLDS', action => 'SUSPEND', object => $hold->id } )->count;
355
362
356
    $hold = $builder->build_object(
363
    $hold = $builder->build_object(
357
        {   class => 'Koha::Holds',
364
        {
358
            value => { suspend => 0, suspend_until => undef, waitingdate => undef, found => undef }
365
            class => 'Koha::Holds',
366
            value => {
367
                suspended            => 0,
368
                suspended_until_date => undef,
369
                waiting_date         => undef,
370
                status               => 'placed'
371
            }
359
        }
372
        }
360
    );
373
    );
361
374
(-)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 669-675 is(CanItemBeReserved($borrowernumbers[0], $itemnumber)->{status}, 'OK', Link Here
669
t::lib::Mocks::mock_preference( 'item-level_itypes',     1 );
667
t::lib::Mocks::mock_preference( 'item-level_itypes',     1 );
670
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
668
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' );
671
669
672
$dbh->do('DELETE FROM reserves');
670
$dbh->do('DELETE FROM holds');
673
$dbh->do('DELETE FROM issues');
671
$dbh->do('DELETE FROM issues');
674
$dbh->do('DELETE FROM items');
672
$dbh->do('DELETE FROM items');
675
$dbh->do('DELETE FROM biblio');
673
$dbh->do('DELETE FROM biblio');
Lines 715-721 t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'PatronLibrary' ); Link Here
715
subtest 'Test max_holds per library/patron category' => sub {
713
subtest 'Test max_holds per library/patron category' => sub {
716
    plan tests => 6;
714
    plan tests => 6;
717
715
718
    $dbh->do('DELETE FROM reserves');
716
    $dbh->do('DELETE FROM holds');
719
717
720
    $biblio = $builder->build_sample_biblio;
718
    $biblio = $builder->build_sample_biblio;
721
    $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
719
    $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber})->itemnumber;
Lines 743-749 subtest 'Test max_holds per library/patron category' => sub { Link Here
743
    }
741
    }
744
742
745
    my $count =
743
    my $count =
746
      Koha::Holds->search( { borrowernumber => $borrowernumbers[0] } )->count();
744
      Koha::Holds->search( { patron_id => $borrowernumbers[0] } )->count();
747
    is( $count, 3, 'Patron now has 3 holds' );
745
    is( $count, 3, 'Patron now has 3 holds' );
748
746
749
    my $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
747
    my $ret = CanItemBeReserved( $borrowernumbers[0], $itemnumber );
Lines 928-934 subtest 'CanItemBeReserved / holds_per_day tests' => sub { Link Here
928
    # Update last hold so reservedate is in the past, so 2 holds, but different day
926
    # Update last hold so reservedate is in the past, so 2 holds, but different day
929
    $hold = Koha::Holds->find($res_id);
927
    $hold = Koha::Holds->find($res_id);
930
    my $yesterday = dt_from_string() - DateTime::Duration->new( days => 1 );
928
    my $yesterday = dt_from_string() - DateTime::Duration->new( days => 1 );
931
    $hold->reservedate($yesterday)->store;
929
    $hold->created_date($yesterday)->store;
932
930
933
    is_deeply(
931
    is_deeply(
934
        CanItemBeReserved( $patron->borrowernumber, $itemnumber_2 ),
932
        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 111-117 foreach ( $borrower_branchcode, $least_cost_branch_code, @other_branches ) { Link Here
111
}
111
}
112
112
113
# Remove existing reserves, makes debugging easier
113
# Remove existing reserves, makes debugging easier
114
$dbh->do("DELETE FROM reserves");
114
$dbh->do("DELETE FROM holds");
115
my $bibitems = undef;
115
my $bibitems = undef;
116
my $priority = 1;
116
my $priority = 1;
117
# Make a reserve
117
# Make a reserve
Lines 124-130 AddReserve( Link Here
124
    }
124
    }
125
);
125
);
126
#                           $resdate, $expdate, $notes, $title, $checkitem, $found
126
#                           $resdate, $expdate, $notes, $title, $checkitem, $found
127
$dbh->do("UPDATE reserves SET reservedate = DATE_SUB( reservedate, INTERVAL 1 DAY )");
127
$dbh->do("UPDATE holds SET created_date = DATE_SUB( created_date, INTERVAL 1 DAY )");
128
128
129
# Tests
129
# Tests
130
my $use_cost_matrix_sth = $dbh->prepare("UPDATE systempreferences SET value = ? WHERE variable = 'UseTransportCostMatrix'");
130
my $use_cost_matrix_sth = $dbh->prepare("UPDATE systempreferences SET value = ? WHERE variable = 'UseTransportCostMatrix'");
Lines 289-302 $items_insert_sth->execute( $barcode + 0, $branchcodes[0], $branchcodes[0] ); Link Here
289
$items_insert_sth->execute( $barcode + 1, $branchcodes[1], $branchcodes[1] );
289
$items_insert_sth->execute( $barcode + 1, $branchcodes[1], $branchcodes[1] );
290
$items_insert_sth->execute( $barcode + 2, $branchcodes[1], $branchcodes[1] );
290
$items_insert_sth->execute( $barcode + 2, $branchcodes[1], $branchcodes[1] );
291
291
292
$dbh->do("DELETE FROM reserves");
292
$dbh->do("DELETE FROM holds");
293
my $sth = $dbh->prepare(q{
293
my $sth = $dbh->prepare(q{
294
    INSERT INTO reserves (
294
    INSERT INTO holds (
295
        borrowernumber,
295
        patron_id,
296
        biblionumber,
296
        biblio_id,
297
        branchcode,
297
        pickup_library_id,
298
        priority,
298
        priority,
299
        reservedate
299
        created_date
300
    ) VALUES ( ?,?,?,?, CURRENT_DATE() )
300
    ) VALUES ( ?,?,?,?, CURRENT_DATE() )
301
});
301
});
302
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
302
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
Lines 384-390 $dbh->do("DELETE FROM issues"); Link Here
384
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
384
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
385
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
385
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
386
C4::Context->clear_syspref_cache();
386
C4::Context->clear_syspref_cache();
387
$dbh->do("DELETE FROM reserves");
387
$dbh->do("DELETE FROM holds");
388
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
388
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
389
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
389
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
390
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
390
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
Lines 402-408 t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary') Link Here
402
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
402
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
403
t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '1' );
403
t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '1' );
404
C4::Context->clear_syspref_cache();
404
C4::Context->clear_syspref_cache();
405
$dbh->do("DELETE FROM reserves");
405
$dbh->do("DELETE FROM holds");
406
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
406
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
407
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[1], 2 );
407
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[1], 2 );
408
408
Lines 444-450 t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '0' ); Link Here
444
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
444
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
445
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
445
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
446
C4::Context->clear_syspref_cache();
446
C4::Context->clear_syspref_cache();
447
$dbh->do("DELETE FROM reserves");
447
$dbh->do("DELETE FROM holds");
448
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
448
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
449
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
449
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
450
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
450
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
Lines 461-467 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue givi Link Here
461
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
461
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
462
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
462
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
463
C4::Context->clear_syspref_cache();
463
C4::Context->clear_syspref_cache();
464
$dbh->do("DELETE FROM reserves");
464
$dbh->do("DELETE FROM holds");
465
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
465
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
466
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
466
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
467
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
467
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
Lines 478-484 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue givi Link Here
478
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
478
t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
479
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
479
t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
480
C4::Context->clear_syspref_cache();
480
C4::Context->clear_syspref_cache();
481
$dbh->do("DELETE FROM reserves");
481
$dbh->do("DELETE FROM holds");
482
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
482
$sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
483
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
483
$sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
484
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
484
$sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
Lines 501-507 $borrowernumber = $borrower3->{borrowernumber}; Link Here
501
my $library_A = $library1->{branchcode};
501
my $library_A = $library1->{branchcode};
502
my $library_B = $library2->{branchcode};
502
my $library_B = $library2->{branchcode};
503
my $library_C = $borrower3->{branchcode};
503
my $library_C = $borrower3->{branchcode};
504
$dbh->do("DELETE FROM reserves");
504
$dbh->do("DELETE FROM holds");
505
$dbh->do("DELETE FROM issues");
505
$dbh->do("DELETE FROM issues");
506
$dbh->do("DELETE FROM items");
506
$dbh->do("DELETE FROM items");
507
$dbh->do("DELETE FROM biblio");
507
$dbh->do("DELETE FROM biblio");
Lines 566-572 $itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } Link Here
566
$borrowernumber = $borrower2->{borrowernumber};
566
$borrowernumber = $borrower2->{borrowernumber};
567
$library_A = $library1->{branchcode};
567
$library_A = $library1->{branchcode};
568
$library_B = $library2->{branchcode};
568
$library_B = $library2->{branchcode};
569
$dbh->do("DELETE FROM reserves");
569
$dbh->do("DELETE FROM holds");
570
$dbh->do("DELETE FROM issues");
570
$dbh->do("DELETE FROM issues");
571
$dbh->do("DELETE FROM items");
571
$dbh->do("DELETE FROM items");
572
$dbh->do("DELETE FROM biblio");
572
$dbh->do("DELETE FROM biblio");
Lines 619-625 $borrowernumber = $borrower3->{borrowernumber}; Link Here
619
$library_A = $library1->{branchcode};
619
$library_A = $library1->{branchcode};
620
$library_B = $library2->{branchcode};
620
$library_B = $library2->{branchcode};
621
$library_C = $library3->{branchcode};
621
$library_C = $library3->{branchcode};
622
$dbh->do("DELETE FROM reserves");
622
$dbh->do("DELETE FROM holds");
623
$dbh->do("DELETE FROM issues");
623
$dbh->do("DELETE FROM issues");
624
$dbh->do("DELETE FROM items");
624
$dbh->do("DELETE FROM items");
625
$dbh->do("DELETE FROM biblio");
625
$dbh->do("DELETE FROM biblio");
Lines 829-835 my $wrong_itemtype = $builder->build({ source => 'Itemtype', value => { notforlo Link Here
829
my $right_itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
829
my $right_itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
830
$borrowernumber = $borrower3->{borrowernumber};
830
$borrowernumber = $borrower3->{borrowernumber};
831
my $branchcode = $library1->{branchcode};
831
my $branchcode = $library1->{branchcode};
832
$dbh->do("DELETE FROM reserves");
832
$dbh->do("DELETE FROM holds");
833
$dbh->do("DELETE FROM issues");
833
$dbh->do("DELETE FROM issues");
834
$dbh->do("DELETE FROM items");
834
$dbh->do("DELETE FROM items");
835
$dbh->do("DELETE FROM biblio");
835
$dbh->do("DELETE FROM biblio");
Lines 1205-1211 subtest "Test Local Holds Priority - Ensure no duplicate requests in holds queue Link Here
1205
1205
1206
    $dbh->do("DELETE FROM tmp_holdsqueue");
1206
    $dbh->do("DELETE FROM tmp_holdsqueue");
1207
    $dbh->do("DELETE FROM hold_fill_targets");
1207
    $dbh->do("DELETE FROM hold_fill_targets");
1208
    $dbh->do("DELETE FROM reserves");
1208
    $dbh->do("DELETE FROM holds");
1209
    $dbh->do("DELETE FROM circulation_rules");
1209
    $dbh->do("DELETE FROM circulation_rules");
1210
    Koha::Biblios->delete();
1210
    Koha::Biblios->delete();
1211
1211
(-)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 551-565 subtest 'Holds test for branch transfer limits' => sub { Link Here
551
552
552
    $reply = C4::ILSDI::Services::HoldItem( $query );
553
    $reply = C4::ILSDI::Services::HoldItem( $query );
553
    is( $reply->{code}, undef, "Item hold, Item can be transferred" );
554
    is( $reply->{code}, undef, "Item hold, Item can be transferred" );
554
    my $hold = Koha::Holds->search({ itemnumber => $item->itemnumber, borrowernumber => $patron->{borrowernumber} })->next;
555
    my $hold = Koha::Holds->search({ item_id => $item->itemnumber, patron_id => $patron->{borrowernumber} })->next;
555
    is( $hold->branchcode, $pickup_branch->{branchcode}, 'The library id is correctly set' );
556
    is( $hold->pickup_library_id, $pickup_branch->{branchcode}, 'The library id is correctly set' );
556
557
557
    Koha::Holds->search()->delete();
558
    Koha::Holds->search()->delete();
558
559
559
    $reply = C4::ILSDI::Services::HoldTitle( $query );
560
    $reply = C4::ILSDI::Services::HoldTitle( $query );
560
    is( $reply->{code}, undef, "Record hold, Item con be transferred" );
561
    is( $reply->{code}, undef, "Record hold, Item con be transferred" );
561
    $hold = Koha::Holds->search({ biblionumber => $item->biblionumber, borrowernumber => $patron->{borrowernumber} })->next;
562
    $hold = Koha::Holds->search({ biblio_id => $item->biblionumber, patron_id => $patron->{borrowernumber} })->next;
562
    is( $hold->branchcode, $pickup_branch->{branchcode}, 'The library id is correctly set' );
563
    is( $hold->pickup_library_id, $pickup_branch->{branchcode}, 'The library id is correctly set' );
563
564
564
    $schema->storage->txn_rollback;
565
    $schema->storage->txn_rollback;
565
};
566
};
Lines 605-623 subtest 'Holds test with start_date and end_date' => sub { Link Here
605
606
606
    my $reply = C4::ILSDI::Services::HoldItem( $query );
607
    my $reply = C4::ILSDI::Services::HoldItem( $query );
607
    is ($reply->{pickup_location}, $pickup_library->branchname, "Item hold with date parameters was placed");
608
    is ($reply->{pickup_location}, $pickup_library->branchname, "Item hold with date parameters was placed");
608
    my $hold = Koha::Holds->search({ biblionumber => $item->biblionumber})->next();
609
    my $hold = Koha::Holds->search({ biblio_id => $item->biblionumber})->next();
609
    is( $hold->biblionumber, $item->biblionumber, "correct biblionumber");
610
    is( $hold->biblio_id, $item->biblionumber, "correct biblionumber");
610
    is( $hold->reservedate, '2020-03-20', "Item hold has correct start date" );
611
    is( $hold->created_date, '2020-03-20', "Item hold has correct start date" );
611
    is( $hold->expirationdate, '2020-04-22', "Item hold has correct end date" );
612
    is( $hold->expiration_date, '2020-04-22', "Item hold has correct end date" );
612
613
613
    $hold->delete();
614
    $hold->delete();
614
615
615
    $reply = C4::ILSDI::Services::HoldTitle( $query );
616
    $reply = C4::ILSDI::Services::HoldTitle( $query );
616
    is ($reply->{pickup_location}, $pickup_library->branchname, "Record hold with date parameters was placed");
617
    is ($reply->{pickup_location}, $pickup_library->branchname, "Record hold with date parameters was placed");
617
    $hold = Koha::Holds->search({ biblionumber => $item->biblionumber})->next();
618
    $hold = Koha::Holds->search({ biblio_id => $item->biblionumber})->next();
618
    is( $hold->biblionumber, $item->biblionumber, "correct biblionumber");
619
    is( $hold->biblio_id, $item->biblionumber, "correct biblionumber");
619
    is( $hold->reservedate, '2020-03-20', "Record hold has correct start date" );
620
    is( $hold->created_date, '2020-03-20', "Record hold has correct start date" );
620
    is( $hold->expirationdate, '2020-04-22', "Record hold has correct end date" );
621
    is( $hold->expiration_date, '2020-04-22', "Record hold has correct end date" );
621
622
622
    $schema->storage->txn_rollback;
623
    $schema->storage->txn_rollback;
623
};
624
};
(-)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 77-83 subtest 'holds + current_holds' => sub { Link Here
77
    my $holds = $biblio->holds;
77
    my $holds = $biblio->holds;
78
    is( ref($holds), 'Koha::Holds', '->holds should return a Koha::Holds object' );
78
    is( ref($holds), 'Koha::Holds', '->holds should return a Koha::Holds object' );
79
    is( $holds->count, 1, '->holds should only return 1 hold' );
79
    is( $holds->count, 1, '->holds should only return 1 hold' );
80
    is( $holds->next->borrowernumber, $patron->borrowernumber, '->holds should return the correct hold' );
80
    is( $holds->next->patron_id, $patron->borrowernumber, '->holds should return the correct hold' );
81
    $holds->delete;
81
    $holds->delete;
82
82
83
    # Add a hold in the future
83
    # Add a hold in the future
Lines 98-122 subtest 'holds + current_holds' => sub { Link Here
98
};
98
};
99
99
100
subtest 'waiting_or_in_transit' => sub {
100
subtest 'waiting_or_in_transit' => sub {
101
101
    plan tests => 4;
102
    plan tests => 4;
103
102
    my $item = $builder->build_sample_item;
104
    my $item = $builder->build_sample_item;
103
    my $reserve = $builder->build({
105
    my $hold = $builder->build_object({
104
        source => 'Reserve',
106
        class => 'Koha::Holds',
105
        value => {
107
        value => {
106
            biblionumber => $item->biblionumber,
108
            biblio_id => $item->biblionumber,
107
            found => undef
108
        }
109
        }
109
    });
110
    });
110
111
111
    $reserve = Koha::Holds->find($reserve->{reserve_id});
112
    $biblio = $item->biblio;
112
    $biblio = $item->biblio;
113
113
114
    is($biblio->has_items_waiting_or_intransit, 0, 'Item is neither waiting nor in transit');
114
    is($biblio->has_items_waiting_or_intransit, 0, 'Item is neither waiting nor in transit');
115
115
116
    $reserve->found('W')->store;
116
    $hold->set_waiting();
117
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is waiting');
117
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is waiting');
118
118
119
    $reserve->found('T')->store;
119
    $hold->set_transfer();
120
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is in transit');
120
    is($biblio->has_items_waiting_or_intransit, 1, 'Item is in transit');
121
121
122
    my $transfer = $builder->build({
122
    my $transfer = $builder->build({
Lines 128-134 subtest 'waiting_or_in_transit' => sub { Link Here
128
        }
128
        }
129
    });
129
    });
130
    my $t = Koha::Database->new()->schema()->resultset( 'Branchtransfer' )->find($transfer->{branchtransfer_id});
130
    my $t = Koha::Database->new()->schema()->resultset( 'Branchtransfer' )->find($transfer->{branchtransfer_id});
131
    $reserve->found(undef)->store;
131
    $hold->status('placed')->store;
132
    is($biblio->has_items_waiting_or_intransit, 1, 'Item has transfer');
132
    is($biblio->has_items_waiting_or_intransit, 1, 'Item has transfer');
133
};
133
};
134
134
(-)a/t/db_dependent/Koha/Club/Hold.t (-1 / +1 lines)
Lines 131-137 subtest 'add' => sub { Link Here
131
131
132
    my $hold = Koha::Holds->find($patron_hold->hold_id);
132
    my $hold = Koha::Holds->find($patron_hold->hold_id);
133
133
134
    is($patron_hold->patron_id, $hold->borrowernumber, 'Patron must be the same');
134
    is($patron_hold->patron_id, $hold->patron_id, 'Patron must be the same');
135
135
136
    $schema->storage->txn_rollback;
136
    $schema->storage->txn_rollback;
137
}
137
}
(-)a/t/db_dependent/Koha/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 1382-1395 subtest 'holds' => sub { Link Here
1382
        biblionumber => $biblio->biblionumber,
1382
        biblionumber => $biblio->biblionumber,
1383
    });
1383
    });
1384
    is($item->holds->count, 0, "Nothing returned if no holds");
1384
    is($item->holds->count, 0, "Nothing returned if no holds");
1385
    my $hold1 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'T' }});
1385
    my $hold1 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'in_transit', completed => 0 }});
1386
    my $hold2 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'W' }});
1386
    my $hold2 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'waiting', completed => 0 }});
1387
    my $hold3 = $builder->build({ source => 'Reserve', value => { itemnumber=>$item->itemnumber, found => 'W' }});
1387
    my $hold3 = $builder->build({ source => 'Hold', value => { item_id=>$item->itemnumber, status => 'waiting', completed => 0 }});
1388
1388
1389
    is($item->holds()->count,3,"Three holds found");
1389
    is($item->holds()->count,3,"Three holds found");
1390
    is($item->holds({found => 'W'})->count,2,"Two waiting holds found");
1390
    is($item->holds({status => 'waiting'})->count,2,"Two waiting holds found");
1391
    is_deeply($item->holds({found => 'T'})->next->unblessed,$hold1,"Found transit holds matches the hold");
1391
    is_deeply($item->holds({status => 'in_transit'})->next->unblessed,$hold1,"Found transit holds matches the hold");
1392
    is($item->holds({found => undef})->count, 0,"Nothing returned if no matching holds");
1392
    is($item->holds({status => 'placed'})->count, 0,"Nothing returned if no matching holds");
1393
};
1393
};
1394
1394
1395
subtest 'biblio' => sub {
1395
subtest 'biblio' => sub {
(-)a/t/db_dependent/Koha/Object.t (-2 / +2 lines)
Lines 272-278 subtest "to_api() tests" => sub { Link Here
272
272
273
    my $biblio = $builder->build_sample_biblio();
273
    my $biblio = $builder->build_sample_biblio();
274
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
274
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
275
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { itemnumber => $item->itemnumber } });
275
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { item_id => $item->itemnumber, completed => 0 } });
276
276
277
    my $embeds = { 'items' => {} };
277
    my $embeds = { 'items' => {} };
278
278
Lines 297-303 subtest "to_api() tests" => sub { Link Here
297
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
297
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
298
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
298
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
299
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
299
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
300
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->reserve_id, 'Hold matches');
300
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->id, 'Hold matches');
301
    is_deeply($biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root');
301
    is_deeply($biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root');
302
302
303
    my $hold_api = $hold->to_api(
303
    my $hold_api = $hold->to_api(
(-)a/t/db_dependent/Koha/Objects.t (-3 / +3 lines)
Lines 338-344 subtest "to_api() tests" => sub { Link Here
338
    my $hold_1   = $builder->build_object(
338
    my $hold_1   = $builder->build_object(
339
        {
339
        {
340
            class => 'Koha::Holds',
340
            class => 'Koha::Holds',
341
            value => { itemnumber => $item_1->itemnumber }
341
            value => { item_id => $item_1->itemnumber, completed => 0 }
342
        }
342
        }
343
    );
343
    );
344
344
Lines 347-353 subtest "to_api() tests" => sub { Link Here
347
    my $hold_2   = $builder->build_object(
347
    my $hold_2   = $builder->build_object(
348
        {
348
        {
349
            class => 'Koha::Holds',
349
            class => 'Koha::Holds',
350
            value => { itemnumber => $item_2->itemnumber }
350
            value => { item_id => $item_2->itemnumber, completed => 0 }
351
        }
351
        }
352
    );
352
    );
353
353
Lines 391-397 subtest "to_api() tests" => sub { Link Here
391
        ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
391
        ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
392
        is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches');
392
        is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches');
393
        ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
393
        ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
394
        is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->reserve_id, 'Hold matches');
394
        is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->id, 'Hold matches');
395
395
396
        $i++;
396
        $i++;
397
    }
397
    }
(-)a/t/db_dependent/Koha/Patrons.t (-7 / +7 lines)
Lines 469-476 subtest "delete" => sub { Link Here
469
    my $patron           = $builder->build( { source => 'Borrower' } );
469
    my $patron           = $builder->build( { source => 'Borrower' } );
470
    my $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} );
470
    my $retrieved_patron = Koha::Patrons->find( $patron->{borrowernumber} );
471
    my $hold             = $builder->build(
471
    my $hold             = $builder->build(
472
        {   source => 'Reserve',
472
        {   source => 'Hold',
473
            value  => { borrowernumber => $patron->{borrowernumber} }
473
            value  => { patron_id => $patron->{borrowernumber}, completed => 0 }
474
        }
474
        }
475
    );
475
    );
476
    my $list = $builder->build(
476
    my $list = $builder->build(
Lines 485-493 subtest "delete" => sub { Link Here
485
485
486
    is( Koha::Patrons->find( $patron->{borrowernumber} ), undef, 'Koha::Patron->delete should have deleted the patron' );
486
    is( Koha::Patrons->find( $patron->{borrowernumber} ), undef, 'Koha::Patron->delete should have deleted the patron' );
487
487
488
    is (Koha::Old::Holds->search( { reserve_id => $hold->{ reserve_id } } )->count, 1, q|Koha::Patron->delete should have cancelled patron's holds| );
488
    is (Koha::Holds->search( { id => $hold->{id}, status => 'cancelled' } )->count, 1, q|Koha::Patron->delete should have cancelled patron's holds| );
489
489
490
    is( Koha::Holds->search( { borrowernumber => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have cancelled patron's holds 2| );
490
    is( Koha::Holds->search( { patron_id => $patron->{borrowernumber}, completed => 0 } )->count, 0, q|Koha::Patron->delete should have cancelled patron's holds 2| );
491
491
492
    is( Koha::Virtualshelves->search( { owner => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have deleted patron's lists| );
492
    is( Koha::Virtualshelves->search( { owner => $patron->{borrowernumber} } )->count, 0, q|Koha::Patron->delete should have deleted patron's lists| );
493
493
Lines 993-1000 subtest 'holds and old_holds' => sub { Link Here
993
    is( $holds->count, 2, 'There should be 2 holds placed by this patron' );
993
    is( $holds->count, 2, 'There should be 2 holds placed by this patron' );
994
994
995
    my $old_holds = $patron->old_holds;
995
    my $old_holds = $patron->old_holds;
996
    is( ref($old_holds), 'Koha::Old::Holds',
996
    is( ref($old_holds), 'Koha::Holds',
997
        'Koha::Patron->old_holds should return a Koha::Old::Holds objects' );
997
        'Koha::Patron->old_holds should return a Koha::Holds objects' );
998
    is( $old_holds->count, 0, 'There should not be any old holds yet');
998
    is( $old_holds->count, 0, 'There should not be any old holds yet');
999
999
1000
    my $hold = $holds->next;
1000
    my $hold = $holds->next;
Lines 2028-2034 subtest 'lock' => sub { Link Here
2028
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
2028
    my $patron2 = $builder->build_object( { class => 'Koha::Patrons' } );
2029
    my $hold = $builder->build_object({
2029
    my $hold = $builder->build_object({
2030
        class => 'Koha::Holds',
2030
        class => 'Koha::Holds',
2031
        value => { borrowernumber => $patron1->borrowernumber },
2031
        value => { patron_id => $patron1->borrowernumber, completed => 0 },
2032
    });
2032
    });
2033
2033
2034
    t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 3 );
2034
    t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 3 );
(-)a/t/db_dependent/Koha/Z3950Responder/Session.t (-1 / +1 lines)
Lines 32-38 subtest 'add_item_status' => sub { Link Here
32
    my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField( "items.itemnumber" );
32
    my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField( "items.itemnumber" );
33
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
33
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
34
    my $item_field_1 = scalar $item_marc_1->field($itemtag);
34
    my $item_field_1 = scalar $item_marc_1->field($itemtag);
35
    $builder->build({ source => 'Reserve', value=> { itemnumber => $item_1->itemnumber } });
35
    $builder->build({ source => 'Hold', value=> { item_id => $item_1->itemnumber } });
36
    $builder->build(
36
    $builder->build(
37
        {
37
        {
38
            source => 'Branchtransfer',
38
            source => 'Branchtransfer',
(-)a/t/db_dependent/Koha/Z3950Responder/Session2.t (-1 / +1 lines)
Lines 55-61 subtest 'add_item_status' => sub { Link Here
55
    );
55
    );
56
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
56
    my $item_marc_1 = C4::Items::GetMarcItem( $item_1->biblionumber, $item_1->itemnumber );
57
    my $item_field_1 = scalar $item_marc_1->field('952');
57
    my $item_field_1 = scalar $item_marc_1->field('952');
58
    $builder->build({ source => 'Reserve', value=> { itemnumber => $item_1->itemnumber } });
58
    $builder->build({ source => 'Hold', value=> { item_id => $item_1->itemnumber } });
59
    $builder->build(
59
    $builder->build(
60
        {
60
        {
61
            source => 'Branchtransfer',
61
            source => 'Branchtransfer',
(-)a/t/db_dependent/Letters/TemplateToolkit.t (-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 123-129 my ($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber, $barcod Link Here
123
123
124
is($status, "Reserved", "CheckReserves Test 1");
124
is($status, "Reserved", "CheckReserves Test 1");
125
125
126
ok(exists($reserve->{reserve_id}), 'CheckReserves() include reserve_id in its response');
126
ok(exists($reserve->{id}), 'CheckReserves() include reserve_id in its response');
127
127
128
($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber);
128
($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber);
129
is($status, "Reserved", "CheckReserves Test 2");
129
is($status, "Reserved", "CheckReserves Test 2");
Lines 267-280 ModReserveAffect($itemnum_cpl, $requesters{$branch_3}, 0); Link Here
267
267
268
# Now it should have different priorities.
268
# Now it should have different priorities.
269
my $biblio = Koha::Biblios->find( $bibnum2 );
269
my $biblio = Koha::Biblios->find( $bibnum2 );
270
my $holds = $biblio->holds({}, { order_by => 'reserve_id' });;
270
my $holds = $biblio->holds({}, { order_by => 'id' });;
271
is($holds->next->priority, 0, 'Item is correctly waiting');
271
is($holds->next->priority, 0, 'Item is correctly waiting');
272
is($holds->next->priority, 1, 'Item is correctly priority 1');
272
is($holds->next->priority, 1, 'Item is correctly priority 1');
273
is($holds->next->priority, 2, 'Item is correctly priority 2');
273
is($holds->next->priority, 2, 'Item is correctly priority 2');
274
274
275
my @reserves = Koha::Holds->search({ borrowernumber => $requesters{$branch_3} })->waiting();
275
my @reserves = Koha::Holds->search({ patron_id => $requesters{$branch_3} })->waiting();
276
is( @reserves, 1, 'GetWaiting got only the waiting reserve' );
276
is( @reserves, 1, 'GetWaiting got only the waiting reserve' );
277
is( $reserves[0]->borrowernumber(), $requesters{$branch_3}, 'GetWaiting got the reserve for the correct borrower' );
277
is( $reserves[0]->patron_id(), $requesters{$branch_3}, 'GetWaiting got the reserve for the correct borrower' );
278
278
279
279
280
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum2));
280
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum2));
Lines 312-318 my $messages; Link Here
312
# the one placed by the CPL patron, as the other two patron's hold
312
# the one placed by the CPL patron, as the other two patron's hold
313
# requests cannot be filled by that item per policy.
313
# requests cannot be filled by that item per policy.
314
(undef, $messages, undef, undef) = AddReturn('bug10272_CPL', $branch_2);
314
(undef, $messages, undef, undef) = AddReturn('bug10272_CPL', $branch_2);
315
is( $messages->{ResFound}->{borrowernumber},
315
is( $messages->{ResFound}->{patron_id},
316
    $requesters{$branch_1},
316
    $requesters{$branch_1},
317
    'restrictive library\'s items only fill requests by own patrons (bug 10272)');
317
    'restrictive library\'s items only fill requests by own patrons (bug 10272)');
318
318
Lines 324-342 is( $messages->{ResFound}->{borrowernumber}, Link Here
324
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', '' );
324
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', '' );
325
325
326
(undef, $messages, undef, undef) = AddReturn('bug10272_FPL', $branch_2);
326
(undef, $messages, undef, undef) = AddReturn('bug10272_FPL', $branch_2);
327
is( $messages->{ResFound}->{borrowernumber},
327
is( $messages->{ResFound}->{patron_id},
328
    $requesters{$branch_3},
328
    $requesters{$branch_3},
329
    'for generous library, its items fill first hold request in line (bug 10272)');
329
    'for generous library, its items fill first hold request in line (bug 10272)');
330
330
331
$biblio = Koha::Biblios->find( $biblionumber );
331
$biblio = Koha::Biblios->find( $biblionumber );
332
$holds = $biblio->holds;
332
$holds = $biblio->holds;
333
is($holds->count, 1, "Only one reserves for this biblio");
333
is($holds->count, 1, "Only one reserves for this biblio");
334
$holds->next->reserve_id;
335
334
336
# Tests for bug 9761 (ConfirmFutureHolds): new CheckReserves lookahead parameter, and corresponding change in AddReturn
335
# Tests for bug 9761 (ConfirmFutureHolds): new CheckReserves lookahead parameter, and corresponding change in AddReturn
337
# Note that CheckReserve uses its lookahead parameter and does not check ConfirmFutureHolds pref (it should be passed if needed like AddReturn does)
336
# Note that CheckReserve uses its lookahead parameter and does not check ConfirmFutureHolds pref (it should be passed if needed like AddReturn does)
338
# Test 9761a: Add a reserve without date, CheckReserve should return it
337
# Test 9761a: Add a reserve without date, CheckReserve should return it
339
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
338
$dbh->do("DELETE FROM holds WHERE biblio_id=?",undef,($bibnum));
340
AddReserve(
339
AddReserve(
341
    {
340
    {
342
        branchcode     => $branch_1,
341
        branchcode     => $branch_1,
Lines 404-410 is($new_count, $hold_notice_count + 1, 'patron not notified a second time (bug 1 Link Here
404
t::lib::Mocks::mock_preference('IndependentBranches', 0);
403
t::lib::Mocks::mock_preference('IndependentBranches', 0);
405
$item = Koha::Items->find($item->itemnumber);
404
$item = Koha::Items->find($item->itemnumber);
406
is(
405
is(
407
    $item->safe_delete,
406
    $item->safe_to_delete,
408
    'book_reserved',
407
    'book_reserved',
409
    'item that is captured to fill a hold cannot be deleted',
408
    'item that is captured to fill a hold cannot be deleted',
410
);
409
);
Lines 432-438 AddReserve( Link Here
432
431
433
$holds = $item->current_holds;
432
$holds = $item->current_holds;
434
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
433
my $dtf = Koha::Database->new->schema->storage->datetime_parser;
435
my $future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
434
my $future_holds = $holds->search({ created_date => { '>' => $dtf->format_date( dt_from_string ) } } );
436
is( $future_holds->count, 0, 'current_holds does not return a future next available hold');
435
is( $future_holds->count, 0, 'current_holds does not return a future next available hold');
437
# 9788b: current_holds does not return future item level hold
436
# 9788b: current_holds does not return future item level hold
438
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
437
$dbh->do("DELETE FROM reserves WHERE biblionumber=?",undef,($bibnum));
Lines 446-456 AddReserve( Link Here
446
        itemnumber       => $item->itemnumber,
445
        itemnumber       => $item->itemnumber,
447
    }
446
    }
448
); #item level hold
447
); #item level hold
449
$future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
448
$future_holds = $holds->search({ created_date => { '>' => $dtf->format_date( dt_from_string ) } } );
450
is( $future_holds->count, 0, 'current_holds does not return a future item level hold' );
449
is( $future_holds->count, 0, 'current_holds does not return a future item level hold' );
451
# 9788c: current_holds returns future wait (confirmed future hold)
450
# 9788c: current_holds returns future wait (confirmed future hold)
452
ModReserveAffect( $item->itemnumber,  $requesters{$branch_1} , 0); #confirm hold
451
ModReserveAffect( $item->itemnumber,  $requesters{$branch_1} , 0); #confirm hold
453
$future_holds = $holds->search({ reservedate => { '>' => $dtf->format_date( dt_from_string ) } } );
452
$future_holds = $holds->search({ created_date => { '>' => $dtf->format_date( dt_from_string ) } } );
454
is( $future_holds->count, 1, 'current_holds returns a future wait (confirmed future hold)' );
453
is( $future_holds->count, 1, 'current_holds returns a future wait (confirmed future hold)' );
455
# End of tests for bug 9788
454
# End of tests for bug 9788
456
455
Lines 544-560 is( Link Here
544
    'CanReserveBeCanceledFromOpac should return undef if called without borrowernumber'
543
    'CanReserveBeCanceledFromOpac should return undef if called without borrowernumber'
545
);
544
);
546
545
547
my $cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
546
my $cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
548
is($cancancel, 1, 'Can user cancel its own reserve');
547
is($cancancel, 1, 'Can user cancel its own reserve');
549
548
550
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_2});
549
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_2});
551
is($cancancel, 0, 'Other user cant cancel reserve');
550
is($cancancel, 0, 'Other user cant cancel reserve');
552
551
553
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 1);
552
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 1);
554
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
553
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
555
is($cancancel, 0, 'Reserve in transfer status cant be canceled');
554
is($cancancel, 0, 'Reserve in transfer status cant be canceled');
556
555
557
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
556
$dbh->do('DELETE FROM holds', undef, ($bibnum));
558
AddReserve(
557
AddReserve(
559
    {
558
    {
560
        branchcode     => $branch_1,
559
        branchcode     => $branch_1,
Lines 566-572 AddReserve( Link Here
566
(undef, $canres, undef) = CheckReserves($item->itemnumber);
565
(undef, $canres, undef) = CheckReserves($item->itemnumber);
567
566
568
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 0);
567
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 0);
569
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
568
$cancancel = CanReserveBeCanceledFromOpac($canres->{id}, $requesters{$branch_1});
570
is($cancancel, 0, 'Reserve in waiting status cant be canceled');
569
is($cancancel, 0, 'Reserve in waiting status cant be canceled');
571
570
572
# End of tests for bug 12876
571
# End of tests for bug 12876
Lines 634-640 Koha::CirculationRules->set_rules( Link Here
634
633
635
# tests for MoveReserve in relation to ConfirmFutureHolds (BZ 14526)
634
# tests for MoveReserve in relation to ConfirmFutureHolds (BZ 14526)
636
#   hold from A pos 1, today, no fut holds: MoveReserve should fill it
635
#   hold from A pos 1, today, no fut holds: MoveReserve should fill it
637
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
636
$dbh->do('DELETE FROM holds');
638
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 0);
637
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 0);
639
t::lib::Mocks::mock_preference('AllowHoldDateInFuture', 1);
638
t::lib::Mocks::mock_preference('AllowHoldDateInFuture', 1);
640
AddReserve(
639
AddReserve(
Lines 655-661 AddReserve( Link Here
655
        borrowernumber => $borrowernumber,
654
        borrowernumber => $borrowernumber,
656
        biblionumber   => $bibnum,
655
        biblionumber   => $bibnum,
657
        priority       => 1,
656
        priority       => 1,
658
        found          => 'W',
657
        found          => 'waiting',
659
    }
658
    }
660
);
659
);
661
MoveReserve( $item->itemnumber, $borrowernumber );
660
MoveReserve( $item->itemnumber, $borrowernumber );
Lines 829-841 subtest 'ReservesNeedReturns' => sub { Link Here
829
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 1); # Test with feature disabled
828
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 1); # Test with feature disabled
830
    my $hold = place_item_hold( $patron, $item, $library, $priority );
829
    my $hold = place_item_hold( $patron, $item, $library, $priority );
831
    is( $hold->priority, $priority, 'If ReservesNeedReturns is 1, priority must not have been set to changed' );
830
    is( $hold->priority, $priority, 'If ReservesNeedReturns is 1, priority must not have been set to changed' );
832
    is( $hold->found, undef, 'If ReservesNeedReturns is 1, found must not have been set waiting' );
831
    is( $hold->status, 'placed', 'If ReservesNeedReturns is 1, status must not have been set waiting' );
833
    $hold->delete;
832
    $hold->delete;
834
833
835
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 0); # '0' means 'Automatically mark a hold as found and waiting'
834
    t::lib::Mocks::mock_preference('ReservesNeedReturns', 0); # '0' means 'Automatically mark a hold as status and waiting'
836
    $hold = place_item_hold( $patron, $item, $library, $priority );
835
    $hold = place_item_hold( $patron, $item, $library, $priority );
837
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
836
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
838
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
837
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and no other status, status must have been set waiting' );
839
    $hold->delete;
838
    $hold->delete;
840
839
841
    $item->onloan('2010-01-01')->store;
840
    $item->onloan('2010-01-01')->store;
Lines 851-861 subtest 'ReservesNeedReturns' => sub { Link Here
851
    t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1); # '0' means damaged holds not allowed
850
    t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1); # '0' means damaged holds not allowed
852
    $hold = place_item_hold( $patron, $item, $library, $priority );
851
    $hold = place_item_hold( $patron, $item, $library, $priority );
853
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and damaged holds allowed, priority must have been set to 0' );
852
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and damaged holds allowed, priority must have been set to 0' );
854
    is( $hold->found,  'W', 'If ReservesNeedReturns is 0 and damaged holds allowed, found must have been set waiting' );
853
    is( $hold->status,  'waiting', 'If ReservesNeedReturns is 0 and damaged holds allowed, status must have been set waiting' );
855
    $hold->delete;
854
    $hold->delete;
856
855
857
    my $hold_1 = place_item_hold( $patron, $item, $library, $priority );
856
    my $hold_1 = place_item_hold( $patron, $item, $library, $priority );
858
    is( $hold_1->found,  'W', 'First hold on item is set to waiting with ReservesNeedReturns set to 0' );
857
    is( $hold_1->status,  'waiting', 'First hold on item is set to waiting with ReservesNeedReturns set to 0' );
859
    is( $hold_1->priority, 0, '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' );
860
    $hold = place_item_hold( $patron_2, $item, $library, $priority );
859
    $hold = place_item_hold( $patron_2, $item, $library, $priority );
861
    is( $hold->priority, 1, 'If ReservesNeedReturns is 0 but item already on hold priority must be set to 1' );
860
    is( $hold->priority, 1, 'If ReservesNeedReturns is 0 but item already on hold priority must be set to 1' );
Lines 872-892 subtest 'ReservesNeedReturns' => sub { Link Here
872
    });
871
    });
873
    $item->damaged(0)->store;
872
    $item->damaged(0)->store;
874
    $hold = place_item_hold( $patron, $item, $library, $priority );
873
    $hold = place_item_hold( $patron, $item, $library, $priority );
875
    is( $hold->found, undef, 'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
874
    is( $hold->status, 'placed', 'If ReservesNeedReturns is 0 but item in transit the hold must not be set to waiting' );
876
    is( $hold->priority, 1,  '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' );
877
    $hold->delete;
876
    $hold->delete;
878
    $transfer->delete;
877
    $transfer->delete;
879
878
880
    $hold = place_item_hold( $patron, $item, $library, $priority );
879
    $hold = place_item_hold( $patron, $item, $library, $priority );
881
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
880
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and no other status, priority must have been set to 0' );
882
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
881
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and no other status, found must have been set waiting' );
883
    $hold_1 = place_item_hold( $patron, $item, $library, $priority );
882
    $hold_1 = place_item_hold( $patron, $item, $library, $priority );
884
    is( $hold_1->priority, 1, 'If ReservesNeedReturns is 0 but item has a hold priority is 1' );
883
    is( $hold_1->priority, 1, 'If ReservesNeedReturns is 0 but item has a hold priority is 1' );
885
    $hold_1->suspend(1)->store; # We suspend the hold
884
    $hold_1->suspended(1)->store; # We suspend the hold
886
    $hold->delete; # Delete the waiting hold
885
    $hold->delete; # Delete the waiting hold
887
    $hold = place_item_hold( $patron, $item, $library, $priority );
886
    $hold = place_item_hold( $patron, $item, $library, $priority );
888
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and other hold(s) suspended, priority must have been set to 0' );
887
    is( $hold->priority, 0, 'If ReservesNeedReturns is 0 and other hold(s) suspended, priority must have been set to 0' );
889
    is( $hold->found, 'W', 'If ReservesNeedReturns is 0 and other  hold(s) suspended, found must have been set waiting' );
888
    is( $hold->status, 'waiting', 'If ReservesNeedReturns is 0 and other  hold(s) suspended, found must have been set waiting' );
890
889
891
890
892
891
Lines 932-937 subtest 'reserves.item_level_hold' => sub { Link Here
932
931
933
    subtest 'item level hold' => sub {
932
    subtest 'item level hold' => sub {
934
        plan tests => 2;
933
        plan tests => 2;
934
935
        $schema->storage->txn_begin;
936
935
        my $reserve_id = AddReserve(
937
        my $reserve_id = AddReserve(
936
            {
938
            {
937
                branchcode     => $item->homebranch,
939
                branchcode     => $item->homebranch,
Lines 943-962 subtest 'reserves.item_level_hold' => sub { Link Here
943
        );
945
        );
944
946
945
        my $hold = Koha::Holds->find($reserve_id);
947
        my $hold = Koha::Holds->find($reserve_id);
946
        is( $hold->item_level_hold, 1, 'item_level_hold should be set when AddReserve is called with a specific item' );
948
        is( $hold->item_level, 1, 'item_level should be set when AddReserve is called with a specific item' );
947
949
948
        # Mark it waiting
950
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber );
949
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 1 );
950
951
951
        # Revert the waiting status
952
        # Revert the waiting status
952
        C4::Reserves::RevertWaitingStatus(
953
        C4::Reserves::RevertWaitingStatus(
953
            { itemnumber => $item->itemnumber } );
954
            { itemnumber => $item->itemnumber } );
954
955
955
        $hold = Koha::Holds->find($reserve_id);
956
        $hold->discard_changes;
956
957
957
        is( $hold->itemnumber, $item->itemnumber, 'Itemnumber should not be removed when the waiting status is revert' );
958
        is( $hold->item_id, $item->itemnumber, 'Itemnumber should not be removed when the waiting status is revert' );
958
959
959
        $hold->delete;    # cleanup
960
        $schema->storage->txn_rollback;
960
    };
961
    };
961
962
962
    subtest 'biblio level hold' => sub {
963
    subtest 'biblio level hold' => sub {
Lines 971-989 subtest 'reserves.item_level_hold' => sub { Link Here
971
        );
972
        );
972
973
973
        my $hold = Koha::Holds->find($reserve_id);
974
        my $hold = Koha::Holds->find($reserve_id);
974
        is( $hold->item_level_hold, 0, 'item_level_hold should not be set when AddReserve is called without a specific item' );
975
        is( $hold->item_level, 0, 'item_level should not be set when AddReserve is called without a specific item' );
975
976
976
        # Mark it waiting
977
        # Mark it waiting
977
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber, 1 );
978
        ModReserveAffect( $item->itemnumber, $patron->borrowernumber );
978
979
979
        $hold = Koha::Holds->find($reserve_id);
980
        $hold = Koha::Holds->find($reserve_id);
980
        is( $hold->itemnumber, $item->itemnumber, 'Itemnumber should be set on hold confirmation' );
981
        is( $hold->item_id, $item->itemnumber, 'Itemnumber should be set on hold confirmation' );
981
982
982
        # Revert the waiting status
983
        # Revert the waiting status
983
        C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
984
        C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
984
985
985
        $hold = Koha::Holds->find($reserve_id);
986
        $hold = Koha::Holds->find($reserve_id);
986
        is( $hold->itemnumber, undef, 'Itemnumber should be removed when the waiting status is revert' );
987
        is( $hold->item_id, undef, 'Itemnumber should be removed when the waiting status is revert' );
987
988
988
        $hold->delete;
989
        $hold->delete;
989
    };
990
    };
Lines 1021-1036 subtest 'MoveReserve additional test' => sub { Link Here
1021
            itemnumber     => $item_1->itemnumber,
1022
            itemnumber     => $item_1->itemnumber,
1022
        }
1023
        }
1023
    );
1024
    );
1024
    is($patron_1->holds->next()->reserve_id, $reserve_1, "The 1st patron has a hold");
1025
    is($patron_1->holds->next()->id, $reserve_1, "The 1st patron has a hold");
1025
    is($patron_2->holds->next()->reserve_id, $reserve_2, "The 2nd patron has a hold");
1026
    is($patron_2->holds->next()->id, $reserve_2, "The 2nd patron has a hold");
1026
1027
1027
    # Fake the holds queue
1028
    # Fake the holds queue
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));
1029
    $dbh->do(q{INSERT INTO hold_fill_targets VALUES (?, ?, ?, ?, ?,?)},undef,($patron_1->borrowernumber,$biblio->biblionumber,$item_1->itemnumber,$item_1->homebranch,0,$reserve_1));
1029
1030
1030
    # The 2nd hold should be filed even if the item is preselected for the first hold
1031
    # The 2nd hold should be filed even if the item is preselected for the first hold
1031
    MoveReserve($item_1->itemnumber,$patron_2->borrowernumber);
1032
    MoveReserve($item_1->itemnumber,$patron_2->borrowernumber);
1032
    is($patron_2->holds->count, 0, "The 2nd patrons no longer has a hold");
1033
    is($patron_2->holds({ completed => 0 })->count, 0, "The 2nd patrons no longer has a hold");
1033
    is($patron_2->old_holds->next()->reserve_id, $reserve_2, "The 2nd patrons hold was filled and moved to old holds");
1034
    is($patron_2->holds({ completed => 1 })->next()->id, $reserve_2, "The 2nd patrons hold was filled and moved to old holds");
1034
1035
1035
};
1036
};
1036
1037
Lines 1086-1103 subtest 'CheckReserves additional tests' => sub { Link Here
1086
        {
1087
        {
1087
            class => "Koha::Holds",
1088
            class => "Koha::Holds",
1088
            value => {
1089
            value => {
1089
                found            => undef,
1090
                priority         => 1,
1090
                priority         => 1,
1091
                itemnumber       => undef,
1091
                item_id          => undef,
1092
                biblionumber     => $item->biblionumber,
1092
                biblio_id        => $item->biblionumber,
1093
                waitingdate      => undef,
1093
                item_level       => 0,
1094
                cancellationdate => undef,
1094
                lowest_priority  => 0,
1095
                item_level_hold  => 0,
1095
                expiration_date  => undef,
1096
                lowestPriority   => 0,
1097
                expirationdate   => undef,
1098
                suspend_until    => undef,
1099
                suspend          => 0,
1100
                itemtype         => undef,
1101
            }
1096
            }
1102
        }
1097
        }
1103
    );
1098
    );
Lines 1105-1123 subtest 'CheckReserves additional tests' => sub { Link Here
1105
        {
1100
        {
1106
            class => "Koha::Holds",
1101
            class => "Koha::Holds",
1107
            value => {
1102
            value => {
1108
                found            => undef,
1109
                priority         => 2,
1103
                priority         => 2,
1110
                biblionumber     => $item->biblionumber,
1104
                item_id          => $item->biblionumber,
1111
                borrowernumber   => $reserve1->borrowernumber,
1105
                patron_id        => $reserve1->patron_id,
1112
                itemnumber       => undef,
1106
                item_id          => undef,
1113
                waitingdate      => undef,
1107
                suspended_until  => undef,
1114
                cancellationdate => undef,
1108
                suspended        => 0,
1115
                item_level_hold  => 0,
1109
                item_type       => undef,
1116
                lowestPriority   => 0,
1117
                expirationdate   => undef,
1118
                suspend_until    => undef,
1119
                suspend          => 0,
1120
                itemtype         => undef,
1121
            }
1110
            }
1122
        }
1111
        }
1123
    );
1112
    );
Lines 1126-1133 subtest 'CheckReserves additional tests' => sub { Link Here
1126
        {
1115
        {
1127
            source => 'TmpHoldsqueue',
1116
            source => 'TmpHoldsqueue',
1128
            value  => {
1117
            value  => {
1129
                borrowernumber => $reserve1->borrowernumber,
1118
                borrowernumber => $reserve1->patron_id,
1130
                biblionumber   => $reserve1->biblionumber,
1119
                biblionumber   => $reserve1->biblio_id,
1131
            }
1120
            }
1132
        }
1121
        }
1133
    );
1122
    );
Lines 1135-1156 subtest 'CheckReserves additional tests' => sub { Link Here
1135
        {
1124
        {
1136
            source => 'HoldFillTarget',
1125
            source => 'HoldFillTarget',
1137
            value  => {
1126
            value  => {
1138
                borrowernumber     => $reserve1->borrowernumber,
1127
                borrowernumber     => $reserve1->patron_id,
1139
                biblionumber       => $reserve1->biblionumber,
1128
                biblionumber       => $reserve1->biblio_id,
1140
                itemnumber         => $item->itemnumber,
1129
                itemnumber         => $item->itemnumber,
1141
                item_level_request => 0,
1130
                item_level_request => 0,
1142
            }
1131
            }
1143
        }
1132
        }
1144
    );
1133
    );
1145
1134
1146
    ModReserveAffect( $item->itemnumber, $reserve1->borrowernumber, 1,
1135
    ModReserveAffect( $item->itemnumber, $reserve1->patron_id, 1,
1147
        $reserve1->reserve_id );
1136
        $reserve1->id );
1148
    my ( $status, $matched_reserve, $possible_reserves ) =
1137
    my ( $status, $matched_reserve, $possible_reserves ) =
1149
      CheckReserves( $item->itemnumber );
1138
      CheckReserves( $item->itemnumber );
1150
1139
1151
    is( $status, 'Transferred', "We found a reserve" );
1140
    is( $status, 'Transferred', "We found a reserve" );
1152
    is( $matched_reserve->{reserve_id},
1141
    is( $matched_reserve->{reserve_id},
1153
        $reserve1->reserve_id, "We got the Transit reserve" );
1142
        $reserve1->id, "We got the Transit reserve" );
1154
    is( scalar @$possible_reserves, 2, 'We do get both reserves' );
1143
    is( scalar @$possible_reserves, 2, 'We do get both reserves' );
1155
1144
1156
    my $patron_B = $builder->build_object({ class => "Koha::Patrons" });
1145
    my $patron_B = $builder->build_object({ class => "Koha::Patrons" });
(-)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 250-260 subtest 'Test build with NULL values' => sub { Link Here
250
    is( $info->{is_nullable} && $item && !defined( $item->{barcode} ), 1,
250
    is( $info->{is_nullable} && $item && !defined( $item->{barcode} ), 1,
251
        'Barcode can be NULL' );
251
        'Barcode can be NULL' );
252
    # Nullable FK
252
    # Nullable FK
253
    $params = { source => 'Reserve', value  => { itemnumber => undef }};
253
    $params = { source => 'Hold', value  => { item_id => undef }};
254
    my $reserve = $builder->build( $params );
254
    my $hold = $builder->build( $params );
255
    $info = $schema->source( 'Reserve' )->column_info( 'itemnumber' );
255
    $info = $schema->source( 'Hold' )->column_info( 'item_id' );
256
    is( $reserve && $info->{is_nullable} && $info->{is_foreign_key} &&
256
    is( $hold && $info->{is_nullable} && $info->{is_foreign_key} &&
257
        !defined( $reserve->{itemnumber} ), 1, 'Nullable FK' );
257
        !defined( $hold->{item_id} ), 1, 'Nullable FK' );
258
};
258
};
259
259
260
260
Lines 396-401 subtest 'build_object() tests' => sub { Link Here
396
            $module =~ s|^.*/(Koha.*)\.pm$|$1|;
396
            $module =~ s|^.*/(Koha.*)\.pm$|$1|;
397
            $module =~ s|/|::|g;
397
            $module =~ s|/|::|g;
398
            next if $module eq 'Koha::Objects';
398
            next if $module eq 'Koha::Objects';
399
            next if $module eq 'Koha::Old::Holds'; #This is a view now
399
            eval "require $module";
400
            eval "require $module";
400
            my $object = $builder->build_object( { class => $module } );
401
            my $object = $builder->build_object( { class => $module } );
401
            is( ref($object), $module->object_class, "Testing $module" );
402
            is( ref($object), $module->object_class, "Testing $module" );
(-)a/t/db_dependent/XSLT.t (-4 / +5 lines)
Lines 117-126 subtest 'buildKohaItemsNamespace status tests' => sub { Link Here
117
    like($xml,qr{<status>In transit</status>},"In-transit status takes precedence over Damaged");
117
    like($xml,qr{<status>In transit</status>},"In-transit status takes precedence over Damaged");
118
118
119
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
119
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
120
        biblionumber => $item->biblionumber,
120
        biblio_id => $item->biblionumber,
121
        itemnumber   => $item->itemnumber,
121
        item_id   => $item->itemnumber,
122
        found        => 'W',
122
        status    => 'waiting',
123
        priority     => 0,
123
        priority  => 0,
124
        completed => 0,
124
        }
125
        }
125
    });
126
    });
126
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
127
    $xml = C4::XSLT::buildKohaItemsNamespace( $item->biblionumber,[]);
(-)a/t/db_dependent/api/v1/holds.t (-37 / +47 lines)
Lines 162-169 my $post_data = { Link Here
162
    expiration_date   => output_pref( { dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 } ),
162
    expiration_date   => output_pref( { dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 } ),
163
};
163
};
164
my $patch_data = {
164
my $patch_data = {
165
    priority        => 2,
165
    priority             => 2,
166
    suspended_until => output_pref( { dt => $suspended_until, dateformat => 'rfc3339' } ),
166
    suspended_until_date => output_pref( { dt => $suspended_until, dateformat => 'rfc3339' } ),
167
};
167
};
168
168
169
subtest "Test endpoints without authentication" => sub {
169
subtest "Test endpoints without authentication" => sub {
Lines 329-336 subtest 'test AllowHoldDateInFuture' => sub { Link Here
329
        biblio_id         => $biblio_1->biblionumber,
329
        biblio_id         => $biblio_1->biblionumber,
330
        item_id           => $item_1->itemnumber,
330
        item_id           => $item_1->itemnumber,
331
        pickup_library_id => $branchcode,
331
        pickup_library_id => $branchcode,
332
        expiration_date   => output_pref( { dt => $expiration_date,  dateformat => 'rfc3339', dateonly => 1 } ),
332
        expiration_date   => output_pref({ dt => $expiration_date, dateformat => 'rfc3339', dateonly => 1 }),
333
        hold_date         => output_pref( { dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 } ),
333
        created_date      => output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }),
334
        priority          => 2,
334
    };
335
    };
335
336
336
    t::lib::Mocks::mock_preference( 'AllowHoldDateInFuture', 0 );
337
    t::lib::Mocks::mock_preference( 'AllowHoldDateInFuture', 0 );
Lines 349-355 subtest 'test AllowHoldDateInFuture' => sub { Link Here
349
350
350
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
351
    $t->post_ok( "//$userid_3:$password@/api/v1/holds" => json => $post_data )
351
      ->status_is(201)
352
      ->status_is(201)
352
      ->json_is('/hold_date', output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }));
353
      ->json_is('/created_date', output_pref({ dt => $future_hold_date, dateformat => 'rfc3339', dateonly => 1 }));
353
};
354
};
354
355
355
$schema->storage->txn_rollback;
356
$schema->storage->txn_rollback;
Lines 471-477 subtest 'suspend and resume tests' => sub { Link Here
471
472
472
    my $hold = $builder->build_object(
473
    my $hold = $builder->build_object(
473
        {   class => 'Koha::Holds',
474
        {   class => 'Koha::Holds',
474
            value => { suspend => 0, suspend_until => undef, waitingdate => undef, found => undef }
475
            value => {
476
                suspended    => 0,
477
                waiting_date => undef,
478
                suspended_until_date => undef,
479
                completed => 0
480
            }
475
        }
481
        }
476
    );
482
    );
477
483
Lines 482-488 subtest 'suspend and resume tests' => sub { Link Here
482
    $hold->discard_changes;    # refresh object
488
    $hold->discard_changes;    # refresh object
483
489
484
    ok( $hold->is_suspended, 'Hold is suspended' );
490
    ok( $hold->is_suspended, 'Hold is suspended' );
485
    $t->json_is('/end_date', undef, 'Hold suspension has no end date');
491
    $t->json_is('/suspended_until_date', undef, 'Hold suspension has no end date');
486
492
487
    my $end_date = output_pref({
493
    my $end_date = output_pref({
488
      dt         => dt_from_string( undef ),
494
      dt         => dt_from_string( undef ),
Lines 498-504 subtest 'suspend and resume tests' => sub { Link Here
498
    $t->json_is(
504
    $t->json_is(
499
      '/end_date',
505
      '/end_date',
500
      output_pref({
506
      output_pref({
501
        dt         => dt_from_string( $hold->suspend_until ),
507
        dt         => dt_from_string( $hold->suspended_until_date ),
502
        dateformat => 'rfc3339',
508
        dateformat => 'rfc3339',
503
        dateonly   => 1
509
        dateonly   => 1
504
      }),
510
      }),
Lines 531-543 subtest 'suspend and resume tests' => sub { Link Here
531
537
532
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
538
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
533
      ->status_is( 400, 'Cannot suspend waiting hold' )
539
      ->status_is( 400, 'Cannot suspend waiting hold' )
534
      ->json_is( '/error', 'Found hold cannot be suspended. Status=W' );
540
      ->json_is( '/error', 'Found hold cannot be suspended. Status=waiting' );
535
541
536
    $hold->set_transfer->discard_changes;
542
    $hold->set_transfer->discard_changes;
537
543
538
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
544
    $t->post_ok( "//$userid:$password@/api/v1/holds/" . $hold->id . "/suspension" )
539
      ->status_is( 400, 'Cannot suspend hold on transfer' )
545
      ->status_is( 400, 'Cannot suspend hold on transfer' )
540
      ->json_is( '/error', 'Found hold cannot be suspended. Status=T' );
546
      ->json_is( '/error', 'Found hold cannot be suspended. Status=in_transit' );
541
547
542
    $schema->storage->txn_rollback;
548
    $schema->storage->txn_rollback;
543
};
549
};
Lines 837-856 subtest 'pickup_locations() tests' => sub { Link Here
837
        {
843
        {
838
            class => 'Koha::Holds',
844
            class => 'Koha::Holds',
839
            value => {
845
            value => {
840
                itemnumber     => undef,
846
                item_id   => undef,
841
                biblionumber   => $item->biblionumber,
847
                biblio_id => $item->biblionumber,
842
                borrowernumber => $patron->borrowernumber
848
                patron_id => $patron->borrowernumber,
849
                completed => 0,
843
            }
850
            }
844
        }
851
        }
845
    );
852
    );
853
846
    # item-level hold
854
    # item-level hold
847
    my $hold_2 = $builder->build_object(
855
    my $hold_2 = $builder->build_object(
848
        {
856
        {
849
            class => 'Koha::Holds',
857
            class => 'Koha::Holds',
850
            value => {
858
            value => {
851
                itemnumber     => $item->itemnumber,
859
                item_id   => $item->itemnumber,
852
                biblionumber   => $item->biblionumber,
860
                biblio_id => $item->biblionumber,
853
                borrowernumber => $patron->borrowernumber
861
                patron_id => $patron->borrowernumber,
862
                completed => 0,
854
            }
863
            }
855
        }
864
        }
856
    );
865
    );
Lines 943-952 subtest 'edit() tests' => sub { Link Here
943
        {
952
        {
944
            class => "Koha::Holds",
953
            class => "Koha::Holds",
945
            value => {
954
            value => {
946
                biblionumber => $biblio->biblionumber,
955
                biblio_id         => $biblio->biblionumber,
947
                branchcode   => $library_3->branchcode,
956
                pickup_library_id => $library_3->branchcode,
948
                itemnumber   => undef,
957
                item_id           => undef,
949
                priority     => 1,
958
                priority          => 1,
959
                completed         => 0,
950
            }
960
            }
951
        }
961
        }
952
    );
962
    );
Lines 970-976 subtest 'edit() tests' => sub { Link Here
970
      ->json_is({ error => 'The supplied pickup location is not valid' });
980
      ->json_is({ error => 'The supplied pickup location is not valid' });
971
981
972
    $biblio_hold->discard_changes;
982
    $biblio_hold->discard_changes;
973
    is( $biblio_hold->branchcode, $library_3->branchcode, 'branchcode remains untouched' );
983
    is( $biblio_hold->pickup_library_id, $library_3->branchcode, 'pickup_library_id remains untouched' );
974
984
975
    $t->patch_ok( "//$userid:$password@/api/v1/holds/" . $biblio_hold->id
985
    $t->patch_ok( "//$userid:$password@/api/v1/holds/" . $biblio_hold->id
976
          => { 'x-koha-override' => 'any' }
986
          => { 'x-koha-override' => 'any' }
Lines 999-1015 subtest 'edit() tests' => sub { Link Here
999
      ->status_is(200);
1009
      ->status_is(200);
1000
1010
1001
    $biblio_hold->discard_changes;
1011
    $biblio_hold->discard_changes;
1002
    is( $biblio_hold->branchcode, $library_2->id, 'Pickup location changed correctly' );
1012
    is( $biblio_hold->pickup_library_id, $library_2->id, 'Pickup location changed correctly' );
1003
1013
1004
    # Test item-level holds
1014
    # Test item-level holds
1005
    my $item_hold = $builder->build_object(
1015
    my $item_hold = $builder->build_object(
1006
        {
1016
        {
1007
            class => "Koha::Holds",
1017
            class => "Koha::Holds",
1008
            value => {
1018
            value => {
1009
                biblionumber => $biblio->biblionumber,
1019
                biblio_id         => $biblio->biblionumber,
1010
                branchcode   => $library_3->branchcode,
1020
                pickup_library_id => $library_3->branchcode,
1011
                itemnumber   => $item->itemnumber,
1021
                item_id           => $item->itemnumber,
1012
                priority     => 1,
1022
                priority          => 1,
1023
                completed         => 0,
1013
            }
1024
            }
1014
        }
1025
        }
1015
    );
1026
    );
Lines 1033-1039 subtest 'edit() tests' => sub { Link Here
1033
      ->json_is({ error => 'The supplied pickup location is not valid' });
1044
      ->json_is({ error => 'The supplied pickup location is not valid' });
1034
1045
1035
    $item_hold->discard_changes;
1046
    $item_hold->discard_changes;
1036
    is( $item_hold->branchcode, $library_3->branchcode, 'branchcode remains untouched' );
1047
    is( $item_hold->pickup_library_id, $library_3->branchcode, 'branchcode remains untouched' );
1037
1048
1038
    $t->patch_ok( "//$userid:$password@/api/v1/holds/" . $item_hold->id
1049
    $t->patch_ok( "//$userid:$password@/api/v1/holds/" . $item_hold->id
1039
          => { 'x-koha-override' => 'any' }
1050
          => { 'x-koha-override' => 'any' }
Lines 1059-1065 subtest 'edit() tests' => sub { Link Here
1059
      ->status_is(200);
1070
      ->status_is(200);
1060
1071
1061
    $item_hold->discard_changes;
1072
    $item_hold->discard_changes;
1062
    is( $item_hold->branchcode, $library_2->id, 'Pickup location changed correctly' );
1073
    is( $item_hold->pickup_library_id, $library_2->id, 'Pickup location changed correctly' );
1063
1074
1064
    $schema->storage->txn_rollback;
1075
    $schema->storage->txn_rollback;
1065
};
1076
};
Lines 1131-1140 subtest 'add() tests' => sub { Link Here
1131
        {
1142
        {
1132
            class => "Koha::Holds",
1143
            class => "Koha::Holds",
1133
            value => {
1144
            value => {
1134
                biblionumber => $biblio->biblionumber,
1145
                biblio_id         => $biblio->biblionumber,
1135
                branchcode   => $library_3->branchcode,
1146
                pickup_library_id => $library_3->branchcode,
1136
                itemnumber   => undef,
1147
                item_id           => undef,
1137
                priority     => 1,
1148
                priority          => 1,
1138
            }
1149
            }
1139
        }
1150
        }
1140
    );
1151
    );
Lines 1160-1169 subtest 'add() tests' => sub { Link Here
1160
        {
1171
        {
1161
            class => "Koha::Holds",
1172
            class => "Koha::Holds",
1162
            value => {
1173
            value => {
1163
                biblionumber => $biblio->biblionumber,
1174
                biblio_id         => $biblio->biblionumber,
1164
                branchcode   => $library_3->branchcode,
1175
                pickup_library_id => $library_3->branchcode,
1165
                itemnumber   => $item->itemnumber,
1176
                item_id           => $item->itemnumber,
1166
                priority     => 1,
1177
                priority          => 1,
1167
            }
1178
            }
1168
        }
1179
        }
1169
    );
1180
    );
1170
- 

Return to bug 25260