add global_unique-pbx_title to disable duplicate checking on svc_pbx.title
[freeside.git] / FS / FS / svc_pbx.pm
1 package FS::svc_pbx;
2
3 use strict;
4 use base qw( FS::svc_External_Common );
5 use FS::Record qw( qsearch qsearchs dbh );
6 use FS::Conf;
7 use FS::cust_svc;
8 use FS::svc_phone;
9 use FS::svc_acct;
10
11 =head1 NAME
12
13 FS::svc_pbx - Object methods for svc_pbx records
14
15 =head1 SYNOPSIS
16
17   use FS::svc_pbx;
18
19   $record = new FS::svc_pbx \%hash;
20   $record = new FS::svc_pbx { '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   $error = $record->suspend;
31
32   $error = $record->unsuspend;
33
34   $error = $record->cancel;
35
36 =head1 DESCRIPTION
37
38 An FS::svc_pbx object represents a PBX tenant.  FS::svc_pbx inherits from
39 FS::svc_Common.  The following fields are currently supported:
40
41 =over 4
42
43 =item svcnum
44
45 Primary key (assigned automatcially for new accounts)
46
47 =item id
48
49 (Unique?) number of external record
50
51 =item title
52
53 PBX name
54
55 =item max_extensions
56
57 Maximum number of extensions
58
59 =item max_simultaneous
60
61 Maximum number of simultaneous users
62
63 =back
64
65 =head1 METHODS
66
67 =over 4
68
69 =item new HASHREF
70
71 Creates a new PBX tenant.  To add the PBX tenant to the database, see
72 L<"insert">.
73
74 Note that this stores the hash reference, not a distinct copy of the hash it
75 points to.  You can ask the object for a copy with the I<hash> method.
76
77 =cut
78
79 sub table { 'svc_pbx'; }
80
81 sub table_info {
82   {
83     'name' => 'PBX',
84     'name_plural' => 'PBXs', #optional,
85     'longname_plural' => 'PBXs', #optional
86     'sorts' => 'svcnum', # optional sort field (or arrayref of sort fields, main first)
87     'display_weight' => 70,
88     'cancel_weight'  => 90,
89     'fields' => {
90       'id'    => 'ID',
91       'title' => 'Name',
92       'max_extensions' => 'Maximum number of User Extensions',
93       'max_simultaneous' => 'Maximum number of simultaneous users',
94 #      'field'         => 'Description',
95 #      'another_field' => { 
96 #                           'label'     => 'Description',
97 #                          'def_label' => 'Description for service definitions',
98 #                          'type'      => 'text',
99 #                          'disable_default'   => 1, #disable switches
100 #                          'disable_fixed'     => 1, #
101 #                          'disable_inventory' => 1, #
102 #                        },
103 #      'foreign_key'   => { 
104 #                           'label'        => 'Description',
105 #                          'def_label'    => 'Description for service defs',
106 #                          'type'         => 'select',
107 #                          'select_table' => 'foreign_table',
108 #                          'select_key'   => 'key_field_in_table',
109 #                          'select_label' => 'label_field_in_table',
110 #                        },
111
112     },
113   };
114 }
115
116 =item search_sql STRING
117
118 Class method which returns an SQL fragment to search for the given string.
119
120 =cut
121
122 #XXX
123 #or something more complicated if necessary
124 #sub search_sql {
125 #  my($class, $string) = @_;
126 #  $class->search_sql_field('title', $string);
127 #}
128
129 =item label
130
131 Returns the title field for this PBX tenant.
132
133 =cut
134
135 sub label {
136   my $self = shift;
137   $self->title;
138 }
139
140 =item insert
141
142 Adds this record to the database.  If there is an error, returns the error,
143 otherwise returns false.
144
145 The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be 
146 defined.  An FS::cust_svc record will be created and inserted.
147
148 =cut
149
150 sub insert {
151   my $self = shift;
152   my $error;
153
154   $error = $self->SUPER::insert;
155   return $error if $error;
156
157   '';
158 }
159
160 =item delete
161
162 Delete this record from the database.
163
164 =cut
165
166 sub delete {
167   my $self = shift;
168
169   local $SIG{HUP} = 'IGNORE';
170   local $SIG{INT} = 'IGNORE';
171   local $SIG{QUIT} = 'IGNORE';
172   local $SIG{TERM} = 'IGNORE';
173   local $SIG{TSTP} = 'IGNORE';
174   local $SIG{PIPE} = 'IGNORE';
175
176   my $oldAutoCommit = $FS::UID::AutoCommit;
177   local $FS::UID::AutoCommit = 0;
178   my $dbh = dbh;
179
180   foreach my $svc_phone (qsearch('svc_phone', { 'pbxsvc' => $self->svcnum } )) {
181     $svc_phone->pbxsvc('');
182     my $error = $svc_phone->replace;
183     if ( $error ) {
184       $dbh->rollback if $oldAutoCommit;
185       return $error;
186     }
187   }
188
189   foreach my $svc_acct  (qsearch('svc_acct',  { 'pbxsvc' => $self->svcnum } )) {
190     my $error = $svc_acct->delete;
191     if ( $error ) {
192       $dbh->rollback if $oldAutoCommit;
193       return $error;
194     }
195   }
196
197   my $error = $self->SUPER::delete;
198   if ( $error ) {
199     $dbh->rollback if $oldAutoCommit;
200     return $error;
201   }
202
203   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
204   '';
205 }
206
207
208 =item replace OLD_RECORD
209
210 Replaces the OLD_RECORD with this one in the database.  If there is an error,
211 returns the error, otherwise returns false.
212
213 =cut
214
215 #sub replace {
216 #  my ( $new, $old ) = ( shift, shift );
217 #  my $error;
218 #
219 #  $error = $new->SUPER::replace($old);
220 #  return $error if $error;
221 #
222 #  '';
223 #}
224
225 =item suspend
226
227 Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
228
229 =item unsuspend
230
231 Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
232
233 =item cancel
234
235 Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
236
237 =item check
238
239 Checks all fields to make sure this is a valid PBX tenant.  If there is
240 an error, returns the error, otherwise returns false.  Called by the insert
241 and repalce methods.
242
243 =cut
244
245 sub check {
246   my $self = shift;
247
248   my $x = $self->setfixed;
249   return $x unless ref($x);
250   my $part_svc = $x;
251
252
253   $self->SUPER::check;
254 }
255
256 #XXX this is a way-too simplistic implementation
257 # at the very least, title should be unique across exports that need that or
258 # controlled by a conf setting or something
259 sub _check_duplicate {
260   my $self = shift;
261
262   my $conf = new FS::Conf;
263   return '' if $conf->config('global_unique-pbx_title') eq 'disabled';
264
265   $self->lock_table;
266
267   if ( qsearchs( 'svc_pbx', { 'title' => $self->title } ) ) {
268     return "Name in use";
269   } else {
270     return '';
271   }
272 }
273
274 =item get_cdrs
275
276 Returns a set of Call Detail Records (see L<FS::cdr>) associated with this 
277 service.  By default, "associated with" means that the "charged_party" field of
278 the CDR matches the "title" field of the service.
279
280 =over 2
281
282 Accepts the following options:
283
284 =item for_update => 1: SELECT the CDRs "FOR UPDATE".
285
286 =item status => "" (or "done"): Return only CDRs with that processing status.
287
288 =item inbound => 1: No-op for svc_pbx CDR processing.
289
290 =item default_prefix => "XXX": Also accept the phone number of the service prepended 
291 with the chosen prefix.
292
293 =item disable_src => 1: No-op for svc_pbx CDR processing.
294
295 =back
296
297 =cut
298
299 sub get_cdrs {
300   my($self, %options) = @_;
301   my %hash = ();
302   my @where = ();
303
304   my @fields = ( 'charged_party' );
305   $hash{'freesidestatus'} = $options{'status'}
306     if exists($options{'status'});
307   
308   my $for_update = $options{'for_update'} ? 'FOR UPDATE' : '';
309
310   my $title = $self->title;
311
312   my $prefix = $options{'default_prefix'};
313
314   my @orwhere =  map " $_ = '$title'        ", @fields;
315   push @orwhere, map " $_ = '$prefix$title' ", @fields
316     if length($prefix);
317   if ( $prefix =~ /^\+(\d+)$/ ) {
318     push @orwhere, map " $_ = '$1$title' ", @fields
319   }
320
321   push @where, ' ( '. join(' OR ', @orwhere ). ' ) ';
322
323   if ( $options{'begin'} ) {
324     push @where, 'startdate >= '. $options{'begin'};
325   }
326   if ( $options{'end'} ) {
327     push @where, 'startdate < '.  $options{'end'};
328   }
329
330   my $extra_sql = ( keys(%hash) ? ' AND ' : ' WHERE ' ). join(' AND ', @where );
331
332   my @cdrs =
333     qsearch( {
334       'table'      => 'cdr',
335       'hashref'    => \%hash,
336       'extra_sql'  => $extra_sql,
337       'order_by'   => "ORDER BY startdate $for_update",
338     } );
339
340   @cdrs;
341 }
342
343 =back
344
345 =head1 BUGS
346
347 =head1 SEE ALSO
348
349 L<FS::svc_Common>, L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>,
350 L<FS::cust_pkg>, schema.html from the base documentation.
351
352 =cut
353
354 1;
355