[freeside-commits] branch FREESIDE_4_BRANCH updated. 169c72822ed292c03b61e536f1028830fdea9dbc

Mark Wells mark at 420.am
Fri Feb 5 16:18:43 PST 2016


The branch, FREESIDE_4_BRANCH has been updated
       via  169c72822ed292c03b61e536f1028830fdea9dbc (commit)
       via  4779617c2bd662f15069f622077c207141f0ef2c (commit)
      from  78a248c6f5f1f134215454d9d827bdff540a5206 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 169c72822ed292c03b61e536f1028830fdea9dbc
Author: Mark Wells <mark at freeside.biz>
Date:   Fri Feb 5 16:00:55 2016 -0800

    refactor CDR profit/loss report also, #40103

diff --git a/httemplate/search/customer_cdr_profit.html b/httemplate/search/customer_cdr_profit.html
index 8dc0663..c535109 100644
--- a/httemplate/search/customer_cdr_profit.html
+++ b/httemplate/search/customer_cdr_profit.html
@@ -1,121 +1,11 @@
-% if ( $cgi->param('_type') =~ /(xls)$/ ) {
-<%perl>
-  # egregious false laziness w/ search/report_tax-xls.cgi
-  my $format = $FS::CurrentUser::CurrentUser->spreadsheet_format;
-  my $filename = $cgi->url(-relative => 1);
-  $filename =~ s/\.html$//;
-  $filename .= $format->{extension};
-  http_header('Content-Type' => $format->{mime_type});
-  http_header('Content-Disposition' => qq!attachment;filename="$filename"!);
-
-  my $output = '';
-  my $XLS = IO::String->new($output);
-  my $workbook = $format->{class}->new($XLS)
-    or die "Error opening .xls file: $!";
-
-  my $worksheet = $workbook->add_worksheet('Summary');
-
-  my %format = (
-    header => {
-      size      => 11,
-      bold      => 1,
-      align     => 'center',
-      valign    => 'vcenter',
-      text_wrap => 1,
-    },
-    money => {
-      size      => 11,
-      align     => 'right',
-      valign    => 'bottom',
-      num_format=> 8,
-    },
-    '' => {},
-  );
-  my %default = (
-      font      => 'Calibri',
-      border    => 1,
-  );
-  foreach (keys %format) {
-    my %f = (%default, %{$format{$_}});
-    $format{$_} = $workbook->add_format(%f);
-    $format{"m_$_"} = $workbook->add_format(%f);
-  }
-
-  my ($r, $c) = (0, 0);
-  for my $row (@rows) {
-    $c = 0;
-    my $thisrow = shift @cells;
-    for my $cell (@$thisrow) {
-      if (!ref($cell)) {
-        # placeholder, so increment $c so that we write to the correct place
-        $c++;
-        next;
-      }
-      # format name
-      my $f = '';
-      $f = 'header' if $row->{header} or $cell->{header};
-      $f = 'money' if $cell->{format} eq 'money';
-      if ( $cell->{rowspan} > 1 or $cell->{colspan} > 1 ) {
-        my $range = xl_range_formula(
-          'Summary',
-          $r, $r - 1 + ($cell->{rowspan} || 1),
-          $c, $c - 1 + ($cell->{colspan} || 1)
-        );
-        #warn "merging $range\n";
-        $worksheet->merge_range($range, $cell->{value}, $format{"m_$f"});
-      } else {
-      #warn "writing ".xl_rowcol_to_cell($r, $c)."\n";
-        $worksheet->write( $r, $c, $cell->{value}, $format{$f} );
-      }
-      $c += $cell->{colspan} || 1;
-    } #$cell
-  $r++;
-  } #$row
-  $workbook->close;
-
-  http_header('Content-Length' => length($output));
-  $m->print($output);
-</%perl>
-% } else {
-<& /elements/header.html, $title &>
-% my $myself = $cgi->self_url;
-<P ALIGN="right" CLASS="noprint">
-Download full reports<BR>
-as <A HREF="<% "$myself;_type=xls" %>">Excel spreadsheet</A>
-</P>
-<style type="text/css">
-.report * {
-  background-color: #f8f8f8;
-  border: 1px solid #999999;
-  padding: 2px;
-}
-.report td {
-  text-align: right;
-}
-.total { background-color: #f5f6be; }
-.shaded { background-color: #c8c8c8; }
-.totalshaded { background-color: #bfc094; }
-</style>
-<table class="report" width="100%" cellspacing=0>
-% foreach my $rowinfo (@rows) {
-  <tr<% $rowinfo->{class} ? ' class="'.$rowinfo->{class}.'"' : ''%>>
-%   my $thisrow = shift @cells;
-%   foreach my $cell (@$thisrow) {
-%     next if !ref($cell); # placeholders
-%     my $td = $cell->{header} ? 'th' : 'td';
-%     my $style = '';
-%     $style .= ' class="'.$cell->{class}.'"' if $cell->{class};
-%     $style .= " rowspan=".$cell->{rowspan} if $cell->{rowspan} > 1;
-%     $style .= " colspan=".$cell->{colspan} if $cell->{colspan} > 1;
-%     $style .= ' style="color: red"' if $cell->{value} < 0;
-      <<%$td%><%$style%>><% $cell->{value} |h %></<%$td%>>
-%   }
-  </tr>
-% }
-</table>
-
-<& /elements/footer.html &>
-% }
+<& elements/grid-report.html,
+  title => $title,
+  rows  => \@rows,
+  cells => \@cells,
+  head  => $head,
+  # would be better handled with Mason inheritance? consider this. easy enough
+  # to change it at this point.
+&>
 <%init>
 
 die "access denied"
@@ -213,7 +103,11 @@ foreach my $cust_main (@cust_main) { # correspond to cross_params
     for my $item (0..3) { # recur/recur_cost/usage/usage_cost
       my $value = $data->{data}[$item][$col][$row];
       $skip = 0 if abs($value) > 0.005;
-      push @thisrow, { value => sprintf('%0.2f', $value), format => 'money' };
+      push @thisrow, {
+        value => sprintf('%0.2f', $value),
+        format => 'money',
+        class => ($value < 0 ? 'negative' : ''),
+      };
       $total[$col * 5 + $item] += $value;
       $profit += (($item % 2) ? -1 : 1) * $value;
     } #item
@@ -250,4 +144,9 @@ for my $col (0..($ncols * 5)-1) { # month and recur/recur_cost/usage/usage_cost/
 }
 push @cells, \@thisrow;
 
+my $head = q[
+<style>
+  .negative { color: red }
+</style>
+];
 </%init>
diff --git a/httemplate/search/elements/grid-report.html b/httemplate/search/elements/grid-report.html
index cb06b2b..98e8178 100644
--- a/httemplate/search/elements/grid-report.html
+++ b/httemplate/search/elements/grid-report.html
@@ -5,6 +5,9 @@ which the user can request as an Excel spreadsheet. /elements/header.html
 and /elements/footer.html are included automatically, so don't include them
 again.
 
+This element defines "total", "shaded", and "totalshaded" CSS classes. For
+anything else, insert a <style> element via the 'head' argument.
+
 Usage:
 
 <& elements/grid-report.html,
@@ -21,7 +24,7 @@ Usage:
         header => 1,
         rowspan => 2,
         colspan => 3,
-        class => 'highlight',
+        class => 'shaded',
       },
       ...
     ],
@@ -144,7 +147,6 @@ Usage:
 <P ALIGN="right" CLASS="noprint">
 Download full reports<BR>
 as <A HREF="<% "$myself;_type=xls" %>">Excel spreadsheet</A><BR>
-% # as <A HREF="<% "$myself;_type=csv" %>">CSV file</A> # is this still needed?
 </P>
 <style type="text/css">
 .report * {
@@ -155,9 +157,9 @@ as <A HREF="<% "$myself;_type=xls" %>">Excel spreadsheet</A><BR>
 .report td {
   text-align: right;
 }
-.total * { background-color: #f5f6be; }
-.shaded * { background-color: #c8c8c8; }
-.totalshaded * { background-color: #bfc094; }
+.total { background-color: #f5f6be; }
+.shaded { background-color: #c8c8c8; }
+.totalshaded { background-color: #bfc094; }
 </style>
 <table class="report" width="100%" cellspacing=0>
 % foreach my $rowinfo (@rows) {

commit 4779617c2bd662f15069f622077c207141f0ef2c
Author: Mark Wells <mark at freeside.biz>
Date:   Fri Feb 5 15:16:12 2016 -0800

    refactor and fix customer accounting summary report, #24112 and #40103

diff --git a/httemplate/search/customer_accounting_summary.html b/httemplate/search/customer_accounting_summary.html
index 744b313..a8e5033 100644
--- a/httemplate/search/customer_accounting_summary.html
+++ b/httemplate/search/customer_accounting_summary.html
@@ -1,120 +1,8 @@
-% if ( $cgi->param('_type') =~ /(xls)$/ ) {
-<%perl>
-  # egregious false laziness w/ search/report_tax-xls.cgi
-  my $format = $FS::CurrentUser::CurrentUser->spreadsheet_format;
-  my $filename = $cgi->url(-relative => 1);
-  $filename =~ s/\.html$//;
-  $filename .= $format->{extension};
-  http_header('Content-Type' => $format->{mime_type});
-  http_header('Content-Disposition' => qq!attachment;filename="$filename"!);
-
-  my $output = '';
-  my $XLS = IO::String->new($output);
-  my $workbook = $format->{class}->new($XLS)
-    or die "Error opening .xls file: $!";
-
-  my $worksheet = $workbook->add_worksheet('Summary');
-
-  my %format = (
-    header => {
-      size      => 11,
-      bold      => 1,
-      align     => 'center',
-      valign    => 'vcenter',
-      text_wrap => 1,
-    },
-    money => {
-      size      => 11,
-      align     => 'right',
-      valign    => 'bottom',
-      num_format=> 8,
-    },
-    '' => {},
-  );
-  my %default = (
-      font      => 'Calibri',
-      border    => 1,
-  );
-  foreach (keys %format) {
-    my %f = (%default, %{$format{$_}});
-    $format{$_} = $workbook->add_format(%f);
-    $format{"m_$_"} = $workbook->add_format(%f);
-  }
-
-  my ($r, $c) = (0, 0);
-  for my $row (@rows) {
-    $c = 0;
-    my $thisrow = shift @cells;
-    for my $cell (@$thisrow) {
-      if (!ref($cell)) {
-        # placeholder, so increment $c so that we write to the correct place
-        $c++;
-        next;
-      }
-      # format name
-      my $f = '';
-      $f = 'header' if $row->{header} or $cell->{header};
-      $f = 'money' if $cell->{format} eq 'money';
-      if ( $cell->{rowspan} > 1 or $cell->{colspan} > 1 ) {
-        my $range = xl_range_formula(
-          'Summary',
-          $r, $r - 1 + ($cell->{rowspan} || 1),
-          $c, $c - 1 + ($cell->{colspan} || 1)
-        );
-        #warn "merging $range\n";
-        $worksheet->merge_range($range, $cell->{value}, $format{"m_$f"});
-      } else {
-      #warn "writing ".xl_rowcol_to_cell($r, $c)."\n";
-        $worksheet->write( $r, $c, $cell->{value}, $format{$f} );
-      }
-      $c++;
-    } #$cell
-  $r++;
-  } #$row
-  $workbook->close;
-
-  http_header('Content-Length' => length($output));
-  $m->print($output);
-</%perl>
-% } else {
-<& /elements/header.html, $title &>
-% my $myself = $cgi->self_url;
-<P ALIGN="right" CLASS="noprint">
-Download full reports<BR>
-as <A HREF="<% "$myself;_type=xls" %>">Excel spreadsheet</A><BR>
-% # as <A HREF="<% "$myself;_type=csv" %>">CSV file</A> # is this still needed?
-</P>
-<style type="text/css">
-.report * {
-  background-color: #f8f8f8;
-  border: 1px solid #999999;
-  padding: 2px;
-}
-.report td {
-  text-align: right;
-}
-.total * { background-color: #f5f6be; }
-.shaded * { background-color: #c8c8c8; }
-.totalshaded * { background-color: #bfc094; }
-</style>
-<table class="report" width="100%" cellspacing=0>
-% foreach my $rowinfo (@rows) {
-  <tr<% $rowinfo->{class} ? ' class="'.$rowinfo->{class}.'"' : ''%>>
-%   my $thisrow = shift @cells;
-%   foreach my $cell (@$thisrow) {
-%     next if !ref($cell); # placeholders
-%     my $td = $cell->{header} ? 'th' : 'td';
-%     my $style = '';
-%     $style .= " rowspan=".$cell->{rowspan} if $cell->{rowspan} > 1;
-%     $style .= " colspan=".$cell->{colspan} if $cell->{colspan} > 1;
-      <<%$td%><%$style%>><% $cell->{value} |h %></<%$td%>>
-%   }
-  </tr>
-% }
-</table>
-
-<& /elements/footer.html &>
-% }
+<& elements/grid-report.html,
+  title => $title,
+  rows  => \@rows,
+  cells => \@cells,
+&>
 <%init>
 
 die "access denied"
@@ -224,17 +112,14 @@ my @cells; # arrayrefs of cell info
 $rows[0] = {};
 $cells[0] = [
   { header => 1, rowspan => 2, colspan => ($setuprecur ? 4 : 3) },
-  ($setuprecur ? '' : ()),
   map {
     { header => 1, colspan => ($grossdiscount ? 3 : 2), value => time2str('%b %Y', $_) },
-    ''
   } @{ $data->{speriod} }
 ];
 my $ncols = scalar(@{ $data->{speriod} });
 
 $rows[1] = {};
-$cells[1] = [ '',
-  ($setuprecur ? '' : ()),
+$cells[1] = [
   map { 
   ( ($grossdiscount 
       ? (
@@ -270,8 +155,6 @@ foreach my $cust_main (@cust_main) { # correspond to cross_params
           rowspan => ($setuprecur ? 2 : 1),
         },
       ;
-    } else {
-      push @thisrow, '';
     }
     if ( $setuprecur ) {
       # subheading
@@ -310,8 +193,6 @@ for my $subrow (0..($setuprecur ? 1 : 0)) {
         header => 1,
         colspan => 3,
         rowspan => ($setuprecur ? 2 : 1), };
-  } else {
-    push @thisrow, '';
   }
   if ( $setuprecur ) {
     push @thisrow,
diff --git a/httemplate/search/elements/grid-report.html b/httemplate/search/elements/grid-report.html
new file mode 100644
index 0000000..cb06b2b
--- /dev/null
+++ b/httemplate/search/elements/grid-report.html
@@ -0,0 +1,187 @@
+<%doc>
+
+Simple display front-end for reports that produce some kind of data table,
+which the user can request as an Excel spreadsheet. /elements/header.html
+and /elements/footer.html are included automatically, so don't include them
+again.
+
+Usage:
+
+<& elements/grid-report.html,
+  title => 'My Report',
+  rows => [
+    { header => 1, },
+    ...
+  ],
+  cells => [
+    [ # row 0
+      { value => '123.45',
+        # optional
+        format => 'money',
+        header => 1,
+        rowspan => 2,
+        colspan => 3,
+        class => 'highlight',
+      },
+      ...
+    ],
+  ],
+  head => q[<div>Thing to insert before the table</div>],
+  foot => q[<span>That's all folks!</span>].
+&>
+</%doc>
+% if ( $cgi->param('_type') =~ /(xls)$/ ) {
+<%perl>
+  # egregious false laziness w/ search/report_tax-xls.cgi
+  # and search/customer_cdr_profit.html
+  my $format = $FS::CurrentUser::CurrentUser->spreadsheet_format;
+  my $filename = $cgi->url(-relative => 1);
+  $filename =~ s/\.html$//;
+  $filename .= $format->{extension};
+  http_header('Content-Type' => $format->{mime_type});
+  http_header('Content-Disposition' => qq!attachment;filename="$filename"!);
+
+  my $output = '';
+  my $XLS = IO::String->new($output);
+  my $workbook = $format->{class}->new($XLS)
+    or die "Error opening .xls file: $!";
+
+  my $worksheet = $workbook->add_worksheet('Summary');
+
+  my %format = (
+    header => {
+      size      => 11,
+      bold      => 1,
+      align     => 'center',
+      valign    => 'vcenter',
+      text_wrap => 1,
+    },
+    money => {
+      size      => 11,
+      align     => 'right',
+      valign    => 'bottom',
+      num_format=> 8,
+    },
+    '' => {},
+  );
+  my %default = (
+      font      => 'Calibri',
+      border    => 1,
+  );
+  foreach (keys %format) {
+    my %f = (%default, %{$format{$_}});
+    $format{$_} = $workbook->add_format(%f);
+    $format{"m_$_"} = $workbook->add_format(%f);
+  }
+
+  my ($r, $c) = (0, 0);
+  # indices in these correspond to column positions
+  my @rowspans;
+  my @widths;
+  
+  for my $row (@rows) {
+    $c = 0;
+    my $thisrow = shift @cells;
+    for my $cell (@$thisrow) {
+      # skip over cells that are occupied by rowspans above them
+      while ($rowspans[$c]) {
+        $rowspans[$c]--;
+        $c++;
+      }
+
+      # skip this cell if it's empty, also
+      next if !ref($cell);
+      # format name
+      my $f = '';
+      $f = 'header' if $row->{header} or $cell->{header};
+      $f = 'money' if $cell->{format} eq 'money';
+      if ( $cell->{rowspan} > 1 or $cell->{colspan} > 1 ) {
+        my $range = xl_range_formula(
+          'Summary',
+          $r, $r - 1 + ($cell->{rowspan} || 1),
+          $c, $c - 1 + ($cell->{colspan} || 1)
+        );
+        #warn "merging $range\n";
+        $worksheet->merge_range($range, $cell->{value}, $format{"m_$f"});
+      } else {
+      #warn "writing ".xl_rowcol_to_cell($r, $c)."\n";
+        $worksheet->write( $r, $c, $cell->{value}, $format{$f} );
+      }
+
+      # estimate column width, as in search-xls, but without date formats
+      my $width = length($cell->{value}) / ($cell->{colspan} || 1);
+      $width *= 1.1 if $f eq 'header';
+      $width++ if $f eq 'money'; # for money symbol
+      $width += 2; # pad it
+
+      for (1 .. ($cell->{colspan} || 1)) {
+        # adjust minimum widths to allow for this cell's contents
+        $widths[$c] = $width if $width > ($widths[$c] || 0);
+
+        # and if this cell has a rowspan, block off that many rows below it
+        if ( $cell->{rowspan} > 1 ) {
+          $rowspans[$c] = $cell->{rowspan} - 1;
+        }
+        $c++;
+      }
+    } #$cell
+  $r++;
+  } #$row
+
+  $c = 0;
+  for my $c (0 .. scalar(@widths) - 1) {
+    $worksheet->set_column($c, $c, $widths[$c]);
+  }
+  $workbook->close;
+
+  http_header('Content-Length' => length($output));
+  $m->print($output);
+</%perl>
+% } else {
+<& /elements/header.html, $title &>
+<% $head %>
+% my $myself = $cgi->self_url;
+<P ALIGN="right" CLASS="noprint">
+Download full reports<BR>
+as <A HREF="<% "$myself;_type=xls" %>">Excel spreadsheet</A><BR>
+% # as <A HREF="<% "$myself;_type=csv" %>">CSV file</A> # is this still needed?
+</P>
+<style type="text/css">
+.report * {
+  background-color: #f8f8f8;
+  border: 1px solid #999999;
+  padding: 2px;
+}
+.report td {
+  text-align: right;
+}
+.total * { background-color: #f5f6be; }
+.shaded * { background-color: #c8c8c8; }
+.totalshaded * { background-color: #bfc094; }
+</style>
+<table class="report" width="100%" cellspacing=0>
+% foreach my $rowinfo (@rows) {
+  <tr<% $rowinfo->{class} ? ' class="'.$rowinfo->{class}.'"' : ''%>>
+%   my $thisrow = shift @cells;
+%   foreach my $cell (@$thisrow) {
+%     next if !ref($cell); # placeholders
+%     my $td = $cell->{header} ? 'th' : 'td';
+%     my $style = '';
+%     $style .= " rowspan=".$cell->{rowspan} if $cell->{rowspan} > 1;
+%     $style .= " colspan=".$cell->{colspan} if $cell->{colspan} > 1;
+%     $style .= ' class="' . $cell->{class} . '"' if $cell->{class};
+      <<%$td%><%$style%>><% $cell->{value} |h %></<%$td%>>
+%   }
+  </tr>
+% }
+</table>
+<% $foot %>
+<& /elements/footer.html &>
+% }
+<%args>
+$title
+ at rows
+ at cells
+$head => ''
+$foot => ''
+</%args>

-----------------------------------------------------------------------

Summary of changes:
 httemplate/search/customer_accounting_summary.html |  131 +-------------
 httemplate/search/customer_cdr_profit.html         |  137 ++------------
 httemplate/search/elements/grid-report.html        |  189 ++++++++++++++++++++
 3 files changed, 213 insertions(+), 244 deletions(-)
 create mode 100644 httemplate/search/elements/grid-report.html




More information about the freeside-commits mailing list