+my @rows; # hashes of row info
+my @cells; # arrayrefs of cell info
+# We use Excel currency format, but not Excel dates, because
+# these are whole months and there's no nice way to express that.
+# This is the historical behavior for monthly reports.
+
+# header row
+$rows[0] = {};
+$cells[0] = [
+ { header => 1, rowspan => 2, colspan => ($setuprecur ? 4 : 3) },
+ map {
+ { header => 1, colspan => ($grossdiscount ? 3 : 2), value => time2str('%b %Y', $_) },
+ } @{ $data->{speriod} }
+];
+my $ncols = scalar(@{ $data->{speriod} });
+
+$rows[1] = {};
+$cells[1] = [
+ map {
+ ( ($grossdiscount
+ ? (
+ { header => 1, value => mt('Gross') },
+ { header => 1, value => mt('Discount') }
+ )
+ : { header => 1, value => mt('Billed') }
+ ),
+ { header => 1, value => mt('Paid') },
+ ) } (1..$ncols)
+];
+
+# use PDL; # ha ha, I just might.
+my $row = 0;
+foreach my $cust_main (@cust_main) { # correspond to cross_params
+ my $skip = 1; # skip the customer iff ALL of their values are zero
+ for my $subrow (0..($setuprecur ? 1 : 0)) { # the setup/recur axis
+ push @rows, { class => $subrow ? 'shaded' : '' };
+ my @thisrow;
+ if ( $subrow == 0 ) {
+ # customer name
+ push @thisrow,
+ { value => $cust_main->name,
+ header => 1,
+ rowspan => ($setuprecur ? 2 : 1),
+ },
+ { value => $cust_main->state, #cust_main->bill_location->state,
+ header => 1,
+ rowspan => ($setuprecur ? 2 : 1),
+ },
+ { value => $cust_main->salesnum ? $cust_main->sales->salesperson : '',
+ header => 1,
+ rowspan => ($setuprecur ? 2 : 1),
+ },
+ ;
+ }
+ if ( $setuprecur ) {
+ # subheading
+ push @thisrow,
+ { value => $subrow ? mt('recurring') : mt('setup'),
+ header => 1 };
+ }
+ for my $col (0..$ncols-1) { # the month
+ for my $subcol (0..($grossdiscount ? 2 : 1)) { # the billed/paid or gross/discount/paid axis
+ my $item = $subrow * ($grossdiscount ? 3 : 2) + $subcol;
+ my $value = $data->{data}[$item][$col][$row];
+ $skip = 0 if abs($value) > 0.005;
+ push @thisrow, { value => sprintf('%0.2f', $value), format => 'money' };
+ $total[( ($ncols * $subrow) + $col ) * ($grossdiscount ? 3 : 2) + $subcol] += $value;
+ } #subcol
+ } #col
+ push @cells, \@thisrow;
+ } #subrow
+ if ( $skip ) {
+ # all values are zero--remove the rows we just added
+ pop @rows;
+ pop @cells;
+ if ( $setuprecur ) {
+ pop @rows;
+ pop @cells;
+ }
+ }
+ $row++;
+}
+for my $subrow (0..($setuprecur ? 1 : 0)) {
+ push @rows, { class => ($subrow ? 'totalshaded' : 'total') };
+ my @thisrow;
+ if ( $subrow == 0 ) {
+ push @thisrow,
+ { value => mt('Total'),
+ header => 1,
+ colspan => 3,
+ rowspan => ($setuprecur ? 2 : 1), };
+ }
+ if ( $setuprecur ) {
+ push @thisrow,
+ { value => $subrow ? mt('recurring') : mt('setup'),
+ header => 1 };
+ }
+ for my $col (0..($ncols * ($grossdiscount ? 3 : 2))-1) { # month and billed/paid or gross/discount/paid axis
+ my $value = $total[($subrow * $ncols * ($grossdiscount ? 3 : 2)) + $col];
+ push @thisrow, { value => sprintf('%0.2f', $value), format => 'money' };
+ }
+ push @cells, \@thisrow;
+} #subrow