customer churn report, #30132
[freeside.git] / FS / FS / cust_main / Status.pm
1 package FS::cust_main::Status;
2
3 use strict;
4 use vars qw( $conf ); # $module ); #$DEBUG $me );
5 use FS::UID;
6 use FS::cust_pkg;
7
8 #use Tie::IxHash;
9
10 use FS::UID qw( getotaker dbh driver_name );
11
12 #$DEBUG = 0;
13 #$me = '[FS::cust_main::Status]';
14
15 install_callback FS::UID sub { 
16   $conf = new FS::Conf;
17   #$module = $conf->config('cust_main-status_module') || 'Classic';
18 };
19
20 =head1 NAME
21
22 FS::cust_main::Status - Status mixin for cust_main
23
24 =head1 SYNOPSIS
25
26 =head1 DESCRIPTION
27
28 These methods are available on FS::cust_main objects:
29
30 =head1 METHODS
31
32 =over 4
33
34 =item statuscolors
35
36 Returns an (ordered with Tie::IxHash) hash reference of possible status
37 names and colors.
38
39 =cut
40
41 sub statuscolors {
42   #my $self = shift; #i guess i'm a class method
43
44   my %statuscolors;
45
46   my $module = $conf->config('cust_main-status_module') || 'Classic';
47
48   if ( $module eq 'Classic' ) {
49     tie %statuscolors, 'Tie::IxHash',
50       'prospect'  => '7e0079', #'000000', #black?  naw, purple
51       'active'    => '00CC00', #green
52       'ordered'   => '009999', #teal? cyan?
53       'inactive'  => '0000CC', #blue
54       'suspended' => 'FF9900', #yellow
55       'cancelled' => 'FF0000', #red
56     ;
57   } elsif ( $module eq 'Recurring' ) {
58     tie %statuscolors, 'Tie::IxHash',
59       'prospect'  => '7e0079', #'000000', #black?  naw, purple
60       'active'    => '00CC00', #green
61       'ordered'   => '009999', #teal? cyan?
62       'suspended' => 'FF9900', #yellow
63       'cancelled' => 'FF0000', #red
64       'inactive'  => '0000CC', #blue
65     ;
66   } else {
67     die "unknown status module $module";
68   }
69
70   \%statuscolors;
71
72 }
73
74 =item cancelled_sql
75
76 =cut
77
78 sub cancelled_sql {
79   my $self = shift;
80
81   my $recurring_sql = FS::cust_pkg->recurring_sql;
82   my $cancelled_sql = FS::cust_pkg->cancelled_sql;
83   my $select_count_pkgs = $self->select_count_pkgs_sql;
84
85   my $sql = "
86         0 < ( $select_count_pkgs )
87     AND 0 = ( $select_count_pkgs AND $recurring_sql
88                   AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
89             )
90     AND 0 < ( $select_count_pkgs AND $cancelled_sql   )
91   ";
92
93   my $module = $conf->config('cust_main-status_module') || 'Classic';
94
95   if ( $module eq 'Classic' ) {
96     $sql .=
97       " AND 0 = (  $select_count_pkgs AND ". FS::cust_pkg->inactive_sql. " ) ";
98   #} elsif ( $module eq 'Recurring' ) {
99   #} else {
100   #  die "unknown status module $module";
101   }
102
103   $sql;
104
105 }
106
107 =back
108
109 =head1 CLASS METHODS
110
111 =over 4
112
113 =item churn_sql START, END
114
115 Returns an SQL statement for the customer churn status query.  The columns
116 returned are the custnum and the number of active, suspended, and cancelled
117 packages (excluding one-time packages) at the start date ("s_active",
118 "s_suspended", and "s_cancelled") and the end date ("e_active", etc.).
119
120 =cut
121
122 # not sure this belongs here...FS::cust_main::Packages?
123
124 sub churn_sql {
125   my $self = shift;
126   my ($speriod, $eperiod) = @_;
127
128   my $s_sql = FS::h_cust_pkg->status_as_of_sql($speriod);
129   my $e_sql = FS::h_cust_pkg->status_as_of_sql($eperiod);
130
131   my @select = (
132     'custnum',
133     'COALESCE(SUM(s.is_active::int),0)     as s_active',
134     'COALESCE(SUM(s.is_suspended::int),0)  as s_suspended',
135     'COALESCE(SUM(s.is_cancelled::int),0)  as s_cancelled',
136     'COALESCE(SUM(e.is_active::int),0)     as e_active',
137     'COALESCE(SUM(e.is_suspended::int),0)  as e_suspended',
138     'COALESCE(SUM(e.is_cancelled::int),0)  as e_cancelled',
139   );
140   my $from = "($s_sql) AS s FULL JOIN ($e_sql) AS e USING (custnum)";
141
142   return "SELECT ".join(',', @select)." FROM $from GROUP BY custnum";
143 }
144
145 =head1 BUGS
146
147 =head1 SEE ALSO
148
149 L<FS::cust_main>
150
151 =cut
152
153 1;
154