allow enabling and disabling if tax_rate rows in groups (RT 3566)
[freeside.git] / httemplate / browse / tax_rate.cgi
1 <% include( 'elements/browse.html',
2      'title'          => "Tax Rates $title",
3      'name_singular'  => 'tax rate',
4      'menubar'        => \@menubar,
5      'html_init'      => $html_init,
6      'html_form'      => $html_form,
7      'query'          => {
8                            'table'     => 'tax_rate',
9                            'hashref'   => $hashref,
10                            'order_by'  => 'ORDER BY geocode, taxclassnum',
11                            'extra_sql' => $extra_sql,
12                          },
13      'count_query'    => $count_query,
14      'header'         => \@header,
15      'header2'        => \@header2,
16      'fields'         => \@fields,
17      'align'          => $align,
18      'color'          => \@color,
19      'cell_style'     => \@cell_style,
20      'links'          => \@links,
21      'link_onclicks'  => \@link_onclicks,
22   )
23 %>
24 <%once>
25
26 my $conf = new FS::Conf;
27 my $money_char = $conf->config('money_char') || '$';
28
29 my $rate_sub = sub {
30   my $tax_rate = shift;
31
32   my $units = $tax_rate->unittype_name;
33   $units =~ s/ /&nbsp;/g;
34
35   my @rate = ();
36   push @rate,
37       ($tax_rate->tax * 100). '%&nbsp;<FONT SIZE="-1">(edit)</FONT>'
38     if $tax_rate->tax > 0 || $tax_rate->taxbase > 0;
39   push @rate,
40       ($tax_rate->excessrate * 100). '%&nbsp;<FONT SIZE="-1">(edit)</FONT>'
41     if $tax_rate->excessrate > 0;
42   push @rate,
43       $money_char. $tax_rate->fee.
44       qq!&nbsp;per&nbsp;$units<FONT SIZE="-1">(edit)</FONT>!
45     if $tax_rate->fee > 0 || $tax_rate->feebase > 0;
46   push @rate,
47       $money_char. $tax_rate->excessfee.
48       qq!&nbsp;per&nbsp;$units<FONT SIZE="-1">(edit)</FONT>!
49     if $tax_rate->excessfee > 0;
50
51
52   [ map [ {'data'=>$_} ], @rate ];
53 };
54
55 my $limit_sub = sub {
56   my $tax_rate = shift;
57
58   my $maxtype = $tax_rate->maxtype_name;
59   $maxtype =~ s/ /&nbsp;/g;
60
61   my $units = $tax_rate->unittype_name;
62   $units =~ s/ /&nbsp;/g;
63
64   my @limit = ();
65   push @limit,
66        sprintf("$money_char%.2f&nbsp%s", $tax_rate->taxbase, $maxtype )
67     if $tax_rate->taxbase > 0;
68   push @limit,
69        sprintf("$money_char%.2f&nbsp;tax", $tax_rate->taxmax )
70     if $tax_rate->taxmax > 0;
71   push @limit,
72        $tax_rate->feebase. "&nbsp;$units". ($tax_rate->feebase == 1 ? '' : 's')
73     if $tax_rate->feebase > 0;
74   push @limit,
75        $tax_rate->feemax. "&nbsp;$units". ($tax_rate->feebase == 1 ? '' : 's')
76     if $tax_rate->feemax > 0;
77
78   push @limit, 'Excluding&nbsp;setup&nbsp;fee'
79     if $tax_rate->setuptax =~ /^Y$/i;
80
81   push @limit, 'Excluding&nbsp;recurring&nbsp;fee'
82     if $tax_rate->recurtax =~ /^Y$/i;
83
84   [ map [ {'data'=>$_} ], @limit ];
85 };
86
87 my $oldrow;
88 my $cell_style;
89 my $cell_style_sub = sub {
90   my $row = shift;
91   if ( $oldrow ne $row ) {
92     if ( $oldrow ) {
93       if ( $oldrow->country ne $row->country ) {
94         $cell_style = 'border-top:1px solid #000000';
95       } elsif ( $oldrow->state ne $row->state ) {
96         $cell_style = 'border-top:1px solid #cccccc'; #default?
97       } elsif ( $oldrow->state eq $row->state ) {
98         #$cell_style = 'border-top:dashed 1px dark gray';
99         $cell_style = 'border-top:1px dashed #cccccc';
100       }
101     }
102     $oldrow = $row;
103   }
104   return $cell_style;
105 };
106
107 my $select_link = [ 'javascript:void(0);', sub { ''; } ];
108
109 my $select_onclick = sub {
110   my $row = shift;
111   my $taxnum = $row->taxnum;
112   my $color = '#333399';
113   qq!overlib( OLiframeContent('${p}edit/tax_rate.html?$taxnum', 540, 620, 'edit_tax_rate_popup' ), CAPTION, 'Edit tax rate', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK, BGCOLOR, '$color', CGCOLOR, '$color' ); return false;!;
114 };
115
116 </%once>
117 <%init>
118
119 die "access denied"
120   unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
121
122 my @menubar;
123 my $title = '';
124
125 my $data_vendor = '';
126 if ( $cgi->param('data_vendor') =~ /^(\w+)$/ ) {
127   $data_vendor = $1;
128   $title = "$data_vendor";
129 }
130 $cgi->delete('data_vendor');
131
132 my $geocode = '';
133 if ( $cgi->param('geocode') =~ /^(\w+)$/ ) {
134   $geocode = $1;
135   $title = " geocode $geocode";
136 }
137 $cgi->delete('geocode');
138
139 $title = " for $title" if $title;
140
141 my $taxclassnum = '';
142 if ( $cgi->param('taxclassnum') =~ /^(\d+)$/ ) {
143   $taxclassnum = $1;
144   my $tax_class = qsearchs('tax_class', {'taxclassnum' => $taxclassnum});
145   if ($tax_class) {
146     $title .= " for ". $tax_class->taxclass.
147               " (".  $tax_class->description. ") tax class";
148   }else{
149     $taxclassnum = '';
150   }
151 }
152 $cgi->delete('taxclassnum');
153
154 my $tax_type = $1
155   if ( $cgi->param('tax_type') =~ /^(\d+)$/ );
156 my $tax_cat = $1
157   if ( $cgi->param('tax_cat') =~ /^(\d+)$/ );
158
159 my @taxclassnum = ();
160 if ($tax_type || $tax_cat ) {
161   my $compare = "LIKE '". ( $tax_type || "%" ). ":". ( $tax_cat || "%" ). "'";
162   $compare = "= '$tax_type:$tax_cat'" if ($tax_type && $tax_cat);
163   my @tax_class =
164     qsearch({ 'table'     => 'tax_class',
165               'hashref'   => {},
166               'extra_sql' => "WHERE taxclass $compare",
167            });
168   if (@tax_class) {
169     @taxclassnum = map { $_->taxclassnum } @tax_class;
170     $tax_class[0]->description =~ /^(.*):(.*)/;
171     $title .= " for";
172     $title .= " $tax_type ($1) tax type" if $tax_type;
173     $title .= " and" if ($tax_type && $tax_cat);
174     $title .= " $tax_cat ($2) tax category" if $tax_cat;
175   }else{
176     $tax_type = '';
177     $tax_cat = '';
178   }
179 }
180 $cgi->delete('tax_type');
181 $cgi->delete('tax_cat');
182
183 if ( $geocode || $taxclassnum ) {
184   push @menubar, 'View all tax rates' => $p.'browse/tax_rate.cgi';
185 }
186
187 $cgi->param('dummy', 1);
188
189 #restore this so pagination works
190 $cgi->param('data_vendor',  $data_vendor) if $data_vendor;
191 $cgi->param('geocode',  $geocode) if $geocode;
192 $cgi->param('taxclassnum', $taxclassnum ) if $taxclassnum;
193 $cgi->param('tax_type', $tax_type ) if $tax_type;
194 $cgi->param('tax_cat', $tax_cat ) if $tax_cat;
195
196 my $html_form = include('/elements/init_overlib.html'). '<BR><BR>'.
197   join(' ',
198     map {
199       include('/elements/popup_link.html',
200                {
201                  'action' => $p. "misc/enable_or_disable_tax.html?action=$_&".
202                              $cgi->query_string,
203                  'label' => ucfirst($_). ' all these taxes',
204                  'actionlabel' => ucfirst($_). ' taxes',
205                },
206              );
207     }
208     qw(disable enable)
209   );
210
211 my $hashref = {};
212 my $extra_sql = '';
213 if ( $data_vendor ) {
214   $extra_sql .= ' WHERE data_vendor = '. dbh->quote($data_vendor);
215 }
216
217 if ( $geocode ) {
218   $extra_sql .= ( $extra_sql =~ /WHERE/i ? ' AND ' : ' WHERE ' ).
219                 ' geocode LIKE '. dbh->quote($geocode.'%');
220 }
221
222 if ( $taxclassnum ) {
223   $extra_sql .= ( $extra_sql =~ /WHERE/i ? ' AND ' : ' WHERE ' ).
224                 ' taxclassnum  = '. dbh->quote($taxclassnum);
225 }
226
227 if ( @taxclassnum ) {
228   $extra_sql .= ( $extra_sql =~ /WHERE/i ? ' AND ' : ' WHERE ' ).
229                 join(' OR ', map { " taxclassnum  = $_ " } @taxclassnum );
230 }
231
232 my $count_query = "SELECT COUNT(*) FROM tax_rate $extra_sql";
233
234 $cell_style = '';
235
236 my @header        = ( 'Location Code',  );
237 my @header2       = ( '', );
238 my @links         = ( '', );
239 my @link_onclicks = ( '', );
240 my $align = 'l';
241
242 my @fields = (
243   'geocode',
244 );
245
246 my @color = (
247   '000000',
248 );
249
250 push @header, qq!Tax class (<A HREF="${p}edit/tax_class.html">add new</A>)!;
251 push @header2, '(per-tax classification)';
252 push @fields, 'taxclass_description';
253 push @color, '000000';
254 push @links, '';
255 push @link_onclicks, '';
256 $align .= 'l';
257
258 push @header, 'Tax name',
259               'Rate', #'Tax',
260               'Limits',
261               ;
262
263 push @header2, '(printed on invoices)',
264                '',
265                '',
266                ;
267
268 push @fields, 
269   sub { shift->taxname || 'Tax' },
270   $rate_sub,
271   $limit_sub,
272 ;
273
274 push @color,
275   sub { shift->taxname ? '000000' : '666666' },
276   sub { shift->tax     ? '000000' : '666666' },
277   '000000',
278 ;
279
280 $align .= 'lrl';
281
282 my @cell_style = map $cell_style_sub, (1..scalar(@header));
283
284 push @links,         '', $select_link,    '';
285 push @link_onclicks, '', $select_onclick, '';
286
287 my $html_init = '';
288
289 $html_init .= qq(
290   <SCRIPT TYPE="text/javascript" SRC="${fsurl}elements/overlibmws.js"></SCRIPT>
291   <SCRIPT TYPE="text/javascript" SRC="${fsurl}elements/overlibmws_iframe.js"></SCRIPT>
292   <SCRIPT TYPE="text/javascript" SRC="${fsurl}elements/overlibmws_draggable.js"></SCRIPT>
293   <SCRIPT TYPE="text/javascript" SRC="${fsurl}elements/iframecontentmws.js"></SCRIPT>
294
295 );
296
297 $html_init .= qq(
298   <FORM>
299     <TABLE>
300       <TR>
301         <TD><SELECT NAME="data_vendor" onChange="this.form.submit()">
302 );
303
304 my $sql = "SELECT DISTINCT data_vendor FROM tax_rate ORDER BY data_vendor";
305 my $dbh = dbh;
306 my $sth = $dbh->prepare($sql) or die $dbh->errstr;
307 $sth->execute or die $sth->errstr;
308 for (['(choose data vendor)'], @{$sth->fetchall_arrayref}) {
309   $html_init .= '<OPTION VALUE="'. $_->[0]. '"'.
310                 ($_->[0] eq $data_vendor ? " SELECTED" : "").
311                 '">'.  $_->[0];
312 }
313 $html_init .= qq(
314         </SELECT>
315
316         <TD><INPUT NAME="geocode" TYPE="text" SIZE="12" VALUE="$geocode"></TD>
317
318 <!-- generic
319         <TD><INPUT NAME="taxclassnum" TYPE="text" SIZE="12" VALUE="$taxclassnum"></TD>
320         <TD><INPUT TYPE="submit" VALUE="Filter by tax_class"></TD>
321 -->
322
323 <!-- cch specific -->
324         <TD><SELECT NAME="tax_type" onChange="this.form.submit()">
325 );
326
327 $sql = "SELECT DISTINCT ".
328        "substring(taxclass from 1 for position(':' in taxclass)-1),".
329        "substring(description from 1 for position(':' in description)-1) ".
330        "FROM tax_class WHERE data_vendor='cch' ORDER BY 2";
331
332 $sth = $dbh->prepare($sql) or die $dbh->errstr;
333 $sth->execute or die $sth->errstr;
334 for (['', '(choose tax type)'], @{$sth->fetchall_arrayref}) {
335   $html_init .= '<OPTION VALUE="'. $_->[0]. '"'.
336                  ($_->[0] eq $tax_type ? " SELECTED" : "").
337                  '">'. $_->[1];
338 }
339
340 $html_init .= qq(
341         </SELECT>
342
343         <TD><SELECT NAME="tax_cat" onChange="this.form.submit()">
344 );
345
346 $sql = "SELECT DISTINCT ".
347        "substring(taxclass from position(':' in taxclass)+1),".
348        "substring(description from position(':' in description)+1) ".
349        "from tax_class WHERE data_vendor='cch' ORDER BY 2";
350
351 $sth = $dbh->prepare($sql) or die $dbh->errstr;
352 $sth->execute or die $sth->errstr;
353 for (['', '(choose tax category)'], @{$sth->fetchall_arrayref}) {
354   $html_init .= '<OPTION VALUE="'. $_->[0]. '"'.
355                  ($_->[0] eq $tax_cat ? " SELECTED" : "").
356                  '">'.  $_->[1];
357 }
358
359 $html_init .= qq(
360         </SELECT>
361
362       </TR>
363       <TR>
364         <TD></TD>
365         <TD><INPUT TYPE="submit" VALUE="Filter by geocode"></TD>
366         <TD></TD>
367         <TD></TD>
368       </TR>
369     </TABLE>
370   </FORM>
371
372 );
373
374 </%init>