Optimize "Customer has a referring customer" condition, RT#74452
[freeside.git] / httemplate / search / cust_pkg_susp.cgi
1 <% include('/elements/header.html', $title) %>
2 <% include('/elements/table-grid.html') %>
3   <TR>
4 % foreach (@head) {
5     <TH CLASS="grid" BGCOLOR="#cccccc"><% $_ %></TH>
6 % }
7   </TR>
8 % my $r=0;
9 % foreach my $row (@rows) {
10   <TR>
11 %   foreach (@$row) {
12     <TD CLASS="grid" STYLE="border: 1px solid #cccccc" ALIGN="right" BGCOLOR="<% $r % 2 ? '#ffffff' : '#eeeeee' %>"><% $_ %></TD>
13 %   }
14   </TR>
15 %   $r++;
16 % }
17   <TR>
18 % foreach (@totals) {
19     <TD CLASS="grid" STYLE="border: 1px solid #cccccc" ALIGN="right" BGCOLOR="<% $r % 2 ? '#ffffff' : '#eeeeee' %>"><B><% $_ %></B></TD>
20 % }
21   </TR>
22 </TABLE>
23 <%init>
24
25 my $curuser = $FS::CurrentUser::CurrentUser;
26
27 die "access denied"
28   unless $curuser->access_right('Summarize packages');
29
30 my $money_char = FS::Conf->new()->config('money_char') || '$';
31
32 $FS::Record::DEBUG=0;
33
34 my $title = 'Suspension/Unsuspension Report';
35 my ($begin, $end) = FS::UI::Web::parse_beginning_ending($cgi);
36 if($begin > 0) {
37   $title = "$title (".
38     ($cgi->param('beginning') || 'beginning').' - '.
39     ($cgi->param('ending') || 'present').')';
40 }
41
42
43 my $begin_sql = $begin ? "AND h2.history_date > $begin" : '';
44 my $end_sql   = $end   ? "AND h2.history_date < $end" : '';
45
46 my $h_sql = # self-join FTW!
47 "SELECT h1.pkgpart, count(h1.pkgnum) as pkgcount
48   FROM h_cust_pkg AS h1 INNER JOIN h_cust_pkg AS h2 ON (h1.pkgnum = h2.pkgnum)
49   WHERE h1.history_action = 'replace_old' AND h2.history_action = 'replace_new'
50   AND h2.historynum - h1.historynum = 1
51   $begin_sql $end_sql";
52 # This assumes replace_old and replace_new records get consecutive 
53 # numbers. That's true in every case I've seen but is not actually 
54 # enforced anywhere.  If this is a problem we can match them up 
55 # line by line but that's cumbersome.
56
57 my @conds = (
58   '(h1.susp is null OR h1.susp = 0) AND (h2.susp is not null AND h2.susp != 0)',
59   '(h1.susp is not null AND h1.susp != 0) AND (h2.susp is null OR h2.susp = 0)',
60 );
61
62 my @results;
63 foreach my $cond (@conds) {
64   my $sql = "$h_sql AND $cond GROUP BY h1.pkgpart";
65   my $sth = dbh->prepare($sql) or die dbh->errstr;
66   $sth->execute() or die $sth->errstr;
67   push @results, { map { @$_ } @{ $sth->fetchall_arrayref() } };
68
69  
70 my @pay_cond;
71 push @pay_cond, "cust_bill_pay._date < $end" if $end;
72 push @pay_cond, "cust_bill_pay._date > $begin" if $begin;
73
74 my $extra_sql = '';
75 $extra_sql = 'WHERE '. join(' AND ', @pay_cond) if @pay_cond;
76 $extra_sql .= ( $extra_sql ? ' AND ' : ' WHERE ' ).
77               $curuser->agentnums_sql( 'table' => 'cust_main' );
78
79 my $pkg_payments = {
80   map { $_->pkgpart => $_->total_pay }
81   qsearch({
82     'table'     => 'cust_pkg',
83     'select'    => 'pkgpart, sum(cust_bill_pay_pkg.amount) AS total_pay',
84     'addl_from' => 'LEFT  JOIN cust_main         USING ( custnum )
85                     INNER JOIN cust_bill_pkg     USING (pkgnum)
86                     INNER JOIN cust_bill_pay_pkg USING (billpkgnum)
87                     INNER JOIN cust_bill_pay     USING (billpaynum)',
88     'extra_sql' => "$extra_sql GROUP BY pkgpart",
89 }) };
90
91 my @head = ('Package', 'Suspended', 'Unsuspended', 'Payments');
92 my @rows = ();
93 my @totals = map {0} @head;
94 $totals[0] = 'Total';
95
96 my $pkg_agentnums_sql = $curuser->agentnums_sql(
97                           'null'       => 1,
98                           'table'      => 'part_pkg',
99                         );
100
101 my $extra_sql = " WHERE $pkg_agentnums_sql";
102
103 foreach my $part_pkg (qsearch({ 'table'     => 'part_pkg',
104                                 'hashref'   => {},
105                                 'extra_sql' => $extra_sql,
106                              })
107                      )
108 {
109   my @row = ();
110   next if !$part_pkg->freq; # exclude one-time packages
111   my $pkgpart = $part_pkg->pkgpart;
112   push @row, 
113     $part_pkg->pkg,
114     $results[0]->{$pkgpart} || 0,
115     $results[1]->{$pkgpart} || 0,
116     sprintf("%.02f",$pkg_payments->{$pkgpart});
117
118   $totals[$_] += $row[$_] foreach (1..3);
119   $row[3] = $money_char.$row[3];
120
121   push @rows, \@row;
122 }
123 $totals[3] = $money_char.$totals[3];
124
125 </%init>