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

(-)a/C4/Reserves.pm (-7 / +42 lines)
Lines 854-860 sub CheckReserves { Link Here
854
           items.biblioitemnumber,
854
           items.biblioitemnumber,
855
           itemtypes.notforloan,
855
           itemtypes.notforloan,
856
           items.notforloan AS itemnotforloan,
856
           items.notforloan AS itemnotforloan,
857
           items.itemnumber
857
           items.itemnumber,
858
           items.homebranch,
859
           items.holdingbranch
858
           FROM   items
860
           FROM   items
859
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
861
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
860
           LEFT JOIN itemtypes   ON items.itype   = itemtypes.itemtype
862
           LEFT JOIN itemtypes   ON items.itype   = itemtypes.itemtype
Lines 866-872 sub CheckReserves { Link Here
866
           items.biblioitemnumber,
868
           items.biblioitemnumber,
867
           itemtypes.notforloan,
869
           itemtypes.notforloan,
868
           items.notforloan AS itemnotforloan,
870
           items.notforloan AS itemnotforloan,
869
           items.itemnumber
871
           items.itemnumber,
872
           items.homebranch,
873
           items.holdingbranch
870
           FROM   items
874
           FROM   items
871
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
875
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
872
           LEFT JOIN itemtypes   ON biblioitems.itemtype   = itemtypes.itemtype
876
           LEFT JOIN itemtypes   ON biblioitems.itemtype   = itemtypes.itemtype
Lines 882-893 sub CheckReserves { Link Here
882
        $sth->execute($barcode);
886
        $sth->execute($barcode);
883
    }
887
    }
884
    # note: we get the itemnumber because we might have started w/ just the barcode.  Now we know for sure we have it.
888
    # note: we get the itemnumber because we might have started w/ just the barcode.  Now we know for sure we have it.
885
    my ( $biblio, $bibitem, $notforloan_per_itemtype, $notforloan_per_item, $itemnumber ) = $sth->fetchrow_array;
889
    my ( $biblio, $bibitem, $notforloan_per_itemtype, $notforloan_per_item,
890
        $itemnumber, $item_homebranch, $item_holdingbranch )
891
      = $sth->fetchrow_array;
886
892
887
    return ( '' ) unless $itemnumber; # bail if we got nothing.
893
    return ( '' ) unless $itemnumber; # bail if we got nothing.
888
894
889
    # if item is not for loan it cannot be reserved either.....
895
    # if item is not for loan it cannot be reserved either.....
890
    #    execpt where items.notforloan < 0 :  This indicates the item is holdable. 
896
    # except where items.notforloan < 0 :  This indicates the item is holdable.
891
    return ( '' ) if  ( $notforloan_per_item > 0 ) or $notforloan_per_itemtype;
897
    return ( '' ) if  ( $notforloan_per_item > 0 ) or $notforloan_per_itemtype;
892
898
893
    # Find this item in the reserves
899
    # Find this item in the reserves
Lines 899-919 sub CheckReserves { Link Here
899
    # $highest is the most important item we've seen so far.
905
    # $highest is the most important item we've seen so far.
900
    my $highest;
906
    my $highest;
901
    if (scalar @reserves) {
907
    if (scalar @reserves) {
908
        my $LocalHoldsPriority = C4::Context->preference('LocalHoldsPriority');
909
        my $LocalHoldsPriorityPatronControl = C4::Context->preference('LocalHoldsPriorityPatronControl');
910
        my $LocalHoldsPriorityItemControl = C4::Context->preference('LocalHoldsPriorityItemControl');
911
902
        my $priority = 10000000;
912
        my $priority = 10000000;
903
        foreach my $res (@reserves) {
913
        foreach my $res (@reserves) {
904
            if ( $res->{'itemnumber'} == $itemnumber && $res->{'priority'} == 0) {
914
            if ( $res->{'itemnumber'} == $itemnumber && $res->{'priority'} == 0) {
905
                return ( "Waiting", $res, \@reserves ); # Found it
915
                return ( "Waiting", $res, \@reserves ); # Found it
906
            } else {
916
            } else {
917
                # Lazy fetch for borrower and item. We only need to know about the patron and item
918
                # each and every time if we are using LocalHoldsPriority. This is a great place to
919
                # leverage the inherent lazy fetching of DBIx::Class.
920
                my $borrowerinfo;
921
                my $iteminfo;
922
923
                my $local_hold_match;
924
                if ($LocalHoldsPriority) {
925
                    $borrowerinfo = C4::Members::GetMember( borrowernumber => $res->{'borrowernumber'} );
926
                    $iteminfo = C4::Items::GetItem($itemnumber);
927
928
                    my $local_holds_priority_item_branchcode =
929
                      $iteminfo->{$LocalHoldsPriorityItemControl};
930
                    my $local_holds_priority_patron_branchcode =
931
                      ( $LocalHoldsPriorityPatronControl eq 'PickupLibrary' )
932
                      ? $res->{branchcode}
933
                      : ( $LocalHoldsPriorityPatronControl eq 'HomeLibrary' )
934
                      ? $borrowerinfo->{branchcode}
935
                      : undef;
936
                    $local_hold_match =
937
                      $local_holds_priority_item_branchcode eq
938
                      $local_holds_priority_patron_branchcode;
939
                }
940
907
                # See if this item is more important than what we've got so far
941
                # See if this item is more important than what we've got so far
908
                if ( $res->{'priority'} && $res->{'priority'} < $priority ) {
942
                if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
909
                    my $borrowerinfo=C4::Members::GetMember(borrowernumber => $res->{'borrowernumber'});
943
                    $borrowerinfo ||= C4::Members::GetMember( borrowernumber => $res->{'borrowernumber'} );
910
                    my $iteminfo=C4::Items::GetItem($itemnumber);
944
                    $iteminfo ||= C4::Items::GetItem($itemnumber);
911
                    my $branch = GetReservesControlBranch( $iteminfo, $borrowerinfo );
945
                    my $branch = GetReservesControlBranch( $iteminfo, $borrowerinfo );
912
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$iteminfo->{'itype'});
946
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$iteminfo->{'itype'});
913
                    next if ($branchitemrule->{'holdallowed'} == 0);
947
                    next if ($branchitemrule->{'holdallowed'} == 0);
914
                    next if (($branchitemrule->{'holdallowed'} == 1) && ($branch ne $borrowerinfo->{'branchcode'}));
948
                    next if (($branchitemrule->{'holdallowed'} == 1) && ($branch ne $borrowerinfo->{'branchcode'}));
915
                    $priority = $res->{'priority'};
949
                    $priority = $res->{'priority'};
916
                    $highest  = $res;
950
                    $highest  = $res;
951
                    last if $local_hold_match;
917
                }
952
                }
918
            }
953
            }
919
        }
954
        }
(-)a/installer/data/mysql/sysprefs.sql (+3 lines)
Lines 172-177 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
172
('LinkerOptions','','','A pipe-separated list of options for the linker.','free'),
172
('LinkerOptions','','','A pipe-separated list of options for the linker.','free'),
173
('LinkerRelink','1',NULL,'If ON the authority linker will relink headings that have previously been linked every time it runs.','YesNo'),
173
('LinkerRelink','1',NULL,'If ON the authority linker will relink headings that have previously been linked every time it runs.','YesNo'),
174
('LocalCoverImages','0','1','Display local cover images on intranet details pages.','YesNo'),
174
('LocalCoverImages','0','1','Display local cover images on intranet details pages.','YesNo'),
175
('LocalHoldsPriority',  '0', NULL,  'Enables the LocalHoldsPriority feature',  'YesNo'),
176
('LocalHoldsPriorityItemControl',  'holdingbranch',  'holdingbranch|homebranch',  'decides if the feature operates using the item''s home or holding library.',  'Choice'),
177
('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'),
175
('ManInvInNoissuesCharge','1',NULL,'MANUAL_INV charges block checkouts (added to noissuescharge).','YesNo'),
178
('ManInvInNoissuesCharge','1',NULL,'MANUAL_INV charges block checkouts (added to noissuescharge).','YesNo'),
176
('MARCAuthorityControlField008','|| aca||aabn           | a|a     d',NULL,NULL,'Textarea'),
179
('MARCAuthorityControlField008','|| aca||aabn           | a|a     d',NULL,NULL,'Textarea'),
177
('MARCOrgCode','OSt','','Define MARC Organization Code - http://www.loc.gov/marc/organizations/orgshome.html','free'),
180
('MARCOrgCode','OSt','','Define MARC Organization Code - http://www.loc.gov/marc/organizations/orgshome.html','free'),
(-)a/installer/data/mysql/updatedatabase.pl (+12 lines)
Lines 7743-7748 if(CheckVersion($DBversion)) { Link Here
7743
    SetVersion($DBversion);
7743
    SetVersion($DBversion);
7744
}
7744
}
7745
7745
7746
$DBversion = "3.15.00.XXX";
7747
if ( CheckVersion($DBversion) ) {
7748
    $dbh->do(q{
7749
        INSERT INTO systempreferences ( variable, value, options, explanation, type ) VALUES
7750
        ('LocalHoldsPriority',  '0', NULL,  'Enables the LocalHoldsPriority feature',  'YesNo'),
7751
        ('LocalHoldsPriorityItemControl',  'holdingbranch',  'holdingbranch|homebranch',  'decides if the feature operates using the item''s home or holding library.',  'Choice'),
7752
        ('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')
7753
    });
7754
    print "Upgrade to $DBversion done (Bug 11126 - Make the holds system optionally give precedence to local holds)\n";
7755
    SetVersion($DBversion);
7756
}
7757
7746
=head1 FUNCTIONS
7758
=head1 FUNCTIONS
7747
7759
7748
=head2 TableExists($table)
7760
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (+15 lines)
Lines 495-500 Circulation: Link Here
495
                  yes: Allow
495
                  yes: Allow
496
                  no: "Don't allow"
496
                  no: "Don't allow"
497
            - a patron to place a hold on a record where the patron already has one or more items attached to that record checked out.
497
            - a patron to place a hold on a record where the patron already has one or more items attached to that record checked out.
498
        -
499
            - pref: LocalHoldsPriority
500
              choices:
501
                  yes: Give
502
                  no: "Don't give"
503
            - priority for filling holds to patrons whose
504
            - pref: LocalHoldsPriorityPatronControl
505
              choices:
506
                  PickupLibrary: "pickup library"
507
                  HomeLibrary: "home library"
508
            - matches the item's
509
            - pref: LocalHoldsPriorityItemControl
510
              choices:
511
                  homebranch: "home library"
512
                  holdingbranch: "holding library"
498
    Fines Policy:
513
    Fines Policy:
499
        -
514
        -
500
            - Calculate fines based on days overdue
515
            - 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