4 use base qw( FS::svc_External_Common );
5 use FS::Record qw( qsearch qsearchs dbh );
6 use FS::PagedSearch qw( psearch );
14 FS::svc_pbx - Object methods for svc_pbx records
20 $record = new FS::svc_pbx \%hash;
21 $record = new FS::svc_pbx { 'column' => 'value' };
23 $error = $record->insert;
25 $error = $new_record->replace($old_record);
27 $error = $record->delete;
29 $error = $record->check;
31 $error = $record->suspend;
33 $error = $record->unsuspend;
35 $error = $record->cancel;
39 An FS::svc_pbx object represents a PBX tenant. FS::svc_pbx inherits from
40 FS::svc_Common. The following fields are currently supported:
46 Primary key (assigned automatcially for new accounts)
50 (Unique?) number of external record
58 Maximum number of extensions
60 =item max_simultaneous
62 Maximum number of simultaneous users
72 Creates a new PBX tenant. To add the PBX tenant to the database, see
75 Note that this stores the hash reference, not a distinct copy of the hash it
76 points to. You can ask the object for a copy with the I<hash> method.
80 sub table { 'svc_pbx'; }
85 'name_plural' => 'PBXs',
86 'lcname_plural' => 'PBXs',
87 'longname_plural' => 'PBXs',
88 'sorts' => 'svcnum', # optional sort field (or arrayref of sort fields, main first)
89 'display_weight' => 70,
90 'cancel_weight' => 90,
94 'max_extensions' => 'Maximum number of User Extensions',
95 'max_simultaneous' => 'Maximum number of simultaneous users',
100 =item search_sql STRING
102 Class method which returns an SQL fragment to search for the given string.
107 #or something more complicated if necessary
109 # my($class, $string) = @_;
110 # $class->search_sql_field('title', $string);
115 Returns the title field for this PBX tenant.
126 Adds this record to the database. If there is an error, returns the error,
127 otherwise returns false.
129 The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
130 defined. An FS::cust_svc record will be created and inserted.
138 $error = $self->SUPER::insert;
139 return $error if $error;
146 Delete this record from the database.
153 local $SIG{HUP} = 'IGNORE';
154 local $SIG{INT} = 'IGNORE';
155 local $SIG{QUIT} = 'IGNORE';
156 local $SIG{TERM} = 'IGNORE';
157 local $SIG{TSTP} = 'IGNORE';
158 local $SIG{PIPE} = 'IGNORE';
160 my $oldAutoCommit = $FS::UID::AutoCommit;
161 local $FS::UID::AutoCommit = 0;
164 foreach my $svc_phone (qsearch('svc_phone', { 'pbxsvc' => $self->svcnum } )) {
165 $svc_phone->pbxsvc('');
166 my $error = $svc_phone->replace;
168 $dbh->rollback if $oldAutoCommit;
173 foreach my $svc_acct (qsearch('svc_acct', { 'pbxsvc' => $self->svcnum } )) {
174 my $error = $svc_acct->delete;
176 $dbh->rollback if $oldAutoCommit;
181 my $error = $self->SUPER::delete;
183 $dbh->rollback if $oldAutoCommit;
187 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
192 =item replace OLD_RECORD
194 Replaces the OLD_RECORD with this one in the database. If there is an error,
195 returns the error, otherwise returns false.
200 # my ( $new, $old ) = ( shift, shift );
203 # $error = $new->SUPER::replace($old);
204 # return $error if $error;
211 Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
215 Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
219 Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
223 Checks all fields to make sure this is a valid PBX tenant. If there is
224 an error, returns the error, otherwise returns false. Called by the insert
232 my $x = $self->setfixed;
233 return $x unless ref($x);
240 sub _check_duplicate {
243 my $conf = new FS::Conf;
247 foreach my $field ('title', 'id') {
248 my $global_unique = $conf->config("global_unique-pbx_$field");
249 # can be 'disabled', 'enabled', or empty.
250 # if empty, check per exports; if not empty or disabled, check
252 next if $global_unique eq 'disabled';
253 my @dup = $self->find_duplicates(
254 ($global_unique ? 'global' : 'export') , $field
257 return "duplicate $field '".$self->getfield($field).
258 "': conflicts with svcnum ".$dup[0]->svcnum;
263 =item psearch_cdrs OPTIONS
265 Returns a paged search (L<FS::PagedSearch>) for Call Detail Records
266 associated with this service. By default, "associated with" means that
267 the "charged_party" field of the CDR matches the "title" field of the
268 service. To access the CDRs themselves, call "->fetch" on the resulting
273 Accepts the following options:
275 =item for_update => 1: SELECT the CDRs "FOR UPDATE".
277 =item status => "" (or "done"): Return only CDRs with that processing status.
279 =item inbound => 1: No-op for svc_pbx CDR processing.
281 =item default_prefix => "XXX": Also accept the phone number of the service prepended
282 with the chosen prefix.
284 =item disable_src => 1: No-op for svc_pbx CDR processing.
286 =item by_svcnum => 1: Select CDRs where the svcnum field matches, instead of
287 title/charged_party. Normally this field is set after processing.
289 =item by_ip_addr => 'src' or 'dst': Select CDRs where the src_ip_addr or
290 dst_ip_addr field matches title. In this case, some special logic is applied
291 to allow title to indicate a range of IP addresses.
293 =item begin, end: Start and end of date range, as unix timestamp.
295 =item cdrtypenum: Only return CDRs with this type number.
302 my($self, %options) = @_;
306 my @fields = ( 'charged_party' );
307 $hash{'freesidestatus'} = $options{'status'}
308 if exists($options{'status'});
310 if ($options{'cdrtypenum'}) {
311 $hash{'cdrtypenum'} = $options{'cdrtypenum'};
314 my $for_update = $options{'for_update'} ? 'FOR UPDATE' : '';
316 if ( $options{'by_svcnum'} ) {
317 $hash{'svcnum'} = $self->svcnum;
319 elsif ( $options{'by_ip_addr'} =~ /^src|dst$/) {
320 my $field = 'cdr.'.$options{'by_ip_addr'}.'_ip_addr';
321 push @where, FS::cdr->ip_addr_sql($field, $self->title);
325 my $title = $self->title;
327 my $prefix = $options{'default_prefix'};
329 my @orwhere = map " $_ = '$title' ", @fields;
330 push @orwhere, map " $_ = '$prefix$title' ", @fields
332 if ( $prefix =~ /^\+(\d+)$/ ) {
333 push @orwhere, map " $_ = '$1$title' ", @fields
336 push @where, ' ( '. join(' OR ', @orwhere ). ' ) ';
339 if ( $options{'begin'} ) {
340 push @where, 'startdate >= '. $options{'begin'};
342 if ( $options{'end'} ) {
343 push @where, 'startdate < '. $options{'end'};
346 my $extra_sql = ( keys(%hash) ? ' AND ' : ' WHERE ' ). join(' AND ', @where )
352 'extra_sql' => $extra_sql,
353 'order_by' => "ORDER BY startdate $for_update",
357 =item get_cdrs (DEPRECATED)
359 Like psearch_cdrs, but returns all the L<FS::cdr> objects at once, in a
360 single list. Arguments are the same as for psearch_cdrs. This can take
361 an unreasonably large amount of memory and is best avoided.
367 my $psearch = $self->psearch_cdrs($_);
368 qsearch ( $psearch->{query} )
377 L<FS::svc_Common>, L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>,
378 L<FS::cust_pkg>, schema.html from the base documentation.