per-agent subtotals on sales report, #18566
authorMark Wells <mark@freeside.biz>
Mon, 13 Aug 2012 23:21:36 +0000 (16:21 -0700)
committerMark Wells <mark@freeside.biz>
Mon, 13 Aug 2012 23:21:36 +0000 (16:21 -0700)
httemplate/graph/cust_bill_pkg.cgi
httemplate/graph/elements/monthly.html
httemplate/graph/elements/report.html
httemplate/graph/report_cust_bill_pkg.html

index e7a3bd2..c334ae9 100644 (file)
@@ -8,6 +8,7 @@
                 'graph_labels' => \@labels,
                 'colors'       => \@colors,
                 'links'        => \@links,
+                'no_graph'     => \@no_graph,
                 'remove_empty' => 1,
                 'bottom_total' => 1,
                 'bottom_link'  => $bottom_link,
@@ -118,6 +119,7 @@ my @params = ();
 my @labels = ();
 my @colors = ();
 my @links  = ();
+my @no_graph;
 
 my @components = ( 'SRU' );
 # split/omit components as appropriate
@@ -134,6 +136,11 @@ elsif ( $use_usage == 2 ) {
   $components[-1] =~ s/U//;
 }
 
+# Categorization of line items goes
+# Agent -> Referral -> Package class -> Component (setup/recur/usage)
+# If per-agent totals are enabled, they go under the Agent level.
+# There aren't any other kinds of subtotals.
+
 foreach my $agent ( $all_agent || $sel_agent || qsearch('agent', { 'disabled' => '' } ) ) {
 
   my $col_scheme = Color::Scheme->new
@@ -146,7 +153,11 @@ foreach my $agent ( $all_agent || $sel_agent || qsearch('agent', { 'disabled' =>
   ### fixup the color handling for package classes...
   ### and usage
 
-  foreach my $part_referral ( $all_part_referral || $sel_part_referral || qsearch('part_referral', { 'disabled' => '' } ) ) {
+  foreach my $part_referral (
+    $all_part_referral ||
+    $sel_part_referral ||
+    qsearch('part_referral', { 'disabled' => '' } ) 
+  ) {
 
     foreach my $pkg_class ( @pkg_class ) {
       foreach my $component ( @components ) {
@@ -186,9 +197,46 @@ foreach my $agent ( $all_agent || $sel_agent || qsearch('agent', { 'disabled' =>
         @onetime_colors = ($col_scheme->colors)[2,6,10,3,7,11]
           unless @onetime_colors;
         push @colors, shift @recur_colors;
-
-      }
+        push @no_graph, 0;
+
+      } #foreach $component
+    } #foreach $pkg_class
+  } #foreach $part_referral
+
+  if ( $cgi->param('agent_totals') and !$all_agent ) {
+    my $row_agentnum = $agent->agentnum;
+    # Include all components that are anywhere on this report
+    my $component = join('', @components);
+
+    my @row_params = (  'agentnum'              => $row_agentnum,
+                        'use_override'          => $use_override,
+                        'average_per_cust_pkg'  => $average_per_cust_pkg,
+                        'distribute'            => $distribute,
+                        'charges'               => $component,
+                     );
+    my $row_link = "$link;".
+                   "agentnum=$row_agentnum;".
+                   "distribute=$distribute;".
+                   "charges=$component";
+    
+    # Also apply any refnum/classnum filters
+    if ( !$all_class and scalar(@pkg_class) == 1 ) {
+      # then a specific class has been chosen, but it may be the empty class
+      my $row_classnum = ref($pkg_class[0]) ? $pkg_class[0]->classnum : 0;
+      push @row_params, 'classnum' => $row_classnum;
+      $row_link .= ";classnum=$row_classnum";
     }
+    if ( $sel_part_referral ) {
+      push @row_params, 'refnum' => $sel_part_referral->refnum;
+      $row_link .= ";refnum=".$sel_part_referral->refnum;
+    }
+
+    push @items, 'cust_bill_pkg';
+    push @labels, mt('[_1] - Subtotal', $agent->agent);
+    push @params, \@row_params;
+    push @links, $row_link;
+    push @colors, '000000'; # better idea?
+    push @no_graph, 1;
   }
 
   $hue += $hue_increment;
index 839a387..c736de6 100644 (file)
@@ -20,6 +20,7 @@ Example:
     'link_fromparam'  => 'param_from', #defaults to 'begin'
     'link_toparam'    => 'param_to',   #defaults to 'end'
     'daily'           => 1, # omit for monthly granularity
+    'no_graph'        => \@no_graph, # items to leave off the graph (subtotals)
 
     #optional, pulled from CGI params if not specified
     'start_month'     => $smonth,
@@ -49,18 +50,19 @@ Example:
             'items'         => $data->{'items'},
             'data'          => $data->{'data'},
             'row_labels'    => $data->{'item_labels'},
-            'graph_labels'  => $opt{'graph_labels'} || $data->{'item_labels'},
+            'graph_labels'  => \@graph_labels,
             'col_labels'    => $col_labels,
             'axis_labels'   => $data->{label},
-            'colors'        => $data->{colors},
+            'colors'        => \@colors,
             'links'         => \@links,
+            'no_graph'      => \@no_graph,
             'bottom_link'   => \@bottom_link,
             'transpose'     => $opt{'daily'},
-            map { $_, $opt{$_} } (qw(title 
-                                    nototal 
-                                    graph_type 
-                                    bottom_total 
-                                    sprintf 
+            map { $_, $opt{$_} } (qw(title
+                                    nototal
+                                    graph_type
+                                    bottom_total
+                                    sprintf
                                     disable_money
                                     chart_options)),
           ) %>
@@ -103,7 +105,7 @@ if ( $opt{'daily'} ) { # daily granularity
 my %reportopts = (
       'items'        => \@items,
       'params'       => $opt{'params'},
-      'item_labels'  => ( $cgi->param('_type') =~ /^(png)$/
+      'item_labels'  => ( $cgi->param('_type') =~ /^(png)$/ 
                             ? $opt{'graph_labels'}
                             : $opt{'labels'}
                         ),
@@ -140,12 +142,20 @@ my $col_labels = [ map { my $m = $_; $m =~ s/^(\d+)\//$mon[$1-1] / ; $m }
                              @{$data->{label}} ];
 $col_labels = $data->{label} if $opt{'daily'};
 
+my @colors;
+my @graph_labels;
+my @no_graph;
 if ( $opt{'remove_empty'} ) {
-  # need to filter out series labels for collapsed rows
-  $opt{'graph_labels'} = [ 
-    map { $opt{'graph_labels'}[$_] } 
-    @{ $data->{indices} }
-  ];
+  # then filter out per-item things for collapsed rows
+  foreach my $i (@{ $data->{'indices'} }) {
+    push @colors,       $opt{'colors'}[$i];
+    push @graph_labels, $opt{'graph_labels'}[$i];
+    push @no_graph,     $opt{'no_graph'}[$i];
+  }
+} else {
+  @colors       = @{ $opt{'colors'} };
+  @graph_labels = @{ $opt{'graph_labels'} };
+  @no_graph     = @{ $opt{'no_graph'} || [] };
 }
 
 my @links;
index f774616..98b4778 100644 (file)
@@ -14,6 +14,7 @@ Example:
     'graph_labels'    => \@graph_labels,  #defaults to row_labels
 
     'links'           => \@links,         #optional
+    'no_graph'        => \@no_graph,      #optional
 
     #these run parallel to the elements of each @item
     'col_labels'      => \@col_labels,    #required
@@ -128,7 +129,19 @@ any delimiter and linked from the elements in @data.
 %   
 <% $output %>
 % } elsif ( $cgi->param('_type') eq 'png' ) {
-%
+%   # delete any items that shouldn't be on the graph
+%   if ( my $no_graph = $opt{'no_graph'} ) {
+%     my $i = 0;
+%     while (@$no_graph) {
+%       if ( shift @$no_graph ) {
+%         splice @data, $i, 1;
+%         splice @{$opt{'graph_labels'}}, $i, 1;
+%         splice @{$opt{'colors'}}, $i, 1;
+%         $i--; # because everything is shifted down
+%       }
+%       $i++;
+%     }
+%   }
 %   my $graph_type = 'LinesPoints';
 %   if ( $opt{'graph_type'} =~ /^(LinesPoints|Mountain|Bars)$/ ) {
 %     $graph_type = $1;
index 4cedcef..31792e8 100644 (file)
   <TD>Show projected data for future months</TD>
 </TR>
 
-<% include('/elements/tr-select-agent.html',
-             'label'         => 'Agent ',
-             'disable_empty' => 0,
-             'pre_options'   => [ 'all' => 'all (aggregate)' ],
-             'empty_label'   => 'all (breakdown)',
-          )
-%>
-
-<% include('/elements/tr-select-part_referral.html',
-             'label'         => 'Advertising source ',
-             'disable_empty' => 0,
-             'pre_options'   => [ 'all' => 'all (aggregate)' ],
-             'empty_label'   => 'all (breakdown)',
-          )
-%>
-
-<% include('/elements/tr-select-pkg_class.html',
-              'pre_options' => [ 'all'  => 'all (aggregate)',
-                                 '0' => 'all (breakdown)' ],
-              'empty_label' => '(empty class)',
-           )
-%>
+<SCRIPT TYPE="text/javascript">
+function enable_agent_totals(obj) {
+%# enable it iff we are breaking down by agent AND something else
+  obj.form.agent_totals.disabled = !(
+    obj.form.agentnum.value == '' && (
+      obj.form.refnum.value == ''   ||
+      obj.form.classnum.value == 0  ||
+      obj.form.use_setup.value == 1 ||
+      obj.form.use_usage.value == 1
+    )
+  );
+}
+</SCRIPT>
+
+<& /elements/tr-select-agent.html,
+  'field'         => 'agentnum',
+  'label'         => 'Agent ',
+  'disable_empty' => 0,
+  'pre_options'   => [ 'all' => 'all (aggregate)' ],
+  'empty_label'   => 'all (breakdown)',
+  'onchange'      => 'enable_agent_totals',
+&>
+
+<& /elements/tr-select-part_referral.html,
+  'field'         => 'refnum',
+  'label'         => 'Advertising source ',
+  'disable_empty' => 0,
+  'pre_options'   => [ 'all' => 'all (aggregate)' ],
+  'empty_label'   => 'all (breakdown)',
+  'onchange'      => 'enable_agent_totals'
+&>
+
+<& /elements/tr-select-pkg_class.html,
+  'field'       => 'classnum',
+  'pre_options' => [ 'all'  => 'all (aggregate)',
+                        '0' => 'all (breakdown)' ],
+  'empty_label' => '(empty class)',
+  'onchange'    => 'enable_agent_totals',
+&>
 
 <!--
 <TR>
     'field'   => 'use_'.lc($_),
     'options' => [ 0, 1, 2 ],
     'labels'  => { 0 => 'Combine', 1 => 'Separate', 2 => 'Do not show' },
+    'onchange'=> 'enable_agent_totals',
 &>
 % }
 
 <TR>
+  <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="agent_totals" VALUE="1" DISABLED="1"></TD>
+  <TD>Show per-agent subtotals</TD>
+</TR>
+
+<TR>
   <TD ALIGN="right"><INPUT TYPE="checkbox" NAME="use_override" VALUE="1"></TD>
   <TD>Separate sub-packages from parents</TD>
 </TR>