deposit slips
[freeside.git] / httemplate / search / tax_sales.cgi
1
2 <% include('/graph/elements/report.html',
3      'title'      => 'Monthly Sales and Taxes Report',
4      'items'      => \@row_labels,
5      'data'       => \@rowdata,
6      'row_labels' => \@row_labels,
7      'colors'     => \@rowcolors,
8      'bgcolors'   => \@rowbgcolors,
9      'col_labels' => \@col_labels,
10      'graph_type' => 'none',
11    ) %>
12
13 <%init>
14
15 die "access denied"
16   unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
17
18 # validate cgi input
19 my $start_month = $cgi->param('start_month');
20 die "Bad start month" unless $start_month =~ /^\d*$/;
21 my $start_year = $cgi->param('start_year');
22 die "Bad start year" unless $start_year =~ /^\d*$/;
23 my $end_month = $cgi->param('end_month');
24 die "Bad end month" unless $end_month =~ /^\d*$/;
25 my $end_year = $cgi->param('end_year');
26 die "Bad end year" unless $end_year =~ /^\d*$/;
27 die "End year before start year" if $end_year < $start_year;
28 die "End month before start month" if ($start_year == $end_year) && ($end_month < $start_month);
29 my $country = $cgi->param('country');
30 die "Bad country code" unless $country =~ /^\w\w$/;
31
32 # Data structure for building final table
33 # row order will be calculated separately
34 #
35 # $data->{$rowlabel} = \@rowvalues
36 #
37
38 my $data = {};
39
40 ### Calculate package values
41
42 my @pkg_class = qsearch('pkg_class');
43 my @pkg_classnum = map { $_->classnum } @pkg_class;
44 unshift(@pkg_classnum,0);
45 my @pkg_classname = map { $_->classname } @pkg_class;
46 unshift(@pkg_classname,'(empty class)');
47
48 # some false laziness with graph/elements/monthly.html
49 my %reportopts = (
50   'items'        => [ qw( cust_bill_pkg cust_bill_pkg_credits ) ],
51   'cross_params' => [ map { [ 'classnum', $_ ] } @pkg_classnum ],
52   'start_month'  => $start_month,
53   'start_year'   => $start_year,
54   'end_month'    => $end_month,
55   'end_year'     => $end_year,
56 );
57 my $pkgreport = new FS::Report::Table::Monthly(%reportopts);
58 my $pkgdata = $pkgreport->data;
59
60 # assuming every month/year combo is included in results,
61 # just use this list for the final table
62 my @col_labels = @{$pkgdata->{'label'}}; 
63
64 # unpack report data into a more manageable format
65 foreach my $item ( qw( invoiced credited ) ) { # invoiced, credited
66   my $itemref = shift @{$pkgdata->{'data'}};
67   foreach my $label (@{$pkgdata->{'label'}}) { # month/year
68     my $labelref = shift @$itemref;
69     foreach my $classname (@pkg_classname) {   # pkg class
70       my $value = shift @$labelref;
71       my $rowlabel = $classname.' '.$item;
72       $data->{$rowlabel} ||= [];
73       push(@{$data->{$rowlabel}},$value);
74     }
75   }
76 }
77
78 ### Calculate tax values
79
80 # false laziness w report_tax.html, put this in FS::Report::Tax?
81 my $sth = dbh->prepare('SELECT DISTINCT(COALESCE(taxname, \'Tax\')) FROM cust_main_county');
82 $sth->execute or die $sth->errstr;
83 my @taxnames = map { $_->[0] } @{ $sth->fetchall_arrayref };
84 $sth->finish;
85
86 # get DateTime objects for start & end
87 my $startdate = DateTime->new(
88                   year => $start_year,
89                   month => $start_month,
90                   day => 1
91                 );
92 my $enddate   = DateTime->new(
93                   year => $end_year,
94                   month => $end_month,
95                   day => 1
96                 );
97 $enddate->add( months => 1 )->subtract( seconds => 1 ); # the last second of the month
98
99 # common to all tax reports
100 my %params = ( 
101   'country' => $country,
102   'credit_date' => 'cust_bill',
103 );
104
105 # run a report for each month, for each tax
106 my $countdate = $startdate->clone;
107 while ($countdate < $enddate) {
108
109   # set report start date, iterate to end of this month, set report end date
110   $params{'beginning'} = $countdate->epoch;
111   $params{'ending'} = $countdate->add( months => 1 )->subtract( seconds => 1 )->epoch;
112
113   # run a report for each tax name
114   foreach my $taxname (@taxnames) {
115     $params{'taxname'} = $taxname;
116     my $report = FS::Report::Tax::ByName->report(%params);
117
118     # extract totals from report, kinda awkward
119     my $pkgclass = ''; # this will get more complicated if we breakdown by pkgclass
120     my @values = (0,0);
121     if ($report->{'total'}->{$pkgclass}) {
122       my %totals = map { $$_[0] => $$_[2] } @{$report->{'total'}->{$pkgclass}};
123       $values[0] = $totals{'tax'};
124       $values[1] = $totals{'credit'};
125     }
126
127     # treat each tax class like it's an additional pkg class
128     foreach my $item ( qw ( invoiced credited ) ) {
129       my $rowlabel = $taxname . ' ' . $item;
130       my $value = shift @values;
131       $data->{$rowlabel} ||= [];
132       push(@{$data->{$rowlabel}},$value);
133     }
134
135   }
136
137   # iterate to next month
138   $countdate->add( seconds => 1 );
139 }
140
141 # put the data in the order we want it
142 my @row_labels;
143 my @rowdata;
144 my @rowcolors;
145 my @rowbgcolors;
146 my $pkgcount = 0; #for colors
147 foreach my $classname (@pkg_classname,@taxnames) {
148   my $istax = ($pkgcount++ < @pkg_classname) ? 0 : 1;
149   my @classlabels = ();
150   my @classdata = ();
151   my @classcolors = ();
152   my @classbgcolors = ();
153   my $hasdata = 0;
154   foreach my $item ( qw( invoiced credited ) ) {
155     my $rowlabel = $classname . ' ' . $item;
156     my $rowdata  = $data->{$rowlabel};
157     my $rowcolor = $istax ? '0000ff' : '000000';
158     my $rowbgcolor  = ($item eq 'credited') ? 'cccccc' : 'ffffff';
159     $hasdata = 1 if grep { $_ } @$rowdata;
160     push(@classlabels,$rowlabel);
161     push(@classdata,$rowdata);
162     push(@classcolors,$rowcolor);
163     push(@classbgcolors,$rowbgcolor);
164   }
165   next unless $hasdata; # don't include class if it has no data in time range
166   push(@row_labels,@classlabels);
167   push(@rowdata,@classdata);
168   push(@rowcolors,@classcolors);
169   push(@rowbgcolors,@classbgcolors);
170 }
171
172 </%init>