fix unapplied payment report, RT#73048, fallout from #25944
[freeside.git] / httemplate / search / elements / grid-report.html
1 <%doc>
2
3 Simple display front-end for reports that produce some kind of data table,
4 which the user can request as an Excel spreadsheet. /elements/header.html
5 and /elements/footer.html are included automatically, so don't include them
6 again.
7
8 This element defines "total", "shaded", and "totalshaded" CSS classes. For
9 anything else, insert a <style> element via the 'head' argument.
10
11 Usage:
12
13 <& elements/grid-report.html,
14   title => 'My Report',
15   rows => [
16     { header => 1, },
17     ...
18   ],
19   cells => [
20     [ # row 0
21       { value => '123.45',
22         # optional
23         format => 'money',
24         header => 1,
25         rowspan => 2,
26         colspan => 3,
27         class => 'shaded',
28       },
29       ...
30     ],
31   ],
32   head => q[<div>Thing to insert before the table</div>],
33   foot => q[<span>That's all folks!</span>].
34 &>
35 </%doc>
36 % if ( $cgi->param('_type') =~ /(xls)$/ ) {
37 <%perl>
38   # egregious false laziness w/ search/report_tax-xls.cgi
39   # and search/customer_cdr_profit.html
40   my $format = $FS::CurrentUser::CurrentUser->spreadsheet_format;
41   my $filename = $cgi->url(-relative => 1);
42   $filename =~ s/\.html$//;
43   $filename .= $format->{extension};
44   http_header('Content-Type' => $format->{mime_type});
45   http_header('Content-Disposition' => qq!attachment;filename="$filename"!);
46
47   my $output = '';
48   my $XLS = IO::String->new($output);
49   my $workbook = $format->{class}->new($XLS)
50     or die "Error opening .xls file: $!";
51
52   my $worksheet = $workbook->add_worksheet('Summary');
53
54   my %format = (
55     header => {
56       size      => 11,
57       bold      => 1,
58       align     => 'center',
59       valign    => 'vcenter',
60       text_wrap => 1,
61     },
62     money => {
63       size      => 11,
64       align     => 'right',
65       valign    => 'bottom',
66       num_format=> 8,
67     },
68     '' => {},
69   );
70   my %default = (
71       font      => 'Calibri',
72       border    => 1,
73   );
74   foreach (keys %format) {
75     my %f = (%default, %{$format{$_}});
76     $format{$_} = $workbook->add_format(%f);
77     $format{"m_$_"} = $workbook->add_format(%f);
78   }
79
80   my ($r, $c) = (0, 0);
81   # indices in these correspond to column positions
82   my @rowspans;
83   my @widths;
84   
85   for my $row (@rows) {
86     $c = 0;
87     my $thisrow = shift @cells;
88     for my $cell (@$thisrow) {
89       # skip over cells that are occupied by rowspans above them
90       while ($rowspans[$c]) {
91         $rowspans[$c]--;
92         $c++;
93       }
94
95       # skip this cell if it's empty, also
96       next if !ref($cell);
97       # format name
98       my $f = '';
99       $f = 'header' if $row->{header} or $cell->{header};
100       $f = 'money' if $cell->{format} eq 'money';
101       if ( $cell->{rowspan} > 1 or $cell->{colspan} > 1 ) {
102         my $range = xl_range_formula(
103           'Summary',
104           $r, $r - 1 + ($cell->{rowspan} || 1),
105           $c, $c - 1 + ($cell->{colspan} || 1)
106         );
107         #warn "merging $range\n";
108         $worksheet->merge_range($range, $cell->{value}, $format{"m_$f"});
109       } else {
110       #warn "writing ".xl_rowcol_to_cell($r, $c)."\n";
111         $worksheet->write( $r, $c, $cell->{value}, $format{$f} );
112       }
113
114       # estimate column width, as in search-xls, but without date formats
115       my $width = length($cell->{value}) / ($cell->{colspan} || 1);
116       $width *= 1.1 if $f eq 'header';
117       $width++ if $f eq 'money'; # for money symbol
118       $width += 2; # pad it
119
120       for (1 .. ($cell->{colspan} || 1)) {
121         # adjust minimum widths to allow for this cell's contents
122         $widths[$c] = $width if $width > ($widths[$c] || 0);
123
124         # and if this cell has a rowspan, block off that many rows below it
125         if ( $cell->{rowspan} > 1 ) {
126           $rowspans[$c] = $cell->{rowspan} - 1;
127         }
128         $c++;
129       }
130     } #$cell
131   $r++;
132   } #$row
133
134   $c = 0;
135   for my $c (0 .. scalar(@widths) - 1) {
136     $worksheet->set_column($c, $c, $widths[$c]);
137   }
138   $workbook->close;
139
140   http_header('Content-Length' => length($output));
141   $m->print($output);
142 </%perl>
143 % } else {
144 <& /elements/header.html, $title &>
145 <% $head %>
146 % my $myself = $cgi->self_url;
147 <P ALIGN="right" CLASS="noprint">
148 Download full reports<BR>
149 as <A HREF="<% "$myself;_type=xls" %>">Excel spreadsheet</A><BR>
150 </P>
151 <style type="text/css">
152 .report * {
153   background-color: #f8f8f8;
154   border: 1px solid #999999;
155   padding: 2px;
156 }
157 .report td {
158   text-align: right;
159 }
160 .total { background-color: #f5f6be; }
161 .shaded { background-color: #c8c8c8; }
162 .totalshaded { background-color: #bfc094; }
163 </style>
164 <table class="report" width="100%" cellspacing=0>
165 % foreach my $rowinfo (@rows) {
166   <tr<% $rowinfo->{class} ? ' class="'.$rowinfo->{class}.'"' : ''%>>
167 %   my $thisrow = shift @cells;
168 %   foreach my $cell (@$thisrow) {
169 %     next if !ref($cell); # placeholders
170 %     my $td = $cell->{header} ? 'th' : 'td';
171 %     my $style = '';
172 %     $style .= " rowspan=".$cell->{rowspan} if $cell->{rowspan} > 1;
173 %     $style .= " colspan=".$cell->{colspan} if $cell->{colspan} > 1;
174 %     $style .= ' class="' . $cell->{class} . '"' if $cell->{class};
175       <<%$td%><%$style%>><% $cell->{value} |h %></<%$td%>>
176 %   }
177   </tr>
178 % }
179 </table>
180 <% $foot %>
181 <& /elements/footer.html &>
182 % }
183 <%args>
184 $title
185 @rows
186 @cells
187 $head => ''
188 $foot => ''
189 </%args>