This commit was generated by cvs2svn to compensate for changes in r9232,
[freeside.git] / FS / FS / cust_main_Mixin.pm
1 package FS::cust_main_Mixin;
2
3 use strict;
4 use vars qw( $DEBUG $me );
5 use Carp qw( confess );
6 use FS::UID qw(dbh);
7 use FS::cust_main;
8
9 $DEBUG = 0;
10 $me = '[FS::cust_main_Mixin]';
11
12 =head1 NAME
13
14 FS::cust_main_Mixin - Mixin class for records that contain fields from cust_main
15
16 =head1 SYNOPSIS
17
18 package FS::some_table;
19 use vars qw(@ISA);
20 @ISA = qw( FS::cust_main_Mixin FS::Record );
21
22 =head1 DESCRIPTION
23
24 This is a mixin class for records that contain fields from the cust_main table,
25 for example, from a JOINed search.  See httemplate/search/ for examples.
26
27 =head1 METHODS
28
29 =over 4
30
31 =cut
32
33 sub cust_unlinked_msg { '(unlinked)'; }
34 sub cust_linked { $_[0]->custnum; }
35
36 =item display_custnum
37
38 Given an object that contains fields from cust_main (say, from a JOINed
39 search; see httemplate/search/ for examples), returns the equivalent of the
40 FS::cust_main I<name> method, or "(unlinked)" if this object is not linked to
41 a customer.
42
43 =cut
44
45 sub display_custnum {
46   my $self = shift;
47   $self->cust_linked
48     ? FS::cust_main::display_custnum($self)
49     : $self->cust_unlinked_msg;
50 }
51
52 =item name
53
54 Given an object that contains fields from cust_main (say, from a JOINed
55 search; see httemplate/search/ for examples), returns the equivalent of the
56 FS::cust_main I<name> method, or "(unlinked)" if this object is not linked to
57 a customer.
58
59 =cut
60
61 sub name {
62   my $self = shift;
63   $self->cust_linked
64     ? FS::cust_main::name($self)
65     : $self->cust_unlinked_msg;
66 }
67
68 =item ship_name
69
70 Given an object that contains fields from cust_main (say, from a JOINed
71 search; see httemplate/search/ for examples), returns the equivalent of the
72 FS::cust_main I<ship_name> method, or "(unlinked)" if this object is not
73 linked to a customer.
74
75 =cut
76
77 sub ship_name {
78   my $self = shift;
79   $self->cust_linked
80     ? FS::cust_main::ship_name($self)
81     : $self->cust_unlinked_msg;
82 }
83
84 =item contact
85
86 Given an object that contains fields from cust_main (say, from a JOINed
87 search; see httemplate/search/ for examples), returns the equivalent of the
88 FS::cust_main I<contact> method, or "(unlinked)" if this object is not linked
89 to a customer.
90
91 =cut
92
93 sub contact {
94   my $self = shift;
95   $self->cust_linked
96     ? FS::cust_main::contact($self)
97     : $self->cust_unlinked_msg;
98 }
99
100 =item ship_contact
101
102 Given an object that contains fields from cust_main (say, from a JOINed
103 search; see httemplate/search/ for examples), returns the equivalent of the
104 FS::cust_main I<ship_contact> method, or "(unlinked)" if this object is not
105 linked to a customer.
106
107 =cut
108
109 sub ship_contact {
110   my $self = shift;
111   $self->cust_linked
112     ? FS::cust_main::ship_contact($self)
113     : $self->cust_unlinked_msg;
114 }
115
116 =item country_full
117
118 Given an object that contains fields from cust_main (say, from a JOINed
119 search; see httemplate/search/ for examples), returns the equivalent of the
120 FS::cust_main I<country_full> method, or "(unlinked)" if this object is not
121 linked to a customer.
122
123 =cut
124
125 sub country_full {
126   my $self = shift;
127   $self->cust_linked
128     ? FS::cust_main::country_full($self)
129     : $self->cust_unlinked_msg;
130 }
131
132 =item invoicing_list_emailonly
133
134 Given an object that contains fields from cust_main (say, from a JOINed
135 search; see httemplate/search/ for examples), returns the equivalent of the
136 FS::cust_main I<invoicing_list_emailonly> method, or "(unlinked)" if this
137 object is not linked to a customer.
138
139 =cut
140
141 sub invoicing_list_emailonly {
142   my $self = shift;
143   warn "invoicing_list_email only called on $self, ".
144        "custnum ". $self->custnum. "\n"
145     if $DEBUG;
146   $self->cust_linked
147     ? FS::cust_main::invoicing_list_emailonly($self)
148     : $self->cust_unlinked_msg;
149 }
150
151 =item invoicing_list_emailonly_scalar
152
153 Given an object that contains fields from cust_main (say, from a JOINed
154 search; see httemplate/search/ for examples), returns the equivalent of the
155 FS::cust_main I<invoicing_list_emailonly_scalar> method, or "(unlinked)" if
156 this object is not linked to a customer.
157
158 =cut
159
160 sub invoicing_list_emailonly_scalar {
161   my $self = shift;
162   warn "invoicing_list_emailonly called on $self, ".
163        "custnum ". $self->custnum. "\n"
164     if $DEBUG;
165   $self->cust_linked
166     ? FS::cust_main::invoicing_list_emailonly_scalar($self)
167     : $self->cust_unlinked_msg;
168 }
169
170 =item invoicing_list
171
172 Given an object that contains fields from cust_main (say, from a JOINed
173 search; see httemplate/search/ for examples), returns the equivalent of the
174 FS::cust_main I<invoicing_list> method, or "(unlinked)" if this object is not
175 linked to a customer.
176
177 Note: this method is read-only.
178
179 =cut
180
181 #read-only
182 sub invoicing_list {
183   my $self = shift;
184   $self->cust_linked
185     ? FS::cust_main::invoicing_list($self)
186     : ();
187 }
188
189 =item status
190
191 Given an object that contains fields from cust_main (say, from a JOINed
192 search; see httemplate/search/ for examples), returns the equivalent of the
193 FS::cust_main I<status> method, or "(unlinked)" if this object is not linked to
194 a customer.
195
196 =cut
197
198 sub cust_status {
199   my $self = shift;
200   return $self->cust_unlinked_msg unless $self->cust_linked;
201
202   #FS::cust_main::status($self)
203   #false laziness w/actual cust_main::status
204   # (make sure FS::cust_main methods are called)
205   for my $status (qw( prospect active inactive suspended cancelled )) {
206     my $method = $status.'_sql';
207     my $sql = FS::cust_main->$method();;
208     my $numnum = ( $sql =~ s/cust_main\.custnum/?/g );
209     my $sth = dbh->prepare("SELECT $sql") or die dbh->errstr;
210     $sth->execute( ($self->custnum) x $numnum )
211       or die "Error executing 'SELECT $sql': ". $sth->errstr;
212     return $status if $sth->fetchrow_arrayref->[0];
213   }
214 }
215
216 =item ucfirst_cust_status
217
218 Given an object that contains fields from cust_main (say, from a JOINed
219 search; see httemplate/search/ for examples), returns the equivalent of the
220 FS::cust_main I<ucfirst_status> method, or "(unlinked)" if this object is not
221 linked to a customer.
222
223 =cut
224
225 sub ucfirst_cust_status {
226   my $self = shift;
227   $self->cust_linked
228     ? ucfirst( $self->cust_status(@_) ) 
229     : $self->cust_unlinked_msg;
230 }
231
232 =item cust_statuscolor
233
234 Given an object that contains fields from cust_main (say, from a JOINed
235 search; see httemplate/search/ for examples), returns the equivalent of the
236 FS::cust_main I<statuscol> method, or "000000" if this object is not linked to
237 a customer.
238
239 =cut
240
241 sub cust_statuscolor {
242   my $self = shift;
243
244   $self->cust_linked
245     ? FS::cust_main::cust_statuscolor($self)
246     : '000000';
247 }
248
249 =item prospect_sql
250
251 =item active_sql
252
253 =item inactive_sql
254
255 =item suspended_sql
256
257 =item cancelled_sql
258
259 Class methods that return SQL framents, equivalent to the corresponding
260 FS::cust_main method.
261
262 =cut
263
264 #      my \$self = shift;
265 #      \$self->cust_linked
266 #        ? FS::cust_main::${sub}_sql(\$self)
267 #        : '0';
268
269 foreach my $sub (qw( prospect active inactive suspended cancelled )) {
270   eval "
271     sub ${sub}_sql {
272       confess 'cust_main_Mixin ${sub}_sql called with object' if ref(\$_[0]);
273       'cust_main.custnum IS NOT NULL AND '. FS::cust_main->${sub}_sql();
274     }
275   ";
276   die $@ if $@;
277 }
278
279 =item cust_search_sql
280
281 Returns a list of SQL WHERE fragments to search for parameters specified
282 in HASHREF.  Valid parameters are:
283
284 =over 4
285
286 =item agentnum
287
288 =item status
289
290 =item payby
291
292 =back
293
294 =cut
295
296 sub cust_search_sql {
297   my($class, $param) = @_;
298
299   if ( $DEBUG ) {
300     warn "$me cust_search_sql called with params: \n".
301          join("\n", map { "  $_: ". $param->{$_} } keys %$param ). "\n";
302   }
303
304   my @search = ();
305
306   if ( $param->{'agentnum'} && $param->{'agentnum'} =~ /^(\d+)$/ ) {
307     push @search, "cust_main.agentnum = $1";
308   }
309
310   #status (prospect active inactive suspended cancelled)
311   if ( grep { $param->{'status'} eq $_ } FS::cust_main->statuses() ) {
312     my $method = $param->{'status'}. '_sql';
313     push @search, $class->$method();
314   }
315
316   #payby
317   my @payby = ref($param->{'payby'})
318                 ? @{ $param->{'payby'} }
319                 : split(',', $param->{'payby'});
320   @payby = grep /^([A-Z]{4})$/, @payby;
321   if ( @payby ) {
322     push @search, 'cust_main.payby IN ('. join(',', map "'$_'", @payby). ')';
323   }
324
325   #here is the agent virtualization
326   push @search,
327     $FS::CurrentUser::CurrentUser->agentnums_sql( 'table' => 'cust_main' );
328   
329   return @search;
330
331 }
332
333 =back
334
335 =head1 BUGS
336
337 =head1 SEE ALSO
338
339 L<FS::cust_main>, L<FS::Record>
340
341 =cut
342
343 1;
344