self-service keepalives
[freeside.git] / FS / FS / agent.pm
1 package FS::agent;
2
3 use strict;
4 use vars qw( @ISA );
5 use FS::Record qw( dbh qsearch qsearchs );
6 use FS::cust_main;
7 use FS::agent_type;
8
9 @ISA = qw( FS::Record );
10
11 =head1 NAME
12
13 FS::agent - Object methods for agent records
14
15 =head1 SYNOPSIS
16
17   use FS::agent;
18
19   $record = new FS::agent \%hash;
20   $record = new FS::agent { 'column' => 'value' };
21
22   $error = $record->insert;
23
24   $error = $new_record->replace($old_record);
25
26   $error = $record->delete;
27
28   $error = $record->check;
29
30   $agent_type = $record->agent_type;
31
32   $hashref = $record->pkgpart_hashref;
33   #may purchase $pkgpart if $hashref->{$pkgpart};
34
35 =head1 DESCRIPTION
36
37 An FS::agent object represents an agent.  Every customer has an agent.  Agents
38 can be used to track things like resellers or salespeople.  FS::agent inherits
39 from FS::Record.  The following fields are currently supported:
40
41 =over 4
42
43 =item agentnum - primary key (assigned automatically for new agents)
44
45 =item agent - Text name of this agent
46
47 =item typenum - Agent type.  See L<FS::agent_type>
48
49 =item prog - For future use.
50
51 =item freq - For future use.
52
53 =item disabled - Disabled flag, empty or 'Y'
54
55 =item username - Username for the Agent interface
56
57 =item _password - Password for the Agent interface
58
59 =back
60
61 =head1 METHODS
62
63 =over 4
64
65 =item new HASHREF
66
67 Creates a new agent.  To add the agent to the database, see L<"insert">.
68
69 =cut
70
71 sub table { 'agent'; }
72
73 =item insert
74
75 Adds this agent to the database.  If there is an error, returns the error,
76 otherwise returns false.
77
78 =item delete
79
80 Deletes this agent from the database.  Only agents with no customers can be
81 deleted.  If there is an error, returns the error, otherwise returns false.
82
83 =cut
84
85 sub delete {
86   my $self = shift;
87
88   return "Can't delete an agent with customers!"
89     if qsearch( 'cust_main', { 'agentnum' => $self->agentnum } );
90
91   $self->SUPER::delete;
92 }
93
94 =item replace OLD_RECORD
95
96 Replaces OLD_RECORD with this one in the database.  If there is an error,
97 returns the error, otherwise returns false.
98
99 =item check
100
101 Checks all fields to make sure this is a valid agent.  If there is an error,
102 returns the error, otherwise returns false.  Called by the insert and replace
103 methods.
104
105 =cut
106
107 sub check {
108   my $self = shift;
109
110   my $error =
111     $self->ut_numbern('agentnum')
112       || $self->ut_text('agent')
113       || $self->ut_number('typenum')
114       || $self->ut_numbern('freq')
115       || $self->ut_textn('prog')
116   ;
117   return $error if $error;
118
119   if ( $self->dbdef_table->column('disabled') ) {
120     $error = $self->ut_enum('disabled', [ '', 'Y' ] );
121     return $error if $error;
122   }
123
124   if ( $self->dbdef_table->column('username') ) {
125     $error = $self->ut_alphan('username');
126     return $error if $error;
127     if ( length($self->username) ) {
128       my $conflict = qsearchs('agent', { 'username' => $self->username } );
129       return 'duplicate agent username (with '. $conflict->agent. ')'
130         if $conflict && $conflict->agentnum != $self->agentnum;
131       $error = $self->ut_text('password'); # ut_text... arbitrary choice
132     } else {
133       $self->_password('');
134     }
135   }
136
137   return "Unknown typenum!"
138     unless $self->agent_type;
139
140   $self->SUPER::check;
141 }
142
143 =item agent_type
144
145 Returns the FS::agent_type object (see L<FS::agent_type>) for this agent.
146
147 =cut
148
149 sub agent_type {
150   my $self = shift;
151   qsearchs( 'agent_type', { 'typenum' => $self->typenum } );
152 }
153
154 =item pkgpart_hashref
155
156 Returns a hash reference.  The keys of the hash are pkgparts.  The value is
157 true if this agent may purchase the specified package definition.  See
158 L<FS::part_pkg>.
159
160 =cut
161
162 sub pkgpart_hashref {
163   my $self = shift;
164   $self->agent_type->pkgpart_hashref;
165 }
166
167 =item num_prospect_cust_main
168
169 Returns the number of prospects (customers with no packages ever ordered) for
170 this agent.
171
172 =cut
173
174 sub num_prospect_cust_main {
175   shift->num_sql(FS::cust_main->prospect_sql);
176 }
177
178 sub num_sql {
179   my( $self, $sql ) = @_;
180   my $sth = dbh->prepare(
181     "SELECT COUNT(*) FROM cust_main WHERE agentnum = ? AND $sql"
182   ) or die dbh->errstr;
183   $sth->execute($self->agentnum) or die $sth->errstr;
184   $sth->fetchrow_arrayref->[0];
185 }
186
187 =item prospect_cust_main
188
189 Returns the prospects (customers with no packages ever ordered) for this agent,
190 as cust_main objects.
191
192 =cut
193
194 sub prospect_cust_main {
195   shift->cust_main_sql(FS::cust_main->prospect_sql);
196 }
197
198 sub cust_main_sql {
199   my( $self, $sql ) = @_;
200   qsearch( 'cust_main',
201            { 'agentnum' => $self->agentnum },
202            '',
203            " AND $sql"
204   );
205 }
206
207 =item num_active_cust_main
208
209 Returns the number of active customers for this agent.
210
211 =cut
212
213 sub num_active_cust_main {
214   shift->num_sql(FS::cust_main->active_sql);
215 }
216
217 =item active_cust_main
218
219 Returns the active customers for this agent, as cust_main objects.
220
221 =cut
222
223 sub active_cust_main {
224   shift->cust_main_sql(FS::cust_main->active_sql);
225 }
226
227 =item num_susp_cust_main
228
229 Returns the number of suspended customers for this agent.
230
231 =cut
232
233 sub num_susp_cust_main {
234   shift->num_sql(FS::cust_main->susp_sql);
235 }
236
237 =item susp_cust_main
238
239 Returns the suspended customers for this agent, as cust_main objects.
240
241 =cut
242
243 sub susp_cust_main {
244   shift->cust_main_sql(FS::cust_main->susp_sql);
245 }
246
247 =item num_cancel_cust_main
248
249 Returns the number of cancelled customer for this agent.
250
251 =cut
252
253 sub num_cancel_cust_main {
254   shift->num_sql(FS::cust_main->cancel_sql);
255 }
256
257 =item cancel_cust_main
258
259 Returns the cancelled customers for this agent, as cust_main objects.
260
261 =cut
262
263 sub cancel_cust_main {
264   shift->cust_main_sql(FS::cust_main->cancel_sql);
265 }
266
267 =back
268
269 =head1 BUGS
270
271 =head1 SEE ALSO
272
273 L<FS::Record>, L<FS::agent_type>, L<FS::cust_main>, L<FS::part_pkg>, 
274 schema.html from the base documentation.
275
276 =cut
277
278 1;
279