From 2321c844adee4d76850003d61d779a8d2fbae00a Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Thu, 9 May 2013 10:55:55 -0400 Subject: [PATCH] Bug 10276 - Extend IndependentBranches to support groups of libraries This patch adds the ability to have independent library groups. To enable this feature, enable the IndependentBranches system preference. If no libraries are in any independent library groups, IndependentBranches will behave as it always have. If a library is part of an independent library group with one or more libraries, that library will be able to access and modify patrons and items from any library in that group. Let's say we have 3 groups: Group1: LibA LibB LibC Group1: LibD LibE LibF Group3: LibG LibH LibA Note how LibA is in two groups ( Group1 and Group2 ). With this configuration, if IndependentBranches is enabled, libraries will be able to access and edit patrons and items in the following configuration: LibA => LibB, LibC, LibG, LibH LibB => LibA, LibC LibC => LibA, LibB LibD => LibE, LibF LibF => LibD, LibE LibG => LibH, LibA LibH => LibG, LibA Furthermore, let us assume there is a library LibI, which does not belong to any group. That library will only be able to view and edit patrons and items from it's own library. Imagine a library consortium consisting of multiple library systems. This feature would allow a consortium to group libraries by system such that those systems could work independently from one another on a single installation. Test Plan: 1) Apply patches for bugs 10080 and 10206 2) Apply this patch 3) Run updatedatabase.pl 4) Enable IndependentBranches 5) Test independent branches, no changes should be noted 6) Navigate to admin/branches.pl 7) Create a new Independent library group 8) Add your library and some other libraries to that group 9) Re-test IndependentBranches, everything should work as previously, but instead of being limited to just your library, you should have access to everything within your library group. Example: Try to edit an item. If the item is owned by a library in your group, you should be able to edit it. --- C4/Acquisition.pm | 16 +- C4/Branch.pm | 93 +++++++++- C4/Circulation.pm | 20 ++- C4/Items.pm | 46 +++-- C4/Letters.pm | 2 +- C4/Members.pm | 116 +++++++----- C4/Serials.pm | 111 +++++++---- C4/Suggestions.pm | 48 +++-- acqui/basket.pl | 28 ++- admin/branches.pl | 52 ++---- catalogue/moredetail.pl | 15 +- cataloguing/additem.pl | 13 +- circ/circulation-home.pl | 5 +- circ/pendingreserves.pl | 5 +- circ/reserveratios.pl | 6 +- installer/data/mysql/kohastructure.sql | 2 +- installer/data/mysql/updatedatabase.pl | 14 ++- .../prog/en/modules/admin/branches.tt | 210 +++++++++++++------- members/deletemem.pl | 12 +- members/member.pl | 2 +- 20 files changed, 539 insertions(+), 277 deletions(-) diff --git a/C4/Acquisition.pm b/C4/Acquisition.pm index 74aae85..02e386c 100644 --- a/C4/Acquisition.pm +++ b/C4/Acquisition.pm @@ -877,9 +877,8 @@ sub GetPendingOrders { my $userenv = C4::Context->userenv; if ( C4::Context->preference("IndependentBranches") ) { if ( ($userenv) && ( $userenv->{flags} != 1 ) ) { - $strsth .= " AND (borrowers.branchcode = ? - or borrowers.branchcode = '')"; - push @query_params, $userenv->{branch}; + my $branches = GetIndependentGroupModificationRights( { stringify => 1 } ); + $strsth .= qq{ AND (borrowers.branchcode IN ( $branches ) OR borrowers.branchcode = '') }; } } if ($supplierid) { @@ -1654,7 +1653,8 @@ sub GetParcel { if ( C4::Context->preference("IndependentBranches") ) { my $userenv = C4::Context->userenv; if ( ($userenv) && ( $userenv->{flags} != 1 ) ) { - $strsth .= " and (borrowers.branchcode = ? + my $branches = GetIndependentGroupModificationRights( { stringify => 1 } ); + $strsth .= " and (borrowers.branchcode IN ( $branches ) or borrowers.branchcode = '')"; push @query_params, $userenv->{branch}; } @@ -1873,8 +1873,8 @@ sub GetLateOrders { if (C4::Context->preference("IndependentBranches") && C4::Context->userenv && C4::Context->userenv->{flags} != 1 ) { - $from .= ' AND borrowers.branchcode LIKE ? '; - push @query_params, C4::Context->userenv->{branch}; + my $branches = GetIndependentGroupModificationRights( { stringify => 1 } ); + $from .= qq{ AND borrowers.branchcode IN ( $branches ) }; } my $query = "$select $from $having\nORDER BY latesince, basketno, borrowers.branchcode, supplier"; $debug and print STDERR "GetLateOrders query: $query\nGetLateOrders args: " . join(" ",@query_params); @@ -2043,8 +2043,8 @@ sub GetHistory { if ( C4::Context->preference("IndependentBranches") ) { my $userenv = C4::Context->userenv; if ( $userenv && ($userenv->{flags} || 0) != 1 ) { - $query .= " AND (borrowers.branchcode = ? OR borrowers.branchcode ='' ) "; - push @query_params, $userenv->{branch}; + my $branches = GetIndependentGroupModificationRights( { stringify => 1 } ); + $query .= qq{ AND ( borrowers.branchcode = ? OR borrowers.branchcode IN ( $branches ) ) }; } } $query .= " ORDER BY id"; diff --git a/C4/Branch.pm b/C4/Branch.pm index bdc01dc..81d9dc3 100644 --- a/C4/Branch.pm +++ b/C4/Branch.pm @@ -19,6 +19,7 @@ package C4::Branch; use strict; #use warnings; FIXME - Bug 2505 require Exporter; +use Carp; use C4::Context; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); @@ -42,6 +43,7 @@ BEGIN { &GetBranchCategories &GetBranchesInCategory &ModBranchCategoryInfo + &GetIndependentGroupModificationRights &DelBranch &DelBranchCategory &CheckCategoryUnique @@ -114,8 +116,8 @@ sub GetBranches { my $query="SELECT * FROM branches"; my @bind_parameters; if ($onlymine && C4::Context->userenv && C4::Context->userenv->{branch}){ - $query .= ' WHERE branchcode = ? '; - push @bind_parameters, C4::Context->userenv->{branch}; + my $branches = GetIndependentGroupModificationRights({ stringify => 1 }); + $query .= qq{ WHERE branchcode IN ( $branches ) }; } $query.=" ORDER BY branchname"; $sth = $dbh->prepare($query); @@ -301,7 +303,10 @@ C<$results> is an hashref sub GetBranchCategory { my ($catcode) = @_; - return unless $catcode; + unless ( $catcode ) { + carp("No category code passed in!"); + return; + } my $dbh = C4::Context->dbh; my $sth; @@ -371,7 +376,7 @@ the categories were already here, and minimally used. #TODO manage category types. rename possibly to 'agency domains' ? as borrowergroups are called categories. sub GetCategoryTypes { - return ( 'searchdomain','properties'); + return ( 'searchdomain','independent_groups'); } =head2 GetBranch @@ -426,6 +431,86 @@ sub GetBranchesInCategory { return( \@branches ); } +=head2 GetIndependentGroupModificationRights + + GetIndependentGroupModificationRights( + { + branch => $this_branch, + for => $other_branch, + stringify => 1, + } + ); + + Returns a list of branches this branch shares a common + independent group with. + + If 'branch' is not provided, it will be looked up via + C4::Context->userenv->{branch}. + + If 'for' is provided, the lookup is limited to that branch. + + If called in a list context, returns a list of + branchcodes ( including $this_branch ). + + If called in a scalar context, it returns + a count of matching branchcodes. Returns 1 if + + If stringify param is passed, the return value will + be a string of the comma delimited branchcodes. This + is useful for "branchcode IN $branchcodes" clauses + in SQL queries. + + $this_branch and $other_branch are equal for efficiency. + + So you can write: + my @branches = GetIndependentGroupModificationRights(); + or something like: + if ( GetIndependentGroupModificationRights( { for => $other_branch } ) ) { do_stuff(); } + +=cut + +sub GetIndependentGroupModificationRights { + my ($params) = @_; + + my $this_branch = $params->{branch}; + my $other_branch = $params->{for}; + my $stringify = $params->{stringify}; + + $this_branch ||= C4::Context->userenv->{branch}; + + carp("No branch found!") unless ($this_branch); + + return 1 if ( $this_branch eq $other_branch ); + + my $sql = q{ + SELECT DISTINCT(branchcode) + FROM branchrelations + JOIN branchcategories USING ( categorycode ) + WHERE categorycode IN ( + SELECT categorycode + FROM branchrelations + WHERE branchcode = ? + ) + AND branchcategories.categorytype = 'independent_group' + }; + + my @params; + push( @params, $this_branch ); + + if ($other_branch) { + $sql .= q{ AND branchcode = ? }; + push( @params, $other_branch ); + } + + my $dbh = C4::Context->dbh; + my @branchcodes = @{ $dbh->selectcol_arrayref( $sql, {}, @params ) }; + + return join( ',', map { qq{'$_'} } ( @branchcodes, $this_branch ) ) + if ($stringify); + + return wantarray() ? ( @branchcodes, $this_branch ) : scalar(@branchcodes); +} + =head2 GetBranchInfo $results = GetBranchInfo($branchcode); diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 982edfb..05addad 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -894,14 +894,18 @@ sub CanBookBeIssued { $alerts{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'alert' ); } if ( C4::Context->preference("IndependentBranches") ) { - my $userenv = C4::Context->userenv; - if ( C4::Context->IsSuperLibrarian() ) { - if ( $item->{C4::Context->preference("HomeOrHoldingBranch")} ne $userenv->{branch} ){ - $issuingimpossible{ITEMNOTSAMEBRANCH} = 1; - $issuingimpossible{'itemhomebranch'} = $item->{C4::Context->preference("HomeOrHoldingBranch")}; - } - $needsconfirmation{BORRNOTSAMEBRANCH} = GetBranchName( $borrower->{'branchcode'} ) - if ( $borrower->{'branchcode'} ne $userenv->{branch} ); + unless ( C4::Context->IsSuperLibrarian() ) { + $issuingimpossible{ITEMNOTSAMEBRANCH} = 1 + unless ( + GetIndependentGroupModificationRights( + { + for => $item->{ C4::Context->preference("HomeOrHoldingBranch") } + } + ) + ); + $needsconfirmation{BORRNOTSAMEBRANCH} = + GetBranchName( $borrower->{'branchcode'} ) + if ( $borrower->{'branchcode'} ne C4::Context->userenv->{branch} ); } } diff --git a/C4/Items.pm b/C4/Items.pm index b42ab86..9d61dea 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -32,6 +32,7 @@ use C4::Log; use List::MoreUtils qw/any/; use Data::Dumper; # used as part of logging item record changes, not just for # debugging; so please don't remove this +use C4::Branch qw/GetIndependentGroupModificationRights/; use vars qw($VERSION @ISA @EXPORT); @@ -1251,18 +1252,22 @@ sub GetItemsInfo { my $datedue = ''; $isth->execute( $data->{'itemnumber'} ); if ( my $idata = $isth->fetchrow_hashref ) { - $data->{borrowernumber} = $idata->{borrowernumber}; - $data->{cardnumber} = $idata->{cardnumber}; - $data->{surname} = $idata->{surname}; - $data->{firstname} = $idata->{firstname}; + $data->{borrowernumber} = $idata->{borrowernumber}; + $data->{cardnumber} = $idata->{cardnumber}; + $data->{surname} = $idata->{surname}; + $data->{firstname} = $idata->{firstname}; $data->{lastreneweddate} = $idata->{lastreneweddate}; - $datedue = $idata->{'date_due'}; - if (C4::Context->preference("IndependentBranches")){ - my $userenv = C4::Context->userenv; - unless ( C4::Context->IsSuperLibrarian() ) { - $data->{'NOTSAMEBRANCH'} = 1 if ($idata->{'bcode'} ne $userenv->{branch}); - } - } + $datedue = $idata->{'date_due'}; + + if ( C4::Context->preference("IndependentBranches") ) { + unless ( + C4::Context->IsSuperLibrarian() + || GetIndependentGroupModificationRights( { for => $idata->{'bcode'} } ) + ) + { + $data->{'NOTSAMEBRANCH'} = 1; + } + } } if ( $data->{'serial'}) { $ssth->execute($data->{'itemnumber'}) ; @@ -2214,12 +2219,18 @@ sub DelItemCheck { my $item = GetItem($itemnumber); my $onloan=$sth->fetchrow; - if ($onloan){ - $error = "book_on_loan" + if ($onloan) { + $error = "book_on_loan"; } - elsif ( !( C4::Context->userenv->{flags} & 1 ) - and C4::Context->preference("IndependentBranches") - and ( C4::Context->userenv->{branch} ne $item->{'homebranch'} ) ) + elsif ( + !C4::Context->IsSuperLibrarian() + && C4::Context->preference("IndependentBranches") + && !GetIndependentGroupModificationRights( + { + for => $item->{ C4::Context->preference("HomeOrHoldingBranch") } + } + ) + ) { $error = "not_same_branch"; } @@ -2695,7 +2706,8 @@ sub PrepareItemrecordDisplay { if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) { if ( ( C4::Context->preference("IndependentBranches") ) && !C4::Context->IsSuperLibrarian() ) { - my $sth = $dbh->prepare( "SELECT branchcode,branchname FROM branches WHERE branchcode = ? ORDER BY branchname" ); + my $branches = GetIndependentGroupModificationRights( { stringify => 1 } ); + my $sth = $dbh->prepare( "SELECT branchcode,branchname FROM branches WHERE branchcode IN ( $branches ) ORDER BY branchname" ); $sth->execute( C4::Context->userenv->{branch} ); push @authorised_values, "" unless ( $tagslib->{$tag}->{$subfield}->{mandatory} ); diff --git a/C4/Letters.pm b/C4/Letters.pm index 93bc34d..19a970b 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -126,7 +126,7 @@ our %letter; sub getletter { my ( $module, $code, $branchcode ) = @_; - $branchcode ||= ''; + $branchcode ||= q{}; if ( C4::Context->preference('IndependentBranches') and $branchcode diff --git a/C4/Members.pm b/C4/Members.pm index 37bfb3f..af67e22 100644 --- a/C4/Members.pm +++ b/C4/Members.pm @@ -26,6 +26,7 @@ use C4::Context; use C4::Dates qw(format_date_in_iso format_date); use Digest::MD5 qw(md5_base64); use String::Random qw( random_string ); +use Clone qw(clone); use Date::Calc qw/Today Add_Delta_YM check_date Date_to_Days/; use C4::Log; # logaction use C4::Overdues; @@ -40,7 +41,7 @@ use DateTime; use DateTime::Format::DateParse; use Koha::DateUtils; use Text::Unaccent qw( unac_string ); - +use C4::Branch qw( GetIndependentGroupModificationRights ); our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug); BEGIN { @@ -257,24 +258,23 @@ sub Search { # Mentioning for the reference if ( C4::Context->preference("IndependentBranches") ) { # && !$showallbranches){ - if ( my $userenv = C4::Context->userenv ) { - my $branch = $userenv->{'branch'}; - if ( !C4::Context->IsSuperLibrarian() && $branch ){ - if (my $fr = ref $filter) { - if ( $fr eq "HASH" ) { - $filter->{branchcode} = $branch; - } - else { - foreach (@$filter) { - $_ = { '' => $_ } unless ref $_; - $_->{branchcode} = $branch; - } - } + unless ( C4::Context->IsSuperLibrarian() ){ + $filter = clone( $filter ); # Modify a copy only + my @branches = GetIndependentGroupModificationRights(); + if ( my $fr = ref $filter ) { + if ( $fr eq "HASH" ) { + $filter->{branchcode} = \@branches; } else { - $filter = { '' => $filter, branchcode => $branch }; + foreach (@$filter) { + $_ = { '' => $_ } unless ref $_; + $_->{branchcode} = \@branches; + } } - } + } + else { + $filter = { '' => $filter, branchcode => \@branches }; + } } } @@ -1313,6 +1313,12 @@ sub checkuniquemember { ($dateofbirth) ? "SELECT borrowernumber,categorycode FROM borrowers WHERE surname=? and firstname=? and dateofbirth=?" : "SELECT borrowernumber,categorycode FROM borrowers WHERE surname=? and firstname=?"; + + if ( C4::Context->preference('IndependentBranches') ) { + my $branches = GetIndependentGroupModificationRights( { stringify => 1 } ); + $request .= " AND branchcode IN ( $branches )"; + } + my $sth = $dbh->prepare($request); if ($collectivity) { $sth->execute( uc($surname) ); @@ -2063,13 +2069,14 @@ sub GetBorrowersToExpunge { my $filterdate = $params->{'not_borrowered_since'}; my $filterexpiry = $params->{'expired_before'}; my $filtercategory = $params->{'category_code'}; - my $filterbranch = $params->{'branchcode'} || - ((C4::Context->preference('IndependentBranches') - && C4::Context->userenv - && !C4::Context->IsSuperLibrarian() - && C4::Context->userenv->{branch}) - ? C4::Context->userenv->{branch} - : ""); + my $filterbranch = $params->{'branchcode'}; + my @filterbranches = + ( C4::Context->preference('IndependentBranches') + && C4::Context->userenv + && !C4::Context->IsSuperLibrarian() + && C4::Context->userenv->{branch} ) + ? GetIndependentGroupModificationRights() + : ($filterbranch); my $dbh = C4::Context->dbh; my $query = " @@ -2084,9 +2091,10 @@ sub GetBorrowersToExpunge { AND borrowernumber NOT IN (SELECT guarantorid FROM borrowers WHERE guarantorid IS NOT NULL AND guarantorid <> 0) "; my @query_params; - if ( $filterbranch && $filterbranch ne "" ) { - $query.= " AND borrowers.branchcode = ? "; - push( @query_params, $filterbranch ); + if ( @filterbranches ) { + my $placeholders = join( ',', ('?') x @filterbranches ); + $query.= " AND borrowers.branchcode IN ( $placeholders )"; + push( @query_params, @filterbranches ); } if ( $filterexpiry ) { $query .= " AND dateexpiry < ? "; @@ -2129,13 +2137,16 @@ I<$result> is a ref to an array which all elements are a hasref. =cut sub GetBorrowersWhoHaveNeverBorrowed { - my $filterbranch = shift || - ((C4::Context->preference('IndependentBranches') - && C4::Context->userenv - && !C4::Context->IsSuperLibrarian() - && C4::Context->userenv->{branch}) - ? C4::Context->userenv->{branch} - : ""); + my $filterbranch = shift; + + my @filterbranches = + ( C4::Context->preference('IndependentBranches') + && C4::Context->userenv + && !C4::Context->IsSuperLibrarian() + && C4::Context->userenv->{branch} ) + ? GetIndependentGroupModificationRights() + : ($filterbranch); + my $dbh = C4::Context->dbh; my $query = " SELECT borrowers.borrowernumber,max(timestamp) as latestissue @@ -2143,10 +2154,12 @@ sub GetBorrowersWhoHaveNeverBorrowed { LEFT JOIN issues ON borrowers.borrowernumber = issues.borrowernumber WHERE issues.borrowernumber IS NULL "; + my @query_params; - if ($filterbranch && $filterbranch ne ""){ - $query.=" AND borrowers.branchcode= ?"; - push @query_params,$filterbranch; + if (@filterbranches) { + my $placeholders = join( ',', ('?') x @filterbranches ); + $query .= " AND borrowers.branchcode IN ( $placeholders ) "; + push( @query_params, @filterbranches ); } warn $query if $debug; @@ -2179,25 +2192,32 @@ This hashref is containt the number of time this borrowers has borrowed before I sub GetBorrowersWithIssuesHistoryOlderThan { my $dbh = C4::Context->dbh; my $date = shift ||POSIX::strftime("%Y-%m-%d",localtime()); - my $filterbranch = shift || - ((C4::Context->preference('IndependentBranches') - && C4::Context->userenv - && !C4::Context->IsSuperLibrarian() - && C4::Context->userenv->{branch}) - ? C4::Context->userenv->{branch} - : ""); + my $filterbranch = shift; + + my @filterbranches = + ( C4::Context->preference('IndependentBranches') + && C4::Context->userenv + && !C4::Context->IsSuperLibrarian() + && C4::Context->userenv->{branch} ) + ? GetIndependentGroupModificationRights() + : ($filterbranch); + my $query = " SELECT count(borrowernumber) as n,borrowernumber FROM old_issues WHERE returndate < ? AND borrowernumber IS NOT NULL "; + my @query_params; - push @query_params, $date; - if ($filterbranch){ - $query.=" AND branchcode = ?"; - push @query_params, $filterbranch; - } + push( @query_params, $date ); + + if (@filterbranches) { + my $placeholders = join( ',', ('?') x @filterbranches ); + $query .= " AND branchcode IN ( $placeholders ) "; + push( @query_params, @filterbranches ); + } + $query.=" GROUP BY borrowernumber "; warn $query if $debug; my $sth = $dbh->prepare($query); diff --git a/C4/Serials.pm b/C4/Serials.pm index 08bf633..b82d63f 100644 --- a/C4/Serials.pm +++ b/C4/Serials.pm @@ -215,13 +215,20 @@ sub GetSerialInformation { my ($serialid) = @_; my $dbh = C4::Context->dbh; my $query = qq| - SELECT serial.*, serial.notes as sernotes, serial.status as serstatus,subscription.*,subscription.subscriptionid as subsid |; + SELECT serial.*, + serial.notes as sernotes, + serial.status as serstatus, + subscription.*, + subscription.subscriptionid as subsid + |; if ( C4::Context->preference('IndependentBranches') && C4::Context->userenv - && C4::Context->userenv->{'flags'} != 1 + && C4::Context->userenv->{'flags'} % 2 != 1 && C4::Context->userenv->{'branch'} ) { - $query .= " - , ((subscription.branchcode <>\"" . C4::Context->userenv->{'branch'} . "\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit "; + my $branches = GetIndependentGroupModificationRights( { stringify => 1 } ); + $query .= qq| + , ( ( subscription.branchcode NOT IN ( $branches ) ) AND subscription.branchcode <> '' AND subscription.branchcode IS NOT NULL ) AS cannotedit + |; } $query .= qq| FROM serial LEFT JOIN subscription ON subscription.subscriptionid=serial.subscriptionid @@ -315,33 +322,36 @@ subscription, subscriptionhistory, aqbooksellers.name, biblio.title sub GetSubscription { my ($subscriptionid) = @_; my $dbh = C4::Context->dbh; - my $query = qq( + + my $query = qq| SELECT subscription.*, subscriptionhistory.*, aqbooksellers.name AS aqbooksellername, biblio.title AS bibliotitle, - subscription.biblionumber as bibnum); + subscription.biblionumber as bibnum + |; + if ( C4::Context->preference('IndependentBranches') && C4::Context->userenv - && C4::Context->userenv->{'flags'} != 1 - && C4::Context->userenv->{'branch'} ) { - $query .= " - , ((subscription.branchcode <>\"" . C4::Context->userenv->{'branch'} . "\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit "; + && C4::Context->userenv->{'flags'} % 2 != 1 + && C4::Context->userenv->{'branch'} ) + { + my $branches = + GetIndependentGroupModificationRights( { stringify => 1 } ); + + $query .= qq| + , ( ( subscription.branchcode NOT IN ( $branches ) ) AND subscription.branchcode <> '' AND subscription.branchcode IS NOT NULL ) AS cannotedit + |; } - $query .= qq( + + $query .= qq| FROM subscription LEFT JOIN subscriptionhistory ON subscription.subscriptionid=subscriptionhistory.subscriptionid LEFT JOIN aqbooksellers ON subscription.aqbooksellerid=aqbooksellers.id LEFT JOIN biblio ON biblio.biblionumber=subscription.biblionumber WHERE subscription.subscriptionid = ? - ); + |; - # if (C4::Context->preference('IndependentBranches') && - # C4::Context->userenv && - # C4::Context->userenv->{'flags'} != 1){ - # # $debug and warn "flags: ".C4::Context->userenv->{'flags'}; - # $query.=" AND subscription.branchcode IN ('".C4::Context->userenv->{'branch'}."',\"\")"; - # } $debug and warn "query : $query\nsubsid :$subscriptionid"; my $sth = $dbh->prepare($query); $sth->execute($subscriptionid); @@ -358,8 +368,10 @@ sub GetSubscription { sub GetFullSubscription { my ($subscriptionid) = @_; my $dbh = C4::Context->dbh; - my $query = qq| - SELECT serial.serialid, + + my $query = qq| + SELECT + serial.serialid, serial.serialseq, serial.planneddate, serial.publisheddate, @@ -369,14 +381,22 @@ sub GetFullSubscription { aqbooksellers.name as aqbooksellername, biblio.title as bibliotitle, subscription.branchcode AS branchcode, - subscription.subscriptionid AS subscriptionid |; + subscription.subscriptionid AS subscriptionid + |; + if ( C4::Context->preference('IndependentBranches') && C4::Context->userenv - && C4::Context->userenv->{'flags'} != 1 - && C4::Context->userenv->{'branch'} ) { - $query .= " - , ((subscription.branchcode <>\"" . C4::Context->userenv->{'branch'} . "\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit "; + && C4::Context->userenv->{'flags'} % 2 != 1 + && C4::Context->userenv->{'branch'} ) + { + my $branches = + GetIndependentGroupModificationRights( { stringify => 1 } ); + + $query .= qq| + , ( ( subscription.branchcode NOT IN ( $branches ) ) AND subscription.branchcode <> '' AND subscription.branchcode IS NOT NULL ) AS cannotedit + |; } + $query .= qq| FROM serial LEFT JOIN subscription ON @@ -486,13 +506,16 @@ sub GetSubscriptionsFromBiblionumber { $subs->{ "periodicity" . $subs->{periodicity} } = 1; $subs->{ "numberpattern" . $subs->{numberpattern} } = 1; $subs->{ "status" . $subs->{'status'} } = 1; - $subs->{'cannotedit'} = - ( C4::Context->preference('IndependentBranches') + $subs->{'cannotedit'} = ( + C4::Context->preference('IndependentBranches') && C4::Context->userenv && !C4::Context->IsSuperLibrarian() && C4::Context->userenv->{branch} && $subs->{branchcode} - && ( C4::Context->userenv->{branch} ne $subs->{branchcode} ) ); + && GetIndependentGroupModificationRights( + { for => $subs->{branchcode} } + ) + ); if ( $subs->{enddate} eq '0000-00-00' ) { $subs->{enddate} = ''; @@ -516,8 +539,10 @@ sub GetSubscriptionsFromBiblionumber { sub GetFullSubscriptionsFromBiblionumber { my ($biblionumber) = @_; my $dbh = C4::Context->dbh; - my $query = qq| - SELECT serial.serialid, + + my $query = qq| + SELECT + serial.serialid, serial.serialseq, serial.planneddate, serial.publisheddate, @@ -526,13 +551,20 @@ sub GetFullSubscriptionsFromBiblionumber { year(IF(serial.publisheddate="00-00-0000",serial.planneddate,serial.publisheddate)) as year, biblio.title as bibliotitle, subscription.branchcode AS branchcode, - subscription.subscriptionid AS subscriptionid|; + subscription.subscriptionid AS subscriptionid + |; + if ( C4::Context->preference('IndependentBranches') && C4::Context->userenv && C4::Context->userenv->{'flags'} != 1 - && C4::Context->userenv->{'branch'} ) { - $query .= " - , ((subscription.branchcode <>\"" . C4::Context->userenv->{'branch'} . "\") and subscription.branchcode <>\"\" and subscription.branchcode IS NOT NULL) as cannotedit "; + && C4::Context->userenv->{'branch'} ) + { + my $branches = + GetIndependentGroupModificationRights( { stringify => 1 } ); + + $query .= qq| + , ( ( subscription.branchcode NOT IN ( $branches ) ) AND subscription.branchcode <> '' AND subscription.branchcode IS NOT NULL ) AS cannotedit + |; } $query .= qq| @@ -626,13 +658,16 @@ sub GetSubscriptions { my @results; while ( my $line = $sth->fetchrow_hashref ) { - $line->{'cannotedit'} = - ( C4::Context->preference('IndependentBranches') + $line->{'cannotedit'} = ( + C4::Context->preference('IndependentBranches') && C4::Context->userenv - && !C4:Context->IsSuperLibrarian() + && !C4::Context->IsSuperLibrarian() && C4::Context->userenv->{branch} && $line->{branchcode} - && ( C4::Context->userenv->{branch} ne $line->{branchcode} ) ); + && GetIndependentGroupModificationRights( + { for => $line->{branchcode} } + ) + ); push @results, $line; } return @results; diff --git a/C4/Suggestions.pm b/C4/Suggestions.pm index 51a3d38..1b23d12 100644 --- a/C4/Suggestions.pm +++ b/C4/Suggestions.pm @@ -32,6 +32,7 @@ use C4::Letters; use List::MoreUtils qw(any); use C4::Dates qw(format_date_in_iso); use base qw(Exporter); +use C4::Branch qw(GetIndependentGroupModificationRights); our $VERSION = 3.07.00.049; our @EXPORT = qw( @@ -132,17 +133,12 @@ sub SearchSuggestion { } # filter on user branch - if ( C4::Context->preference('IndependentBranches') ) { - my $userenv = C4::Context->userenv; - if ($userenv) { - if ( !C4::Context->IsSuperLibrarian() && !$suggestion->{branchcode} ) - { - push @sql_params, $$userenv{branch}; - push @query, q{ - AND (suggestions.branchcode=? OR suggestions.branchcode='') - }; - } - } + if ( C4::Context->preference('IndependentBranches') && !C4::Context->IsSuperLibrarian() && !$suggestion->{branchcode} ) { + my $branches = + GetIndependentGroupModificationRights( { stringify => 1 } ); + push ( @query, qq{ + AND (suggestions.branchcode IN ( $branches ) OR suggestions.branchcode='') + } ); } else { if ( defined $suggestion->{branchcode} && $suggestion->{branchcode} ) { unless ( $suggestion->{branchcode} eq '__ANY__' ) { @@ -340,13 +336,20 @@ sub GetSuggestionByStatus { # filter on branch if ( C4::Context->preference("IndependentBranches") || $branchcode ) { - my $userenv = C4::Context->userenv; - if ($userenv) { - unless ( C4::Context->IsSuperLibrarian() ) { - push @sql_params, $userenv->{branch}; - $query .= q{ AND (U1.branchcode = ? OR U1.branchcode ='') }; - } + + if ( C4::Context->userenv + && C4::Context->preference("IndependentBranches") + && !C4::Context->IsSuperLibrarian() ) + { + + my $branches = + GetIndependentGroupModificationRights( { stringify => 1 } ); + + $query .= qq{ + AND (U1.branchcode IN ( $branches ) OR U1.branchcode ='') + }; } + if ($branchcode) { push @sql_params, $branchcode; $query .= q{ AND (U1.branchcode = ? OR U1.branchcode ='') }; @@ -392,12 +395,19 @@ sub CountSuggestion { if ( C4::Context->preference("IndependentBranches") && !C4::Context->IsSuperLibrarian() ) { - my $query = q{ + my $branches = + GetIndependentGroupModificationRights( { stringify => 1 } ); + + my $query = qq{ SELECT count(*) FROM suggestions LEFT JOIN borrowers ON borrowers.borrowernumber=suggestions.suggestedby WHERE STATUS=? - AND (borrowers.branchcode='' OR borrowers.branchcode=?) + AND ( + borrowers.branchcode IN ( $branches ) + OR + borrowers.branchcode=? + ) }; $sth = $dbh->prepare($query); $sth->execute( $status, $userenv->{branch} ); diff --git a/acqui/basket.pl b/acqui/basket.pl index 06d4d1a..27a94e8 100755 --- a/acqui/basket.pl +++ b/acqui/basket.pl @@ -35,6 +35,7 @@ use C4::Members qw/GetMember/; #needed for permissions checking for changing ba use C4::Items; use C4::Suggestions; use Date::Calc qw/Add_Delta_Days/; +use C4::Branch qw/GetIndependentGroupModificationRights/; =head1 NAME @@ -105,11 +106,17 @@ if ( $op eq 'delete_confirm' ) { $template->param( delete_confirm => 1 ); if ( C4::Context->preference("IndependentBranches") ) { my $userenv = C4::Context->userenv; - unless ( $userenv->{flags} == 1 ) { - my $validtest = ( $basket->{creationdate} eq '' ) - || ( $userenv->{branch} eq $basket->{branch} ) + if ( $userenv->{flags} % 2 != 1 ) { + my $validtest = + ( $basket->{creationdate} eq '' ) || ( $userenv->{branch} eq '' ) - || ( $basket->{branch} eq '' ); + || ( $basket->{branch} eq '' ) + || ( + GetIndependentGroupModificationRights( + { for => $basket->{branch} } + ) + ); + unless ($validtest) { print $query->redirect("../mainpage.pl"); exit 1; @@ -194,11 +201,16 @@ if ( $op eq 'delete_confirm' ) { # get librarian branch... if ( C4::Context->preference("IndependentBranches") ) { my $userenv = C4::Context->userenv; - unless ( $userenv->{flags} == 1 ) { - my $validtest = ( $basket->{creationdate} eq '' ) - || ( $userenv->{branch} eq $basket->{branch} ) + if ( $userenv->{flags} % 2 != 1 ) { + my $validtest = + ( $basket->{creationdate} eq '' ) || ( $userenv->{branch} eq '' ) - || ( $basket->{branch} eq '' ); + || ( $basket->{branch} eq '' ) + || ( + GetIndependentGroupModificationRights( + { for => $basket->{branch} } + ) + ); unless ($validtest) { print $query->redirect("../mainpage.pl"); exit 1; diff --git a/admin/branches.pl b/admin/branches.pl index 9e6b14a..29d7843 100755 --- a/admin/branches.pl +++ b/admin/branches.pl @@ -258,7 +258,7 @@ sub editbranchform { $oldprinter = $data->{'branchprinter'} || ''; _branch_to_template($data, $innertemplate); } - $innertemplate->param( categoryloop => $catinfo ); + $innertemplate->param( branch_categories => $catinfo ); foreach my $thisprinter ( keys %$printers ) { push @printerloop, { @@ -277,25 +277,8 @@ sub editbranchform { } sub editcatform { - - # prepares the edit form... - my ($categorycode,$innertemplate) = @_; - # warn "cat : $categorycode"; - my @cats; - my $data; - if ($categorycode) { - my $data = GetBranchCategory($categorycode); - $innertemplate->param( - categorycode => $data->{'categorycode'}, - categoryname => $data->{'categoryname'}, - codedescription => $data->{'codedescription'}, - show_in_pulldown => $data->{'show_in_pulldown'}, - ); - } - for my $ctype (GetCategoryTypes()) { - push @cats , { type => $ctype , selected => ($data->{'categorytype'} and $data->{'categorytype'} eq $ctype) }; - } - $innertemplate->param(categorytype => \@cats); + my ( $categorycode, $innertemplate ) = @_; + $innertemplate->param( category => GetBranchCategory($categorycode) ); } sub branchinfotable { @@ -366,25 +349,20 @@ sub branchinfotable { push @loop_data, \%row; } - my @branchcategories = (); - for my $ctype ( GetCategoryTypes() ) { - my $catinfo = GetBranchCategories($ctype); - my @categories; - foreach my $cat (@$catinfo) { - push @categories, { - categoryname => $cat->{'categoryname'}, - categorycode => $cat->{'categorycode'}, - codedescription => $cat->{'codedescription'}, - categorytype => $cat->{'categorytype'}, - }; - } - push @branchcategories, { categorytype => $ctype , $ctype => 1 , catloop => ( @categories ? \@categories : undef) }; - } + + my $catinfo = GetBranchCategories(); + my $categories; + foreach my $cat (@$catinfo) { + $categories->{ $cat->{categorytype} }->{ $cat->{'categorycode'} } = { + categoryname => $cat->{'categoryname'}, + codedescription => $cat->{'codedescription'}, + }; + } + $innertemplate->param( - branches => \@loop_data, - branchcategories => \@branchcategories + branches => \@loop_data, + branch_categories => $categories ); - } sub _branch_to_template { diff --git a/catalogue/moredetail.pl b/catalogue/moredetail.pl index e092827..33aa64e 100755 --- a/catalogue/moredetail.pl +++ b/catalogue/moredetail.pl @@ -172,13 +172,20 @@ foreach my $item (@items){ $item->{status_advisory} = 1; } - if (C4::Context->preference("IndependentBranches")) { - #verifying rights + if ( C4::Context->preference("IndependentBranches") ) { + my $userenv = C4::Context->userenv(); - unless (($userenv->{'flags'} == 1) or ($userenv->{'branch'} eq $item->{'homebranch'})) { - $item->{'nomod'}=1; + unless ( + $userenv->{'flags'} % 2 != 1 + || GetIndependentGroupModificationRights( + { for => $item->{'homebranch'} } + ) + ) + { + $item->{'nomod'} = 1; } } + $item->{'homebranchname'} = GetBranchName($item->{'homebranch'}); $item->{'holdingbranchname'} = GetBranchName($item->{'holdingbranch'}); if ($item->{'datedue'}) { diff --git a/cataloguing/additem.pl b/cataloguing/additem.pl index f2a5ccb..081b289 100755 --- a/cataloguing/additem.pl +++ b/cataloguing/additem.pl @@ -690,10 +690,19 @@ foreach my $field (@fields) { || $subfieldvalue; } - if (($field->tag eq $branchtagfield) && ($subfieldcode eq $branchtagsubfield) && C4::Context->preference("IndependentBranches")) { + if ( $field->tag eq $branchtagfield + && $subfieldcode eq $branchtagsubfield + && C4::Context->preference("IndependentBranches") ) + { #verifying rights my $userenv = C4::Context->userenv(); - unless (($userenv->{'flags'} == 1) or (($userenv->{'branch'} eq $subfieldvalue))){ + unless ( + $userenv->{'flags'} % 2 == 1 + || GetIndependentGroupModificationRights( + { for => $subfieldvalue } + ) + ) + { $this_row{'nomod'} = 1; } } diff --git a/circ/circulation-home.pl b/circ/circulation-home.pl index d4f5a2c..e834ebe 100755 --- a/circ/circulation-home.pl +++ b/circ/circulation-home.pl @@ -23,6 +23,7 @@ use C4::Auth; use C4::Output; use C4::Context; use C4::Koha; +use C4::Branch qw/GetIndependentGroupModificationRights/; my $query = new CGI; my ($template, $loggedinuser, $cookie, $flags) @@ -38,7 +39,9 @@ my $fa = getframeworkinfo('FA'); $template->param( fast_cataloging => 1 ) if (defined $fa); # Checking if the transfer page needs to be displayed -$template->param( display_transfer => 1 ) if ( ($flags->{'superlibrarian'} == 1) || (C4::Context->preference("IndependentBranches") == 0) ); +$template->param( display_transfer => 1 ) + if ( $flags->{'superlibrarian'} == 1 + || scalar GetIndependentGroupModificationRights() ); output_html_with_http_headers $query, $cookie, $template->output; diff --git a/circ/pendingreserves.pl b/circ/pendingreserves.pl index 9a60ec1..9106c26 100755 --- a/circ/pendingreserves.pl +++ b/circ/pendingreserves.pl @@ -32,6 +32,7 @@ use C4::Auth; use C4::Dates qw/format_date format_date_in_iso/; use C4::Debug; use Date::Calc qw/Today Add_Delta_YMD/; +use C4::Branch qw/GetIndependentGroupModificationRights/; my $input = new CGI; my $startdate=$input->param('from'); @@ -152,8 +153,8 @@ if ( $run_report ) { if (C4::Context->preference('IndependentBranches')){ - $strsth .= " AND items.holdingbranch=? "; - push @query_params, C4::Context->userenv->{'branch'}; + my @branches = GetIndependentGroupModificationRights( { stringify => 1 } ); + $strsth .= " AND items.holdingbranch IN ( $branches ) "; } $strsth .= " GROUP BY reserves.biblionumber ORDER BY biblio.title "; diff --git a/circ/reserveratios.pl b/circ/reserveratios.pl index 29cd0b6..bbec1e7 100755 --- a/circ/reserveratios.pl +++ b/circ/reserveratios.pl @@ -113,9 +113,9 @@ my $strsth = $sqldatewhere "; -if (C4::Context->preference('IndependentBranches')){ - $strsth .= " AND items.holdingbranch=? "; - push @query_params, C4::Context->userenv->{'branch'}; +if ( C4::Context->preference('IndependentBranches') ) { + my $branches = GetIndependentGroupModificationRights( { stringify => 1 } ); + $strsth .= " AND items.holdingbranch IN ( $branches ) "; } $strsth .= " GROUP BY reserves.biblionumber ORDER BY reservecount DESC"; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 7628983..39f7673 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -340,7 +340,7 @@ CREATE TABLE `branchcategories` ( -- information related to library/branch group `categorycode` varchar(10) NOT NULL default '', -- unique identifier for the library/branch group `categoryname` varchar(32), -- name of the library/branch group `codedescription` mediumtext, -- longer description of the library/branch group - `categorytype` varchar(16), -- says whether this is a search group or a properties group + `categorytype` ENUM( 'searchdomain', 'independent_group' ) NULL DEFAULT NULL, -- says whether this is a search group or an independent group `show_in_pulldown` tinyint(1) NOT NULL DEFAULT '0', -- says this group should be in the opac libararies pulldown if it is enabled PRIMARY KEY (`categorycode`), KEY `show_in_pulldown` (`show_in_pulldown`) diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 74aeb3e..ca1989a 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -6938,7 +6938,19 @@ $DBversion = "3.13.00.002"; if ( CheckVersion($DBversion) ) { $dbh->do("UPDATE systempreferences SET variable = 'IndependentBranches' WHERE variable = 'IndependantBranches'"); print "Upgrade to $DBversion done (Bug 10080 - Change system pref IndependantBranches to IndependentBranches)\n"; - SetVersion ($DBversion); + SetVersion ($DBversion); +} + +$DBversion = "3.11.00.XXX"; +if ( CheckVersion($DBversion) ) { + $dbh->do(q{ + ALTER TABLE branchcategories + CHANGE categorytype categorytype + ENUM( 'searchdomain', 'independent_group' ) + NULL DEFAULT NULL + }); + print "Upgrade to $DBversion done (Remove branch property groups, add independent groups)\n"; + SetVersion ($DBversion); } $DBversion = '3.13.00.003'; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/branches.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/branches.tt index 5bf9567..73680b9 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/branches.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/branches.tt @@ -103,20 +103,50 @@ tinyMCE.init({ - [% IF ( categoryloop ) %]
Group(s): -
    - [% FOREACH categoryloo IN categoryloop %] -
  1. - [% IF categoryloo.selected %] - - [% ELSE %] - - [% END %] - [% categoryloo.codedescription %] -
  2. - [% END %] -
-
[% END %] + + [% IF ( branch_categories ) %] +
+ Group(s): +
    +
    + Search domain + [% FOREACH bc IN branch_categories %] + [% IF bc.categorytype == "searchdomain" %] +
  1. + + [% IF ( bc.selected ) %] + + [% ELSE %] + + [% END %] + [% bc.codedescription %] +
  2. + [% END %] + [% END %] +
    +
+
    +
    + Independent library groups + [% FOREACH bc IN branch_categories %] + [% IF bc.categorytype == "independent_group" %] +
  1. + + [% IF ( bc.selected ) %] + + [% ELSE %] + + [% END %] + [% bc.codedescription %] +
  2. + [% END %] + [% END %] +
  3. If independent library groups are enabled ( via the IndependentBranches system preference ), a library may access and alter records and patrons from libraries in any group that also library belongs to. A library may belong to multiple library groups.
  4. +
    +
+
+ [% END %] +
  1. @@ -252,90 +282,122 @@ tinyMCE.init({ [% ELSE %]
    There are no libraries defined. Start defining libraries.
    [% END %] - - [% IF ( branchcategories ) %] - [% FOREACH branchcategorie IN branchcategories %] -

    Group(s): [% IF ( branchcategorie.properties ) %]Properties[% ELSE %][% IF ( branchcategorie.searchdomain ) %]Search domain[% END %][% END %]

    - [% IF ( branchcategorie.catloop ) %] - - - - - - - - - - - - [% FOREACH catloo IN branchcategorie.catloop %] - - - - - - - - [% END %] - -
    NameCodeDescription  
    [% catloo.categoryname %][% catloo.categorycode %][% catloo.codedescription %] - Edit - - Delete -
    + +

    Search domain groups

    + [% IF branch_categories.searchdomain %] + + + + + + + + + + + + [% FOREACH bc IN branch_categories.searchdomain %] + + + + + + + + [% END %] + +
    NameCodeDescription  
    [% bc.value.categoryname %][% bc.key %][% bc.value.codedescription %] + Edit + + Delete +
    + [% ELSE %] + No search domain groups defined. + [% END %] + Add a new group. + +

    Independent library groups:

    + [% IF branch_categories.independent_group %] + + + + + + + + + + + + [% FOREACH bc IN branch_categories.independent_group %] + + + + + + + + [% END %] + +
    NameCodeDescription  
    [% bc.value.categoryname %][% bc.key %][% bc.value.codedescription %] + Edit + + Delete +
    [% ELSE %] - No [% IF ( branchcategorie.properties ) %]properties[% ELSIF ( branchcategorie.searchdomain ) %]search domain[% END %] defined. Add a new group. + No independent library groups defined. [% END %] - [% END %] - [% ELSE %] -

    No groups defined.

    - [% END %] + Add a new group. [% END %] [% IF ( editcategory ) %] -

    [% IF ( categorycode ) %]Edit group [% categorycode %][% ELSE %]Add group[% END %]

    +

    [% IF ( category ) %]Edit group [% category.categorycode %][% ELSE %]Add group[% END %]

    - [% IF ( categorycode ) %] - - [% ELSE %] - - [% END %] + [% IF ( category.categorycode ) %] + + [% ELSE %] + + [% END %]
    1. - [% IF ( categorycode ) %] + [% IF ( category.categorycode ) %] Category code: - - [% categorycode %] + + [% category.categorycode %] [% ELSE %] - - + + [% END %]
    2. - +
    3. - +
    4. - [% IF ( show_in_pulldown ) %] + [% IF ( category.show_in_pulldown ) %] [% ELSE %] @@ -343,7 +405,13 @@ tinyMCE.init({
    -
    +
    + [% IF category %] + + [% ELSE %] + + [% END %] +
    [% END %] diff --git a/members/deletemem.pl b/members/deletemem.pl index 7dca073..6bfd0de 100755 --- a/members/deletemem.pl +++ b/members/deletemem.pl @@ -67,10 +67,16 @@ if ($bor->{category_type} eq "S") { } if (C4::Context->preference("IndependentBranches")) { - my $userenv = C4::Context->userenv; if ( !C4::Context->IsSuperLibrarian() && $bor->{'branchcode'}){ - unless ($userenv->{branch} eq $bor->{'branchcode'}){ - print $input->redirect("/cgi-bin/koha/members/moremember.pl?borrowernumber=$member&error=CANT_DELETE_OTHERLIBRARY"); + unless ( + GetIndependentGroupModificationRights( + { for => $bor->{'branchcode'} } + ) + ) + { + print $input->redirect( + "/cgi-bin/koha/members/moremember.pl?borrowernumber=$member&error=CANT_DELETE_OTHERLIBRARY" + ); exit; } } diff --git a/members/member.pl b/members/member.pl index 47f7cb7..87d64db 100755 --- a/members/member.pl +++ b/members/member.pl @@ -49,7 +49,7 @@ my ($template, $loggedinuser, $cookie) my $theme = $input->param('theme') || "default"; -my $patron = $input->Vars; +my $patron = { $input->Vars }; foreach (keys %$patron){ delete $$patron{$_} unless($$patron{$_}); } -- 1.7.2.5