Bug 7304: More permissions for budgets
authorJulian Maurice <julian.maurice@biblibre.com>
Fri, 18 May 2012 07:12:43 +0000 (09:12 +0200)
committerPaul Poulain <paul.poulain@biblibre.com>
Wed, 27 Jun 2012 14:25:44 +0000 (16:25 +0200)
- Possibility to add users to a budget
- Restrictions changed to:
  - None
  - Owner
  - Owner and users
  - Owner, users and library
- Restricted users cannot spent on these budgets (they cannot modify them
  either)

Modified pages:
 - admin/aqbudgets.pl
 - admin/aqplan.pl
 - suggestion/suggestion.pl
 - acqui/acqui-home.pl
 - acqui/addorderiso2709.pl
 - acqui/basket.pl
 - acqui/neworderempty.pl

Unit tests in t/Budgets/CanUserUseBudget.t and t/Budgets/CanUserModifyBudget.t

Bug 7304 tmp

Signed-off-by: Paul Poulain <paul.poulain@biblibre.com>

26 files changed:
C4/Budgets.pm
acqui/acqui-home.pl
acqui/addorderiso2709.pl
acqui/basket.pl
acqui/neworderempty.pl
admin/aqbudget_user_search.pl [moved from admin/aqbudget_owner_search.pl with 58% similarity]
admin/aqbudgets.pl
admin/aqplan.pl
installer/data/mysql/de-DE/mandatory/userpermissions.sql
installer/data/mysql/en/mandatory/userpermissions.sql
installer/data/mysql/es-ES/mandatory/userpermissions.sql
installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql
installer/data/mysql/it-IT/necessari/userpermissions.sql
installer/data/mysql/kohastructure.sql
installer/data/mysql/nb-NO/1-Obligatorisk/userpermissions.sql
installer/data/mysql/pl-PL/mandatory/userpermissions.sql
installer/data/mysql/ru-RU/mandatory/permissions_and_user_flags.sql
installer/data/mysql/uk-UA/mandatory/permissions_and_user_flags.sql
installer/data/mysql/updatedatabase.pl
koha-tmpl/intranet-tmpl/prog/en/js/acq.js
koha-tmpl/intranet-tmpl/prog/en/modules/admin/aqbudget_owner_search.tt [deleted file]
koha-tmpl/intranet-tmpl/prog/en/modules/admin/aqbudget_user_search.tt [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/modules/admin/aqbudgets.tt
suggestion/suggestion.pl
t/Budgets/CanUserModifyBudget.t [new file with mode: 0644]
t/Budgets/CanUserUseBudget.t [new file with mode: 0644]

index 7a261d0..e9732ac 100644 (file)
@@ -44,6 +44,11 @@ BEGIN {
         &GetPeriodsCount
         &GetChildBudgetsSpent
 
+        &GetBudgetUsers
+        &ModBudgetUsers
+        &CanUserUseBudget
+        &CanUserModifyBudget
+
            &GetBudgetPeriod
         &GetBudgetPeriods
         &ModBudgetPeriod
@@ -652,6 +657,159 @@ sub GetBudgets {
     return SearchInTable("aqbudgets",$filters, $orderby, undef,undef, undef, "wide");
 }
 
+=head2 GetBudgetUsers
+
+    my @borrowernumbers = &GetBudgetUsers($budget_id);
+
+Return the list of borrowernumbers linked to a budget
+
+=cut
+
+sub GetBudgetUsers {
+    my ($budget_id) = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        SELECT borrowernumber
+        FROM aqbudgetborrowers
+        WHERE budget_id = ?
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute($budget_id);
+
+    my @borrowernumbers;
+    while (my ($borrowernumber) = $sth->fetchrow_array) {
+        push @borrowernumbers, $borrowernumber
+    }
+
+    return @borrowernumbers;
+}
+
+=head2 ModBudgetUsers
+
+    &ModBudgetUsers($budget_id, @borrowernumbers);
+
+Modify the list of borrowernumbers linked to a budget
+
+=cut
+
+sub ModBudgetUsers {
+    my ($budget_id, @budget_users_id) = @_;
+
+    return unless $budget_id;
+
+    my $dbh = C4::Context->dbh;
+    my $query = "DELETE FROM aqbudgetborrowers WHERE budget_id = ?";
+    my $sth = $dbh->prepare($query);
+    $sth->execute($budget_id);
+
+    $query = qq{
+        INSERT INTO aqbudgetborrowers (budget_id, borrowernumber)
+        VALUES (?,?)
+    };
+    $sth = $dbh->prepare($query);
+    foreach my $borrowernumber (@budget_users_id) {
+        next unless $borrowernumber;
+        $sth->execute($budget_id, $borrowernumber);
+    }
+}
+
+sub CanUserUseBudget {
+    my ($borrower, $budget, $userflags) = @_;
+
+    if (not ref $borrower) {
+        $borrower = C4::Members::GetMember(borrowernumber => $borrower);
+    }
+    if (not ref $budget) {
+        $budget = GetBudget($budget);
+    }
+
+    return 0 unless ($borrower and $budget);
+
+    if (not defined $userflags) {
+        $userflags = C4::Auth::getuserflags($borrower->{flags},
+            $borrower->{userid});
+    }
+
+    unless ($userflags->{superlibrarian}
+    || (ref $userflags->{acquisition}
+        && $userflags->{acquisition}->{budget_manage_all})
+    || (!ref $userflags->{acquisition} && $userflags->{acquisition}))
+    {
+        if (not exists $userflags->{acquisition}) {
+            return 0;
+        }
+
+        if (!ref $userflags->{acquisition} && !$userflags->{acquisition}) {
+            return 0;
+        }
+
+        # Budget restricted to owner
+        if ($budget->{budget_permission} == 1
+        && $budget->{budget_owner_id}
+        && $budget->{budget_owner_id} != $borrower->{borrowernumber}) {
+            return 0;
+        }
+
+        my @budget_users = GetBudgetUsers($budget->{budget_id});
+
+        # Budget restricted to owner, users and library
+        if ($budget->{budget_permission} == 2
+        && $budget->{budget_owner_id}
+        && $budget->{budget_owner_id} != $borrower->{borrowernumber}
+        && (0 == grep {$borrower->{borrowernumber} == $_} @budget_users)
+        && defined $budget->{budget_branchcode}
+        && $budget->{budget_branchcode} ne C4::Context->userenv->{branch}) {
+            return 0;
+        }
+
+        # Budget restricted to owner and users
+        if ($budget->{budget_permission} == 3
+        && $budget->{budget_owner_id}
+        && $budget->{budget_owner_id} != $borrower->{borrowernumber}
+        && (0 == grep {$borrower->{borrowernumber} == $_} @budget_users)) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+sub CanUserModifyBudget {
+    my ($borrower, $budget, $userflags) = @_;
+
+    if (not ref $borrower) {
+        $borrower = C4::Members::GetMember(borrowernumber => $borrower);
+    }
+    if (not ref $budget) {
+        $budget = GetBudget($budget);
+    }
+
+    return 0 unless ($borrower and $budget);
+
+    if (not defined $userflags) {
+        $userflags = C4::Auth::getuserflags($borrower->{flags},
+            $borrower->{userid});
+    }
+
+    unless ($userflags->{superlibrarian}
+    || (ref $userflags->{acquisition}
+        && $userflags->{acquisition}->{budget_manage_all})
+    || (!ref $userflags->{acquisition} && $userflags->{acquisition}))
+    {
+        if (!CanUserUseBudget($borrower, $budget, $userflags)) {
+            return 0;
+        }
+
+        if (ref $userflags->{acquisition}
+        && !$userflags->{acquisition}->{budget_modify}) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
 # -------------------------------------------------------------------
 
 =head2 GetCurrencies
index 69482a8..8b6c584 100755 (executable)
@@ -41,7 +41,7 @@ use C4::Debug;
 use C4::Suggestions;
 
 my $query = CGI->new;
-my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
     {   template_name   => 'acqui/acqui-home.tmpl',
         query           => $query,
         type            => 'intranet',
@@ -78,9 +78,7 @@ if ( $cur_format eq 'FR' ) {
 my $status           = $query->param('status') || "ASKED";
 my $suggestions_count       = CountSuggestion($status);
 
-my $budget_arr =
-  GetBudgetHierarchy( '', $user->{branchcode},
-    $template->{VARS}->{'USER_INFO'}[0]->{'borrowernumber'} );
+my $budget_arr = GetBudgetHierarchy;
 
 my $total      = 0;
 my $totspent   = 0;
@@ -93,7 +91,9 @@ my $totspent_active     = 0;
 my $totordered_active   = 0;
 my $totavail_active     = 0;
 
+my @budget_loop;
 foreach my $budget ( @{$budget_arr} ) {
+    next unless (CanUserUseBudget($loggedinuser, $budget, $userflags));
 
     $budget->{budget_code_indent} =~ s/\ /\&nbsp\;/g;
 
@@ -136,11 +136,13 @@ foreach my $budget ( @{$budget_arr} ) {
     for my $field (qw( budget_amount budget_spent budget_ordered budget_avail ) ) {
         $budget->{$field} = $num_formatter->format_price( $budget->{$field} );
     }
+
+    push @budget_loop, $budget;
 }
 
 $template->param(
     type          => 'intranet',
-    loop_budget   => $budget_arr,
+    loop_budget   => \@budget_loop,
     branchname    => $branchname,
     total         => $num_formatter->format_price($total),
     totspent      => $num_formatter->format_price($totspent),
index 23020c7..002fbf5 100755 (executable)
@@ -46,14 +46,15 @@ use C4::Branch;         # GetBranches
 use C4::Members;
 
 my $input = new CGI;
-my ($template, $loggedinuser, $cookie) = get_template_and_user({
-                                        template_name => "acqui/addorderiso2709.tmpl",
-                                        query => $input,
-                                        type => "intranet",
-                                        authnotrequired => 0,
-                                        flagsrequired   => { acquisition => 'order_manage' },
-                                        debug => 1,
-                                        });
+my ($template, $loggedinuser, $cookie, $userflags) = get_template_and_user({
+    template_name => "acqui/addorderiso2709.tmpl",
+    query => $input,
+    type => "intranet",
+    authnotrequired => 0,
+    flagsrequired   => { acquisition => 'order_manage' },
+    debug => 1,
+});
+
 my $cgiparams = $input->Vars;
 my $op = $cgiparams->{'op'};
 my $booksellerid  = $input->param('booksellerid');
@@ -276,8 +277,9 @@ my $budget = GetBudget($budget_id);
 
 # build budget list
 my $budget_loop = [];
-$budgets = GetBudgetHierarchy( q{}, $borrower->{branchcode}, $borrower->{borrowernumber} );
+$budgets = GetBudgetHierarchy;
 foreach my $r ( @{$budgets} ) {
+    next unless (CanUserUseBudget($borrower, $r, $userflags));
     if ( !defined $r->{budget_amount} || $r->{budget_amount} == 0 ) {
         next;
     }
index de66891..67ace5c 100755 (executable)
@@ -68,7 +68,7 @@ my $query        = new CGI;
 my $basketno     = $query->param('basketno');
 my $booksellerid = $query->param('booksellerid');
 
-my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
     {
         template_name   => "acqui/basket.tmpl",
         query           => $query,
@@ -351,12 +351,14 @@ my $total_est_gste;
     my @orders = GetOrders($basketno);
 
     my $borrower= GetMember('borrowernumber' => $loggedinuser);
-    my $budgets = GetBudgetHierarchy(q{},$borrower->{branchcode},$borrower->{borrowernumber});
+    my $budgets = GetBudgetHierarchy;
     my $has_budgets = 0;
     foreach my $r (@{$budgets}) {
         if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
             next;
         }
+        next unless (CanUserUseBudget($loggedinuser, $r, $userflags));
+
         $has_budgets = 1;
         last;
     }
index 08693d1..a461a1b 100755 (executable)
@@ -110,7 +110,7 @@ my $new = 'no';
 
 my $budget_name;
 
-my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user(
     {
         template_name   => "acqui/neworderempty.tmpl",
         query           => $input,
@@ -251,8 +251,9 @@ my ( $flags, $homebranch )= ($borrower->{'flags'},$borrower->{'branchcode'});
 my $budget =  GetBudget($budget_id);
 # build budget list
 my $budget_loop = [];
-my $budgets = GetBudgetHierarchy(q{},$borrower->{branchcode},$borrower->{borrowernumber});
+my $budgets = GetBudgetHierarchy;
 foreach my $r (@{$budgets}) {
+    next unless (CanUserUseBudget($borrower, $r, $userflags));
     if (!defined $r->{budget_amount} || $r->{budget_amount} == 0) {
         next;
     }
similarity index 58%
rename from admin/aqbudget_owner_search.pl
rename to admin/aqbudget_user_search.pl
index 5c73e9e..1bef153 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 
-# script to find a guarantor
+# script to find owner and users for a budget
 
 # Copyright 2008-2009 BibLibre SARL
 #
@@ -19,8 +19,8 @@
 # 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 C4::Auth ;
 use C4::Output;
 use CGI;
@@ -32,7 +32,7 @@ my $input = new CGI;
 my $dbh = C4::Context->dbh;
 
 my ( $template, $loggedinuser, $cookie, $staff_flags ) = get_template_and_user(
-    {   template_name   => "admin/aqbudget_owner_search.tmpl",
+    {   template_name   => "admin/aqbudget_user_search.tt",
         query           => $input,
         type            => "intranet",
         authnotrequired => 0,
@@ -41,16 +41,10 @@ my ( $template, $loggedinuser, $cookie, $staff_flags ) = get_template_and_user(
     }
 );
 
-my $theme = $input->param('theme') || "default";
-
 # only used if allowthemeoverride is set
-my $member  = $input->param('member');
-my $orderby = $input->param('orderby');
+my $type = $input->param('type');
+my $member  = $input->param('member') // '';
 
-my $op = $input->param('op');
-$template->param( $op || else => 1, );
-
-$orderby = "surname,firstname" unless $orderby;
 $member =~ s/,//g;     #remove any commas from search string
 $member =~ s/\*/%/g;
 if ( $member eq '' ) {
@@ -59,33 +53,20 @@ if ( $member eq '' ) {
     $template->param( results => 1 );
 }
 
-my ( $count, $count2, $results );
 my @resultsdata;
-my $toggle = 0;
 
 if ( $member ) {
-       my $results= Search($member,"surname");
+    my $results = Search($member, "surname");
 
     foreach my $res (@$results) {
-
         my $perms = haspermission( $res->{'userid'} );
-        my $subperms =  get_user_subpermissions  ($res->{'userid'} );
-
+        my $subperms = get_user_subpermissions( $res->{'userid'} );
 
         # if the member has 'acqui' permission set, then display to table.
-        if (    $perms->{superlibrarian} == 1  || 
-                $perms->{acquisition} == 1  || 
-                $subperms->{acquisition}->{'budget_manage'} || 
-                $subperms->{acquisition}->{'budget_modify'} || 
-                $subperms->{acquisition}->{'budget_add_del'}  ) {
-
-            $count2++;
-            #find out stats
-#            my ( $od, $issue, $fines ) = GetMemberIssuesAndFines( $res->{'borrowerid'} );
-                       #This looks unused and very unuseful
-            my $guarantorinfo = uc( $res->{'surname'} ) . " , " . ucfirst( $res->{'firstname'} );
-            my $budget_owner_name = $res->{'firstname'} . ' ' . $res->{'surname'}, my $budget_owner_id = $res->{'borrowernumber'};
-
+        if ( $perms->{superlibrarian} == 1  ||
+             $perms->{acquisition} == 1  ||
+             exists $subperms->{acquisition} )
+        {
             my %row = (
                 borrowernumber    => $res->{'borrowernumber'},
                 cardnumber        => $res->{'cardnumber'},
@@ -93,12 +74,6 @@ if ( $member ) {
                 firstname         => $res->{'firstname'},
                 categorycode      => $res->{'categorycode'},
                 branchcode        => $res->{'branchcode'},
-                guarantorinfo     => $guarantorinfo,
-                budget_owner_id   => $budget_owner_id,
-                budget_owner_name => $budget_owner_name,
-#                odissue           => "$od/$issue",
-#                fines             => $fines,
-#                borrowernotes     => $res->{'borrowernotes'}
             );
             push( @resultsdata, \%row );
         }
@@ -106,8 +81,8 @@ if ( $member ) {
 }
 
 $template->param(
+    type => $type,
     member => $member,
-    numres => $count2,
     resultsloop => \@resultsdata
 );
 
index 39fffdb..c5f99e3 100755 (executable)
@@ -19,8 +19,8 @@
 # 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 List::Util qw/min/;
 use Number::Format qw(format_price);
@@ -56,15 +56,17 @@ $template->param( symbol => $cur->{symbol},
                   currency => $cur->{currency}
                );
 
-my $op = $input->param('op');
+my $op = $input->param('op') // '';
 
 # see if the user want to see all budgets or only owned ones
 my $show_mine    = 1; #SHOW BY DEFAULT
-my $show         = $input->param('show'); # SET TO 1, BY A FORM SUMBIT
+my $show         = $input->param('show') // 0; # SET TO 1, BY A FORM SUMBIT
 $show_mine       = $input->param('show_mine') if $show == 1;
 
 # IF USER DOESNT HAVE PERM FOR AN 'ADD', THEN REDIRECT TO THE DEFAULT VIEW...
-if  (  not defined $template->{VARS}->{'CAN_user_acquisition_budget_add_del'}  &&  $op ==  'add_form'  )   {
+if (not defined $template->{VARS}->{'CAN_user_acquisition_budget_add_del'}
+    and $op eq 'add_form')
+{
     $op = '';
 }
 my $num=FormatNumber;
@@ -73,7 +75,7 @@ my $script_name               = "/cgi-bin/koha/admin/aqbudgets.pl";
 my $budget_hash               = $input->Vars;
 my $budget_id                 = $$budget_hash{budget_id};
 my $budget_permission         = $input->param('budget_permission');
-my $filter_budgetbranch       = $input->param('filter_budgetbranch');
+my $filter_budgetbranch       = $input->param('filter_budgetbranch') // '';
 my $filter_budgetname         = $input->param('filter_budgetname');
 #filtering non budget keys
 delete $$budget_hash{$_} foreach grep {/filter|^op$|show/} keys %$budget_hash;
@@ -126,7 +128,12 @@ if ($op eq 'add_form') {
     #  pass the period_id to build the dropbox - because we only want to show  budgets from this period
     my $dropbox_disabled;
     if (defined $budget_id ) {    ### MOD
-        $budget           = GetBudget($budget_id);
+        $budget = GetBudget($budget_id);
+        if (!CanUserModifyBudget($borrowernumber, $budget, $staffflags)) {
+            $template->param(error_not_authorised_to_modify => 1);
+            output_html_with_http_headers $input, $cookie, $template->output;
+            exit;
+        }
         $dropbox_disabled = BudgetHasChildren($budget_id);
         my $borrower = &GetMember( borrowernumber=>$budget->{budget_owner_id} );
         $budget->{budget_owner_name} = $borrower->{'firstname'} . ' ' . $borrower->{'surname'};
@@ -189,6 +196,24 @@ if ($op eq 'add_form') {
         $template->param($budget_permission => 1);
     }
 
+    if ($budget) {
+        my @budgetusers = GetBudgetUsers($budget->{budget_id});
+        my @budgetusers_loop;
+        foreach my $borrowernumber (@budgetusers) {
+            my $member = C4::Members::GetMember(
+                borrowernumber => $borrowernumber);
+            push @budgetusers_loop, {
+                firstname => $member->{firstname},
+                surname => $member->{surname},
+                borrowernumber => $borrowernumber
+            };
+        }
+        $template->param(
+            budget_users => \@budgetusers_loop,
+            budget_users_ids => join ':', @budgetusers
+        );
+    }
+
     # if no buget_id is passed then its an add
     $template->param(
         add_validate                  => 1,
@@ -218,10 +243,24 @@ if ($op eq 'add_form') {
     if ( $op eq 'delete_confirmed' ) {
         my $rc = DelBudget($budget_id);
     }elsif( $op eq 'add_validate' ) {
+        my @budgetusersid;
+        if (defined $$budget_hash{'budget_users_ids'}){
+            @budgetusersid = split(':', $budget_hash->{'budget_users_ids'});
+        }
+
         if ( defined $$budget_hash{budget_id} ) {
-            ModBudget( $budget_hash );
+            if (CanUserModifyBudget($borrowernumber, $budget_hash->{budget_id},
+                $staffflags)
+            ) {
+                ModBudget( $budget_hash );
+                ModBudgetUsers($budget_hash->{budget_id}, @budgetusersid);
+            }
+            else {
+                $template->param(error_not_authorised_to_modify => 1);
+            }
         } else {
             AddBudget( $budget_hash );
+            ModBudgetUsers($budget_hash->{budget_id}, @budgetusersid);
         }
     }
     my $branches = GetBranches();
@@ -230,8 +269,10 @@ if ($op eq 'add_form') {
         %$period,
     );
 
-    my $moo = GetBudgetHierarchy($$period{budget_period_id}, C4::Context->userenv->{branchcode}, $show_mine?$borrower_id:'');
-    my @budgets = @$moo; #FIXME
+    my @budgets = @{
+        GetBudgetHierarchy($$period{budget_period_id},
+            C4::Context->userenv->{branchcode}, $show_mine ? $borrower_id : '')
+    };
 
     my $toggle = 0;
     my @loop;
@@ -245,31 +286,9 @@ if ($op eq 'add_form') {
         $budget->{'total_levels_spent'} = GetChildBudgetsSpent($budget->{"budget_id"});
 
         # PERMISSIONS
-        unless($staffflags->{'superlibrarian'} % 2   == 1 ) {
-            #IF NO PERMS, THEN DISABLE EDIT/DELETE
-            unless ( $template->{VARS}->{'CAN_user_acquisition_budget_modify'} ) {
-                $budget->{'budget_lock'} = 1;
-            }
-            # check budget permission
-            if ( $$period{budget_period_locked} == 1 ) {
-                $budget->{'budget_lock'} = 1;
-
-            } elsif ( $budget->{budget_permission} == 1 ) {
-
-                if ( $borrower_id != $budget->{'budget_owner_id'} ) {
-                    $budget->{'budget_lock'} = 1;
-                }
-                # check parent perms too
-                my $parents_perm = 0;
-                if ( $budget->{depth} > 0 ) {
-                    $parents_perm = CheckBudgetParentPerm( $budget, $borrower_id );
-                    delete $budget->{'budget_lock'} if $parents_perm == '1';
-                }
-            } elsif ( $budget->{budget_permission} == 2 ) {
-
-                $budget->{'budget_lock'} = 1 if $user_branchcode ne $budget->{budget_branchcode};
-            }
-        }    # ...SUPER_LIB END
+        unless(CanUserModifyBudget($borrowernumber, $budget, $staffflags)) {
+            $budget->{'budget_lock'} = 1;
+        }
 
         # if a budget search doesnt match, next
         if ($filter_budgetname) {
@@ -288,7 +307,9 @@ if ($op eq 'add_form') {
         $budget->{'budget_remaining'} = $budget->{'budget_amount'} - $budget->{'total_levels_spent'};
 
 # if amount == 0 dont display...
-        delete  $budget->{'budget_unalloc_sublevel'} if  $budget->{'budget_unalloc_sublevel'} == 0 ;
+        delete $budget->{'budget_unalloc_sublevel'}
+            if (!defined $budget->{'budget_unalloc_sublevel'}
+            or $budget->{'budget_unalloc_sublevel'} == 0);
 
         $budget->{'remaining_pos'} = 1 if $budget->{'budget_remaining'} > 0;
         $budget->{'remaining_neg'} = 1 if $budget->{'budget_remaining'} < 0;
@@ -312,7 +333,7 @@ if ($op eq 'add_form') {
             push @budget_hierarchy, { element_name => $parent->{"budget_name"}, element_id => $parent->{"budget_id"} };
             $parent_id = $parent->{"budget_parent_id"};
         }
-        push  @budget_hierarchy, { element_name => $period->{"budget_period_description"} }; 
+        push  @budget_hierarchy, { element_name => $period->{"budget_period_description"} };
         @budget_hierarchy = reverse(@budget_hierarchy);
 
         push( @loop, {  %{$budget},
index ffb1145..9cc8c59 100755 (executable)
@@ -354,6 +354,10 @@ my ( @budget_lines, %cell_hash );
 foreach my $budget (@budgets) {
     my $budget_lock;
 
+    unless (CanUserUseBudget($borrowernumber, $budget, $staff_flags)) {
+        $budget_lock = 1
+    }
+
     # check budget permission
     if ( $period->{budget_period_locked} == 1 ) {
         $budget_lock = 1;
index 54fd531..a4bda59 100644 (file)
@@ -16,6 +16,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
    (11, 'group_manage', 'Bestellgruppen vewalten'),
    (11, 'order_receive', 'Lieferungen verwalten'),
    (11, 'budget_add_del', 'Konten hinzufügen/ändern, aber bestehende nicht ändern'),
+   (11, 'budget_manage_all', 'Manage all budgets'),
    (13, 'edit_news', 'Nachrichten für OPAC und Dienstoberfläche verfassen'),
    (13, 'label_creator', 'Etiketten und Barcodes aus Katalog- und Benutzerdaten erstellen'),
    (13, 'edit_calendar', 'Schließtage eintragen'),
index 70f89e2..72cc70f 100644 (file)
@@ -16,6 +16,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
    (11, 'group_manage', 'Manage orders & basketgroups'),
    (11, 'order_receive', 'Manage orders & basket'),
    (11, 'budget_add_del', 'Add and delete budgets (but cant modify budgets)'),
+   (11, 'budget_manage_all', 'Manage all budgets'),
    (13, 'edit_news', 'Write news for the OPAC and staff interfaces'),
    (13, 'label_creator', 'Create printable labels and barcodes from catalog and patron data'),
    (13, 'edit_calendar', 'Define days when the library is closed'),
index 70f89e2..72cc70f 100644 (file)
@@ -16,6 +16,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
    (11, 'group_manage', 'Manage orders & basketgroups'),
    (11, 'order_receive', 'Manage orders & basket'),
    (11, 'budget_add_del', 'Add and delete budgets (but cant modify budgets)'),
+   (11, 'budget_manage_all', 'Manage all budgets'),
    (13, 'edit_news', 'Write news for the OPAC and staff interfaces'),
    (13, 'label_creator', 'Create printable labels and barcodes from catalog and patron data'),
    (13, 'edit_calendar', 'Define days when the library is closed'),
index d6362e8..c96e9c6 100644 (file)
@@ -33,6 +33,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
    (11, 'group_manage', 'Gérer les commandes et les bons de commande'),
    (11, 'order_receive', 'Gérer les réceptions'),
    (11, 'budget_add_del', 'Ajouter et supprimer les budgets (mais pas modifier)'),
+   (11, 'budget_manage_all', 'Gérer tous les budgets'),
    (13, 'manage_csv_profiles', 'Gérer les profils d''export CSV'),
    (13, 'moderate_tags', 'Modérer les tags des adhérents'),
    (13, 'rotating_collections', 'Gérer les collections tournantes'),
index 03dd32c..8be056c 100644 (file)
@@ -18,6 +18,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
    (11, 'group_manage', 'Gestisci ordini e raccoglitori raggruppati'),
    (11, 'order_receive', 'Gestisci arrivi'),
    (11, 'budget_add_del', 'Aggiungi e cancella budgets (senza modificarli)'),
+   (11, 'budget_manage_all', 'Manage all budgets'),
    (13, 'edit_news', 'Scrivi le news per l\'OPAC e per l\'interfaccia staff'),
    (13, 'label_creator', 'Crea etichette da stampare e barcodes dal catalogo e dai dati degli utenti'),
    (13, 'edit_calendar', 'Definisci i giorni di chiusura della biblioteca'),
index 54498c3..e1105a5 100644 (file)
@@ -2642,6 +2642,22 @@ CREATE TABLE `aqbudgets` (
   PRIMARY KEY  (`budget_id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
+--
+-- Table structure for table aqbudgetborrowers
+--
+
+DROP TABLE IF EXISTS aqbudgetborrowers;
+CREATE TABLE aqbudgetborrowers (
+  budget_id int(11) NOT NULL,
+  borrowernumber int(11) NOT NULL,
+  PRIMARY KEY (budget_id, borrowernumber),
+  CONSTRAINT aqbudgetborrowers_ibfk_1 FOREIGN KEY (budget_id)
+    REFERENCES aqbudgets (budget_id)
+    ON DELETE CASCADE ON UPDATE CASCADE,
+  CONSTRAINT aqbudgetborrowers_ibfk_2 FOREIGN KEY (borrowernumber)
+    REFERENCES borrowers (borrowernumber)
+    ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
 -- Table structure for table `aqbudgetperiods`
index fd3989d..3ef9666 100644 (file)
@@ -37,6 +37,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
    (11, 'group_manage', 'Administrere bestillinger og kurv-grupper'),
    (11, 'order_receive', 'Administrere bestillinger og kurver'),
    (11, 'budget_add_del', 'Legge til og slette budsjetter (men ikke endre budsjetter)'),
+   (11, 'budget_manage_all', 'Manage all budgets'),
    (13, 'edit_news', 'Legge ut nyhter i OPACen og det interne grensesnittet'),
    (13, 'label_creator', 'Lage etiketter og strekkoder basert på bibliografiske poster og lånerdata'),
    (13, 'edit_calendar', 'Definere dager da biblioteket er stengt'),
index a9629c5..4cd583e 100644 (file)
@@ -16,6 +16,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
    (11, 'group_manage', 'Manage orders & basketgroups'),
    (11, 'order_receive', 'Manage orders & basket'),
    (11, 'budget_add_del', 'Add and delete budgets (but cant modify budgets)'),
+   (11, 'budget_manage_all', 'Manage all budgets'),
    (13, 'edit_news', 'RTworzeniei publikowanie wiadomości w interfejsie bibliotekarza i OPAC'),
    (13, 'label_creator', 'Create printable labels and barcodes from catalog and patron data'),
    (13, 'edit_calendar', 'Define days when the library is closed'),
index 07b1545..f77ca01 100644 (file)
@@ -40,6 +40,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
    (11, 'group_manage', 'Manage orders & basketgroups'),
    (11, 'order_receive', 'Manage orders & basket'),
    (11, 'budget_add_del', 'Add and delete budgets (but cant modify budgets)'),
+   (11, 'budget_manage_all', 'Manage all budgets'),
    (13, 'edit_news',                   'Написание новостей для электронного каталога и интерфейса библиотекарей'),
    (13, 'label_creator',               'Создание печатных наклеек и штрихкодов из каталога и с данными о пользователях'),
    (13, 'edit_calendar',               'Определение дней, когда библиотека закрыта'),
index 40034cf..5e8b6f0 100644 (file)
@@ -40,6 +40,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
    (11, 'group_manage', 'Manage orders & basketgroups'),
    (11, 'order_receive', 'Manage orders & basket'),
    (11, 'budget_add_del', 'Add and delete budgets (but cant modify budgets)'),
+   (11, 'budget_manage_all', 'Manage all budgets'),
    (13, 'edit_news',                   'Написання новин для електронного каталогу та інтерфейсу бібліотекарів'),
    (13, 'label_creator',               'Створення друкованих наклейок і штрих-кодів з каталогу та з даними про користувачів'),
    (13, 'edit_calendar',               'Визначення днів, коли бібліотека закрита'),
index d06a188..a0fafb5 100755 (executable)
@@ -5392,6 +5392,30 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
     SetVersion ($DBversion);
 }
 
+$DBversion = "XXX";
+if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
+    $dbh->do("DROP TABLE IF EXISTS aqbudgetborrowers");
+    $dbh->do("
+        CREATE TABLE aqbudgetborrowers (
+          budget_id int(11) NOT NULL,
+          borrowernumber int(11) NOT NULL,
+          PRIMARY KEY (budget_id, borrowernumber),
+          CONSTRAINT aqbudgetborrowers_ibfk_1 FOREIGN KEY (budget_id)
+            REFERENCES aqbudgets (budget_id)
+            ON DELETE CASCADE ON UPDATE CASCADE,
+          CONSTRAINT aqbudgetborrowers_ibfk_2 FOREIGN KEY (borrowernumber)
+            REFERENCES borrowers (borrowernumber)
+            ON DELETE CASCADE ON UPDATE CASCADE
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+    ");
+    $dbh->do("
+        INSERT INTO permissions (module_bit, code, description)
+        VALUES (11, 'budget_manage_all', 'Manage all budgets')
+    ");
+    print "Upgrade to $DBversion done (Add aqbudgetborrowers table)\n";
+    SetVersion($DBversion);
+}
+
 =head1 FUNCTIONS
 
 =head2 TableExists($table)
index 70e988e..2efeba0 100644 (file)
@@ -531,14 +531,7 @@ function log(message) {
     logLine.appendChild(log.window_.document.createTextNode(message));
     log.window_.document.body.appendChild(logLine);
 }
-//=======================================================================
-
 
-
-    function ownerPopup(f) {
-    window.open("/cgi-bin/koha/admin/aqbudget_owner_search.pl?op=budget",'PatronPopup','width=740,height=450,location=yes,toolbar=no,scrollbars=yes,resize=yes');
-    }
-        //
 //=======================================================================
 function getElementsByClass( searchClass, domNode, tagName) {
     if (domNode == null) domNode = document;
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/aqbudget_owner_search.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/aqbudget_owner_search.tt
deleted file mode 100644 (file)
index 79ebcd8..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-[% INCLUDE 'doc-head-open.inc' %]
-<title>Koha &rsaquo; Budget owner search</title>
-[% INCLUDE 'doc-head-close.inc' %]
-    <style type="text/css">
-    #custom-doc { width:44.46em;*width:43.39em;min-width:578px; margin:auto; text-align:left; }
-    </style>
-
-<script type="text/javascript">
-//<![CDATA[
-
-// modify parent window owner element
-function returnOwner(ownerId, ownerName){
-    var top1 = top.opener;
-    top1.document.getElementById('budget_owner_name').innerHTML = ownerName;
-    top1.document.getElementById('budget_owner_id').value = ownerId;
-    window.close();
-}
-//]]>
-</script>
-
-
-</head>
-<body id="admin_aqbudget_owner_search" class="admin">
-<div id="custom-doc" class="yui-t7">
-   <div id="bd">
-       <div class="yui-g">
-
-
-<h3>Search for budget owner</h3>
-       <form action="/cgi-bin/koha/admin/aqbudget_owner_search.pl" method="post">
-               <fieldset>
-               <input type="text" name="member" id="member" value="[% member %]" class="focus" />
-
-
-<!--
- Ordered by
-               <select name="orderby">
-                       <option value="surname,firstname">Surname</option>
-                       <option value="cardnumber">Cardnumber</option>
-               </select>
--->
-
-<input type="submit" class="button" value="Search" /></fieldset>
-<div class="hint">Only staff with superlibrarian or acquisitions permissions are returned in the search results</div>
-
-       </form>
-
-
-[% IF ( results ) %]
-       <p>Searched for <span class="ex">[% member %]</span>, [% numresults %] patron(s) found:</p>
-       <table>
-               <tr>
-                       <th>Cardnumber</th>
-                       <th>Name</th>
-                       <th>Library</th>
-                       <th>Categorycode</th>
-            <th>Select?</th>
-               </tr>
-
-               [% FOREACH resultsloo IN resultsloop %]
-            [% IF ( resultsloo.toggle ) %]<tr>[% ELSE %]<tr class="highlight">[% END %]
-                               <td>[% resultsloo.cardnumber %]</td>
-                <td>[% resultsloo.surname %], [% resultsloo.firstname %]</td>
-                               <td>[% resultsloo.branchcode %]</td>
-                               <td>[% resultsloo.categorycode %]</td>
-                <td>
-                 <input type="button" value="Select" onclick="returnOwner('[% resultsloo.budget_owner_id %]', '[% resultsloo.budget_owner_name %]');"  />
-                </td>
-                       </tr>
-               [% END %]
-       </table>
-[% END %]
-
-<div id="closewindow"><a href="#" class="close">Cancel</a></div>
-</div>
-</div>
-[% INCLUDE 'intranet-bottom.inc' %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/aqbudget_user_search.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/aqbudget_user_search.tt
new file mode 100644 (file)
index 0000000..316a00a
--- /dev/null
@@ -0,0 +1,111 @@
+[% INCLUDE 'doc-head-open.inc' %]
+<title>Koha &rsaquo; Budget
+    [% IF (type == 'owner') %]
+        owner
+    [% ELSE %]
+        user
+    [% END %]
+    search
+</title>
+[% INCLUDE 'doc-head-close.inc' %]
+    <style type="text/css">
+    #custom-doc {
+        width:44.46em;
+        *width:43.39em;
+        min-width:578px;
+        margin:auto;
+        text-align:left;
+    }
+    </style>
+
+    <script type="text/javascript">
+    //<![CDATA[
+
+    // modify parent window owner element
+    function add_user(borrowernumber, surname, firstname) {
+        [% IF (type == 'owner') %]
+            top.opener.edit_owner(borrowernumber, surname, firstname);
+            window.close();
+        [% ELSE %]
+            var ret = top.opener.add_user(borrowernumber, surname, firstname);
+            if (ret != 0) {
+                alert(_("This user is already in the list."));
+            }
+        [% END %]
+    }
+
+    //]]>
+    </script>
+</head>
+
+<body id="admin_aqbudget_owner_search" class="admin">
+<div id="custom-doc" class="yui-t7">
+<div id="bd">
+<div class="yui-g">
+
+<h3>Search for budget
+    [% IF (type == 'owner') %]
+        owner
+    [% ELSE %]
+        user
+    [% END %]
+</h3>
+<form action="/cgi-bin/koha/admin/aqbudget_user_search.pl" method="post">
+    <fieldset>
+        <input type="text" name="member" id="member" value="[% member %]"
+            class="focus" />
+
+        <input type="hidden" name="type" value="[% type %]" />
+        <input type="submit" class="button" value="Search" />
+    </fieldset>
+
+    <div class="hint">
+        Only staff with superlibrarian or acquisitions permissions are returned
+        in the search results.
+    </div>
+</form>
+
+
+[% IF ( results ) %]
+    <p>Searched for <span class="ex">[% member %]</span>,
+    [% resultsloop.size || 0 %] patron(s) found:</p>
+
+    <table>
+        <thead>
+            <tr>
+                <th>Cardnumber</th>
+                <th>Name</th>
+                <th>Library</th>
+                <th>Categorycode</th>
+                <th>Select?</th>
+            </tr>
+        </thead>
+
+        <tbody>
+            [% FOREACH result IN resultsloop %]
+                <tr>
+                    <td>[% result.cardnumber %]</td>
+                    <td>[% result.surname %], [% result.firstname %]</td>
+                    <td>[% result.branchcode %]</td>
+                    <td>[% result.categorycode %]</td>
+                    <td>
+                    <a style="cursor:pointer"
+                        onclick="add_user(
+                            '[% result.borrowernumber %]',
+                            '[% result.surname %]',
+                            '[% result.firstname %]'
+                        );"
+                    />Select</a>
+                    </td>
+                </tr>
+            [% END %]
+        </tbody>
+    </table>
+[% END %]
+
+<div id="closewindow">
+    <a href="#" class="close">Close</a>
+</div>
+</div>
+</div>
+[% INCLUDE 'intranet-bottom.inc' %]
index bf778c7..ba308b6 100644 (file)
@@ -6,12 +6,66 @@
 [% IF ( add_form ) %]
 <script type="text/javascript">
 //<![CDATA[
-//
-     var actTotal ="";
 
-    function ownerRemove(f) {
-        document.getElementById('budget_owner_name').innerHTML = '';
-        document.getElementById('budget_owner_id').value = '';
+    function userPopup() {
+        window.open("/cgi-bin/koha/admin/aqbudget_user_search.pl?type=user",
+            'PatronPopup',
+            'width=740,height=450,location=yes,toolbar=no,'
+            + 'scrollbars=yes,resize=yes'
+        );
+    }
+
+    function ownerPopup() {
+        window.open("/cgi-bin/koha/admin/aqbudget_user_search.pl?type=owner",
+            'PatronPopup',
+            'width=740,height=450,location=yes,toolbar=no,'
+            + 'scrollbars=yes,resize=yes'
+        );
+    }
+
+    function edit_owner(borrowernumber, surname, firstname) {
+        $('#budget_owner_name').empty();
+        $('#budget_owner_id').val('');
+        if (borrowernumber) {
+            var ownerlink = '<a href="/cgi-bin/koha/members/moremember.pl'
+                + '?borrowernumber=' + borrowernumber + '">'
+                + firstname + ' ' + surname + '</a>';
+            $('#budget_owner_name').html(ownerlink);
+            $('#budget_owner_id').val(borrowernumber);
+        }
+    }
+
+    function ownerRemove() {
+        edit_owner(0);
+    }
+
+    function add_user(borrowernumber, surname, firstname) {
+        var ids = $("#budget_users_id").val().split(':');
+        if(borrowernumber && ids.indexOf(borrowernumber) == -1) {
+            var li = '<li id="user_' + borrowernumber + '">'
+                + '<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber='
+                + borrowernumber + '">' + firstname + ' ' + surname
+                + '</a> [<a style="cursor:pointer"'
+                + 'onclick="del_user(' + borrowernumber +')">Remove</a>]</li>';
+            $(li).insertBefore("li#add_user_button");
+            ids.push(borrowernumber);
+            $("#budget_users_id").val(ids.join(':'));
+        } else {
+            return -1;
+        }
+        return 0;
+    }
+
+    function del_user(borrowernumber) {
+        var ids = $("#budget_users_id").val().split(':');
+        if (borrowernumber) {
+            var idx = ids.indexOf(borrowernumber+'');
+            if (idx != -1) {
+                ids.splice(idx, 1);
+                $("#budget_users_id").val(ids.join(':'));
+                $("li#user_" + borrowernumber).remove();
+            }
+        }
     }
 
     function Check(f) {
@@ -19,8 +73,6 @@
         var _alertString="";
         var alertString2;
 
-        // var actTotal ="";
-
         if (!(isNotNull(f.budget_code,1))) {
             _alertString += _("- Budget code cannot be blank") + "\n";
         }
 <div id="yui-main">
 <div class="yui-b" id="content">
 
+
 [% UNLESS ( delete_confirm ) %][% INCLUDE 'budgets-admin-toolbar.inc' %][% END %]
+
+[% IF (error_not_authorised_to_modify) %]
+    <div class="error">
+        <p>You are not authorised to modify this fund</p>
+    </div>
+[% END %]
+
 [% IF ( else ) %]
 
 <h1>Funds for '[% budget_period_description %]'</h1>
 
 <!-- ********************************************************************************************** -->
 <!-- create add/mod entry form -->
-[% IF ( add_form ) %]
+[% IF ( add_form && !error_not_authorised_to_modify ) %]
 <form action="/cgi-bin/koha/admin/aqbudgets.pl" name="Aform" method="post">
     <fieldset class="rows">
     <legend>[% IF ( budget_id ) %]Modify[% ELSE %]Add[% END %] Fund
 
     <li>
     <label for="budget_expend">Expenditure: </label>
-    <input type="text" name="budget_expend" id="budget_expend" value="[% budget_expend %]" size="8" /><input type="hidden" name="budget_owner_id" id="budget_owner_id" value="[% budget_owner_id %]" />
+    <input type="text" name="budget_expend" id="budget_expend" value="[% budget_expend %]" size="8" />
     </li>
 
     <li>
-    <span class="label">Owner: </span>
-    <span  id="budget_owner_name">
-    <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% budget_owner_id %]">[% budget_owner_name %]</a>
-    </span>
-
-    <!-- FIXME: hardcoded button positions :/ -->
-    <input style="" type="button" id="edit_owner" value="Edit owner" onclick="ownerPopup(); return false;" />
-    <input style=""  type="button" id="remove_owner" value="Remove owner" onclick="ownerRemove(this.form); return false;" />
+        <span class="label">Owner: </span>
+        <span  id="budget_owner_name">
+        <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% budget_owner_id %]">
+            [% budget_owner_name %]
+        </a>
+        </span>
+        <input type="hidden" name="budget_owner_id" id="budget_owner_id"
+            value="[% budget_owner_id %]" />
+
+        <!-- FIXME: hardcoded button positions :/ -->
+        <input type="button" id="edit_owner" value="Edit owner"
+            onclick="ownerPopup(); return false;" />
+        <input type="button" id="remove_owner" value="Remove owner"
+            onclick="ownerRemove(); return false;" />
     </li>
 
     <li>
+        <span class="label">Users:</span>
+        <ul style="float:left;" id="budget_users">
+            [% FOREACH user IN budget_users %]
+                <li id="user_[% user.borrowernumber %]">
+                    <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% user.borrowernumber %]">
+                        [% user.firstname %] [% user.surname %]
+                    </a>
+                    [<a style="cursor:pointer"
+                    onclick="del_user([% user.borrowernumber %])">Remove</a>]
+                </li>
+            [% END %]
+            <li id="add_user_button">
+                <input type="button" onclick="userPopup()" value="Add users" />
+            </li>
+        </ul>
+        <input type="hidden" name="budget_users_ids" id="budget_users_id" value="[% budget_users_ids %]" />
+    <li>
     <label for="budget_branchcode">Library: </label>
     <select name="budget_branchcode" id="budget_branchcode">
     <option value=""></option>
     <li>
     <label for="budget_permission">Restrict access to: </label>
     <select name="budget_permission" id="budget_permission">
-    [% IF ( budget_perm_0 ) %]<option value="0" selected="selected">None</option>[% ELSE %]<option value="0">None</option>[% END %]
-    [% IF ( budget_perm_1 ) %]<option value="1" selected="selected">Owner</option>[% ELSE %]<option value="1">Owner</option>[% END %]
-    [% IF ( budget_perm_2 ) %]<option value="2" selected="selected">Library</option>[% ELSE %]<option value="2">Library</option>[% END %]
-    </option>
+        [% IF ( budget_perm_0 ) %]
+            <option value="0" selected="selected">
+        [% ELSE %]
+            <option value="0">
+        [% END %]
+            None
+        </option>
+
+        [% IF ( budget_perm_1 ) %]
+            <option value="1" selected="selected">
+        [% ELSE %]
+            <option value="1">
+        [% END %]
+            Owner
+        </option>
+
+        [% IF ( budget_perm_3) %]
+            <option value="3" selected="selected">
+        [% ELSE %]
+            <option value="3">
+        [% END %]
+            Owner and users
+        </option>
+
+        [% IF ( budget_perm_2 ) %]
+            <option value="2" selected="selected">
+        [% ELSE %]
+            <option value="2">
+        [% END %]
+            Owner, users and library
+        </option>
     </select>
     </li>
 
index f7c50b5..6bf188f 100755 (executable)
@@ -92,7 +92,7 @@ delete $$suggestion_ref{$_} foreach qw( suggestedbyme op displayby tabcode edit_
 foreach (keys %$suggestion_ref){
     delete $$suggestion_ref{$_} if (!$$suggestion_ref{$_} && ($op eq 'else' || $op eq 'change'));
 }
-my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+my ( $template, $borrowernumber, $cookie, $userflags ) = get_template_and_user(
         {
             template_name   => "suggestion/suggestion.tmpl",
             query           => $input,
@@ -320,12 +320,19 @@ if ($branchfilter) {
     $budgets = GetBudgets(undef);
 }
 
+my @budgets_loop;
 foreach my $budget ( @{$budgets} ) {
-## Please see file perltidy.ERR
-    $budget->{'selected'}=1 if ($$suggestion_ref{'budgetid'} && $budget->{'budget_id'} eq $$suggestion_ref{'budgetid'})
-};
+    next unless (CanUserUseBudget($borrowernumber, $budget, $userflags));
 
-$template->param( budgetsloop => $budgets);
+    ## Please see file perltidy.ERR
+    $budget->{'selected'} = 1
+        if ($$suggestion_ref{'budgetid'}
+        && $budget->{'budget_id'} eq $$suggestion_ref{'budgetid'});
+
+    push @budgets_loop, $budget;
+}
+
+$template->param( budgetsloop => \@budgets_loop);
 $template->param( "statusselected_$$suggestion_ref{'STATUS'}" =>1) if ($$suggestion_ref{'STATUS'});
 
 # get currencies and rates
diff --git a/t/Budgets/CanUserModifyBudget.t b/t/Budgets/CanUserModifyBudget.t
new file mode 100644 (file)
index 0000000..e75a622
--- /dev/null
@@ -0,0 +1,340 @@
+#!/usr/bin/perl
+
+use Modern::Perl;
+use Test::More tests => 133;
+
+use C4::Budgets;
+
+# Avoid "redefined subroutine" warnings
+local $SIG{__WARN__} = sub { warn $_[0] unless $_[0] =~ /redefined/ };
+*C4::Budgets::GetBudgetUsers = \&Mock_GetBudgetUsers;
+*C4::Context::userenv = \&Mock_userenv;
+
+my %budgetusers = (
+    1 => [],
+    2 => [1],
+    3 => [2],
+    4 => [3],
+    5 => [],
+    6 => [1],
+    7 => [2],
+    8 => [3],
+    9 => [],
+    10 => [1],
+    11 => [2],
+    12 => [3],
+    13 => [],
+    14 => [1],
+    15 => [2],
+    16 => [3],
+);
+
+my $borrower1 = {
+    borrowernumber => 1
+};
+my $borrower2 = {
+    borrowernumber => 2
+};
+
+my $budget1 = {
+    budget_id => 1,
+    budget_permission => 0,
+    budget_owner_id => undef,
+    budget_branchcode => undef,
+};
+my $budget2 = {
+    budget_id => 2,
+    budget_permission => 0,
+    budget_owner_id => undef,
+    budget_branchcode => 'B1',
+};
+my $budget3 = {
+    budget_id => 3,
+    budget_permission => 0,
+    budget_owner_id => 1,
+    budget_branchcode => undef,
+};
+my $budget4 = {
+    budget_id => 4,
+    budget_permission => 0,
+    budget_owner_id => 1,
+    budget_branchcode => 'B1',
+};
+my $budget5 = {
+    budget_id => 5,
+    budget_permission => 1,
+    budget_owner_id => undef,
+    budget_branchcode => undef,
+};
+my $budget6 = {
+    budget_id => 6,
+    budget_permission => 1,
+    budget_owner_id => undef,
+    budget_branchcode => 'B1',
+};
+my $budget7 = {
+    budget_id => 7,
+    budget_permission => 1,
+    budget_owner_id => 1,
+    budget_branchcode => undef,
+};
+my $budget8 = {
+    budget_id => 8,
+    budget_permission => 1,
+    budget_owner_id => 1,
+    budget_branchcode => 'B1',
+};
+my $budget9 = {
+    budget_id => 9,
+    budget_permission => 2,
+    budget_owner_id => undef,
+    budget_branchcode => undef,
+};
+my $budget10 = {
+    budget_id => 10,
+    budget_permission => 2,
+    budget_owner_id => undef,
+    budget_branchcode => 'B1',
+};
+my $budget11 = {
+    budget_id => 11,
+    budget_permission => 2,
+    budget_owner_id => 1,
+    budget_branchcode => undef,
+};
+my $budget12 = {
+    budget_id => 12,
+    budget_permission => 2,
+    budget_owner_id => 1,
+    budget_branchcode => 'B1',
+};
+my $budget13 = {
+    budget_id => 13,
+    budget_permission => 3,
+    budget_owner_id => undef,
+    budget_branchcode => undef,
+};
+my $budget14 = {
+    budget_id => 14,
+    budget_permission => 3,
+    budget_owner_id => undef,
+    budget_branchcode => 'B1',
+};
+my $budget15 = {
+    budget_id => 15,
+    budget_permission => 3,
+    budget_owner_id => 1,
+    budget_branchcode => undef,
+};
+my $budget16 = {
+    budget_id => 16,
+    budget_permission => 3,
+    budget_owner_id => 1,
+    budget_branchcode => 'B1',
+};
+
+my $userenv = {};
+
+
+ok (CanUserModifyBudget($borrower1, $budget1, {superlibrarian => 1}));
+ok (CanUserModifyBudget($borrower1, $budget1, {
+    acquisition => {
+        budget_manage_all => 1
+    }
+}));
+ok (CanUserModifyBudget($borrower1, $budget1, {acquisition => 1}));
+
+ok (!CanUserModifyBudget($borrower1, $budget1, {}));
+ok (!CanUserModifyBudget($borrower1, $budget1, {acquisition => 0}));
+
+my $flags = {acquisition => {budget_modify => 1}};
+
+$userenv->{branch} = 'B1';
+
+# Restriction is 'none'
+ok (CanUserModifyBudget($borrower1, $budget1, $flags));
+ok (CanUserModifyBudget($borrower1, $budget2, $flags));
+ok (CanUserModifyBudget($borrower1, $budget3, $flags));
+ok (CanUserModifyBudget($borrower1, $budget4, $flags));
+ok (CanUserModifyBudget($borrower2, $budget1, $flags));
+ok (CanUserModifyBudget($borrower2, $budget2, $flags));
+ok (CanUserModifyBudget($borrower2, $budget3, $flags));
+ok (CanUserModifyBudget($borrower2, $budget4, $flags));
+
+# Restriction is 'owner'
+ok (CanUserModifyBudget($borrower1, $budget5, $flags));
+ok (CanUserModifyBudget($borrower1, $budget6, $flags));
+ok (CanUserModifyBudget($borrower1, $budget7, $flags));
+ok (CanUserModifyBudget($borrower1, $budget8, $flags));
+ok (CanUserModifyBudget($borrower2, $budget5, $flags));
+ok (CanUserModifyBudget($borrower2, $budget6, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget7, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget8, $flags));
+
+# Restriction is 'owner, users and library'
+ok (CanUserModifyBudget($borrower1, $budget9, $flags));
+ok (CanUserModifyBudget($borrower1, $budget10, $flags));
+ok (CanUserModifyBudget($borrower1, $budget11, $flags));
+ok (CanUserModifyBudget($borrower1, $budget12, $flags));
+ok (CanUserModifyBudget($borrower2, $budget9, $flags));
+ok (CanUserModifyBudget($borrower2, $budget10, $flags));
+ok (CanUserModifyBudget($borrower2, $budget11, $flags));
+ok (CanUserModifyBudget($borrower2, $budget12, $flags));
+
+# Restriction is 'owner and users'
+ok (CanUserModifyBudget($borrower1, $budget13, $flags));
+ok (CanUserModifyBudget($borrower1, $budget14, $flags));
+ok (CanUserModifyBudget($borrower1, $budget15, $flags));
+ok (CanUserModifyBudget($borrower1, $budget16, $flags));
+ok (CanUserModifyBudget($borrower2, $budget13, $flags));
+ok (CanUserModifyBudget($borrower2, $budget14, $flags));
+ok (CanUserModifyBudget($borrower2, $budget15, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget16, $flags));
+
+
+$userenv->{branch} = 'B2';
+
+# Restriction is 'none'
+ok (CanUserModifyBudget($borrower1, $budget1, $flags));
+ok (CanUserModifyBudget($borrower1, $budget2, $flags));
+ok (CanUserModifyBudget($borrower1, $budget3, $flags));
+ok (CanUserModifyBudget($borrower1, $budget4, $flags));
+ok (CanUserModifyBudget($borrower2, $budget1, $flags));
+ok (CanUserModifyBudget($borrower2, $budget2, $flags));
+ok (CanUserModifyBudget($borrower2, $budget3, $flags));
+ok (CanUserModifyBudget($borrower2, $budget4, $flags));
+
+# Restriction is 'owner'
+ok (CanUserModifyBudget($borrower1, $budget5, $flags));
+ok (CanUserModifyBudget($borrower1, $budget6, $flags));
+ok (CanUserModifyBudget($borrower1, $budget7, $flags));
+ok (CanUserModifyBudget($borrower1, $budget8, $flags));
+ok (CanUserModifyBudget($borrower2, $budget5, $flags));
+ok (CanUserModifyBudget($borrower2, $budget6, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget7, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget8, $flags));
+
+# Restriction is 'owner, users and library'
+ok (CanUserModifyBudget($borrower1, $budget9, $flags));
+ok (CanUserModifyBudget($borrower1, $budget10, $flags));
+ok (CanUserModifyBudget($borrower1, $budget11, $flags));
+ok (CanUserModifyBudget($borrower1, $budget12, $flags));
+ok (CanUserModifyBudget($borrower2, $budget9, $flags));
+ok (CanUserModifyBudget($borrower2, $budget10, $flags));
+ok (CanUserModifyBudget($borrower2, $budget11, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget12, $flags));
+
+# Restriction is 'owner and users'
+ok (CanUserModifyBudget($borrower1, $budget13, $flags));
+ok (CanUserModifyBudget($borrower1, $budget14, $flags));
+ok (CanUserModifyBudget($borrower1, $budget15, $flags));
+ok (CanUserModifyBudget($borrower1, $budget16, $flags));
+ok (CanUserModifyBudget($borrower2, $budget13, $flags));
+ok (CanUserModifyBudget($borrower2, $budget14, $flags));
+ok (CanUserModifyBudget($borrower2, $budget15, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget16, $flags));
+
+
+# Same tests as above, without budget_modify permission
+# All tests should failed
+$flags = {acquisition => {order_manage => 1}};
+
+$userenv->{branch} = 'B1';
+
+# Restriction is 'none'
+ok (!CanUserModifyBudget($borrower1, $budget1, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget2, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget3, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget4, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget1, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget2, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget3, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget4, $flags));
+
+# Restriction is 'owner'
+ok (!CanUserModifyBudget($borrower1, $budget5, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget6, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget7, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget8, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget5, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget6, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget7, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget8, $flags));
+
+# Restriction is 'owner, users and library'
+ok (!CanUserModifyBudget($borrower1, $budget9, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget10, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget11, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget12, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget9, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget10, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget11, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget12, $flags));
+
+# Restriction is 'owner and users'
+ok (!CanUserModifyBudget($borrower1, $budget13, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget14, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget15, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget16, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget13, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget14, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget15, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget16, $flags));
+
+
+$userenv->{branch} = 'B2';
+
+# Restriction is 'none'
+ok (!CanUserModifyBudget($borrower1, $budget1, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget2, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget3, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget4, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget1, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget2, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget3, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget4, $flags));
+
+# Restriction is 'owner'
+ok (!CanUserModifyBudget($borrower1, $budget5, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget6, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget7, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget8, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget5, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget6, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget7, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget8, $flags));
+
+# Restriction is 'owner, users and library'
+ok (!CanUserModifyBudget($borrower1, $budget9, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget10, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget11, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget12, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget9, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget10, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget11, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget12, $flags));
+
+# Restriction is 'owner and users'
+ok (!CanUserModifyBudget($borrower1, $budget13, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget14, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget15, $flags));
+ok (!CanUserModifyBudget($borrower1, $budget16, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget13, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget14, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget15, $flags));
+ok (!CanUserModifyBudget($borrower2, $budget16, $flags));
+
+
+# Mocked subs
+
+# C4::Acquisition::GetBudgetUsers
+sub Mock_GetBudgetUsers {
+    my ($budget_id) = @_;
+
+    return @{ $budgetusers{$budget_id} };
+}
+
+# C4::Context->userenv
+sub Mock_userenv {
+    return $userenv;
+}
diff --git a/t/Budgets/CanUserUseBudget.t b/t/Budgets/CanUserUseBudget.t
new file mode 100644 (file)
index 0000000..8219197
--- /dev/null
@@ -0,0 +1,250 @@
+#!/usr/bin/perl
+
+use Modern::Perl;
+use Test::More tests => 69;
+
+use C4::Budgets;
+
+# Avoid "redefined subroutine" warnings
+local $SIG{__WARN__} = sub { warn $_[0] unless $_[0] =~ /redefined/ };
+
+*C4::Budgets::GetBudgetUsers = \&Mock_GetBudgetUsers;
+*C4::Context::userenv = \&Mock_userenv;
+
+my %budgetusers = (
+    1 => [],
+    2 => [1],
+    3 => [2],
+    4 => [3],
+    5 => [],
+    6 => [1],
+    7 => [2],
+    8 => [3],
+    9 => [],
+    10 => [1],
+    11 => [2],
+    12 => [3],
+    13 => [],
+    14 => [1],
+    15 => [2],
+    16 => [3],
+);
+
+my $borrower1 = {
+    borrowernumber => 1
+};
+my $borrower2 = {
+    borrowernumber => 2
+};
+
+my $budget1 = {
+    budget_id => 1,
+    budget_permission => 0,
+    budget_owner_id => undef,
+    budget_branchcode => undef,
+};
+my $budget2 = {
+    budget_id => 2,
+    budget_permission => 0,
+    budget_owner_id => undef,
+    budget_branchcode => 'B1',
+};
+my $budget3 = {
+    budget_id => 3,
+    budget_permission => 0,
+    budget_owner_id => 1,
+    budget_branchcode => undef,
+};
+my $budget4 = {
+    budget_id => 4,
+    budget_permission => 0,
+    budget_owner_id => 1,
+    budget_branchcode => 'B1',
+};
+my $budget5 = {
+    budget_id => 5,
+    budget_permission => 1,
+    budget_owner_id => undef,
+    budget_branchcode => undef,
+};
+my $budget6 = {
+    budget_id => 6,
+    budget_permission => 1,
+    budget_owner_id => undef,
+    budget_branchcode => 'B1',
+};
+my $budget7 = {
+    budget_id => 7,
+    budget_permission => 1,
+    budget_owner_id => 1,
+    budget_branchcode => undef,
+};
+my $budget8 = {
+    budget_id => 8,
+    budget_permission => 1,
+    budget_owner_id => 1,
+    budget_branchcode => 'B1',
+};
+my $budget9 = {
+    budget_id => 9,
+    budget_permission => 2,
+    budget_owner_id => undef,
+    budget_branchcode => undef,
+};
+my $budget10 = {
+    budget_id => 10,
+    budget_permission => 2,
+    budget_owner_id => undef,
+    budget_branchcode => 'B1',
+};
+my $budget11 = {
+    budget_id => 11,
+    budget_permission => 2,
+    budget_owner_id => 1,
+    budget_branchcode => undef,
+};
+my $budget12 = {
+    budget_id => 12,
+    budget_permission => 2,
+    budget_owner_id => 1,
+    budget_branchcode => 'B1',
+};
+my $budget13 = {
+    budget_id => 13,
+    budget_permission => 3,
+    budget_owner_id => undef,
+    budget_branchcode => undef,
+};
+my $budget14 = {
+    budget_id => 14,
+    budget_permission => 3,
+    budget_owner_id => undef,
+    budget_branchcode => 'B1',
+};
+my $budget15 = {
+    budget_id => 15,
+    budget_permission => 3,
+    budget_owner_id => 1,
+    budget_branchcode => undef,
+};
+my $budget16 = {
+    budget_id => 16,
+    budget_permission => 3,
+    budget_owner_id => 1,
+    budget_branchcode => 'B1',
+};
+
+my $userenv = {};
+
+ok (CanUserUseBudget($borrower1, $budget1, {superlibrarian => 1}));
+ok (CanUserUseBudget($borrower1, $budget1, {
+    acquisition => {
+        budget_manage_all => 1
+    }
+}));
+ok (CanUserUseBudget($borrower1, $budget1, {acquisition => 1}));
+
+ok (!CanUserUseBudget($borrower1, $budget1, {}));
+ok (!CanUserUseBudget($borrower1, $budget1, {acquisition => 0}));
+
+my $flags = {acquisition => {order_manage => 1}};
+
+$userenv->{branch} = 'B1';
+
+# Restriction is 'none'
+ok (CanUserUseBudget($borrower1, $budget1, $flags));
+ok (CanUserUseBudget($borrower1, $budget2, $flags));
+ok (CanUserUseBudget($borrower1, $budget3, $flags));
+ok (CanUserUseBudget($borrower1, $budget4, $flags));
+ok (CanUserUseBudget($borrower2, $budget1, $flags));
+ok (CanUserUseBudget($borrower2, $budget2, $flags));
+ok (CanUserUseBudget($borrower2, $budget3, $flags));
+ok (CanUserUseBudget($borrower2, $budget4, $flags));
+
+# Restriction is 'owner'
+ok (CanUserUseBudget($borrower1, $budget5, $flags));
+ok (CanUserUseBudget($borrower1, $budget6, $flags));
+ok (CanUserUseBudget($borrower1, $budget7, $flags));
+ok (CanUserUseBudget($borrower1, $budget8, $flags));
+ok (CanUserUseBudget($borrower2, $budget5, $flags));
+ok (CanUserUseBudget($borrower2, $budget6, $flags));
+ok (!CanUserUseBudget($borrower2, $budget7, $flags));
+ok (!CanUserUseBudget($borrower2, $budget8, $flags));
+
+# Restriction is 'owner, users and library'
+ok (CanUserUseBudget($borrower1, $budget9, $flags));
+ok (CanUserUseBudget($borrower1, $budget10, $flags));
+ok (CanUserUseBudget($borrower1, $budget11, $flags));
+ok (CanUserUseBudget($borrower1, $budget12, $flags));
+ok (CanUserUseBudget($borrower2, $budget9, $flags));
+ok (CanUserUseBudget($borrower2, $budget10, $flags));
+ok (CanUserUseBudget($borrower2, $budget11, $flags));
+ok (CanUserUseBudget($borrower2, $budget12, $flags));
+
+# Restriction is 'owner and users'
+ok (CanUserUseBudget($borrower1, $budget13, $flags));
+ok (CanUserUseBudget($borrower1, $budget14, $flags));
+ok (CanUserUseBudget($borrower1, $budget15, $flags));
+ok (CanUserUseBudget($borrower1, $budget16, $flags));
+ok (CanUserUseBudget($borrower2, $budget13, $flags));
+ok (CanUserUseBudget($borrower2, $budget14, $flags));
+ok (CanUserUseBudget($borrower2, $budget15, $flags));
+ok (!CanUserUseBudget($borrower2, $budget16, $flags));
+
+
+$userenv->{branch} = 'B2';
+
+# Restriction is 'none'
+ok (CanUserUseBudget($borrower1, $budget1, $flags));
+ok (CanUserUseBudget($borrower1, $budget2, $flags));
+ok (CanUserUseBudget($borrower1, $budget3, $flags));
+ok (CanUserUseBudget($borrower1, $budget4, $flags));
+ok (CanUserUseBudget($borrower2, $budget1, $flags));
+ok (CanUserUseBudget($borrower2, $budget2, $flags));
+ok (CanUserUseBudget($borrower2, $budget3, $flags));
+ok (CanUserUseBudget($borrower2, $budget4, $flags));
+
+# Restriction is 'owner'
+ok (CanUserUseBudget($borrower1, $budget5, $flags));
+ok (CanUserUseBudget($borrower1, $budget6, $flags));
+ok (CanUserUseBudget($borrower1, $budget7, $flags));
+ok (CanUserUseBudget($borrower1, $budget8, $flags));
+ok (CanUserUseBudget($borrower2, $budget5, $flags));
+ok (CanUserUseBudget($borrower2, $budget6, $flags));
+ok (!CanUserUseBudget($borrower2, $budget7, $flags));
+ok (!CanUserUseBudget($borrower2, $budget8, $flags));
+
+# Restriction is 'owner, users and library'
+ok (CanUserUseBudget($borrower1, $budget9, $flags));
+ok (CanUserUseBudget($borrower1, $budget10, $flags));
+ok (CanUserUseBudget($borrower1, $budget11, $flags));
+ok (CanUserUseBudget($borrower1, $budget12, $flags));
+ok (CanUserUseBudget($borrower2, $budget9, $flags));
+ok (CanUserUseBudget($borrower2, $budget10, $flags));
+ok (CanUserUseBudget($borrower2, $budget11, $flags));
+ok (!CanUserUseBudget($borrower2, $budget12, $flags));
+
+# Restriction is 'owner and users'
+ok (CanUserUseBudget($borrower1, $budget13, $flags));
+ok (CanUserUseBudget($borrower1, $budget14, $flags));
+ok (CanUserUseBudget($borrower1, $budget15, $flags));
+ok (CanUserUseBudget($borrower1, $budget16, $flags));
+ok (CanUserUseBudget($borrower2, $budget13, $flags));
+ok (CanUserUseBudget($borrower2, $budget14, $flags));
+ok (CanUserUseBudget($borrower2, $budget15, $flags));
+ok (!CanUserUseBudget($borrower2, $budget16, $flags));
+
+
+# Mocked subs
+
+# C4::Acquisition::GetBudgetUsers
+sub Mock_GetBudgetUsers {
+    my ($budget_id) = @_;
+
+    return @{ $budgetusers{$budget_id} };
+}
+
+# C4::Context->userenv
+sub Mock_userenv {
+    return $userenv;
+}