Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / FS / FS / Report / Table / Monthly.pm
index ee4dc5f..f4ba020 100644 (file)
@@ -25,6 +25,7 @@ FS::Report::Table::Monthly - Tables of report data, indexed monthly
     #opt
     'agentnum'    => 54
     'refnum'      => 54
+    'cust_classnum' => [ 1,2,4 ],
     'params'      => [ [ 'paramsfor', 'item_one' ], [ 'item', 'two' ] ], # ...
     'remove_empty' => 1, #collapse empty rows, default 0
     'item_labels' => [ ], #useful with remove_empty
@@ -69,6 +70,9 @@ corresponding to this arrayref.
 
 =item refnum: Limit to customers with this advertising source.
 
+=item cust_classnum: Limit to customers with this classnum; can be an 
+arrayref.
+
 =item remove_empty: Set this to a true value to hide rows that contain 
 only zeroes.  The C<indices> array in the returned data will list the item
 indices that are actually present in the output so that you know what they
@@ -84,6 +88,13 @@ hidden rows (due to C<remove_empty>) filtered out, which is the only
 reason to do this.  Now that we have C<indices> it's probably better to 
 use that.
 
+=item PROCESSING
+
+=item normalize: Set this to an item index to have all other items expressed
+as a percentage of that one.  That item will then be omitted from the output.
+If the normalization item is zero in some period, all the values in that
+period will be undef.
+
 =head1 RETURNED DATA
 
 The C<data> method runs the report and returns a hashref of the following:
@@ -139,6 +150,8 @@ sub data {
 
   my $agentnum = $self->{'agentnum'};
   my $refnum = $self->{'refnum'};
+  my $cust_classnum = $self->{'cust_classnum'} || [];
+  $cust_classnum = [ $cust_classnum ] if !ref($cust_classnum);
 
   if ( $projecting ) {
 
@@ -169,12 +182,18 @@ sub data {
     push @{$data{label}}, "$smonth/$syear"; # sprintf?
 
     my $speriod = timelocal(0,0,0,1,$smonth-1,$syear);
-    push @{$data{speriod}}, $speriod;
     if ( ++$smonth == 13 ) { $syear++; $smonth=1; }
     my $eperiod = timelocal(0,0,0,1,$smonth-1,$syear);
+    # 12-month mode: show results in a sliding window ending at $eperiod,
+    # but starting 12 months before.
+    if ( $self->{'12mo'}) {
+      $speriod = timelocal(0,0,0,1,$smonth-1,$syear-1);
+    }
+
+    push @{$data{speriod}}, $speriod;
     push @{$data{eperiod}}, $eperiod;
 
-    my $col = 0;
+    my $col = 0; # a "column" here is the data corresponding to an item
     my @items = @{$self->{'items'}};
     my $i;
 
@@ -183,6 +202,7 @@ sub data {
       my @param = $self->{'params'} ? @{ $self->{'params'}[$col] }: ();
       push @param, 'project', $projecting;
       push @param, 'refnum' => $refnum if $refnum;
+      push @param, 'cust_classnum' => $cust_classnum if @$cust_classnum;
 
       if ( $self->{'cross_params'} ) {
         my @xdata;
@@ -207,7 +227,30 @@ sub data {
   $data{'colors'}      = $self->{'colors'};
   $data{'links'}       = $self->{'links'} || [];
 
-  if ( !$self->{'cross_params'} and $self->{'remove_empty'} ) {
+  if ( defined $self->{'normalize'} ) {
+    my $norm_col = $self->{'normalize'};
+    my $norm_data = $data{data}->[$norm_col];
+
+    my $row = 0;
+    while ( exists $data{speriod}->[$row] ) {
+      my $col = 0;
+      while ( exists $data{items}->[$col ] ) {
+        if ( $col != $norm_col ) {
+          if ( $norm_data->[$row] == 0 ) {
+            $data{data}->[$col][$row] = undef;
+          } else {
+            $data{data}->[$col][$row] = 
+              ( $data{data}->[$col][$row] * 100 / $norm_data->[$row] );
+          }
+        }
+        $col++;
+      }
+      $row++;
+    }
+  }
+
+  if ( !$self->{'cross_params'} ) {
+    # remove unnecessary rows
 
     my $col = 0;
     #these need to get generalized, sheesh
@@ -221,6 +264,12 @@ sub data {
     my @indices = ();
     foreach my $item ( @{$self->{'items'}} ) {
 
+      # if remove_empty, then remove rows of zeroes
+      my $is_nonzero = scalar( grep { $_ != 0 } @{ $data{'data'}->[$col] });
+      next if ($self->{'remove_empty'} and $is_nonzero == 0);
+      # if normalizing, strip out the norm column
+      next if (defined($self->{'normalize'}) and $self->{'normalize'} == $col);
+
       if ( grep { $_ != 0 } @{$data{'data'}->[$col]} ) {
         push @newitems,  $data{'items'}->[$col];
         push @newlabels, $data{'item_labels'}->[$col];
@@ -229,7 +278,7 @@ sub data {
         push @newlinks,  $data{'links'}->[$col];
         push @indices,   $col;
       }
-
+    } continue {
       $col++;
     }
 
@@ -241,6 +290,7 @@ sub data {
     $data{'indices'}     = \@indices;
 
   }
+
   # clean up after ourselves
   #dbh->rollback;
   # leave in until development is finished, for diagnostics