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

(-)a/C4/Reserves.pm (-5 / +38 lines)
Lines 875-880 sub CheckReserves { Link Here
875
           items.notforloan AS itemnotforloan,
875
           items.notforloan AS itemnotforloan,
876
           items.itemnumber,
876
           items.itemnumber,
877
           items.damaged
877
           items.damaged
878
           items.homebranch,
879
           items.holdingbranch
878
           FROM   items
880
           FROM   items
879
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
881
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
880
           LEFT JOIN itemtypes   ON items.itype   = itemtypes.itemtype
882
           LEFT JOIN itemtypes   ON items.itype   = itemtypes.itemtype
Lines 888-893 sub CheckReserves { Link Here
888
           items.notforloan AS itemnotforloan,
890
           items.notforloan AS itemnotforloan,
889
           items.itemnumber,
891
           items.itemnumber,
890
           items.damaged
892
           items.damaged
893
           items.homebranch,
894
           items.holdingbranch
891
           FROM   items
895
           FROM   items
892
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
896
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
893
           LEFT JOIN itemtypes   ON biblioitems.itemtype   = itemtypes.itemtype
897
           LEFT JOIN itemtypes   ON biblioitems.itemtype   = itemtypes.itemtype
Lines 903-916 sub CheckReserves { Link Here
903
        $sth->execute($barcode);
907
        $sth->execute($barcode);
904
    }
908
    }
905
    # note: we get the itemnumber because we might have started w/ just the barcode.  Now we know for sure we have it.
909
    # note: we get the itemnumber because we might have started w/ just the barcode.  Now we know for sure we have it.
906
    my ( $biblio, $bibitem, $notforloan_per_itemtype, $notforloan_per_item, $itemnumber, $damaged ) = $sth->fetchrow_array;
910
    my ( $biblio, $bibitem, $notforloan_per_itemtype, $notforloan_per_item, $itemnumber, $damaged, $item_homebranch, $item_holdingbranch ) = $sth->fetchrow_array;
907
911
908
    return if ( $damaged && !C4::Context->preference('AllowHoldsOnDamagedItems') );
912
    return if ( $damaged && !C4::Context->preference('AllowHoldsOnDamagedItems') );
909
913
910
    return unless $itemnumber; # bail if we got nothing.
914
    return unless $itemnumber; # bail if we got nothing.
911
915
912
    # if item is not for loan it cannot be reserved either.....
916
    # if item is not for loan it cannot be reserved either.....
913
    #    execpt where items.notforloan < 0 :  This indicates the item is holdable. 
917
    # except where items.notforloan < 0 :  This indicates the item is holdable.
914
    return if  ( $notforloan_per_item > 0 ) or $notforloan_per_itemtype;
918
    return if  ( $notforloan_per_item > 0 ) or $notforloan_per_itemtype;
915
919
916
    # Find this item in the reserves
920
    # Find this item in the reserves
Lines 922-942 sub CheckReserves { Link Here
922
    # $highest is the most important item we've seen so far.
926
    # $highest is the most important item we've seen so far.
923
    my $highest;
927
    my $highest;
924
    if (scalar @reserves) {
928
    if (scalar @reserves) {
929
        my $LocalHoldsPriority = C4::Context->preference('LocalHoldsPriority');
930
        my $LocalHoldsPriorityPatronControl = C4::Context->preference('LocalHoldsPriorityPatronControl');
931
        my $LocalHoldsPriorityItemControl = C4::Context->preference('LocalHoldsPriorityItemControl');
932
925
        my $priority = 10000000;
933
        my $priority = 10000000;
926
        foreach my $res (@reserves) {
934
        foreach my $res (@reserves) {
927
            if ( $res->{'itemnumber'} == $itemnumber && $res->{'priority'} == 0) {
935
            if ( $res->{'itemnumber'} == $itemnumber && $res->{'priority'} == 0) {
928
                return ( "Waiting", $res, \@reserves ); # Found it
936
                return ( "Waiting", $res, \@reserves ); # Found it
929
            } else {
937
            } else {
938
                # Lazy fetch for borrower and item. We only need to know about the patron and item
939
                # each and every time if we are using LocalHoldsPriority. This is a great place to
940
                # leverage the inherent lazy fetching of DBIx::Class.
941
                my $borrowerinfo;
942
                my $iteminfo;
943
944
                my $local_hold_match;
945
                if ($LocalHoldsPriority) {
946
                    $borrowerinfo = C4::Members::GetMember( borrowernumber => $res->{'borrowernumber'} );
947
                    $iteminfo = C4::Items::GetItem($itemnumber);
948
949
                    my $local_holds_priority_item_branchcode =
950
                      $iteminfo->{$LocalHoldsPriorityItemControl};
951
                    my $local_holds_priority_patron_branchcode =
952
                      ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
953
                      ? $res->{branchcode}
954
                      : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )
955
                      ? $borrowerinfo->{branchcode}
956
                      : undef;
957
                    $local_hold_match =
958
                      $local_holds_priority_item_branchcode eq
959
                      $local_holds_priority_patron_branchcode;
960
                }
961
930
                # See if this item is more important than what we've got so far
962
                # See if this item is more important than what we've got so far
931
                if ( $res->{'priority'} && $res->{'priority'} < $priority ) {
963
                if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
932
                    my $borrowerinfo=C4::Members::GetMember(borrowernumber => $res->{'borrowernumber'});
964
                    $borrowerinfo ||= C4::Members::GetMember( borrowernumber => $res->{'borrowernumber'} );
933
                    my $iteminfo=C4::Items::GetItem($itemnumber);
965
                    $iteminfo ||= C4::Items::GetItem($itemnumber);
934
                    my $branch = GetReservesControlBranch( $iteminfo, $borrowerinfo );
966
                    my $branch = GetReservesControlBranch( $iteminfo, $borrowerinfo );
935
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$iteminfo->{'itype'});
967
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$iteminfo->{'itype'});
936
                    next if ($branchitemrule->{'holdallowed'} == 0);
968
                    next if ($branchitemrule->{'holdallowed'} == 0);
937
                    next if (($branchitemrule->{'holdallowed'} == 1) && ($branch ne $borrowerinfo->{'branchcode'}));
969
                    next if (($branchitemrule->{'holdallowed'} == 1) && ($branch ne $borrowerinfo->{'branchcode'}));
938
                    $priority = $res->{'priority'};
970
                    $priority = $res->{'priority'};
939
                    $highest  = $res;
971
                    $highest  = $res;
972
                    last if $local_hold_match;
940
                }
973
                }
941
            }
974
            }
942
        }
975
        }
(-)a/installer/data/mysql/sysprefs.sql (+3 lines)
Lines 179-184 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
179
('LinkerOptions','','','A pipe-separated list of options for the linker.','free'),
179
('LinkerOptions','','','A pipe-separated list of options for the linker.','free'),
180
('LinkerRelink','1',NULL,'If ON the authority linker will relink headings that have previously been linked every time it runs.','YesNo'),
180
('LinkerRelink','1',NULL,'If ON the authority linker will relink headings that have previously been linked every time it runs.','YesNo'),
181
('LocalCoverImages','0','1','Display local cover images on intranet details pages.','YesNo'),
181
('LocalCoverImages','0','1','Display local cover images on intranet details pages.','YesNo'),
182
('LocalHoldsPriority',  '0', NULL,  'Enables the LocalHoldsPriority feature',  'YesNo'),
183
('LocalHoldsPriorityItemControl',  'holdingbranch',  'holdingbranch|homebranch',  'decides if the feature operates using the item''s home or holding library.',  'Choice'),
184
('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'),
182
('ManInvInNoissuesCharge','1',NULL,'MANUAL_INV charges block checkouts (added to noissuescharge).','YesNo'),
185
('ManInvInNoissuesCharge','1',NULL,'MANUAL_INV charges block checkouts (added to noissuescharge).','YesNo'),
183
('MARCAuthorityControlField008','|| aca||aabn           | a|a     d',NULL,'Define the contents of MARC21 authority control field 008 position 06-39','Textarea'),
186
('MARCAuthorityControlField008','|| aca||aabn           | a|a     d',NULL,'Define the contents of MARC21 authority control field 008 position 06-39','Textarea'),
184
('MarcFieldsToOrder','',NULL,'Set the mapping values for a new order line created from a MARC record in a staged file. In a YAML format.','textarea'),
187
('MarcFieldsToOrder','',NULL,'Set the mapping values for a new order line created from a MARC record in a staged file. In a YAML format.','textarea'),
(-)a/installer/data/mysql/updatedatabase.pl (+12 lines)
Lines 8465-8470 if ( CheckVersion($DBversion) ) { Link Here
8465
    SetVersion($DBversion);
8465
    SetVersion($DBversion);
8466
}
8466
}
8467
8467
8468
$DBversion = "3.17.00.XXX";
8469
if ( CheckVersion($DBversion) ) {
8470
    $dbh->do(q{
8471
        INSERT INTO systempreferences ( variable, value, options, explanation, type ) VALUES
8472
        ('LocalHoldsPriority',  '0', NULL,  'Enables the LocalHoldsPriority feature',  'YesNo'),
8473
        ('LocalHoldsPriorityItemControl',  'holdingbranch',  'holdingbranch|homebranch',  'decides if the feature operates using the item''s home or holding library.',  'Choice'),
8474
        ('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')
8475
    });
8476
    print "Upgrade to $DBversion done (Bug 11126 - Make the holds system optionally give precedence to local holds)\n";
8477
    SetVersion($DBversion);
8478
}
8479
8468
=head1 FUNCTIONS
8480
=head1 FUNCTIONS
8469
8481
8470
=head2 TableExists($table)
8482
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (+15 lines)
Lines 508-513 Circulation: Link Here
508
                  yes: Allow
508
                  yes: Allow
509
                  no: "Don't allow"
509
                  no: "Don't allow"
510
            - a patron to place a hold on a record where the patron already has one or more items attached to that record checked out.
510
            - a patron to place a hold on a record where the patron already has one or more items attached to that record checked out.
511
        -
512
            - pref: LocalHoldsPriority
513
              choices:
514
                  yes: Give
515
                  no: "Don't give"
516
            - priority for filling holds to patrons whose
517
            - pref: LocalHoldsPriorityPatronControl
518
              choices:
519
                  PickupLibrary: "pickup library"
520
                  HomeLibrary: "home library"
521
            - matches the item's
522
            - pref: LocalHoldsPriorityItemControl
523
              choices:
524
                  homebranch: "home library"
525
                  holdingbranch: "holding library"
511
    Fines Policy:
526
    Fines Policy:
512
        -
527
        -
513
            - Calculate fines based on days overdue
528
            - Calculate fines based on days overdue
(-)a/t/db_dependent/Holds/LocalHoldsPriority.t (-1 / +119 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
use strict;
4
use warnings;
5
6
use t::lib::Mocks;
7
use C4::Context;
8
use C4::Branch;
9
10
use Test::More tests => 6;
11
use MARC::Record;
12
use C4::Biblio;
13
use C4::Items;
14
use C4::Members;
15
16
BEGIN {
17
    use FindBin;
18
    use lib $FindBin::Bin;
19
    use_ok('C4::Reserves');
20
}
21
22
my $dbh = C4::Context->dbh;
23
24
# Start transaction
25
$dbh->{AutoCommit} = 0;
26
$dbh->{RaiseError} = 1;
27
28
my $borrowers_count = 5;
29
30
# Setup Test------------------------
31
# Helper biblio.
32
diag("Creating biblio instance for testing.");
33
my ( $bibnum, $title, $bibitemnum ) = create_helper_biblio();
34
35
# Helper item for that biblio.
36
diag("Creating item instance for testing.");
37
my ( $item_bibnum, $item_bibitemnum, $itemnumber ) =
38
  AddItem( { homebranch => 'MPL', holdingbranch => 'CPL' }, $bibnum );
39
40
my @branchcodes = qw{XXX RPL CPL MPL CPL MPL};
41
42
# Create some borrowers
43
diag("Creating borrowers.");
44
my @borrowernumbers;
45
foreach ( 1 .. $borrowers_count ) {
46
    my $borrowernumber = AddMember(
47
        firstname    => 'my firstname',
48
        surname      => 'my surname ' . $_,
49
        categorycode => 'S',
50
        branchcode   => $branchcodes[$_],
51
    );
52
    push @borrowernumbers, $borrowernumber;
53
}
54
55
my $biblionumber = $bibnum;
56
57
my @branches = GetBranchesLoop();
58
my $branch   = $branches[0][0]{value};
59
60
# Create five item level holds
61
diag("Creating holds.");
62
my $i = 1;
63
foreach my $borrowernumber (@borrowernumbers) {
64
    AddReserve(
65
        $branchcodes[$i],
66
        $borrowernumber,
67
        $biblionumber,
68
        my $constraint = 'a',
69
        my $bibitems   = q{},
70
        my $priority = $i,
71
        my $resdate,
72
        my $expdate,
73
        my $notes = q{},
74
        $title,
75
        my $checkitem,
76
        my $found,
77
    );
78
79
    $i++;
80
}
81
82
my ($status, $reserve, $all_reserves);
83
84
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 0 );
85
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
86
ok( $reserve->{borrowernumber} eq $borrowernumbers[0], "Recieved expected results with LocalHoldsPriority disabled" );
87
88
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
89
90
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
91
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
92
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
93
ok( $reserve->{borrowernumber} eq $borrowernumbers[2], "Received expected results with PickupLibrary/homebranch" );
94
95
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
96
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
97
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
98
ok( $reserve->{borrowernumber} eq $borrowernumbers[1], "Received expected results with PickupLibrary/holdingbranch" );
99
100
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
101
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
102
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
103
ok( $reserve->{borrowernumber} eq $borrowernumbers[1], "Received expected results with HomeLibrary/holdingbranch" );
104
105
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
106
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
107
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
108
ok( $reserve->{borrowernumber} eq $borrowernumbers[2], "Received expected results with HomeLibrary/homebranch" );
109
110
# Helper method to set up a Biblio.
111
sub create_helper_biblio {
112
    my $bib   = MARC::Record->new();
113
    my $title = 'Silence in the library';
114
    $bib->append_fields(
115
        MARC::Field->new( '100', ' ', ' ', a => 'Moffat, Steven' ),
116
        MARC::Field->new( '245', ' ', ' ', a => $title ),
117
    );
118
    return ( $bibnum, $title, $bibitemnum ) = AddBiblio( $bib, '' );
119
}

Return to bug 11126