1 <& elements/grid-report.html,
6 # would be better handled with Mason inheritance? consider this. easy enough
7 # to change it at this point.
12 unless $FS::CurrentUser::CurrentUser->access_right('Financial reports')
13 && $FS::CurrentUser::CurrentUser->access_right('List rating data');
15 my ($agentnum,$sel_agent);
16 if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
18 $sel_agent = qsearchs('agent', { 'agentnum' => $agentnum } );
19 die "agentnum $agentnum not found!" unless $sel_agent;
21 my $title = $sel_agent ? $sel_agent->agent.' ' : '';
23 $title .= 'Customer CDRs Profit/Loss Report';
25 my @items = ('cust_bill_pkg_recur', 'cust_bill_pkg_recur', 'cust_bill_pkg_detail', 'cust_bill_pkg_detail' );
26 my @params = ( [], [ 'cost' => 1 ], [], [ 'cost' => 1 ] );
29 my @cross_params = ();
32 foreach (qw(agentnum)) {
33 if ( defined $cgi->param($_) ) {
34 $search_hash{$_} = $cgi->param($_);
38 my $query = FS::cust_main::Search->search(\%search_hash);
39 my @cust_main = qsearch($query);
41 foreach my $cust_main (@cust_main) {
42 push @cross_params, [ ('custnum' => $cust_main->custnum) ];
48 cross_params => \@cross_params,
49 agentnum => $agentnum,
51 for ( qw(start_month start_year end_month end_year) ) {
52 if ( $cgi->param($_) =~ /^(\d+)$/ ) {
57 my $report = FS::Report::Table::Monthly->new(%opt);
58 my $data = $report->data;
60 ### False laziness with customer_accounting_summary.html
63 my @rows; # hashes of row info
64 my @cells; # arrayrefs of cell info
65 # We use Excel currency format, but not Excel dates, because
66 # these are whole months and there's no nice way to express that.
67 # This is the historical behavior for monthly reports.
72 { header => 1, rowspan => 2 },
74 { header => 1, colspan => 5, value => time2str('%b %Y', $_) }
75 } @{ $data->{speriod} }
77 my $ncols = scalar(@{ $data->{speriod} });
83 { header => 1, value => mt('Recur Fee') },
84 { header => 1, value => mt('Recur Cost') },
85 { header => 1, value => mt('Usage Fee') },
86 { header => 1, value => mt('Usage Cost') },
87 { header => 1, value => mt('Profit'), class => 'shaded' },
92 foreach my $cust_main (@cust_main) { # correspond to cross_params
93 my $skip = 1; # skip the customer iff ALL of their values are zero
98 { value => $cust_main->name,
101 for my $col (0..$ncols-1) { # the month
103 for my $item (0..3) { # recur/recur_cost/usage/usage_cost
104 my $value = $data->{data}[$item][$col][$row];
105 $skip = 0 if abs($value) > 0.005;
107 value => sprintf('%0.2f', $value),
109 class => ($value < 0 ? 'negative' : ''),
111 $total[$col * 5 + $item] += $value;
112 $profit += (($item % 2) ? -1 : 1) * $value;
115 value => sprintf('%0.2f', $profit),
119 $total[$col * 5 + 4] += $profit;
121 push @cells, \@thisrow;
124 # all values are zero--remove the rows we just added
131 push @rows, { class => 'total' };
134 { value => mt('Total'),
137 for my $col (0..($ncols * 5)-1) { # month and recur/recur_cost/usage/usage_cost/profit
138 my $value = $total[$col];
140 value => sprintf('%0.2f', $value),
142 class => ($col % 5 == 4) ? 'totalshaded' : 'total',
145 push @cells, \@thisrow;
149 .negative { color: red }