2 use base qw( FS::o2m_Common FS::device_Common FS::svc_External_Common );
6 use FS::Record qw( qsearch qsearchs dbh );
7 use FS::PagedSearch qw( psearch );
15 FS::svc_pbx - Object methods for svc_pbx records
21 $record = new FS::svc_pbx \%hash;
22 $record = new FS::svc_pbx { 'column' => 'value' };
24 $error = $record->insert;
26 $error = $new_record->replace($old_record);
28 $error = $record->delete;
30 $error = $record->check;
32 $error = $record->suspend;
34 $error = $record->unsuspend;
36 $error = $record->cancel;
40 An FS::svc_pbx object represents a PBX tenant. FS::svc_pbx inherits from
41 FS::svc_Common. The following fields are currently supported:
47 Primary key (assigned automatcially for new accounts)
51 (Unique?) number of external record
59 Maximum number of extensions
61 =item max_simultaneous
63 Maximum number of simultaneous users
67 The IP address of this PBX, if that's relevant. This must be a valid IP
68 address (or blank), but it's not checked for block assignment or uniqueness.
78 Creates a new PBX tenant. To add the PBX tenant to the database, see
81 Note that this stores the hash reference, not a distinct copy of the hash it
82 points to. You can ask the object for a copy with the I<hash> method.
86 sub table { 'svc_pbx'; }
90 tie my %fields, 'Tie::IxHash',
92 'id' => 'PBX/Tenant ID',
93 'uuid' => 'External UUID',
95 'max_extensions' => 'Maximum number of User Extensions',
96 'max_simultaneous' => 'Maximum number of simultaneous users',
97 'ip_addr' => 'IP address',
102 'name_plural' => 'PBXs',
103 'lcname_plural' => 'PBXs',
104 'longname_plural' => 'PBXs',
105 'sorts' => 'svcnum', # optional sort field (or arrayref of sort fields, main first)
106 'display_weight' => 70,
107 'cancel_weight' => 90,
108 'fields' => \%fields,
112 =item search_sql STRING
114 Class method which returns an SQL fragment to search for the given string.
119 #or something more complicated if necessary
121 # my($class, $string) = @_;
122 # $class->search_sql_field('title', $string);
127 Returns the title field for this PBX tenant.
138 Adds this record to the database. If there is an error, returns the error,
139 otherwise returns false.
141 The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
142 defined. An FS::cust_svc record will be created and inserted.
150 $error = $self->SUPER::insert;
151 return $error if $error;
158 Delete this record from the database.
165 local $SIG{HUP} = 'IGNORE';
166 local $SIG{INT} = 'IGNORE';
167 local $SIG{QUIT} = 'IGNORE';
168 local $SIG{TERM} = 'IGNORE';
169 local $SIG{TSTP} = 'IGNORE';
170 local $SIG{PIPE} = 'IGNORE';
172 my $oldAutoCommit = $FS::UID::AutoCommit;
173 local $FS::UID::AutoCommit = 0;
176 foreach my $svc_phone (qsearch('svc_phone', { 'pbxsvc' => $self->svcnum } )) {
177 $svc_phone->pbxsvc('');
178 my $error = $svc_phone->replace;
180 $dbh->rollback if $oldAutoCommit;
185 foreach my $svc_acct (qsearch('svc_acct', { 'pbxsvc' => $self->svcnum } )) {
186 my $error = $svc_acct->delete;
188 $dbh->rollback if $oldAutoCommit;
193 my $error = $self->SUPER::delete;
195 $dbh->rollback if $oldAutoCommit;
199 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
204 =item replace OLD_RECORD
206 Replaces the OLD_RECORD with this one in the database. If there is an error,
207 returns the error, otherwise returns false.
212 # my ( $new, $old ) = ( shift, shift );
215 # $error = $new->SUPER::replace($old);
216 # return $error if $error;
223 Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
227 Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
231 Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
235 Checks all fields to make sure this is a valid PBX tenant. If there is
236 an error, returns the error, otherwise returns false. Called by the insert
244 my $x = $self->setfixed;
245 return $x unless ref($x);
249 $self->ut_ipn('ip_addr')
250 || $self->SUPER::check;
253 sub _check_duplicate {
256 my $conf = new FS::Conf;
260 foreach my $field ('title', 'id') {
261 my $global_unique = $conf->config("global_unique-pbx_$field");
262 # can be 'disabled', 'enabled', or empty.
263 # if empty, check per exports; if not empty or disabled, check
265 next if $global_unique eq 'disabled';
266 my @dup = $self->find_duplicates(
267 ($global_unique ? 'global' : 'export') , $field
270 return "duplicate $field '".$self->getfield($field).
271 "': conflicts with svcnum ".$dup[0]->svcnum;
276 =item psearch_cdrs OPTIONS
278 Returns a paged search (L<FS::PagedSearch>) for Call Detail Records
279 associated with this service. By default, "associated with" means that
280 the "charged_party" field of the CDR matches the "title" field of the
281 service. To access the CDRs themselves, call "->fetch" on the resulting
286 Accepts the following options:
288 =item for_update => 1: SELECT the CDRs "FOR UPDATE".
290 =item status => "" (or "done"): Return only CDRs with that processing status.
292 =item inbound => 1: No-op for svc_pbx CDR processing.
294 =item default_prefix => "XXX": Also accept the phone number of the service prepended
295 with the chosen prefix.
297 =item disable_src => 1: No-op for svc_pbx CDR processing.
299 =item by_svcnum => 1: Select CDRs where the svcnum field matches, instead of
300 title/charged_party. Normally this field is set after processing.
302 =item by_ip_addr => 'src' or 'dst': Select CDRs where the src_ip_addr or
303 dst_ip_addr field matches title. In this case, some special logic is applied
304 to allow title to indicate a range of IP addresses.
306 =item begin, end: Start and end of date range, as unix timestamp.
308 =item cdrtypenum: Only return CDRs with this type.
310 =item calltypenum: Only return CDRs with this call type.
317 my($self, %options) = @_;
321 my @fields = ( 'charged_party' );
322 $hash{'freesidestatus'} = $options{'status'}
323 if exists($options{'status'});
325 if ($options{'cdrtypenum'}) {
326 $hash{'cdrtypenum'} = $options{'cdrtypenum'};
328 if ($options{'calltypenum'}) {
329 $hash{'calltypenum'} = $options{'calltypenum'};
332 my $for_update = $options{'for_update'} ? 'FOR UPDATE' : '';
334 if ( $options{'by_svcnum'} ) {
335 $hash{'svcnum'} = $self->svcnum;
337 elsif ( $options{'by_ip_addr'} =~ /^src|dst$/) {
338 my $field = 'cdr.'.$options{'by_ip_addr'}.'_ip_addr';
339 push @where, FS::cdr->ip_addr_sql($field, $self->title);
343 my $title = $self->title;
345 my $prefix = $options{'default_prefix'};
347 my @orwhere = map " $_ = '$title' ", @fields;
348 push @orwhere, map " $_ = '$prefix$title' ", @fields
350 if ( $prefix =~ /^\+(\d+)$/ ) {
351 push @orwhere, map " $_ = '$1$title' ", @fields
354 push @where, ' ( '. join(' OR ', @orwhere ). ' ) ';
357 if ( $options{'begin'} ) {
358 push @where, 'startdate >= '. $options{'begin'};
360 if ( $options{'end'} ) {
361 push @where, 'startdate < '. $options{'end'};
364 my $extra_sql = ( keys(%hash) ? ' AND ' : ' WHERE ' ). join(' AND ', @where )
370 'extra_sql' => $extra_sql,
371 'order_by' => "ORDER BY startdate $for_update",
375 =item get_cdrs (DEPRECATED)
377 Like psearch_cdrs, but returns all the L<FS::cdr> objects at once, in a
378 single list. Arguments are the same as for psearch_cdrs. This can take
379 an unreasonably large amount of memory and is best avoided.
385 my $psearch = $self->psearch_cdrs($_);
386 qsearch ( $psearch->{query} )
391 Takes the same options as psearch_cdrs, but returns a single row containing
392 "count" (the number of CDRs) and the sums of the following fields: duration,
393 billsec, rated_price, rated_seconds, rated_minutes.
395 Note that if any calls are not rated, their rated_* fields will be null.
396 If you want to use those fields, pass the 'status' option to limit to
397 calls that have been rated. This is intentional; please don't "fix" it.
403 my $psearch = $self->psearch_cdrs(@_);
404 $psearch->{query}->{'select'} = join(',',
406 map { "SUM($_) AS $_" }
407 qw(duration billsec rated_price rated_seconds rated_minutes)
410 $psearch->{query}->{'extra_sql'} =~ s/ ORDER BY.*$//;
411 qsearchs ( $psearch->{query} );
420 L<FS::svc_Common>, L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>,
421 L<FS::cust_pkg>, schema.html from the base documentation.