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

(-)a/C4/HoldsQueue.pm (-38 / +91 lines)
Lines 732-782 sub MapItemsToHoldRequests { Link Here
732
    my $num_items_remaining = scalar(@$available_items);
732
    my $num_items_remaining = scalar(@$available_items);
733
733
734
    # Look for Local Holds Priority matches first
734
    # Look for Local Holds Priority matches first
735
    if ( C4::Context->preference( 'LocalHoldsPriority' ne "None" ) ) {
735
736
    my $LocalHoldsPriority = C4::Context->preference('LocalHoldsPriority');
737
    if ( $LocalHoldsPriority ne 'None' ) {
736
        my $LocalHoldsPriorityPatronControl = C4::Context->preference('LocalHoldsPriorityPatronControl');
738
        my $LocalHoldsPriorityPatronControl = C4::Context->preference('LocalHoldsPriorityPatronControl');
737
        my $LocalHoldsPriorityItemControl   = C4::Context->preference('LocalHoldsPriorityItemControl');
739
        my $LocalHoldsPriorityItemControl   = C4::Context->preference('LocalHoldsPriorityItemControl');
738
739
        foreach my $request (@$hold_requests) {
740
        foreach my $request (@$hold_requests) {
740
            last if $num_items_remaining == 0;
741
            last if $num_items_remaining == 0;
741
            my $patron = Koha::Patrons->find( $request->{borrowernumber} );
742
            my $patron = Koha::Patrons->find( $request->{borrowernumber} );
742
            next if $patron->category->exclude_from_local_holds_priority;
743
            next if $patron->category->exclude_from_local_holds_priority;
744
            if ( $LocalHoldsPriority eq 'GiveLibrary' || $LocalHoldsPriority eq 'GiveLibraryAndGroup' ) {
745
                my $local_hold_match;
746
                foreach my $item (@$available_items) {
747
                    next if $item->{_object}->exclude_from_local_holds_priority;
748
749
                    next unless _can_item_fill_request( $item, $request, $libraries );
750
751
                    next if $request->{itemnumber} && $request->{itemnumber} != $item->{itemnumber};
752
753
                    my $local_holds_priority_item_branchcode = $item->{$LocalHoldsPriorityItemControl};
754
755
                    my $local_holds_priority_patron_branchcode =
756
                          ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' ) ? $request->{branchcode}
757
                        : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )   ? $request->{borrowerbranch}
758
                        :                                                           undef;
759
760
                    $local_hold_match =
761
                        $local_holds_priority_item_branchcode eq $local_holds_priority_patron_branchcode;
762
763
                    if ($local_hold_match) {
764
                        if (    exists $items_by_itemnumber{ $item->{itemnumber} }
765
                            and not exists $allocated_items{ $item->{itemnumber} }
766
                            and not $request->{allocated} )
767
                        {
768
                            $item_map{ $item->{itemnumber} } = {
769
                                borrowernumber => $request->{borrowernumber},
770
                                biblionumber   => $request->{biblionumber},
771
                                holdingbranch  => $item->{holdingbranch},
772
                                pickup_branch  => $request->{branchcode}
773
                                    || $request->{borrowerbranch},
774
                                reserve_id   => $request->{reserve_id},
775
                                item_level   => $request->{item_level_hold},
776
                                reservedate  => $request->{reservedate},
777
                                reservenotes => $request->{reservenotes},
778
                            };
779
                            $allocated_items{ $item->{itemnumber} }++;
780
                            $request->{allocated} = 1;
781
                            $num_items_remaining--;
782
                        }
783
                    }
784
                }
785
            }
786
        }
743
787
744
            my $local_hold_match;
788
        # Look for local group matches if no library matches were found
745
            foreach my $item (@$available_items) {
789
        if ( $LocalHoldsPriority eq 'GiveLibraryGroup' || $LocalHoldsPriority eq 'GiveLibraryAndGroup' ) {
746
                next if $item->{_object}->exclude_from_local_holds_priority;
790
            my $local_hold_group_match;
747
791
            foreach my $request (@$hold_requests) {
748
                next unless _can_item_fill_request( $item, $request, $libraries );
792
                last if $num_items_remaining == 0;
749
793
                my $patron = Koha::Patrons->find( $request->{borrowernumber} );
750
                next if $request->{itemnumber} && $request->{itemnumber} != $item->{itemnumber};
794
                next if $patron->category->exclude_from_local_holds_priority;
751
795
                foreach my $item (@$available_items) {
752
                my $local_holds_priority_item_branchcode = $item->{$LocalHoldsPriorityItemControl};
796
                    next if $item->{_object}->exclude_from_local_holds_priority;
753
797
754
                my $local_holds_priority_patron_branchcode =
798
                    next unless _can_item_fill_request( $item, $request, $libraries );
755
                      ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' ) ? $request->{branchcode}
799
756
                    : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )   ? $request->{borrowerbranch}
800
                    next if $request->{itemnumber} && $request->{itemnumber} != $item->{itemnumber};
757
                    :                                                           undef;
801
758
802
                    my $local_holds_priority_item_branchcode = $item->{$LocalHoldsPriorityItemControl};
759
                $local_hold_match = $local_holds_priority_item_branchcode eq $local_holds_priority_patron_branchcode;
803
760
804
                    my $local_holds_priority_patron_branchcode =
761
                if ($local_hold_match) {
805
                          ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' ) ? $request->{branchcode}
762
                    if (    exists $items_by_itemnumber{ $item->{itemnumber} }
806
                        : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )   ? $request->{borrowerbranch}
763
                        and not exists $allocated_items{ $item->{itemnumber} }
807
                        :                                                           undef;
764
                        and not $request->{allocated} )
808
765
                    {
809
                    $local_hold_group_match =
766
                        $item_map{ $item->{itemnumber} } = {
810
                        Koha::Libraries->find( { branchcode => $local_holds_priority_item_branchcode } )
767
                            borrowernumber => $request->{borrowernumber},
811
                        ->validate_hold_sibling( { branchcode => $local_holds_priority_patron_branchcode } );
768
                            biblionumber   => $request->{biblionumber},
812
769
                            holdingbranch  => $item->{holdingbranch},
813
                    if ($local_hold_group_match) {
770
                            pickup_branch  => $request->{branchcode}
814
                        if (    exists $items_by_itemnumber{ $item->{itemnumber} }
771
                                || $request->{borrowerbranch},
815
                            and not exists $allocated_items{ $item->{itemnumber} }
772
                            reserve_id   => $request->{reserve_id},
816
                            and not $request->{allocated} )
773
                            item_level   => $request->{item_level_hold},
817
                        {
774
                            reservedate  => $request->{reservedate},
818
                            $item_map{ $item->{itemnumber} } = {
775
                            reservenotes => $request->{reservenotes},
819
                                borrowernumber => $request->{borrowernumber},
776
                        };
820
                                biblionumber   => $request->{biblionumber},
777
                        $allocated_items{ $item->{itemnumber} }++;
821
                                holdingbranch  => $item->{holdingbranch},
778
                        $request->{allocated} = 1;
822
                                pickup_branch  => $request->{branchcode}
779
                        $num_items_remaining--;
823
                                    || $request->{borrowerbranch},
824
                                reserve_id   => $request->{reserve_id},
825
                                item_level   => $request->{item_level_hold},
826
                                reservedate  => $request->{reservedate},
827
                                reservenotes => $request->{reservenotes},
828
                            };
829
                            $allocated_items{ $item->{itemnumber} }++;
830
                            $request->{allocated} = 1;
831
                            $num_items_remaining--;
832
                        }
780
                    }
833
                    }
781
                }
834
                }
782
            }
835
            }
(-)a/installer/data/mysql/mandatory/sysprefs.sql (-1 / +1 lines)
Lines 395-401 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
395
('LoadCheckoutsTableDelay','0','','Delay before auto-loading checkouts table on checkouts screen','Integer'),
395
('LoadCheckoutsTableDelay','0','','Delay before auto-loading checkouts table on checkouts screen','Integer'),
396
('LoadSearchHistoryToTheFirstLoggedUser', '1', NULL, 'If ON, the next user will automatically get the last searches in their history', 'YesNo'),
396
('LoadSearchHistoryToTheFirstLoggedUser', '1', NULL, 'If ON, the next user will automatically get the last searches in their history', 'YesNo'),
397
('LocalCoverImages','0','1','Display local cover images on intranet details pages.','YesNo'),
397
('LocalCoverImages','0','1','Display local cover images on intranet details pages.','YesNo'),
398
('LocalHoldsPriority',  'None', 'GiveLibrary|None|GiveLibraryGroup|GiveLibraryAndGroup' 'Enables the LocalHoldsPriority feature', 'None'  'Choice'),
398
('LocalHoldsPriority',  'None', 'GiveLibrary|None|GiveLibraryGroup|GiveLibraryAndGroup' 'Enables the LocalHoldsPriority feature', 'Choice'),
399
('LocalHoldsPriorityItemControl',  'holdingbranch',  'holdingbranch|homebranch',  'decides if the feature operates using the item''s home or holding library.',  'Choice'),
399
('LocalHoldsPriorityItemControl',  'holdingbranch',  'holdingbranch|homebranch',  'decides if the feature operates using the item''s home or holding library.',  'Choice'),
400
('LocalHoldsPriorityPatronControl',  'PickupLibrary',  'HomeLibrary|PickupLibrary',  'decides if the feature operates using the library set as the patron''s home library, or the library set as the pickup library for the given hold.',  'Choice'),
400
('LocalHoldsPriorityPatronControl',  'PickupLibrary',  'HomeLibrary|PickupLibrary',  'decides if the feature operates using the library set as the patron''s home library, or the library set as the pickup library for the given hold.',  'Choice'),
401
('LockExpiredDelay','','','Delay for locking expired patrons (empty means no locking)','Integer'),
401
('LockExpiredDelay','','','Delay for locking expired patrons (empty means no locking)','Integer'),
(-)a/t/db_dependent/Holds/LocalHoldsPriority.t (-5 / +5 lines)
Lines 112-118 foreach ( 0 .. $borrowers_count - 1 ) { Link Here
112
# Create five record level holds
112
# Create five record level holds
113
AddReserve(
113
AddReserve(
114
    {
114
    {
115
        branchcode     => $library1,
115
        branchcode     => $library1->{branchcode},
116
        borrowernumber => $borrowernumbers[0],
116
        borrowernumber => $borrowernumbers[0],
117
        biblionumber   => $item->biblionumber,
117
        biblionumber   => $item->biblionumber,
118
        priority       => 1,
118
        priority       => 1,
Lines 120-126 AddReserve( Link Here
120
);
120
);
121
AddReserve(
121
AddReserve(
122
    {
122
    {
123
        branchcode     => $library2,
123
        branchcode     => $library2->{branchcode},
124
        borrowernumber => $borrowernumbers[1],
124
        borrowernumber => $borrowernumbers[1],
125
        biblionumber   => $item->biblionumber,
125
        biblionumber   => $item->biblionumber,
126
        priority       => 1,
126
        priority       => 1,
Lines 128-134 AddReserve( Link Here
128
);
128
);
129
AddReserve(
129
AddReserve(
130
    {
130
    {
131
        branchcode     => $library3,
131
        branchcode     => $library3->{branchcode},
132
        borrowernumber => $borrowernumbers[2],
132
        borrowernumber => $borrowernumbers[2],
133
        biblionumber   => $item->biblionumber,
133
        biblionumber   => $item->biblionumber,
134
        priority       => 1,
134
        priority       => 1,
Lines 136-142 AddReserve( Link Here
136
);
136
);
137
AddReserve(
137
AddReserve(
138
    {
138
    {
139
        branchcode     => $library4,
139
        branchcode     => $library4->{branchcode},
140
        borrowernumber => $borrowernumbers[3],
140
        borrowernumber => $borrowernumbers[3],
141
        biblionumber   => $item->biblionumber,
141
        biblionumber   => $item->biblionumber,
142
        priority       => 1,
142
        priority       => 1,
Lines 257-263 subtest 'LocalHoldsPriority, GiveLibraryGroup' => sub { #Test hold group only Link Here
257
    ( $status, $reserve, $all_reserves ) = CheckReserves($item);
257
    ( $status, $reserve, $all_reserves ) = CheckReserves($item);
258
    ok(
258
    ok(
259
        $reserve->{borrowernumber} eq $borrowernumbers[3],
259
        $reserve->{borrowernumber} eq $borrowernumbers[3],
260
        "Local patron in group is given priority when patron home library and item home branch matchh"
260
        "Local patron in group is given priority when patron home library and item home branch match"
261
    );
261
    );
262
};
262
};
263
263
(-)a/t/db_dependent/HoldsQueue.t (-13 / +12 lines)
Lines 84-90 my $itemtype = $builder->build( { source => 'Itemtype', value => { Link Here
84
#Set up the stage
84
#Set up the stage
85
# Sysprefs and cost matrix
85
# Sysprefs and cost matrix
86
t::lib::Mocks::mock_preference( 'HoldsQueueSkipClosed', 0 );
86
t::lib::Mocks::mock_preference( 'HoldsQueueSkipClosed', 0 );
87
t::lib::Mocks::mock_preference( 'LocalHoldsPriority',   0 );
87
t::lib::Mocks::mock_preference( 'LocalHoldsPriority',   'None' );
88
$dbh->do(
88
$dbh->do(
89
    "UPDATE systempreferences SET value = ? WHERE variable = 'StaticHoldsQueueWeight'", undef,
89
    "UPDATE systempreferences SET value = ? WHERE variable = 'StaticHoldsQueueWeight'", undef,
90
    join( ',', @other_branches, $borrower_branchcode, $least_cost_branch_code )
90
    join( ',', @other_branches, $borrower_branchcode, $least_cost_branch_code )
Lines 436-442 is( scalar(@$holds_queue), 2, "Holds not filled with items from closed libraries Link Here
436
t::lib::Mocks::mock_preference( 'HoldsQueueSkipClosed', 0 );
436
t::lib::Mocks::mock_preference( 'HoldsQueueSkipClosed', 0 );
437
437
438
## Test LocalHoldsPriority
438
## Test LocalHoldsPriority
439
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
439
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 'GiveLibrary' );
440
440
441
$dbh->do("DELETE FROM circulation_rules");
441
$dbh->do("DELETE FROM circulation_rules");
442
Koha::CirculationRules->set_rule(
442
Koha::CirculationRules->set_rule(
Lines 583-589 is( Link Here
583
    "Holds queue giving priority to patron who's home library matches item's holding library"
583
    "Holds queue giving priority to patron who's home library matches item's holding library"
584
);
584
);
585
585
586
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 0 );
586
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 'None' );
587
## End testing of LocalHoldsPriority
587
## End testing of LocalHoldsPriority
588
588
589
# Bug 14297
589
# Bug 14297
Lines 1018-1024 subtest "Test Local Holds Priority - Bib level" => sub { Link Here
1018
    plan tests => 3;
1018
    plan tests => 3;
1019
1019
1020
    Koha::Biblios->delete();
1020
    Koha::Biblios->delete();
1021
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              1 );
1021
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              'GiveLibrary' );
1022
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1022
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1023
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1023
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1024
    my $branch   = $builder->build_object( { class => 'Koha::Libraries' } );
1024
    my $branch   = $builder->build_object( { class => 'Koha::Libraries' } );
Lines 1089-1095 subtest "Test Local Holds Priority - Item level" => sub { Link Here
1089
    plan tests => 2;
1089
    plan tests => 2;
1090
1090
1091
    Koha::Biblios->delete();
1091
    Koha::Biblios->delete();
1092
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              1 );
1092
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              'GiveLibrary' );
1093
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1093
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1094
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1094
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1095
    my $branch   = $builder->build_object( { class => 'Koha::Libraries' } );
1095
    my $branch   = $builder->build_object( { class => 'Koha::Libraries' } );
Lines 1161-1167 subtest "Test Local Holds Priority - Item level hold over Record level hold (Bug Link Here
1161
    plan tests => 2;
1161
    plan tests => 2;
1162
1162
1163
    Koha::Biblios->delete();
1163
    Koha::Biblios->delete();
1164
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              1 );
1164
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              'GiveLibrary' );
1165
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1165
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1166
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1166
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1167
    my $branch   = $builder->build_object( { class => 'Koha::Libraries' } );
1167
    my $branch   = $builder->build_object( { class => 'Koha::Libraries' } );
Lines 1232-1238 subtest "Test Local Holds Priority - Get correct item for item level hold" => su Link Here
1232
    plan tests => 3;
1232
    plan tests => 3;
1233
1233
1234
    Koha::Biblios->delete();
1234
    Koha::Biblios->delete();
1235
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              1 );
1235
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              'GiveLibrary' );
1236
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1236
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1237
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1237
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1238
    my $branch   = $builder->build_object( { class => 'Koha::Libraries' } );
1238
    my $branch   = $builder->build_object( { class => 'Koha::Libraries' } );
Lines 1316-1322 subtest "Test Local Holds Priority - Ensure no duplicate requests in holds queue Link Here
1316
    $dbh->do("DELETE FROM circulation_rules");
1316
    $dbh->do("DELETE FROM circulation_rules");
1317
    Koha::Biblios->delete();
1317
    Koha::Biblios->delete();
1318
1318
1319
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              1 );
1319
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              'GiveLibrary' );
1320
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1320
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1321
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1321
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1322
    my $branch   = $builder->build_object( { class => 'Koha::Libraries' } );
1322
    my $branch   = $builder->build_object( { class => 'Koha::Libraries' } );
Lines 1481-1487 subtest 'Excludes from local holds priority' => sub { Link Here
1481
1481
1482
    Koha::Holds->delete;
1482
    Koha::Holds->delete;
1483
1483
1484
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              1 );
1484
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',              'GiveLibrary' );
1485
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1485
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1486
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1486
    t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl',   'homebranch' );
1487
1487
Lines 1612-1618 subtest "Test item group holds" => sub { Link Here
1612
    $dbh->do("DELETE FROM circulation_rules");
1612
    $dbh->do("DELETE FROM circulation_rules");
1613
1613
1614
    t::lib::Mocks::mock_preference( 'HoldsQueueSkipClosed', 0 );
1614
    t::lib::Mocks::mock_preference( 'HoldsQueueSkipClosed', 0 );
1615
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',   0 );
1615
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',   'None' );
1616
1616
1617
    my $library  = $builder->build_object( { class => 'Koha::Libraries' } );
1617
    my $library  = $builder->build_object( { class => 'Koha::Libraries' } );
1618
    my $category = $builder->build_object(
1618
    my $category = $builder->build_object(
Lines 2200-2206 subtest "Test HoldsQueuePrioritizeBranch" => sub { Link Here
2200
2200
2201
    $schema->storage->txn_begin;
2201
    $schema->storage->txn_begin;
2202
2202
2203
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',     0 );
2203
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',     'None' );
2204
    t::lib::Mocks::mock_preference( 'UseTransportCostMatrix', 0 );
2204
    t::lib::Mocks::mock_preference( 'UseTransportCostMatrix', 0 );
2205
2205
2206
    my $branch1  = $builder->build_object( { class => 'Koha::Libraries' } );
2206
    my $branch1  = $builder->build_object( { class => 'Koha::Libraries' } );
Lines 2409-2415 subtest "Canceled holds should be removed from the holds queue" => sub { Link Here
2409
2409
2410
    $schema->storage->txn_begin;
2410
    $schema->storage->txn_begin;
2411
2411
2412
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',     0 );
2412
    t::lib::Mocks::mock_preference( 'LocalHoldsPriority',     'None' );
2413
    t::lib::Mocks::mock_preference( 'UseTransportCostMatrix', 0 );
2413
    t::lib::Mocks::mock_preference( 'UseTransportCostMatrix', 0 );
2414
2414
2415
    my $branch1  = $builder->build_object( { class => 'Koha::Libraries' } );
2415
    my $branch1  = $builder->build_object( { class => 'Koha::Libraries' } );
2416
- 

Return to bug 20747