summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/Schema.pm8
-rw-r--r--FS/FS/svc_Common.pm99
-rw-r--r--FS/FS/svc_acct.pm76
-rw-r--r--FS/FS/svc_pbx.pm16
-rw-r--r--FS/FS/svc_phone.pm11
-rw-r--r--httemplate/edit/elements/edit.html8
-rw-r--r--httemplate/edit/elements/svc_Common.html10
-rwxr-xr-xhttemplate/edit/part_svc.cgi10
-rwxr-xr-xhttemplate/edit/svc_acct.cgi9
-rw-r--r--httemplate/edit/svc_phone.cgi5
-rw-r--r--httemplate/elements/select-svc_pbx.html57
-rw-r--r--httemplate/elements/tr-select-svc_pbx.html60
-rwxr-xr-xhttemplate/view/svc_acct.cgi7
-rw-r--r--httemplate/view/svc_phone.cgi2
14 files changed, 355 insertions, 23 deletions
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 0ffc5bd..8d35c68 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -1586,14 +1586,15 @@ sub tables_hashref {
'downbytes_threshold', 'bigint', 'NULL', '', '', '',
'totalbytes','bigint', 'NULL', '', '', '',
'totalbytes_threshold', 'bigint', 'NULL', '', '', '',
- 'domsvc', 'int', '', '', '', '',
+ 'domsvc', 'int', '', '', '', '',
+ 'pbxsvc', 'int', 'NULL', '', '', '',
'last_login', @date_type, '', '',
'last_logout', @date_type, '', '',
],
'primary_key' => 'svcnum',
#'unique' => [ [ 'username', 'domsvc' ] ],
'unique' => [],
- 'index' => [ ['username'], ['domsvc'] ],
+ 'index' => [ ['username'], ['domsvc'], ['pbxsvc'] ],
},
'acct_rt_transaction' => {
@@ -2514,10 +2515,11 @@ sub tables_hashref {
'pin', 'varchar', 'NULL', $char_d, '', '',
'sip_password', 'varchar', 'NULL', $char_d, '', '',
'phone_name', 'varchar', 'NULL', $char_d, '', '',
+ 'pbxsvc', 'int', 'NULL', '', '', '',
],
'primary_key' => 'svcnum',
'unique' => [],
- 'index' => [ [ 'countrycode', 'phonenum' ] ],
+ 'index' => [ [ 'countrycode', 'phonenum' ], ['pbxsvc'] ],
},
'phone_device' => {
diff --git a/FS/FS/svc_Common.pm b/FS/FS/svc_Common.pm
index a67504a..9b2cf7b 100644
--- a/FS/FS/svc_Common.pm
+++ b/FS/FS/svc_Common.pm
@@ -586,6 +586,105 @@ sub part_svc {
}
+=item svc_pbx
+
+Returns the FS::svc_pbx record for this service, if any (see L<FS::svc_pbx>).
+
+Only makes sense if the service has a pbxsvc field (currently, svc_phone and
+svc_acct).
+
+=cut
+
+# XXX FS::h_svc_{acct,phone} could have a history-aware svc_pbx override
+
+sub svc_pbx {
+ my $self = shift;
+ return '' unless $self->pbxsvc;
+ qsearchs( 'svc_pbx', { 'svcnum' => $self->pbxsvc } );
+}
+
+=item pbx_title
+
+Returns the title of the FS::svc_pbx record associated with this service, if
+any.
+
+Only makes sense if the service has a pbxsvc field (currently, svc_phone and
+svc_acct).
+
+=cut
+
+sub pbx_title {
+ my $self = shift;
+ my $svc_pbx = $self->svc_pbx or return '';
+ $svc_pbx->title;
+}
+
+=item pbx_select_hash %OPTIONS
+
+Can be called as an object method or a class method.
+
+Returns a hash SVCNUM => TITLE ... representing the PBXes this customer
+that may be associated with this service.
+
+Currently available options are: I<pkgnum> I<svcpart>
+
+Only makes sense if the service has a pbxsvc field (currently, svc_phone and
+svc_acct).
+
+=cut
+
+#false laziness w/svc_acct::domain_select_hash
+sub pbx_select_hash {
+ my ($self, %options) = @_;
+ my %pbxes = ();
+ my $part_svc;
+ my $cust_pkg;
+
+ if (ref($self)) {
+ $part_svc = $self->part_svc;
+ $cust_pkg = $self->cust_svc->cust_pkg
+ if $self->cust_svc;
+ }
+
+ $part_svc = qsearchs('part_svc', { 'svcpart' => $options{svcpart} })
+ if $options{'svcpart'};
+
+ $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $options{pkgnum} })
+ if $options{'pkgnum'};
+
+ if ($part_svc && ( $part_svc->part_svc_column('pbxsvc')->columnflag eq 'S'
+ || $part_svc->part_svc_column('pbxsvc')->columnflag eq 'F')) {
+ %pbxes = map { $_->svcnum => $_->title }
+ map { qsearchs('svc_pbx', { 'svcnum' => $_ }) }
+ split(',', $part_svc->part_svc_column('pbxsvc')->columnvalue);
+ } elsif ($cust_pkg) { # && !$conf->exists('svc_acct-alldomains') ) {
+ %pbxes = map { $_->svcnum => $_->title }
+ map { qsearchs('svc_pbx', { 'svcnum' => $_->svcnum }) }
+ map { qsearch('cust_svc', { 'pkgnum' => $_->pkgnum } ) }
+ qsearch('cust_pkg', { 'custnum' => $cust_pkg->custnum });
+ } else {
+ #XXX agent-virt
+ warn "hi";
+ %pbxes = map { $_->svcnum => $_->title } qsearch('svc_pbx', {} );
+ warn %pbxes;
+ }
+
+ if ($part_svc && $part_svc->part_svc_column('pbxsvc')->columnflag eq 'D') {
+ my $svc_pbx = qsearchs('svc_pbx',
+ { 'svcnum' => $part_svc->part_svc_column('pbxsvc')->columnvalue } );
+ if ( $svc_pbx ) {
+ $pbxes{$svc_pbx->svcnum} = $svc_pbx->title;
+ } else {
+ warn "unknown svc_pbx.svcnum for part_svc_column pbxsvc: ".
+ $part_svc->part_svc_column('pbxsvc')->columnvalue;
+
+ }
+ }
+
+ (%pbxes);
+
+}
+
=item set_auto_inventory
Sets any fields which auto-populate from inventory (see L<FS::part_svc>).
diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm
index e5fd582..ca33aa8 100644
--- a/FS/FS/svc_acct.pm
+++ b/FS/FS/svc_acct.pm
@@ -38,6 +38,7 @@ use FS::part_svc;
use FS::svc_acct_pop;
use FS::cust_main_invoice;
use FS::svc_domain;
+use FS::svc_pbx;
use FS::raddb;
use FS::queue;
use FS::radius_usergroup;
@@ -161,45 +162,71 @@ FS::svc_Common. The following fields are currently supported:
=over 4
-=item svcnum - primary key (assigned automatcially for new accounts)
+=item svcnum
+
+Primary key (assigned automatcially for new accounts)
=item username
-=item _password - generated if blank
+=item _password
+
+generated if blank
+
+=item _password_encoding
+
+plain, crypt, ldap (or empty for autodetection)
-=item _password_encoding - plain, crypt, ldap (or empty for autodetection)
+=item sec_phrase
-=item sec_phrase - security phrase
+security phrase
-=item popnum - Point of presence (see L<FS::svc_acct_pop>)
+=item popnum
+
+Point of presence (see L<FS::svc_acct_pop>)
=item uid
=item gid
-=item finger - GECOS
+=item finger
+
+GECOS
+
+=item dir
-=item dir - set automatically if blank (and uid is not)
+set automatically if blank (and uid is not)
=item shell
-=item quota - (unimplementd)
+=item quota
-=item slipip - IP address
+=item slipip
-=item seconds -
+IP address
+
+=item seconds
+
+=item upbytes
+
+=item downbyte
+
+=item totalbytes
+
+=item domsvc
-=item upbytes -
+svcnum from svc_domain
-=item downbytes -
+=item pbxsvc
-=item totalbytes -
+Optional svcnum from svc_pbx
-=item domsvc - svcnum from svc_domain
+=item radius_I<Radius_Attribute>
-=item radius_I<Radius_Attribute> - I<Radius-Attribute> (reply)
+I<Radius-Attribute> (reply)
-=item rc_I<Radius_Attribute> - I<Radius-Attribute> (check)
+=item rc_I<Radius_Attribute>
+
+I<Radius-Attribute> (check)
=back
@@ -275,6 +302,20 @@ sub table_info {
disable_inventory => 1,
},
+ 'domsvc' => {
+ label => 'Domain',
+ type => 'select',
+ select_table => 'svc_domain',
+ select_key => 'svcnum',
+ select_label => 'domain',
+ disable_inventory => 1,
+
+ },
+ 'pbxsvc' => { label => 'PBX',
+ type => 'select-svc_pbx.html',
+ disable_inventory => 1,
+ disable_select => 1, #UI wonky, pry works otherwise
+ },
'usergroup' => {
label => 'RADIUS groups',
type => 'radius_usergroup_selector',
@@ -1011,7 +1052,8 @@ sub check {
my $error = $self->ut_numbern('svcnum')
#|| $self->ut_number('domsvc')
- || $self->ut_foreign_key('domsvc', 'svc_domain', 'svcnum' )
+ || $self->ut_foreign_key( 'domsvc', 'svc_domain', 'svcnum' )
+ || $self->ut_foreign_keyn('pbxsvc', 'svc_pbx', 'svcnum' )
|| $self->ut_textn('sec_phrase')
|| $self->ut_snumbern('seconds')
|| $self->ut_snumbern('upbytes')
diff --git a/FS/FS/svc_pbx.pm b/FS/FS/svc_pbx.pm
index f4ecc04..49509b5 100644
--- a/FS/FS/svc_pbx.pm
+++ b/FS/FS/svc_pbx.pm
@@ -37,7 +37,21 @@ FS::svc_Common. The following fields are currently supported:
=over 4
-=item field - description
+=item svcnum
+
+Primary key (assigned automatcially for new accounts)
+
+=item id
+
+(Unique?) number of external record
+
+=item title
+
+PBX name
+
+=item max_extensions
+
+Maximum number of extensions
=back
diff --git a/FS/FS/svc_phone.pm b/FS/FS/svc_phone.pm
index 88582d3..071b807 100644
--- a/FS/FS/svc_phone.pm
+++ b/FS/FS/svc_phone.pm
@@ -8,6 +8,7 @@ use FS::Msgcat qw(gettext);
use FS::svc_Common;
use FS::part_svc;
use FS::phone_device;
+use FS::svc_pbx;
@ISA = qw( FS::svc_Common );
@@ -67,6 +68,10 @@ Voicemail PIN
=item phone_name
+=item pbxsvc
+
+Optional svcnum from svc_pbx
+
=back
=head1 METHODS
@@ -104,6 +109,11 @@ sub table_info {
},
'sip_password' => 'SIP password',
'phone_name' => 'Name',
+ 'pbxsvc' => { label => 'PBX',
+ type => 'select-svc_pbx.html',
+ disable_inventory => 1,
+ disable_select => 1, #UI wonky, pry works otherwise
+ },
},
};
}
@@ -258,6 +268,7 @@ sub check {
|| $self->ut_anything('sip_password')
|| $self->ut_numbern('pin')
|| $self->ut_textn('phone_name')
+ || $self->ut_foreign_keyn('pbxsvc', 'svc_pbx', 'svcnum' )
;
return $error if $error;
diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html
index 43b7afe..4fe32c1 100644
--- a/httemplate/edit/elements/edit.html
+++ b/httemplate/edit/elements/edit.html
@@ -40,6 +40,10 @@ Example:
'disabled' => 0,
'onchange' => 'javascript_function',
+ 'include_opt_callback' => sub { #my $ = @_;
+ ( 'option' => 'value', );
+ },
+
'm2name_table' => 'table_name',
'm2name_namecol' => 'name_column',
#OR#
@@ -294,6 +298,10 @@ Example:
% $include_common{'colspan'} = $f->{colspan} if $f->{colspan};
% }
%
+% if ( $f->{include_opt_callback} ) {
+% %include_common = ( %include_common, &{ $f->{include_opt_callback} } );
+% }
+%
% my $layer_prefix_on = '';
%
% my $include_sub = sub {
diff --git a/httemplate/edit/elements/svc_Common.html b/httemplate/edit/elements/svc_Common.html
index ef04bd0..31d4739 100644
--- a/httemplate/edit/elements/svc_Common.html
+++ b/httemplate/edit/elements/svc_Common.html
@@ -54,6 +54,7 @@
'field_callback' => sub {
my ($cgi, $object, $f) = @_;
+
my $columndef = $part_svc->part_svc_column($f->{'field'});
my $flag = $columndef->columnflag;
if ( $flag eq 'F' ) {
@@ -62,6 +63,15 @@
: 'hidden';
$f->{'value'} = $columndef->columnvalue;
}
+
+ if ( $f->{'type'} eq 'select-svc_pbx' ) {
+ $f->{'include_opt_callback'} =
+ sub { ( 'pkgnum' => $pkgnum,
+ 'svcpart' => $svcpart,
+ );
+ };
+ }
+
},
'html_init' => sub {
diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi
index 20bc277..d74e0f2 100755
--- a/httemplate/edit/part_svc.cgi
+++ b/httemplate/edit/part_svc.cgi
@@ -289,6 +289,14 @@ that field.
% } #endif
% $html .= '</SELECT>';
%
+% } elsif ( $def->{type} eq 'select-svc_pbx.html' ) {
+%
+% $html .= include('/elements/select-svc_pbx.html',
+% 'element_name' => "${layer}__${field}",
+% 'element_etc' => $disabled,
+% 'multiple' => ($flag eq 'S'),
+% );
+%
% } elsif ( $def->{type} eq 'radius_usergroup_selector' ) {
%
% #XXX disable the RADIUS usergroup selector? ugh it sure does need
@@ -304,7 +312,7 @@ that field.
%
% } else {
%
-% $html .= '<font color="#ff0000">unknown type'. $def->{type};
+% $html .= '<font color="#ff0000">unknown type '. $def->{type};
%
% }
%
diff --git a/httemplate/edit/svc_acct.cgi b/httemplate/edit/svc_acct.cgi
index afbd002..2845c83 100755
--- a/httemplate/edit/svc_acct.cgi
+++ b/httemplate/edit/svc_acct.cgi
@@ -122,7 +122,14 @@ Service # <% $svcnum ? "<B>$svcnum</B>" : " (NEW)" %><BR>
</TD>
</TR>
% }
-%
+
+<% include('/elements/tr-select-svc_pbx.html',
+ 'curr_value' => $svc_acct->pbxsvc,
+ 'part_svc' => $part_svc,
+ 'cust_pkg' => $cust_pkg,
+ )
+%>
+
%#pop
%my $popnum = $svc_acct->popnum || 0;
%if ( $part_svc->part_svc_column('popnum')->columnflag eq 'F' ) {
diff --git a/httemplate/edit/svc_phone.cgi b/httemplate/edit/svc_phone.cgi
index d7629ab..55ee890 100644
--- a/httemplate/edit/svc_phone.cgi
+++ b/httemplate/edit/svc_phone.cgi
@@ -6,6 +6,10 @@
type => 'select-did',
label => 'Phone number',
},
+ { field => 'pbxsvc',
+ type => 'select-svc_pbx',
+ label => 'PBX',
+ },
'sip_password',
'pin',
'phone_name',
@@ -16,6 +20,7 @@
'sip_password' => 'SIP password',
'pin' => 'Voicemail PIN',
'phone_name' => 'Name',
+ 'pbxsvc' => 'PBX',
},
)
%>
diff --git a/httemplate/elements/select-svc_pbx.html b/httemplate/elements/select-svc_pbx.html
new file mode 100644
index 0000000..19bce96
--- /dev/null
+++ b/httemplate/elements/select-svc_pbx.html
@@ -0,0 +1,57 @@
+<SELECT <% $opt{'multiple'} ? 'MULTIPLE' : 'SIZE=1' %>
+ NAME = "<% $opt{'element_name'} || $opt{'field'} || 'pbxsvc' %>"
+ <% $opt{'element_etc'} %>
+>
+
+% unless ( $opt{'multiple'} || $opt{'disable_empty'} ) {
+ <OPTION VALUE=""><% $opt{'empty_label'} || '' %>
+% }
+
+% foreach my $svcnum (
+% sort { $svc_pbx{$a} cmp $svc_pbx{$b} }
+% keys %svc_pbx
+% ) {
+% my $svc_pbx = $svc_pbx{$svcnum};
+% my $selected = ($svcnum == $pbxsvc) ? ' SELECTED' : '';
+
+ <OPTION VALUE="<% $svcnum %>" <% $selected %>><% $svc_pbx{$svcnum} %>
+
+% }
+
+</SELECT>
+<%init>
+
+# false laziness w/select-svc_acct-domain.html
+
+my %opt = @_;
+
+my $pbxsvc = $opt{'curr_value'};
+my $part_svc = $opt{'part_svc'}
+ || qsearchs('part_svc', { 'svcpart' => $opt{'svcpart'} });
+my $svcpart = $part_svc ? $part_svc->svcpart : '';
+
+#optional
+my $cust_pkg = $opt{'cust_pkg'};
+$cust_pkg ||= qsearchs('cust_pkg', { 'pkgnum' => $opt{'pkgnum'} })
+ if $opt{'pkgnum'};
+
+my $pkgnum = $cust_pkg ? $cust_pkg->pkgnum : '';
+
+my %svc_pbx = ();
+
+if ( $pbxsvc ) {
+ my $svc_pbx = qsearchs('svc_pbx', { 'svcnum' => $pbxsvc } );
+ if ( $svc_pbx ) {
+ $svc_pbx{$svc_pbx->svcnum} = $svc_pbx;
+ } else {
+ warn "unknown svc_pbx.svcnum for svc_acct.pbxsvc: $pbxsvc";
+ }
+}
+
+%svc_pbx = (
+ %svc_pbx,
+ FS::svc_Common->pbx_select_hash( 'svcpart' => $svcpart,
+ 'pkgnum' => $pkgnum,
+ )
+);
+</%init>
diff --git a/httemplate/elements/tr-select-svc_pbx.html b/httemplate/elements/tr-select-svc_pbx.html
new file mode 100644
index 0000000..b02bd65
--- /dev/null
+++ b/httemplate/elements/tr-select-svc_pbx.html
@@ -0,0 +1,60 @@
+%if ( $columnflag eq 'F' || !keys(%svc_pbx) ) {
+ <INPUT TYPE="hidden" NAME="<% $opt{'element_name'} || $opt{'field'} || 'pbxsvc' %>" VALUE="<% $pbxsvc %>">
+% } else {
+
+ <TR>
+ <TD ALIGN="right"><% $opt{'label'} || 'PBX' %></TD>
+ <TD>
+ <% include('/elements/select-svc_pbx.html',
+ 'curr_value' => $pbxsvc,
+ 'part_svc' => $part_svc,
+ 'cust_pkg' => $cust_pkg,
+ )
+ %>
+ </TD>
+ </TR>
+% }
+<%init>
+
+# false laziness w/tr-select-svc_acct-domain.html
+
+my %opt = @_;
+
+my $pbxsvc = $opt{'curr_value'};
+
+#required
+my $part_svc = $opt{'part_svc'}
+ || qsearchs('part_svc', { 'svcpart' => $opt{'svcpart'} });
+my $svcpart =
+ $part_svc ? $part_svc->svcpart : '';
+my $columnflag =
+ $part_svc ? $part_svc->part_svc_column('pbxsvc')->columnflag : '';
+
+#optional
+my $cust_pkg = $opt{'cust_pkg'};
+$cust_pkg ||= qsearchs('cust_pkg', { 'pkgnum' => $opt{'pkgnum'} })
+ if $opt{'pkgnum'};
+
+# false laziness w/select-svc_pbx.html
+
+my $pkgnum = $cust_pkg ? $cust_pkg->pkgnum : '';
+
+my %svc_pbx = ();
+
+if ( $pbxsvc ) {
+ my $svc_pbx = qsearchs('svc_pbx', { 'svcnum' => $pbxsvc } );
+ if ( $svc_pbx ) {
+ $svc_pbx{$svc_pbx->svcnum} = $svc_pbx;
+ } else {
+ warn "unknown svc_pbx.svcnum for svc_acct.pbxsvc: $pbxsvc";
+ }
+}
+
+%svc_pbx = (
+ %svc_pbx,
+ FS::svc_Common->pbx_select_hash( 'svcpart' => $svcpart,
+ 'pkgnum' => $pkgnum,
+ )
+);
+
+</%init>
diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi
index 44a2aa6..7e94df1 100755
--- a/httemplate/view/svc_acct.cgi
+++ b/httemplate/view/svc_acct.cgi
@@ -157,6 +157,13 @@ Service #<B><% $svcnum %></B>
<TD BGCOLOR="#ffffff"><% $domain %></TD>
</TR>
+% if ( $svc_acct->pbxsvc ) {
+ <TR>
+ <TD ALIGN="right">PBX</TD>
+ <TD BGCOLOR="#ffffff"><% $svc_acct->pbx_title %></TD>
+ </TR>
+%}
+
<TR>
<TD ALIGN="right">Password</TD>
<TD BGCOLOR="#ffffff">
diff --git a/httemplate/view/svc_phone.cgi b/httemplate/view/svc_phone.cgi
index c5fce62..59ee2d5 100644
--- a/httemplate/view/svc_phone.cgi
+++ b/httemplate/view/svc_phone.cgi
@@ -3,6 +3,7 @@
'fields' => [qw(
countrycode
phonenum
+ pbx_title
sip_password
pin
phone_name
@@ -10,6 +11,7 @@
'labels' => {
'countrycode' => 'Country code',
'phonenum' => 'Phone number',
+ 'pbx_title' => 'PBX',
'sip_password' => 'SIP password',
'pin' => 'PIN',
'phone_name' => 'Name',