In a librairies network, we would like to declare specific values just
for one (or more) librairy.
Here we implement the ability to associate categories, patron attributes
types and/or authorised_values with librairies (branches).

This patch adds 3 new association tables:
- categories_branches ( association table between categories and branches )
- authorised_values_branches ( association table between
  authorised_values and branches )
- borrower_attribute_types_branches (association table between
  borrower_attribute_types and branches )

Plan test:
  - Create (or modify) categories, patron attributes and
    authorised_values and link it with one (or more) library.
  - Set one of these librairies
  - Go to one of the multiple pages where this specific value must be displayed
    and check that it does appear.
  - Set a librairy not concerned.
  - Check on the same pages this value is doest not appear.

A page list:
cataloguing/addbiblio.pl
cataloguing/additems.pl
members/members-home.pl
members/memberentry.pl
acqui/neworderempty.pl
tools/import_borrowers.pl
and others :)

Please say me if filters don't work on some pages.
---
 C4/Budgets.pm                                      |   23 +++++--
 C4/Category.pm                                     |   25 +++++--
 C4/Input.pm                                        |   67 ++++++++++++--------
 C4/Koha.pm                                         |   54 +++++++++++-----
 C4/Members.pm                                      |   63 ++++++++++++------
 C4/Members/AttributeTypes.pm                       |   62 +++++++++++++++++-
 C4/Members/Attributes.pm                           |    2 +
 admin/authorised_values.pl                         |   58 ++++++++++++++++-
 admin/categorie.pl                                 |   46 ++++++++++++--
 admin/patron-attr-types.pl                         |   36 +++++++++-
 cataloguing/addbiblio.pl                           |   21 ++++--
 cataloguing/additem.pl                             |   13 ++--
 installer/data/mysql/kohastructure.sql             |   38 +++++++++++
 installer/data/mysql/updatedatabase.pl             |   17 +++++
 .../prog/en/modules/admin/authorised_values.tt     |   20 ++++++-
 .../prog/en/modules/admin/categorie.tt             |   21 ++++++-
 .../prog/en/modules/admin/patron-attr-types.tt     |   19 ++++++
 members/member.pl                                  |    4 +-
 tools/batchMod.pl                                  |   12 +++-
 tools/import_borrowers.pl                          |    2 +-
 20 files changed, 489 insertions(+), 114 deletions(-)

diff --git a/C4/Budgets.pm b/C4/Budgets.pm
index 7c867e0..8399b5b 100644
--- a/C4/Budgets.pm
+++ b/C4/Budgets.pm
@@ -354,12 +354,25 @@ sub GetBudgetAuthCats  {
 # -------------------------------------------------------------------
 sub GetAuthvalueDropbox {
     my ( $authcat, $default ) = @_;
+    my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} 
: "";
     my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare(
-        'SELECT authorised_value,lib FROM authorised_values
-        WHERE category = ? ORDER BY lib'
-    );
-    $sth->execute( $authcat );
+
+    my $query = qq{
+        SELECT *
+        FROM authorised_values
+    };
+    $query .= qq{
+          LEFT JOIN authorised_values_branches ON ( id = av_id )
+    } if $branch_limit;
+    $query .= qq{
+        WHERE category = ?
+    };
+    $query .= " AND ( branchcode = ? OR branchcode IS NULL )" if $branch_limit;
+    $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
+    my $sth = $dbh->prepare($query);
+    $sth->execute( $authcat, $branch_limit ? $branch_limit : () );
+
+
     my $option_list = [];
     my @authorised_values = ( q{} );
     while (my ($value, $lib) = $sth->fetchrow_array) {
diff --git a/C4/Category.pm b/C4/Category.pm
index 8536128..f12b52f 100644
--- a/C4/Category.pm
+++ b/C4/Category.pm
@@ -71,13 +71,24 @@ C<description>.
 =cut
 
 sub all {
-    my $class = shift;
-    map {
-        utf8::encode($_->{description});
-        $class->new($_);
-    } @{C4::Context->dbh->selectall_arrayref(
-        "SELECT * FROM categories ORDER BY description", { Slice => {} }
-    )};
+    my ( $class ) = @_;
+    my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} 
: "";
+    my $dbh = C4::Context->dbh;
+    # The categories table is small enough for
+    # `SELECT *` to be harmless.
+    my $query = "SELECT * FROM categories";
+    $query .= qq{
+        LEFT JOIN categories_branches ON categories_branches.categorycode = 
categories.categorycode
+        WHERE categories_branches.branchcode = ? OR 
categories_branches.branchcode IS NULL
+    } if $branch_limit;
+    $query .= " ORDER BY description";
+    return map { $class->new($_) } @{
+        $dbh->selectall_arrayref(
+            $query,
+            { Slice => {} },
+            $branch_limit ? $branch_limit : ()
+        )
+    };
 }
 
 
diff --git a/C4/Input.pm b/C4/Input.pm
index 2ee07f3..6ba5ceb 100644
--- a/C4/Input.pm
+++ b/C4/Input.pm
@@ -119,33 +119,48 @@ Returns NULL if no authorised values found
 =cut
 
 sub buildCGIsort {
-       my ($name,$input_name,$data) = @_;
-       my $dbh=C4::Context->dbh;
-       my $query=qq{SELECT * FROM authorised_values WHERE category=? order by 
lib};
-       my $sth=$dbh->prepare($query);
-       $sth->execute($name);
-       my $CGISort;
-       if ($sth->rows>0){
-               my @values;
-               my %labels;
-
-               for (my $i =0;$i<$sth->rows;$i++){
-                       my $results = $sth->fetchrow_hashref;
-                       push @values, $results->{authorised_value};
-                       $labels{$results->{authorised_value}}=$results->{lib};
-               }
-               $CGISort= CGI::scrolling_list(
-                                       -name => $input_name,
-                                       -id =>   $input_name,
-                                       -values => \@values,
-                                       -labels => \%labels,
-                                       -default=> $data,
-                                       -size => 1,
-                                       -multiple => 0);
-       }
-       $sth->finish;
-       return $CGISort;
+    my ( $name, $input_name, $data ) = @_;
+    my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} 
: "";
+
+    my $dbh=C4::Context->dbh;
+    my $query = qq{
+        SELECT *
+        FROM authorised_values
+    };
+    $query .= qq{
+          LEFT JOIN authorised_values_branches ON ( id = av_id )
+    } if $branch_limit;
+    $query .= qq{
+        WHERE category = ?
+    };
+    $query .= qq{ AND ( branchcode = ? OR branchcode IS NULL )} if 
$branch_limit;
+    $query .= qq{ GROUP BY lib ORDER BY lib};
+
+    my $sth=$dbh->prepare($query);
+    $sth->execute( $branch_limit ? $branch_limit : (), $name );
+    my $CGISort;
+    if ($sth->rows>0){
+        my @values;
+        my %labels;
+
+        for (my $i =0;$i<$sth->rows;$i++){
+            my $results = $sth->fetchrow_hashref;
+            push @values, $results->{authorised_value};
+            $labels{$results->{authorised_value}}=$results->{lib};
+        }
+        $CGISort= CGI::scrolling_list(
+                    -name => $input_name,
+                    -id =>   $input_name,
+                    -values => \@values,
+                    -labels => \%labels,
+                    -default=> $data,
+                    -size => 1,
+                    -multiple => 0);
+    }
+    $sth->finish;
+    return $CGISort;
 }
+
 END { }       # module clean-up code here (global destructor)
 
 1;
diff --git a/C4/Koha.pm b/C4/Koha.pm
index 0192989..050e8ae 100644
--- a/C4/Koha.pm
+++ b/C4/Koha.pm
@@ -1007,25 +1007,45 @@ C<$opac> If set to a true value, displays OPAC 
descriptions rather than normal o
 =cut
 
 sub GetAuthorisedValues {
-    my ($category,$selected,$opac) = @_;
-       my @results;
+    my ( $category, $selected, $opac ) = @_;
+    my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} 
: "";
+    my @results;
     my $dbh      = C4::Context->dbh;
-    my $query    = "SELECT * FROM authorised_values";
-    $query .= " WHERE category = '" . $category . "'" if $category;
-    $query .= " ORDER BY category, lib, lib_opac";
+    my $query = qq{
+        SELECT *
+        FROM authorised_values
+    };
+    $query .= qq{
+          LEFT JOIN authorised_values_branches ON ( id = av_id )
+    } if $branch_limit;
+    my @where_strings;
+    my @where_args;
+    if($category) {
+        push @where_strings, "category = ?";
+        push @where_args, $category;
+    }
+    if($branch_limit) {
+        push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
+        push @where_args, $branch_limit;
+    }
+    if(@where_strings > 0) {
+        $query .= " WHERE " . join(" AND ", @where_strings);
+    }
+    $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
+
     my $sth = $dbh->prepare($query);
-    $sth->execute;
-       while (my $data=$sth->fetchrow_hashref) {
-           if ($selected && $selected eq $data->{'authorised_value'} ) {
-                   $data->{'selected'} = 1;
-           }
-           if ($opac && $data->{'lib_opac'}) {
-               $data->{'lib'} = $data->{'lib_opac'};
-           }
-           push @results, $data;
-       }
-    #my $data = $sth->fetchall_arrayref({});
-    return \@results; #$data;
+    $sth->execute( @where_args );
+    while (my $data=$sth->fetchrow_hashref) {
+        if ($selected && $selected eq $data->{'authorised_value'} ) {
+            $data->{'selected'} = 1;
+        }
+        if ($opac && $data->{'lib_opac'}) {
+            $data->{'lib'} = $data->{'lib_opac'};
+        }
+        push @results, $data;
+    }
+    $sth->finish;
+    return \@results;
 }
 
 =head2 GetAuthorisedValueCategories
diff --git a/C4/Members.pm b/C4/Members.pm
index 056f7e4..2d50ef4 100644
--- a/C4/Members.pm
+++ b/C4/Members.pm
@@ -1373,20 +1373,35 @@ to category descriptions.
 
 #'
 sub GetborCatFromCatType {
-    my ( $category_type, $action ) = @_;
-       # FIXME - This API  seems both limited and dangerous. 
+    my ( $category_type, $action, $no_branch_limit ) = @_;
+
+    my $branch_limit = $no_branch_limit
+        ? 0
+        : C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
+
+    # FIXME - This API  seems both limited and dangerous. 
     my $dbh     = C4::Context->dbh;
-    my $request = qq|   SELECT categorycode,description 
-            FROM categories 
-            $action
-            ORDER BY categorycode|;
-    my $sth = $dbh->prepare($request);
-       if ($action) {
-        $sth->execute($category_type);
-    }
-    else {
-        $sth->execute();
+
+    my $request = qq{
+        SELECT categories.categorycode, categories.description
+        FROM categories
+    };
+    $request .= qq{
+        LEFT JOIN categories_branches ON categories.categorycode = 
categories_branches.categorycode
+    } if $branch_limit;
+    if($action) {
+        $request .= " $action ";
+        $request .= " AND (branchcode = ? OR branchcode IS NULL) GROUP BY 
description" if $branch_limit;
+    } else {
+        $request .= " WHERE branchcode = ? OR branchcode IS NULL GROUP BY 
description" if $branch_limit;
     }
+    $request .= " ORDER BY categorycode";
+
+    my $sth = $dbh->prepare($request);
+    $sth->execute(
+        $action ? $category_type : (),
+        $branch_limit ? $branch_limit : ()
+    );
 
     my %labels;
     my @codes;
@@ -1395,6 +1410,7 @@ sub GetborCatFromCatType {
         push @codes, $data->{'categorycode'};
         $labels{ $data->{'categorycode'} } = $data->{'description'};
     }
+    $sth->finish;
     return ( \@codes, \%labels );
 }
 
@@ -1437,16 +1453,21 @@ If no category code provided, the function returns all 
the categories.
 =cut
 
 sub GetBorrowercategoryList {
+    my $no_branch_limit = @_ ? shift : 0;
+    my $branch_limit = $no_branch_limit
+        ? 0
+        : C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
     my $dbh       = C4::Context->dbh;
-    my $sth       =
-    $dbh->prepare(
-    "SELECT * 
-    FROM categories 
-    ORDER BY description"
-        );
-    $sth->execute;
-    my $data =
-    $sth->fetchall_arrayref({});
+    my $query = "SELECT * FROM categories";
+    $query .= qq{
+        LEFT JOIN categories_branches ON categories.categorycode = 
categories_branches.categorycode
+        WHERE branchcode = ? OR branchcode IS NULL GROUP BY description
+    } if $branch_limit;
+    $query .= " ORDER BY description";
+    my $sth = $dbh->prepare( $query );
+    $sth->execute( $branch_limit ? $branch_limit : () );
+    my $data = $sth->fetchall_arrayref( {} );
+    $sth->finish;
     return $data;
 }    # sub getborrowercategory
 
diff --git a/C4/Members/AttributeTypes.pm b/C4/Members/AttributeTypes.pm
index 8c96e54..eb48883 100644
--- a/C4/Members/AttributeTypes.pm
+++ b/C4/Members/AttributeTypes.pm
@@ -69,12 +69,24 @@ If $all_fields is true, then each hashref also contains the 
other fields from bo
 =cut
 
 sub GetAttributeTypes {
-    my ($all) = @_;
-    my $select = $all ? '*' : 'code, description, class';
+    my $all    = @_   ? shift : 0;
+    my $no_branch_limit = @_ ? shift : 0;
+    my $branch_limit = $no_branch_limit
+        ? 0
+        : C4::Context->userenv ? C4::Context->userenv->{"branch"} : 0;
+    my $select = $all ? '*'   : 'DISTINCT(code), description';
+
     my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare("SELECT $select FROM borrower_attribute_types 
ORDER by code");
-    $sth->execute();
+    my $query = "SELECT $select FROM borrower_attribute_types";
+    $query .= qq{
+        LEFT JOIN borrower_attribute_types_branches ON bat_code = code
+        WHERE b_branchcode = ? OR b_branchcode IS NULL
+    } if $branch_limit;
+    $query .= " ORDER BY code";
+    my $sth    = $dbh->prepare($query);
+    $sth->execute( $branch_limit ? $branch_limit : () );
     my $results = $sth->fetchall_arrayref({});
+    $sth->finish;
     return @$results;
 }
 
@@ -166,6 +178,13 @@ sub fetch {
     $self->{'category_description'}      = $row->{'category_description'};
     $self->{'class'}                     = $row->{'class'};
 
+    $sth = $dbh->prepare("SELECT branchcode, branchname FROM 
borrower_attribute_types_branches, branches WHERE b_branchcode = branchcode AND 
bat_code = ?;");
+    $sth->execute( $code );
+    while ( my $data = $sth->fetchrow_hashref ) {
+        push @{ $self->{branches} }, $data;
+    }
+    $sth->finish();
+
     bless $self, $class;
     return $self;
 }
@@ -219,6 +238,22 @@ sub store {
     $sth->bind_param(11, $self->{'code'});
     $sth->execute;
 
+    if ( defined $$self{branches} ) {
+        $sth = $dbh->prepare("DELETE FROM borrower_attribute_types_branches 
WHERE bat_code = ?");
+        $sth->execute( $$self{code} );
+        $sth = $dbh->prepare(
+            "INSERT INTO borrower_attribute_types_branches
+                        ( bat_code, b_branchcode )
+                        VALUES ( ?, ? )"
+        );
+        for my $branchcode ( @{$$self{branches}} ) {
+            next if not $branchcode;
+            $sth->bind_param( 1, $$self{code} );
+            $sth->bind_param( 2, $branchcode );
+            $sth->execute;
+        }
+    }
+    $sth->finish;
 }
 
 =head2 code
@@ -250,6 +285,24 @@ sub description {
     @_ ? $self->{'description'} = shift : $self->{'description'};
 }
 
+=head2 branches
+
+=over 4
+
+my $branches = $attr_type->branches();
+$attr_type->branches($branches);
+
+=back
+
+Accessor.
+
+=cut
+
+sub branches {
+    my $self = shift;
+    @_ ? $self->{branches} = shift : $self->{branches};
+}
+
 =head2 repeatable
 
   my $repeatable = $attr_type->repeatable();
@@ -432,6 +485,7 @@ sub delete {
     my $dbh = C4::Context->dbh;
     my $sth = $dbh->prepare_cached("DELETE FROM borrower_attribute_types WHERE 
code = ?");
     $sth->execute($code);
+    $sth->finish;
 }
 
 =head2 num_patrons
diff --git a/C4/Members/Attributes.pm b/C4/Members/Attributes.pm
index 33d2407..cecb630 100644
--- a/C4/Members/Attributes.pm
+++ b/C4/Members/Attributes.pm
@@ -70,6 +70,7 @@ marked for OPAC display are returned.
 sub GetBorrowerAttributes {
     my $borrowernumber = shift;
     my $opac_only = @_ ? shift : 0;
+    my $branch_limit = @_ ? shift : 0;
 
     my $dbh = C4::Context->dbh();
     my $query = "SELECT code, description, attribute, lib, password, 
display_checkout, category_code, class
@@ -94,6 +95,7 @@ sub GetBorrowerAttributes {
             class             => $row->{'class'},
         }
     }
+    $sth->finish;
     return \@results;
 }
 
diff --git a/admin/authorised_values.pl b/admin/authorised_values.pl
index 1545f0e..e808e1d 100755
--- a/admin/authorised_values.pl
+++ b/admin/authorised_values.pl
@@ -22,6 +22,7 @@ use warnings;
 
 use CGI;
 use C4::Auth;
+use C4::Branch;
 use C4::Context;
 use C4::Koha;
 use C4::Output;
@@ -67,13 +68,32 @@ $template->param(  script_name => $script_name,
 # called by default. Used to create form to add or  modify a record
 if ($op eq 'add_form') {
        my $data;
+    my @selected_branches;
        if ($id) {
                my $sth=$dbh->prepare("select id, category, authorised_value, 
lib, lib_opac, imageurl from authorised_values where id=?");
                $sth->execute($id);
                $data=$sth->fetchrow_hashref;
+        $sth = $dbh->prepare("SELECT b.branchcode, b.branchname FROM 
authorised_values_branches AS avb, branches AS b WHERE avb.branchcode = 
b.branchcode AND avb.av_id = ?;");
+        $sth->execute( $id );
+        while ( my $branch = $sth->fetchrow_hashref ) {
+            push @selected_branches, $branch;
+        }
        } else {
                $data->{'category'} = $input->param('category');
        }
+
+    my $branches = GetBranches;
+    my @branches_loop;
+
+    foreach my $branch (sort keys %$branches) {
+        my $selected = ( grep {$_->{branchcode} eq $branch} @selected_branches 
) ? 1 : 0;
+        push @branches_loop, {
+            branchcode => $branches->{$branch}{branchcode},
+            branchname => $branches->{$branch}{branchname},
+            selected => $selected,
+        };
+    }
+
        if ($id) {
                $template->param(action_modify => 1);
                $template->param('heading_modify_authorized_value_p' => 1);
@@ -92,6 +112,7 @@ if ($op eq 'add_form') {
                          id               => $data->{'id'},
                          imagesets        => C4::Koha::getImageSets( checked 
=> $data->{'imageurl'} ),
                          offset           => $offset,
+                         branches_loop    => \@branches_loop,
                      );
                           
 ################## ADD_VALIDATE ##################################
@@ -102,6 +123,7 @@ if ($op eq 'add_form') {
     my $imageurl     = $input->param( 'imageurl' ) || '';
        $imageurl = '' if $imageurl =~ /removeImage/;
     my $duplicate_entry = 0;
+    my @branches = $input->param('branches');
 
     if ( $id ) { # Update
         my $sth = $dbh->prepare( "SELECT category, authorised_value FROM 
authorised_values WHERE id = ? ");
@@ -125,7 +147,21 @@ if ($op eq 'add_form') {
             my $lib_opac = $input->param('lib_opac');
             undef $lib if ($lib eq ""); # to insert NULL instead of a blank 
string
             undef $lib_opac if ($lib_opac eq ""); # to insert NULL instead of 
a blank string
-            $sth->execute($new_category, $new_authorised_value, $lib, 
$lib_opac, $imageurl, $id);          
+            $sth->execute($new_category, $new_authorised_value, $lib, 
$lib_opac, $imageurl, $id);
+            if ( @branches ) {
+                $sth = $dbh->prepare("DELETE FROM authorised_values_branches 
WHERE av_id = ?");
+                $sth->execute( $id );
+                $sth = $dbh->prepare(
+                    "INSERT INTO authorised_values_branches
+                                ( av_id, branchcode )
+                                VALUES ( ?, ? )"
+                );
+                for my $branchcode ( @branches ) {
+                    next if not $branchcode;
+                    $sth->execute($id, $branchcode);
+                }
+            }
+            $sth->finish;
             print "Content-Type: text/html\n\n<META HTTP-EQUIV=Refresh 
CONTENT=\"0; 
URL=authorised_values.pl?searchfield=".$new_category."&offset=$offset\"></html>";
             exit;
         }
@@ -137,13 +173,25 @@ if ($op eq 'add_form') {
         ($duplicate_entry) = $sth->fetchrow_array();
         unless ( $duplicate_entry ) {
             my $sth=$dbh->prepare( 'INSERT INTO authorised_values
-                                    ( id, category, authorised_value, lib, 
lib_opac, imageurl )
-                                    values (?, ?, ?, ?, ?, ?)' );
+                                    ( category, authorised_value, lib, 
lib_opac, imageurl )
+                                    values (?, ?, ?, ?, ?)' );
            my $lib = $input->param('lib');
            my $lib_opac = $input->param('lib_opac');
            undef $lib if ($lib eq ""); # to insert NULL instead of a blank 
string
            undef $lib_opac if ($lib_opac eq ""); # to insert NULL instead of a 
blank string
-           $sth->execute($id, $new_category, $new_authorised_value, $lib, 
$lib_opac, $imageurl );
+            $sth->execute( $new_category, $new_authorised_value, $lib, 
$lib_opac, $imageurl );
+            $id = $dbh->{'mysql_insertid'};
+            if ( @branches ) {
+                $sth = $dbh->prepare(
+                    "INSERT INTO authorised_values_branches
+                                ( av_id, branchcode )
+                                VALUES ( ?, ? )"
+                );
+                for my $branchcode ( @branches ) {
+                    next if not $branchcode;
+                    $sth->execute($id, $branchcode);
+                }
+            }
            print "Content-Type: text/html\n\n<META HTTP-EQUIV=Refresh 
CONTENT=\"0; 
URL=authorised_values.pl?searchfield=".$input->param('category')."&offset=$offset\"></html>";
            exit;
         }
@@ -176,6 +224,8 @@ if ($op eq 'add_form') {
        my $id = $input->param('id');
        my $sth=$dbh->prepare("delete from authorised_values where id=?");
        $sth->execute($id);
+    $sth = $dbh->prepare("DELETE FROM authorised_values_branches WHERE id = 
?");
+    $sth->execute($id);
        print "Content-Type: text/html\n\n<META HTTP-EQUIV=Refresh CONTENT=\"0; 
URL=authorised_values.pl?searchfield=$searchfield&offset=$offset\"></html>";
        exit;
                                                                                
                        # END $OP eq DELETE_CONFIRMED
diff --git a/admin/categorie.pl b/admin/categorie.pl
index 521346b..e93d0b3 100755
--- a/admin/categorie.pl
+++ b/admin/categorie.pl
@@ -36,11 +36,12 @@
 # with Koha; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-use strict;
-#use warnings; FIXME - Bug 2505
+use Modern::Perl;
+
 use CGI;
 use C4::Context;
 use C4::Auth;
+use C4::Branch;
 use C4::Output;
 use C4::Dates;
 use C4::Form::MessagingPreferences;
@@ -90,16 +91,34 @@ if ($op eq 'add_form') {
        
        #---- if primkey exists, it's a modify action, so read values to 
modify...
        my $data;
+    my @selected_branches;
        if ($categorycode) {
                my $dbh = C4::Context->dbh;
                my $sth=$dbh->prepare("select 
categorycode,description,enrolmentperiod,enrolmentperioddate,upperagelimit,dateofbirthrequired,enrolmentfee,issuelimit,reservefee,hidelostitems,overduenoticerequired,category_type
 from categories where categorycode=?");
                $sth->execute($categorycode);
                $data=$sth->fetchrow_hashref;
-               $sth->finish;
-       }
+
+        $sth = $dbh->prepare("SELECT b.branchcode, b.branchname FROM 
categories_branches AS cb, branches AS b WHERE cb.branchcode = b.branchcode AND 
cb.categorycode = ?");
+        $sth->execute( $categorycode );
+        while ( my $branch = $sth->fetchrow_hashref ) {
+            push @selected_branches, $branch;
+        }
+        $sth->finish;
+    }
 
     $data->{'enrolmentperioddate'} = undef if ($data->{'enrolmentperioddate'} 
eq '0000-00-00');
 
+    my $branches = GetBranches;
+    my @branches_loop;
+    foreach my $branch (sort keys %$branches) {
+        my $selected = ( grep {$$_{branchcode} eq $branch} @selected_branches 
) ? 1 : 0;
+        push @branches_loop, {
+            branchcode => $$branches{$branch}{branchcode},
+            branchname => $$branches{$branch}{branchname},
+            selected => $selected,
+        };
+    }
+
        $template->param(description        => $data->{'description'},
                                enrolmentperiod         => 
$data->{'enrolmentperiod'},
                                enrolmentperioddate     => 
C4::Dates::format_date($data->{'enrolmentperioddate'}),
@@ -113,7 +132,8 @@ if ($op eq 'add_form') {
                                category_type           => 
$data->{'category_type'},
                                DHTMLcalendar_dateformat => 
C4::Dates->DHTMLcalendar(),
                                "type_".$data->{'category_type'} => 1,
-                               SMSSendDriver => 
C4::Context->preference("SMSSendDriver")
+                               SMSSendDriver => 
C4::Context->preference("SMSSendDriver"),
+                branches_loop           => \@branches_loop,
                                );
     if (C4::Context->preference('EnhancedMessagingPreferences')) {
         C4::Form::MessagingPreferences::set_form_values({ categorycode => 
$categorycode } , $template);
@@ -132,6 +152,22 @@ if ($op eq 'add_form') {
        if ($is_a_modif) {
             my $sth=$dbh->prepare("UPDATE categories SET 
description=?,enrolmentperiod=?, 
enrolmentperioddate=?,upperagelimit=?,dateofbirthrequired=?,enrolmentfee=?,reservefee=?,hidelostitems=?,overduenoticerequired=?,category_type=?
 WHERE categorycode=?");
             $sth->execute(map { $input->param($_) } 
('description','enrolmentperiod','enrolmentperioddate','upperagelimit','dateofbirthrequired','enrolmentfee','reservefee','hidelostitems','overduenoticerequired','category_type','categorycode'));
+            my @branches = $input->param("branches");
+            if ( @branches ) {
+                $sth = $dbh->prepare("DELETE FROM categories_branches WHERE 
categorycode = ?");
+                $sth->execute( $input->param( "categorycode" ) );
+                $sth = $dbh->prepare(
+                    "INSERT INTO categories_branches
+                                ( categorycode, branchcode )
+                                VALUES ( ?, ? )"
+                );
+                for my $branchcode ( @branches ) {
+                    next if not $branchcode;
+                    $sth->bind_param( 1, $input->param( "categorycode" ) );
+                    $sth->bind_param( 2, $branchcode );
+                    $sth->execute;
+                }
+            }
             $sth->finish;
         } else {
             my $sth=$dbh->prepare("INSERT INTO categories  
(categorycode,description,enrolmentperiod,enrolmentperioddate,upperagelimit,dateofbirthrequired,enrolmentfee,reservefee,hidelostitems,overduenoticerequired,category_type)
 values (?,?,?,?,?,?,?,?,?,?,?)");
diff --git a/admin/patron-attr-types.pl b/admin/patron-attr-types.pl
index 638456e..108b6a4 100755
--- a/admin/patron-attr-types.pl
+++ b/admin/patron-attr-types.pl
@@ -19,12 +19,13 @@
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 #
 
-use strict;
-use warnings;
+use Modern::Perl;
+
 use CGI;
 use List::MoreUtils qw/uniq/;
 
 use C4::Auth;
+use C4::Branch;
 use C4::Context;
 use C4::Output;
 use C4::Koha;
@@ -82,10 +83,20 @@ exit 0;
 sub add_attribute_type_form {
     my $template = shift;
 
+    my $branches = GetBranches;
+    my @branches_loop;
+    foreach my $branch (sort keys %$branches) {
+        push @branches_loop, {
+            branchcode => $$branches{$branch}{branchcode},
+            branchname => $$branches{$branch}{branchname},
+        };
+    }
+
     $template->param(
         attribute_type_form => 1,
         confirm_op => 'add_attribute_type_confirmed',
         categories => GetBorrowercategoryList,
+        branches_loop => \@branches_loop,
     );
     authorised_value_category_list($template);
     pa_classes($template);
@@ -162,6 +173,8 @@ sub add_update_attribute_type {
     $attr_type->display_checkout($display_checkout);
     $attr_type->category_code($input->param('category_code'));
     $attr_type->class($input->param('class'));
+    my @branches = $input->param('branches');
+    $attr_type->branches( \@branches );
 
     if ($op eq 'edit') {
         $template->param(edited_attribute_type => $attr_type->code());
@@ -244,6 +257,20 @@ sub edit_attribute_type_form {
     authorised_value_category_list($template, 
$attr_type->authorised_value_category());
     pa_classes( $template, $attr_type->class );
 
+
+    my $branches = GetBranches;
+    my @branches_loop;
+    my $selected_branches = $attr_type->branches;
+    foreach my $branch (sort keys %$branches) {
+        my $selected = ( grep {$$_{branchcode} eq $branch} @$selected_branches 
) ? 1 : 0;
+        push @branches_loop, {
+            branchcode => $branches->{$branch}{branchcode},
+            branchname => $branches->{$branch}{branchname},
+            selected => $selected,
+        };
+    }
+    $template->param( branches_loop => \@branches_loop );
+
     $template->param ( category_code => $attr_type->category_code );
     $template->param ( category_description => 
$attr_type->category_description );
 
@@ -259,8 +286,9 @@ sub edit_attribute_type_form {
 sub patron_attribute_type_list {
     my $template = shift;
 
-    my @attr_types = C4::Members::AttributeTypes::GetAttributeTypes();
-    my @classes = uniq( map {$_->{class}} @attr_types );
+    my @attr_types = C4::Members::AttributeTypes::GetAttributeTypes( 1, 1 );
+
+    my @classes = uniq( map { $_->{class} } @attr_types );
     @classes = sort @classes;
 
     my @attributes_loop;
diff --git a/cataloguing/addbiblio.pl b/cataloguing/addbiblio.pl
index d5778a4..b9581f1 100755
--- a/cataloguing/addbiblio.pl
+++ b/cataloguing/addbiblio.pl
@@ -221,8 +221,11 @@ sub build_authorized_values_list {
         #---- "true" authorised value
     }
     else {
+        my $branch_limit = C4::Context->userenv ? 
C4::Context->userenv->{"branch"} : "";
         $authorised_values_sth->execute(
-            $tagslib->{$tag}->{$subfield}->{authorised_value} );
+            $branch_limit ? $branch_limit : (),
+            $tagslib->{$tag}->{$subfield}->{authorised_value}
+        );
 
         push @authorised_values, ""
           unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
@@ -232,6 +235,7 @@ sub build_authorized_values_list {
             $authorised_lib{$value} = $lib;
         }
     }
+    $authorised_values_sth->finish;
     return CGI::scrolling_list(
         -name     => 
"tag_".$tag."_subfield_".$subfield."_".$index_tag."_".$index_subfield,
         -values   => \@authorised_values,
@@ -523,12 +527,14 @@ sub build_tabs {
     my @loop_data = ();
     my $tag;
 
-    my $authorised_values_sth = $dbh->prepare(
-        "select authorised_value,lib
-        from authorised_values
-        where category=? order by lib"
-    );
-    
+    my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} 
: "";
+    my $query = "SELECT authorised_value, lib
+                FROM authorised_values";
+    $query .= qq{ JOIN authorised_values_branches ON ( id = av_id AND ( 
branchcode = ? OR branchcode IS NULL ) )} if $branch_limit;
+    $query .= " WHERE category = ?";
+    $query .= " GROUP BY lib ORDER BY lib, lib_opac";
+    my $authorised_values_sth = $dbh->prepare( $query );
+
     # in this array, we will push all the 10 tabs
     # to avoid having 10 tabs in the template : they will all be in the same 
BIG_LOOP
     my @BIG_LOOP;
@@ -713,6 +719,7 @@ sub build_tabs {
             };
         }
     }
+    $authorised_values_sth->finish;
     $template->param( BIG_LOOP => \@BIG_LOOP );
 }
 
diff --git a/cataloguing/additem.pl b/cataloguing/additem.pl
index 9c8120e..847434c 100755
--- a/cataloguing/additem.pl
+++ b/cataloguing/additem.pl
@@ -104,8 +104,7 @@ sub generate_subfield_form {
   
   my $frameworkcode = &GetFrameworkCode($biblionumber);
         my %subfield_data;
-        my $dbh = C4::Context->dbh;        
-        my $authorised_values_sth = $dbh->prepare("SELECT authorised_value,lib 
FROM authorised_values WHERE category=? ORDER BY lib");
+        my $dbh = C4::Context->dbh;
         
         my $index_subfield = int(rand(1000000)); 
         if ($subfieldtag eq '@'){
@@ -200,11 +199,11 @@ sub generate_subfield_form {
                   #---- "true" authorised value
             }
             else {
-                  push @authorised_values, "" unless ( 
$subfieldlib->{mandatory} );
-                  $authorised_values_sth->execute( 
$subfieldlib->{authorised_value} );
-                  while ( my ( $value, $lib ) = 
$authorised_values_sth->fetchrow_array ) {
-                      push @authorised_values, $value;
-                      $authorised_lib{$value} = $lib;
+                  push @authorised_values, qq{} unless ( 
$subfieldlib->{mandatory} );
+                  my $av = GetAuthorisedValues( 
$subfieldlib->{authorised_value} );
+                  for my $r ( @$av ) {
+                      push @authorised_values, $r->{authorised_value};
+                      $authorised_lib{$r->{authorised_value}} = $r->{lib};
                   }
             }
 
diff --git a/installer/data/mysql/kohastructure.sql 
b/installer/data/mysql/kohastructure.sql
index 4912e19..f921ce8 100644
--- a/installer/data/mysql/kohastructure.sql
+++ b/installer/data/mysql/kohastructure.sql
@@ -2810,6 +2810,44 @@ CREATE TABLE IF NOT EXISTS `social_data` (
   PRIMARY KEY  (`isbn`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
+--
+-- Table structure for table categories_branches
+--
+
+DROP TABLE IF EXISTS categories_branches;
+CREATE TABLE categories_branches( -- association table between categories and 
branches
+    categorycode VARCHAR(10),
+    branchcode VARCHAR(10),
+    FOREIGN KEY (categorycode) REFERENCES categories(categorycode) ON DELETE 
CASCADE,
+    FOREIGN KEY (branchcode) REFERENCES branches(branchcode) ON DELETE CASCADE
+) ENGINE=INNODB DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table authorised_values_branches
+--
+
+DROP TABLE IF EXISTS authorised_values_branches;
+CREATE TABLE authorised_values_branches( -- association table between 
authorised_values and branches
+    av_id INTEGER,
+    branchcode VARCHAR(10),
+    FOREIGN KEY (av_id) REFERENCES authorised_values(id) ON DELETE CASCADE,
+    FOREIGN KEY (branchcode) REFERENCES branches(branchcode) ON DELETE CASCADE
+) ENGINE=INNODB DEFAULT CHARSET=utf8;
+
+
+--
+-- Table structure for table borrower_attribute_types_branches
+--
+
+DROP TABLE IF EXISTS borrower_attribute_types_branches;
+CREATE TABLE borrower_attribute_types_branches( -- association table between 
borrower_attribute_types and branches
+    bat_code VARCHAR(10),
+    b_branchcode VARCHAR(10),
+    FOREIGN KEY (bat_code) REFERENCES borrower_attribute_types(code) ON DELETE 
CASCADE,
+    FOREIGN KEY (b_branchcode) REFERENCES branches(branchcode) ON DELETE 
CASCADE
+) ENGINE=INNODB DEFAULT CHARSET=utf8;
+
+
 /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
 /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
 /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
diff --git a/installer/data/mysql/updatedatabase.pl 
b/installer/data/mysql/updatedatabase.pl
index 503c8ee..f9e287e 100755
--- a/installer/data/mysql/updatedatabase.pl
+++ b/installer/data/mysql/updatedatabase.pl
@@ -5146,6 +5146,23 @@ if ( C4::Context->preference("Version") < 
TransformToNum($DBversion) ) {
     SetVersion($DBversion);
 }
 
+
+
+
+
+
+$DBversion = "3.06.00.XXX";
+if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
+    $dbh->do(qq{CREATE TABLE borrower_attribute_types_branches(bat_code 
VARCHAR(10), b_branchcode VARCHAR(10),FOREIGN KEY (bat_code) REFERENCES 
borrower_attribute_types(code) ON DELETE CASCADE,FOREIGN KEY (b_branchcode) 
REFERENCES branches(branchcode) ON DELETE CASCADE ) ENGINE=INNODB DEFAULT 
CHARSET=utf8;});
+
+    $dbh->do(qq{CREATE TABLE categories_branches(categorycode VARCHAR(10), 
branchcode VARCHAR(10), FOREIGN KEY (categorycode) REFERENCES 
categories(categorycode) ON DELETE CASCADE, FOREIGN KEY (branchcode) REFERENCES 
branches(branchcode) ON DELETE CASCADE ) ENGINE=INNODB DEFAULT CHARSET=utf8;});
+
+    $dbh->do(qq{CREATE TABLE authorised_values_branches(av_id INTEGER, 
branchcode VARCHAR(10), FOREIGN KEY (av_id) REFERENCES authorised_values(id) ON 
DELETE CASCADE, FOREIGN KEY  (branchcode) REFERENCES branches(branchcode) ON 
DELETE CASCADE ) ENGINE=INNODB DEFAULT CHARSET=utf8;});
+
+    print "Upgrade to $DBversion done (Add 3 associations tables with 
branches)\n";
+    SetVersion($DBversion);
+}
+
 =head1 FUNCTIONS
 
 =head2 DropAllForeignKeys($table)
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt 
b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt
index 0c806ce..728615a 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt
@@ -13,7 +13,10 @@
                sortList: [[1,0]],
                headers: { 4: { sorter: false}, 5: { sorter: false}}
                                }).tablesorterPager({container: 
$("#pagertable_authorized_values"),positionFixed: false,size: 50});
-       
+
+    if ( $("#branches option:selected").length < 1 ) {
+        $("#branches option:first").attr("selected", "selected");
+    }
 }); </script>
 
 <script type="text/JavaScript" language="JavaScript">
@@ -77,6 +80,21 @@
             <label for="lib_opac">Description (OPAC)</label>
             <input type="text" name="lib_opac" id="lib_opac" value="[% 
lib_opac %]" maxlength="80" />
         </li>
+        <li><label for="branches">Branches limitation: </label>
+            <select id="branches" name="branches" multiple size="10">
+                <option value="">All branches</option>
+                [% FOREACH branch IN branches_loop %]
+                  [% IF ( branch.selected ) %]
+                    <option selected="selected" value="[% branch.branchcode 
%]">[% branch.branchname %]</option>
+                  [% ELSE %]
+                    <option value="[% branch.branchcode %]">[% 
branch.branchname %]</option>
+                  [% END %]
+                [% END %]
+            </select>
+            <span>Select All if this authorised value must to be displayed all 
the time. Otherwise select librairies you want to associate with this value.
+            </span>
+        </li>
+
                </ol>
                <div id="icons" class="toptabs">
                <h5 style="margin-left:10px;">Choose an Icon:</h5>
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categorie.tt 
b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categorie.tt
index d2c353e..881f545 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categorie.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categorie.tt
@@ -12,6 +12,10 @@
                widgets: ['zebra'],
                headers: { 11: { sorter: false}}
        }).tablesorterPager({container: 
$("#pagertable_categorie"),positionFixed: false,size: 20});
+
+    if ( $("#branches option:selected").length < 1 ) {
+        $("#branches option:first").attr("selected", "selected");
+    }
 }); </script>
 [% INCLUDE 'calendar.inc' %]
 <script type="text/javascript">
@@ -179,7 +183,22 @@
                                        [% IF ( type_P ) %]<option value="P" 
selected="selected">Professional</option>[% ELSE %]<option 
value="P">Professional</option>[% END %]
                                        [% IF ( type_X ) %]<option value="X" 
selected="selected">Statistical</option>[% ELSE %]<option 
value="X">Statistical</option>[% END %]
                                        </select>
-       </li></ol>
+    </li>
+    <li><label for="branches">Branches limitation: </label>
+        <select id="branches" name="branches" multiple size="10">
+            <option value="">All branches</option>
+            [% FOREACH branch IN branches_loop %]
+              [% IF ( branch.selected ) %]
+                <option selected="selected" value="[% branch.branchcode %]">[% 
branch.branchname %]</option>
+              [% ELSE %]
+                <option value="[% branch.branchcode %]">[% branch.branchname 
%]</option>
+              [% END %]
+            [% END %]
+        </select>
+        <span>Select All if this category type must to be displayed all the 
time. Otherwise select librairies you want to associate with this value.
+        </span>
+    </li>
+    </ol>
 </fieldset>
 
     [% IF ( EnhancedMessagingPreferences ) %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/patron-attr-types.tt 
b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/patron-attr-types.tt
index 54bd8f2..3c61a98 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/patron-attr-types.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/patron-attr-types.tt
@@ -15,6 +15,11 @@
 
 <script type="text/javascript">
 //<![CDATA[
+$(document).ready(function() {
+    if ( $("#branches option:selected").length < 1 ) {
+        $("#branches option:first").attr("selected", "selected");
+    }
+} );
 
 function DoCancel(f) {
   f.op.value='';
@@ -186,6 +191,20 @@ function CheckAttributeTypeForm(f) {
                   to be chosen from the authorized value list.  However, an 
authorized value list is not 
                   enforced during batch patron import.</span>
         </li>
+        <li><label for="branches">Branches limitation: </label>
+            <select id="branches" name="branches" multiple size="10">
+                <option value="">All branches</option>
+                [% FOREACH branch IN branches_loop %]
+                  [% IF ( branch.selected ) %]
+                    <option selected="selected" value="[% branch.branchcode 
%]">[% branch.branchname %]</option>
+                  [% ELSE %]
+                    <option value="[% branch.branchcode %]">[% 
branch.branchname %]</option>
+                  [% END %]
+                [% END %]
+            </select>
+            <span>Select All if this attribute type must to be displayed all 
the time. Otherwise select librairies you want to associate with this value.
+            </span>
+        </li>
         <li>
             <label for="category">Category: </label>
             <select name="category_code" id="category">
diff --git a/members/member.pl b/members/member.pl
index 9b793f4..0b4a4c9 100755
--- a/members/member.pl
+++ b/members/member.pl
@@ -134,8 +134,8 @@ foreach my $borrower(@$results[$from..$to-1]){
 
   my %row = (
     count => $index++,
-       %$borrower,
-       %{$categories_dislay{$$borrower{categorycode}}},
+    %$borrower,
+    (defined $categories_dislay{ $borrower->{categorycode} }?   %{ 
$categories_dislay{ $borrower->{categorycode} } }:()),
     overdues => $od,
     issues => $issue,
     odissue => "$od/$issue",
diff --git a/tools/batchMod.pl b/tools/batchMod.pl
index 9d59e3a..e1f5627 100755
--- a/tools/batchMod.pl
+++ b/tools/batchMod.pl
@@ -259,7 +259,13 @@ if ($op eq "show"){
 # now, build the item form for entering a new item
 my @loop_data =();
 my $i=0;
-my $authorised_values_sth = $dbh->prepare("SELECT authorised_value,lib FROM 
authorised_values WHERE category=? ORDER BY lib");
+my $query = qq{
+    SELECT authorised_value, lib FROM authorised_values
+    JOIN authorised_values_branches ON ( id = av_id AND ( branchcode = ? OR 
branchcode IS NULL ) )
+    WHERE category = ?
+    GROUP BY lib ORDER BY lib, lib_opac
+};
+my $authorised_values_sth = $dbh->prepare( $query );
 
 my $branches = GetBranchesLoop();  # build once ahead of time, instead of 
multiple times later.
 
@@ -352,7 +358,7 @@ foreach my $tag (sort keys %{$tagslib}) {
       }
       else {
           push @authorised_values, ""; # unless ( 
$tagslib->{$tag}->{$subfield}->{mandatory} );
-          $authorised_values_sth->execute( 
$tagslib->{$tag}->{$subfield}->{authorised_value} );
+          $authorised_values_sth->execute( C4::Context->userenv ? 
C4::Context->userenv->{"branch"} : "", 
$tagslib->{$tag}->{$subfield}->{authorised_value} );
           while ( my ( $value, $lib ) = $authorised_values_sth->fetchrow_array 
) {
               push @authorised_values, $value;
               $authorised_lib{$value} = $lib;
@@ -420,6 +426,8 @@ foreach my $tag (sort keys %{$tagslib}) {
     $i++
   }
 } # -- End foreach tag
+$authorised_values_sth->finish;
+
 
 
     # what's the next op ? it's what we are not in : an add if we're editing, 
otherwise, and edit.
diff --git a/tools/import_borrowers.pl b/tools/import_borrowers.pl
index 83db522..78353c9 100755
--- a/tools/import_borrowers.pl
+++ b/tools/import_borrowers.pl
@@ -304,7 +304,7 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) {
 } else {
     if ($extended) {
         my @matchpoints = ();
-        my @attr_types = C4::Members::AttributeTypes::GetAttributeTypes();
+        my @attr_types = C4::Members::AttributeTypes::GetAttributeTypes(undef, 
1);
         foreach my $type (@attr_types) {
             my $attr_type = C4::Members::AttributeTypes->fetch($type->{code});
             if ($attr_type->unique_id()) {
-- 
1.7.7.3

_______________________________________________
Koha-patches mailing list
[email protected]
http://lists.koha-community.org/cgi-bin/mailman/listinfo/koha-patches
website : http://www.koha-community.org/
git : http://git.koha-community.org/
bugs : http://bugs.koha-community.org/

Reply via email to