mason include
[freeside.git] / httemplate / search / customer_accounting_summary.html
1 <& elements/grid-report.html,
2   title => $title,
3   rows  => \@rows,
4   cells => \@cells,
5 &>
6 <%init>
7
8 die "access denied"
9   unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
10
11 my ($agentnum,$sel_agent);
12 if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
13   $agentnum = $1;
14   $sel_agent = qsearchs('agent', { 'agentnum' => $agentnum } );
15   die "agentnum $agentnum not found!" unless $sel_agent;
16 }
17 my $title = $sel_agent ? $sel_agent->agent.' ' : '';
18
19 my ($refnum,$sel_part_referral);
20 if ( $cgi->param('refnum') =~ /^(\d+)$/ ) {
21   $refnum = $1;
22   $sel_part_referral = qsearchs('part_referral', { 'refnum' => $refnum } );
23   die "refnum $refnum not found!" unless $sel_part_referral;
24 }
25 $title .=  $sel_part_referral->referral.' '
26   if $sel_part_referral;
27
28 $title .= 'Customer Accounting Summary Report';
29
30 my @items  = ('netsales', 'cashflow');
31 my @params = ( [], [] );
32 my $grossdiscount = $cgi->param('grossdiscount');
33 my $setuprecur = $cgi->param('setuprecur');
34 if ($setuprecur && $grossdiscount) {
35   #see blocks below for more details on each option
36   @items  = ('gross', 'discounted', 'receipts', 'gross', 'discounted', 'receipts');
37   @params = ( 
38     [ setuprecur => 'setup' ],
39     [ setuprecur => 'setup' ],
40     [ setuprecur => 'setup' ],
41     [ setuprecur => 'recur' ],
42     [ setuprecur => 'recur' ],
43     [ setuprecur => 'recur' ],
44   );
45 } elsif ($setuprecur) {
46   # instead of 'cashflow' (payments - refunds), use 'receipts'
47   # (applied payments), because it's divisible into setup and recur.
48   @items = ('netsales', 'receipts', 'netsales', 'receipts');
49   @params = ( 
50     [ setuprecur => 'setup' ],
51     [ setuprecur => 'setup' ],
52     [ setuprecur => 'recur' ],
53     [ setuprecur => 'recur' ],
54   );
55 } elsif ($grossdiscount) {
56   # instead of 'netsales' (invoiced - netcredits)
57   # use 'gross' (invoiced + discounted) and 'discounted' (sum of discounts on invoices)
58   @items  = ('gross', 'discounted', 'cashflow');
59   @params = ( [], [], [] );
60 }
61
62
63 my @labels = ();
64 my @cross_params = ();
65
66 my $status = $cgi->param('status');
67 die "invalid status" unless $status =~ /^\w+|$/;
68
69 my %search_hash;
70 foreach (qw(agentnum refnum status)) {
71   if ( defined $cgi->param($_) ) {
72     $search_hash{$_} = $cgi->param($_);
73   }
74 }
75 $search_hash{'classnum'} = [ $cgi->param('cust_classnum') ] 
76   if grep { $_ eq 'cust_classnum' } $cgi->param;
77
78 my $query = FS::cust_main::Search->search(\%search_hash);
79 my @cust_main = qsearch($query);
80
81 foreach my $cust_main (@cust_main) {
82   push @cross_params, [ ('custnum' => $cust_main->custnum) ];
83 }
84
85 my %opt = (
86   items         => \@items,
87   params        => \@params,
88   cross_params  => \@cross_params,
89   agentnum      => $agentnum,
90   refnum        => $refnum,
91 );
92 for ( qw(start_month start_year end_month end_year) ) {
93   if ( $cgi->param($_) =~ /^(\d+)$/ ) {
94     $opt{$_} = $1;
95   }
96 }
97
98 warn Dumper(OPTIONS => \%opt) if $cgi->param('debug');
99 my $report = FS::Report::Table::Monthly->new(%opt);
100 my $data = $report->data;
101 warn Dumper(DATA => $data) if $cgi->param('debug') >= 2;
102
103 my @total;
104
105 my @rows; # hashes of row info
106 my @cells; # arrayrefs of cell info
107 # We use Excel currency format, but not Excel dates, because
108 # these are whole months and there's no nice way to express that.
109 # This is the historical behavior for monthly reports.
110
111 # header row
112 $rows[0] = {};
113 $cells[0] = [
114   { header => 1, rowspan => 2, colspan => ($setuprecur ? 4 : 3) },
115   map {
116     { header => 1, colspan => ($grossdiscount ? 3 : 2), value => time2str('%b %Y', $_) },
117   } @{ $data->{speriod} }
118 ];
119 my $ncols = scalar(@{ $data->{speriod} });
120
121 $rows[1] = {};
122 $cells[1] = [
123   map { 
124   ( ($grossdiscount 
125       ? (
126          { header => 1, value => mt('Gross') },
127          { header => 1, value => mt('Discount') }
128       )
129       : { header => 1, value => mt('Billed') } 
130     ),
131     { header => 1, value => mt('Paid') },
132   ) } (1..$ncols)
133 ];
134
135 # use PDL; # ha ha, I just might.
136 my $row = 0;
137 foreach my $cust_main (@cust_main) { # correspond to cross_params
138   my $skip = 1; # skip the customer iff ALL of their values are zero
139   for my $subrow (0..($setuprecur ? 1 : 0)) { # the setup/recur axis
140     push @rows, { class => $subrow ? 'shaded' : '' };
141     my @thisrow;
142     if ( $subrow == 0 ) {
143       # customer name
144       push @thisrow,
145         { value   => $cust_main->name,
146           header  => 1,
147           rowspan => ($setuprecur ? 2 : 1),
148         },
149         { value   => $cust_main->state, #cust_main->bill_location->state,
150           header  => 1,
151           rowspan => ($setuprecur ? 2 : 1),
152         },
153         { value => $cust_main->salesnum ? $cust_main->sales->salesperson : '',
154           header  => 1,
155           rowspan => ($setuprecur ? 2 : 1),
156         },
157       ;
158     }
159     if ( $setuprecur ) {
160       # subheading
161       push @thisrow,
162         { value => $subrow ? mt('recurring') : mt('setup'),
163           header => 1 };
164     }
165     for my $col (0..$ncols-1) { # the month
166       for my $subcol (0..($grossdiscount ? 2 : 1)) { # the billed/paid or gross/discount/paid axis
167         my $item = $subrow * ($grossdiscount ? 3 : 2) + $subcol;
168         my $value = $data->{data}[$item][$col][$row];
169         $skip = 0 if abs($value) > 0.005;
170         push @thisrow, { value => sprintf('%0.2f', $value), format => 'money' };
171         $total[( ($ncols * $subrow) + $col ) * ($grossdiscount ? 3 : 2) + $subcol] += $value;
172       } #subcol
173     } #col
174     push @cells, \@thisrow;
175   } #subrow
176   if ( $skip ) {
177     # all values are zero--remove the rows we just added
178     pop @rows;
179     pop @cells;
180     if ( $setuprecur ) {
181       pop @rows;
182       pop @cells;
183     }
184   }
185   $row++;
186 }
187 for my $subrow (0..($setuprecur ? 1 : 0)) {
188   push @rows, { class => ($subrow ? 'totalshaded' : 'total') };
189   my @thisrow;
190   if ( $subrow == 0 ) {
191     push @thisrow,
192       { value => mt('Total'),
193         header => 1,
194         colspan => 3,
195         rowspan => ($setuprecur ? 2 : 1), };
196   }
197   if ( $setuprecur ) {
198     push @thisrow,
199       { value => $subrow ? mt('recurring') : mt('setup'),
200         header => 1 };
201   }
202   for my $col (0..($ncols * ($grossdiscount ? 3 : 2))-1) { # month and billed/paid or gross/discount/paid axis
203     my $value = $total[($subrow * $ncols * ($grossdiscount ? 3 : 2)) + $col];
204     push @thisrow, { value => sprintf('%0.2f', $value), format => 'money' };
205   }
206   push @cells, \@thisrow;
207 } #subrow
208
209 if ( $cgi->param('debug') >= 3 ) {
210   warn Dumper(\@rows, \@cells);
211 }
212
213 my $title = 'Customer Accounting Summary';
214 </%init>