sales tax report in Excel, RT#10321
[freeside.git] / httemplate / search / report_tax-xls.cgi
1 <% $data %>
2 <%init>
3
4 use Spreadsheet::WriteExcel;
5 use Spreadsheet::WriteExcel::Utility 'xl_range_formula';
6 use List::Util 'max';
7 use HTML::TableExtract 'tree';
8
9 my $data = '';
10 my $XLS = new IO::Scalar \$data;
11 my $workbook = Spreadsheet::WriteExcel->new($XLS)
12   or die "Error opening .xls file: $!";
13
14 # hardcoded formats, this could be handled better
15 my $light_gray = $workbook->set_custom_color(63, '#eeeeee');
16 my %format = (
17   title => {
18     size      => 24,
19     align     => 'center',
20     bg_color  => 'silver',
21   },
22   colhead => {
23     size      => 11,
24     bold      => 1,
25     align     => 'center',
26     valign    => 'vcenter',
27     text_wrap => 1,
28   },
29   rowhead => {
30     size      => 11,
31     valign    => 'bottom',
32     text_wrap => 1,
33   },
34   amount  => {
35     size      => 11,
36     align     => 'right',
37     valign    => 'bottom',
38     num_format=> 8,
39   },
40   'size-1' => {
41     size      => 7.5,
42     align     => 'center',
43     valign    => 'vcenter',
44     bold      => 1,
45     text_wrap => 1,
46   },
47   'size+1' => {
48     size      => 12,
49     align     => 'center',
50     valign    => 'vcenter',
51     bold      => 1,
52   },
53   text => {
54     size      => 11,
55     text_wrap => 1,
56   },
57 );
58 my %default = (
59   font      => 'Calibri',
60   bg_color  => $light_gray,
61   border    => 1,
62 );
63 my @widths = ( #ick
64   18, (10.5, 3) x 6, 10.5, 10.5, 3, 10.5, 3, 10.5, 3, 10.5
65 );
66 foreach (keys(%format)) {
67   my %f = (%default, %{$format{$_}});
68   $format{$_} = $workbook->add_format(%f);
69   $format{"m_$_"} = $workbook->add_format(%f); # for merged cells
70   $format{"t_$_"} = $workbook->add_format(%f, bg_color => 'yellow'); # totals
71 }
72 my $ws = $workbook->add_worksheet('taxreport');
73
74 my $htmldoc = include('report_tax.cgi');
75
76 my ($title) = ($htmldoc =~ /<title>\s*(.*)\s*<\/title>/i);
77
78 # attribs option: how to locate the table?  It's the only one with class="grid".
79 my $te = HTML::TableExtract->new(attribs => {class => 'grid'});
80 $te->parse($htmldoc);
81 my $table = $te->first_table_found;
82
83 my @sheet;
84 $sheet[0][0] = {
85   text    => $title,
86   format  => 'title',
87   colspan => '18',
88 };  
89 # excel position
90 my $x = 0;
91 my $y = 3;
92 foreach my $row ($table->rows()) {
93   $x = 0;
94   $sheet[$y] = [];
95   foreach my $cell (@$row) {
96     if ($cell and ref($cell) eq 'HTML::ElementTable::DataElement') {
97       my $f = 'text';
98       if ( $cell->as_HTML =~ /font/i ) {
99         my ($el) = $cell->content_list;
100         $f = 'size'.$el->attr('size') if $el->attr('size');
101       }
102       elsif ( $cell->as_text =~ /^\$/ ) {
103         $f = 'amount'
104       }
105       elsif ( $cell->tag eq 'th' ) {
106         $f = 'colhead';
107       }
108       elsif ( $x == 0 ) {
109         $f = 'rowhead';
110       }
111       $sheet[$y][$x] = {
112         text    => $cell->as_text,
113         format  => $f,
114         rowspan => $cell->attr('rowspan'),
115         colspan => $cell->attr('colspan'),
116       };
117     }
118     $x++;
119   } #for $cell
120   $y++;
121 }
122
123 $y = 0;
124 foreach my $row (@sheet) {
125   $x = 0;
126   my $t_row = 1 if($row->[0]->{'text'} eq 'Total');
127   foreach my $cell (@$row) {
128     if ($cell) {
129       my $f = $cell->{format};
130       if ($cell->{rowspan} > 1 or $cell->{colspan} > 1) {
131         my $range = xl_range_formula(
132           'Taxreport', 
133           $y,
134           $y - 1 + ($cell->{rowspan} || 1),
135           $x,
136           $x - 1 + ($cell->{colspan} || 1)
137         );
138         $ws->merge_range($range, $cell->{text}, $format{"m_$f"});
139       }
140       else {
141         $f = "t_$f" if $t_row;
142         $ws->write($y, $x, $cell->{text}, $format{$f});
143       }
144     } #if $cell
145     $x++;
146   }
147   $y++;
148 }
149
150 for my $x (0..scalar(@widths)-1) {
151   $ws->set_column($x, $x, $widths[$x]);
152 }
153
154 $workbook->close;
155
156 http_header('Content-Type' => 'application/vnd.ms-excel');
157 http_header('Content-Disposition' => 'attachment;filename="report_tax.xls"');
158 </%init>