RT#22952: Employee drop down list in reports shows employee users for all agents
authorJonathan Prykop <jonathan@freeside.biz>
Thu, 5 Mar 2015 00:33:52 +0000 (18:33 -0600)
committerJonathan Prykop <jonathan@freeside.biz>
Thu, 5 Mar 2015 00:33:52 +0000 (18:33 -0600)
FS/FS/access_user.pm
httemplate/elements/select-user.html
httemplate/search/report_cust_bill_pkg_discount.html
httemplate/search/report_cust_credit.html
httemplate/search/report_cust_credit_bill_pkg.html
httemplate/search/report_cust_credit_source_bill_pkg.html
httemplate/search/report_cust_credit_void.html
httemplate/search/report_cust_pkg_discount.html

index 44d3bee..68d2dea 100644 (file)
@@ -354,7 +354,9 @@ sub agentnums_sql {
   if ( $self->access_right($viewall_right) ) {
     push @or, "$agentnum IS NOT NULL";
   } else {
-    push @or, "$agentnum IN (". join(',', $self->agentnums). ')';
+    my @agentnums = $self->agentnums;
+    push @or, "$agentnum IN (". join(',', @agentnums). ')'
+      if @agentnums;
   }
 
   push @or, "$agentnum IS NULL"
@@ -370,17 +372,24 @@ sub agentnums_sql {
 
 Returns true if the user can view the specified agent.
 
+Also accepts optional hashref cache, to avoid redundant database calls.
+
 =cut
 
 sub agentnum {
-  my( $self, $agentnum ) = @_;
+  my( $self, $agentnum, $cache ) = @_;
+  $cache ||= {};
+  return $cache->{$self->usernum}->{$agentnum}
+    if $cache->{$self->usernum}->{$agentnum};
   my $sth = dbh->prepare(
     "SELECT COUNT(*) FROM access_usergroup
                      JOIN access_groupagent USING ( groupnum )
        WHERE usernum = ? AND agentnum = ?"
   ) or die dbh->errstr;
   $sth->execute($self->usernum, $agentnum) or die $sth->errstr;
-  $sth->fetchrow_arrayref->[0];
+  $cache->{$self->usernum}->{$agentnum} = $sth->fetchrow_arrayref->[0];
+  $sth->finish;
+  return $cache->{$self->usernum}->{$agentnum};
 }
 
 =item agents [ HASHREF | OPTION => VALUE ... ]
@@ -400,6 +409,104 @@ sub agents {
   });
 }
 
+=item access_users [ HASHREF | OPTION => VALUE ... ]
+
+Returns an array of FS::access_user objects, one for each non-disabled 
+access_user in the system that shares an agent (via group membership) with 
+the invoking object.  Regardless of options and agents, will always at
+least return the invoking user and any users who have viewall_right.
+
+Accepts the following options:
+
+=over 4
+
+=item table
+
+Only return users who appear in the usernum field of this table
+
+=item disabled
+
+Include disabled users if true (defaults to false)
+
+=item viewall_right
+
+All users will be returned if the current user has the provided 
+access right, regardless of agents (other filters still apply.)  
+Defaults to 'View customers of all agents'
+
+=cut
+
+#Leaving undocumented until such time as this functionality is actually used
+#
+#=item null
+#
+#Users with no agents will be returned.
+#
+#=item null_right
+#
+#Users with no agents will be returned if the current user has the provided
+#access right.
+
+sub access_users {
+  my $self = shift;
+  my %opt = ref($_[0]) ? %{$_[0]} : @_;
+  my $table = $opt{'table'};
+  my $search = { 'table' => 'access_user' };
+  $search->{'hashref'} = $opt{'disabled'} ? {} : { 'disabled' => '' };
+  $search->{'addl_from'} = "INNER JOIN $table ON (access_user.usernum = $table.usernum)"
+    if $table;
+  my @access_users = qsearch($search);
+  my $viewall_right = $opt{'viewall_right'} || 'View customers of all agents';
+  return @access_users if $self->access_right($viewall_right);
+  #filter for users with agents $self can view
+  my @out;
+  my $agentnum_cache = {};
+ACCESS_USER:
+  foreach my $access_user (@access_users) {
+    # you can always view yourself, regardless of agents,
+    # and you can always view someone who can view you, 
+    # since they might have affected your customers
+    if ( ($self->usernum eq $access_user->usernum) 
+         || $access_user->access_right($viewall_right)
+    ) {
+      push(@out,$access_user);
+      next;
+    }
+    # if user has no agents, you need null or null_right to view
+    my @agents = $access_user->agents('viewall_right'=>'NONE'); #handled viewall_right above
+    if (!@agents) {
+      if ( $opt{'null'} ||
+           ( $opt{'null_right'} && $self->access_right($opt{'null_right'}) )
+      ) {
+        push(@out,$access_user);
+      }
+      next;
+    }
+    # otherwise, you need an agent in common
+    foreach my $agent (@agents) {
+      if ($self->agentnum($agent->agentnum,$agentnum_cache)) {
+        push(@out,$access_user);
+        next ACCESS_USER;
+      }
+    }
+  }
+  return @out;
+}
+
+=item access_users_hashref  [ HASHREF | OPTION => VALUE ... ]
+
+Accepts same options as L</access_users>.  Returns a hashref of
+users, with keys of usernum and values of username.
+
+=cut
+
+sub access_users_hashref {
+  my $self = shift;
+  my %access_users = map { $_->usernum => $_->username } 
+                       $self->access_users(@_);
+  return \%access_users;
+}
+
 =item access_right RIGHTNAME | LISTREF
 
 Given a right name or a list reference of right names, returns true if this
index ec2341b..e77788f 100644 (file)
 
 my %opt = @_;
 
-unless ( $opt{'access_user'} ) {
-
-  my $sth = dbh->prepare("
-    SELECT usernum, username FROM access_user
-      WHERE disabled = '' or disabled IS NULL
-  ") or die dbh->errstr;
-  $sth->execute or die $sth->errstr;
-  while ( my $row = $sth->fetchrow_arrayref ) {
-    $opt{'access_user'}->{$row->[0]} = $row->[1];
-  }
-
-}
+$opt{'access_user'} ||= $FS::CurrentUser::CurrentUser->access_users_hashref();
 
 </%init>
index 77affd1..10ccba9 100644 (file)
@@ -13,7 +13,7 @@
 
   <& /elements/tr-select-user.html,
        'label'       => 'Discounts by employee: ',
-       'access_user' => \%access_user,
+       'access_user' => $access_user,
   &>
 
   <& /elements/tr-select-agent.html,
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
 
-my $sth = dbh->prepare("SELECT DISTINCT usernum FROM cust_pkg_discount")
-  or die dbh->errstr;
-$sth->execute or die $sth->errstr;
-my @usernum = map $_->[0], @{$sth->fetchall_arrayref};
-my %access_user =
-  map { $_ => qsearchs('access_user',{'usernum'=>$_})->username }
-      @usernum;
+my $access_user = $FS::CurrentUser::CurrentUser->access_users_hashref('table' => 'cust_pkg_discount');
 
 </%init>
index dbab66a..0d7a277 100644 (file)
@@ -8,7 +8,7 @@
 
   <& /elements/tr-select-user.html,
                 'label'       => emt('Credits by employee: '),
-                'access_user' => \%access_user,
+                'access_user' => $access_user,
   &>
 
   <& /elements/tr-select-agent.html,
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
 
-my $sth = dbh->prepare("SELECT DISTINCT usernum FROM cust_credit")
-  or die dbh->errstr;
-$sth->execute or die $sth->errstr;
-my @usernum = map $_->[0], @{$sth->fetchall_arrayref};
-my %access_user =
-  map { $_ => qsearchs('access_user',{'usernum'=>$_})->username }
-      @usernum;
+my $access_user = $FS::CurrentUser::CurrentUser->access_users_hashref('table' => 'cust_credit');
 
 my $unapplied = $cgi->param('unapplied') ? 1 : 0;
 
index ad0f3f6..1a54a12 100644 (file)
@@ -7,7 +7,7 @@
 
 <& /elements/tr-select-user.html,
               'label'       => emt('Employee: '),
-              'access_user' => \%access_user,
+              'access_user' => $access_user,
 &>
 
 <& /elements/tr-select-agent.html,
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
 
-#false laziness w/report_cust_credit.html
-my $sth = dbh->prepare("SELECT DISTINCT usernum FROM cust_credit")
-  or die dbh->errstr;
-$sth->execute or die $sth->errstr;
-my @usernum = map $_->[0], @{$sth->fetchall_arrayref};
-my %access_user =
-  map { $_ => qsearchs('access_user',{'usernum'=>$_})->username }
-      @usernum;
+my $access_user = $FS::CurrentUser::CurrentUser->access_users_hashref('table' => 'cust_credit');
 
 my $conf = new FS::Conf;
 
index b579b92..7bfacc4 100644 (file)
@@ -7,7 +7,7 @@
 
 <& /elements/tr-select-user.html,
               'label'       => emt('Employee: '),
-              'access_user' => \%access_user,
+              'access_user' => $access_user,
 &>
 
 <& /elements/tr-select-agent.html,
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
 
-#false laziness w/report_cust_credit.html
-my $sth = dbh->prepare("SELECT DISTINCT usernum FROM cust_credit")
-  or die dbh->errstr;
-$sth->execute or die $sth->errstr;
-my @usernum = map $_->[0], @{$sth->fetchall_arrayref};
-my %access_user =
-  map { $_ => qsearchs('access_user',{'usernum'=>$_})->username }
-      @usernum;
+my $access_user = $FS::CurrentUser::CurrentUser->access_users_hashref('table' => 'cust_credit');
 
 my $conf = new FS::Conf;
 
index e967080..16a9e42 100644 (file)
@@ -7,7 +7,7 @@
 
   <& /elements/tr-select-user.html,
                 'label'       => emt('Credit voids by employee: '),
-                'access_user' => \%access_user,
+                'access_user' => $access_user,
   &>
 
   <& /elements/tr-select-agent.html,
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
 
-my $sth = dbh->prepare("SELECT DISTINCT usernum FROM cust_credit_void")
-  or die dbh->errstr;
-$sth->execute or die $sth->errstr;
-my @usernum = map $_->[0], @{$sth->fetchall_arrayref};
-my %access_user =
-  map { $_ => qsearchs('access_user',{'usernum'=>$_})->username }
-      @usernum;
+my $access_user = $FS::CurrentUser::CurrentUser->access_users_hashref('table' => 'cust_credit_void');
 
 my $title = 'Voided credit report';
 
index 7f0e55f..2b9052f 100644 (file)
@@ -23,7 +23,7 @@
 
   <& /elements/tr-select-user.html,
        'label'       => 'Discounts by employee: ',
-       'access_user' => \%access_user,
+       'access_user' => $access_user,
   &>
 
   <& /elements/tr-select-agent.html,
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
 
-my $sth = dbh->prepare("SELECT DISTINCT usernum FROM cust_pkg_discount")
-  or die dbh->errstr;
-$sth->execute or die $sth->errstr;
-my @usernum = map $_->[0], @{$sth->fetchall_arrayref};
-my %access_user =
-  map { $_ => qsearchs('access_user',{'usernum'=>$_})->username }
-      @usernum;
+my $access_user = $FS::CurrentUser::CurrentUser->access_users_hashref('table' => 'cust_pkg_discount');
 
 </%init>