summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/Schema.pm14
-rw-r--r--FS/FS/part_export/ikano.pm102
-rw-r--r--FS/FS/part_svc.pm11
-rw-r--r--FS/FS/svc_dsl.pm63
-rw-r--r--httemplate/edit/elements/edit.html5
-rw-r--r--httemplate/edit/elements/svc_Common.html7
-rwxr-xr-xhttemplate/edit/part_svc.cgi1
-rw-r--r--httemplate/edit/process/svc_dsl.html10
-rw-r--r--httemplate/edit/svc_dsl.cgi125
-rw-r--r--httemplate/view/elements/svc_Common.html10
-rw-r--r--httemplate/view/svc_dsl.cgi62
11 files changed, 401 insertions, 9 deletions
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 89f3c63..39b1ab7 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -1682,7 +1682,7 @@ sub tables_hashref {
'columns' => [
'qualnum', 'serial', '', '', '', '',
'contactnum', 'int', '', '', '', '',
- 'svctn', 'int', 'NULL', '', '', '',
+ 'svctn', 'varchar', 'NULL', 24, '', '',
'svcdb', 'varchar', '', $char_d, '', '',
'vendor_qual_id', 'varchar', 'NULL', $char_d, '', '',
'status', 'char', '', 1, '', '',
@@ -1837,16 +1837,16 @@ sub tables_hashref {
'columns' => [
'svcnum', 'int', '', '', '', '',
'pushed', 'int', 'NULL', '', '', '',
- 'desired_dd', 'int', '', '', '', '',
+ 'desired_dd', 'int', 'NULL', '', '', '',
'dd', 'int', 'NULL', '', '', '',
'vendor_order_id', 'varchar', 'NULL', $char_d, '', '',
'vendor_qual_id', 'varchar', 'NULL', $char_d, '', '',
- 'vendor_order_type', 'char', '', 1, '', '',
+ 'vendor_order_type', 'char', 'NULL', 1, '', '',
'vendor_order_status', 'char', 'NULL', 1, '', '',
- 'first', 'varchar', '', $char_d, '', '',
- 'last', 'varchar', '', $char_d, '', '',
+ 'first', 'varchar', 'NULL', $char_d, '', '',
+ 'last', 'varchar', 'NULL', $char_d, '', '',
'company', 'varchar', 'NULL', $char_d, '', '',
- 'svctn', 'int', 'NULL', '', '', '',
+ 'svctn', 'varchar', 'NULL', 24, '', '',
'loop_type', 'char', 'NULL', 1, '', '',
'lvp', 'varchar', 'NULL', $char_d, '', '',
'cktnum', 'varchar', 'NULL', $char_d, '', '',
@@ -1856,7 +1856,7 @@ sub tables_hashref {
'username', 'varchar', 'NULL', $char_d, '', '',
'password', 'varchar', 'NULL', $char_d, '', '',
'staticips', 'text', 'NULL', '', '', '',
- 'monitored', 'char', '', 1, '', '',
+ 'monitored', 'char', 'NULL', 1, '', '',
'last_pull', 'int', 'NULL', '', '', '',
'notes', 'text', 'NULL', '', '', '',
],
diff --git a/FS/FS/part_export/ikano.pm b/FS/FS/part_export/ikano.pm
new file mode 100644
index 0000000..c44db64
--- /dev/null
+++ b/FS/FS/part_export/ikano.pm
@@ -0,0 +1,102 @@
+package FS::part_export::ikano;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use Date::Format qw( time2str );
+use FS::Record qw(qsearch dbh);
+use FS::part_export;
+use FS::svc_dsl;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'keyid' => { label=>'Ikano keyid' },
+ 'username' => { label=>'Ikano username',
+ default => 'admin',
+ },
+ 'password' => { label=>'Ikano password' },
+ 'check_networks' => { label => 'Check Networks',
+ default => 'ATT,BELLCA',
+ },
+;
+
+%info = (
+ 'svc' => 'svc_dsl',
+ 'desc' => 'Provision DSL to Ikano',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Requires installation of
+<a href="http://search.cpan.org/dist/Net-Ikano">Net::Ikano</a> from CPAN.
+END
+);
+
+sub rebless { shift; }
+
+sub dsl_pull {
+ '';
+}
+
+sub status_line {
+ my($svc_dsl,$date_format,$separator) = (shift,shift,shift);
+ my %orderTypes = ( 'N' => 'New', 'X' => 'Cancel', 'C' => 'Change' );
+ my %orderStatus = ( 'N' => 'New', 'P' => 'Pending', 'X' => 'Cancelled',
+ 'C' => 'Completed', 'E' => 'Error' );
+ my $status = "Ikano ".$orderTypes{$svc_dsl->vendor_order_type}." order #"
+ . $svc_dsl->vendor_order_id . " (Status: "
+ . $orderStatus{$svc_dsl->vendor_order_status} . ") $separator ";
+ my $monitored = $svc_dsl->monitored eq 'Y' ? 'Yes' : 'No';
+ my $pushed = $svc_dsl->pushed ?
+ time2str("$date_format %k:%M",$svc_dsl->pushed) : "never";
+ my $last_pull = $svc_dsl->last_pull ?
+ time2str("$date_format %k:%M",$svc_dsl->last_pull) : "never";
+ my $ddd = $svc_dsl->desired_dd ? time2str($date_format,$svc_dsl->desired_dd)
+ : "";
+ my $dd = $svc_dsl->dd ? time2str($date_format,$svc_dsl->dd) : "";
+ $status .= "$separator Pushed: $pushed Monitored: $monitored Last Pull: ";
+ $status .= "$lastpull $separator $separator Desired Due Date: $ddd ";
+ $status .= "Due Date: $dd";
+ return $status;
+}
+
+sub ikano_command {
+ my( $self, $command, @args ) = @_;
+
+ eval "use Net::Ikano;";
+ die $@ if $@;
+
+ my $ikano = Net::Ikano->new(
+ 'keyid' => $self->option('keyid'),
+ 'username' => $self->option('username'),
+ 'password' => $self->option('password'),
+ #'debug' => 1,
+ );
+
+ $ikano->$command(@args);
+}
+
+sub _export_insert {
+ my( $self, $svc_dsl ) = (shift, shift);
+ '';
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+ '';
+}
+
+sub _export_delete {
+ my( $self, $svc_dsl ) = (shift, shift);
+ '';
+}
+
+sub _export_suspend {
+ my( $self, $svc_dsl ) = (shift, shift);
+ '';
+}
+
+sub _export_unsuspend {
+ my( $self, $svc_dsl ) = (shift, shift);
+ '';
+}
+
+1;
diff --git a/FS/FS/part_svc.pm b/FS/FS/part_svc.pm
index 3ed153e..164bad0 100644
--- a/FS/FS/part_svc.pm
+++ b/FS/FS/part_svc.pm
@@ -459,6 +459,17 @@ sub part_export_did {
grep $_->can('get_dids'), $self->part_export;
}
+=item part_export_dsl_pull
+
+Returns a list of any exports (see L<FS::part_export>) for this service that
+are capable of pulling/pushing DSL orders.
+
+=cut
+
+sub part_export_dsl_pull {
+ my $self = shift;
+ grep $_->can('dsl_pull'), $self->part_export;
+}
=item cust_svc [ PKGPART ]
diff --git a/FS/FS/svc_dsl.pm b/FS/FS/svc_dsl.pm
index 0b4b0d1..2e84dea 100644
--- a/FS/FS/svc_dsl.pm
+++ b/FS/FS/svc_dsl.pm
@@ -155,8 +155,71 @@ points to. You can ask the object for a copy with the I<hash> method.
# the new method can be inherited from FS::Record, if a table method is defined
+sub table_info {
+ my %dis1 = ( disable_default=>1, disable_fixed=>1, disable_inventory=>1, disable_select=>1 );
+ my %dis2 = ( disable_inventory=>1, disable_select=>1 );
+
+ {
+ 'name' => 'DSL',
+ 'sorts' => [ 'svctn' ],
+ 'display_weight' => 55,
+ 'cancel_weight' => 75,
+ 'fields' => {
+ 'pushed' => { label => 'Pushed',
+ type => 'disabled' },
+ 'desired_dd' => { label => 'Desired Due Date', %dis2, },
+ 'dd' => { label => 'Due Date', %dis2, },
+ 'vendor_order_id' => { label => 'Vendor Order Id', %dis2, },
+ 'vendor_qual_id' => { label => 'Vendor Qualification Id',
+ type => 'disabled' },
+ 'vendor_order_type' => { label => 'Vendor Order Type',
+ disable_inventory => 1,
+ },
+ 'vendor_order_status' => { label => 'Vendor Order Status',
+ disable_inventory => 1,
+ },
+ 'first' => { label => 'First Name', %dis2, },
+ 'last' => { label => 'Last Name', %dis2, },
+ 'company' => { label => 'Company Name', %dis2, },
+ 'svctn' => { label => 'Service Telephone Number', },
+ 'loop_type' => { label => 'Loop Type',
+ disable_inventory => 1,
+ },
+ 'lvp' => { label => 'Local Voice Provider',
+ disable_inventory => 1,
+ },
+ 'cktnum' => { label => 'Circuit #', },
+ 'rate_band' => { label => 'Rate Band',
+ disable_inventory => 1,
+ },
+ 'isp_chg' => { label => 'ISP Changing?',
+ type => 'checkbox', %dis2 },
+ 'isp_prev' => { label => 'Current or Previous ISP',
+ disable_inventory => 1,
+ },
+ 'username' => { label => 'PPPoE Username',
+ type => 'text',
+ },
+ 'password' => { label => 'PPPoE Password', %dis2 },
+ 'staticips' => { label => 'Static IPs', %dis1 },
+ 'monitored' => { label => 'Monitored',
+ type => 'checkbox', %dis2 },
+ 'last_pull' => { label => 'Last Pull', type => 'disabled' },
+ 'notes' => { label => 'Order Notes', %dis1 },
+ },
+ };
+}
+
sub table { 'svc_dsl'; }
+sub label {
+ my $self = shift;
+ return $self->svctn if $self->svctn;
+ return $self->username if $self->username;
+ return $self->vendor_order_id if $self->vendor_order_id;
+ return $self->svcnum;
+}
+
=item insert
Adds this record to the database. If there is an error, returns the error,
diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html
index 3d82847..142d0c3 100644
--- a/httemplate/edit/elements/edit.html
+++ b/httemplate/edit/elements/edit.html
@@ -311,6 +311,11 @@ Example:
% foreach grep exists($f->{$_}),
% qw( hashref agent_virt agent_null agent_null_right );
%
+% # fixed
+% $include_common{$_} = $f->{$_}
+% foreach grep exists($f->{$_}),
+% qw( formatted_value );
+%
% #htmlarea
% $include_common{$_} = $f->{$_}
% foreach grep exists($f->{$_}), qw( width height );
diff --git a/httemplate/edit/elements/svc_Common.html b/httemplate/edit/elements/svc_Common.html
index e74f442..2e27f85 100644
--- a/httemplate/edit/elements/svc_Common.html
+++ b/httemplate/edit/elements/svc_Common.html
@@ -29,6 +29,13 @@
die "No part_svc entry!" unless $part_svc;
label_fixup($part_svc, $opt);
+
+ if ( my $cb = $opt{'svc_edit_callback'} ) {
+ my $cust_pkg = $pkgnum
+ ? qsearchs('cust_pkg', {pkgnum=>$pkgnum})
+ : ''; #?
+ &{ $cb }( $cgi,$svc_x, $part_svc,$cust_pkg, $fields,$opt);
+ }
},
'new_hashref_callback' => sub {
diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi
index 50bc79c..d156ccd 100755
--- a/httemplate/edit/part_svc.cgi
+++ b/httemplate/edit/part_svc.cgi
@@ -16,6 +16,7 @@ Service definitions are the templates for items you offer to your customers.
<UL><LI>svc_acct - Accounts - anything with a username (Mailboxes, PPP accounts, shell accounts, RADIUS entries for broadband, etc.)
<LI>svc_domain - Domains
<LI>svc_cert - Certificates
+ <LI>svc_dsl - DSL
<LI>svc_forward - Mail forwarding
<LI>svc_mailinglist - Mailing list
<LI>svc_www - Virtual domain website
diff --git a/httemplate/edit/process/svc_dsl.html b/httemplate/edit/process/svc_dsl.html
new file mode 100644
index 0000000..627329a
--- /dev/null
+++ b/httemplate/edit/process/svc_dsl.html
@@ -0,0 +1,10 @@
+<% include( 'elements/svc_Common.html',
+ 'table' => 'svc_dsl',
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific?
+
+</%init>
diff --git a/httemplate/edit/svc_dsl.cgi b/httemplate/edit/svc_dsl.cgi
new file mode 100644
index 0000000..3568fbd
--- /dev/null
+++ b/httemplate/edit/svc_dsl.cgi
@@ -0,0 +1,125 @@
+<% include( 'elements/svc_Common.html',
+ 'table' => 'svc_dsl',
+ 'fields' => \@fields,
+ 'svc_new_callback' => $new_cb,
+ 'svc_edit_callback' => $edit_cb,
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific?
+
+my $conf = new FS::Conf;
+my $date_format = $conf->config('date_format') || '%m/%d/%Y';
+
+my $ti_fields = FS::svc_dsl->table_info->{'fields'};
+
+my @fields = ();
+my @uneditable = qw( pushed vendor_qual_id isp_chg isp_prev staticips last_pull notes );
+
+my $edit_cb = sub {
+ my( $cgi,$svc_x, $part_svc,$cust_pkg, $fields1,$opt) = @_;
+ my @exports = $part_svc->part_export_dsl_pull;
+ die "more than one DSL-pulling export attached to svcpart ".$part_svc->svcpart
+ if ( scalar(@exports) > 1 );
+
+ if ( scalar(@exports) == 1 ) {
+ my $export = @exports[0];
+ if($export->exporttype eq 'ikano') {
+ @fields = ( 'password', 'monitored', );
+
+ foreach my $hf ( keys %$ti_fields ) {
+ push @fields, {
+ field => $hf,
+ type => 'hidden',
+ value => $svc_x->$hf,
+ } unless ( $hf eq 'password' || $hf eq 'monitored' );
+ }
+ }
+ else {
+ # XXX
+ }
+ }
+ else {
+ # XXX
+ }
+};
+
+my $new_cb = sub {
+ my( $cgi,$svc_x, $part_svc,$cust_pkg, $fields1,$opt) = @_;
+ my @exports = $part_svc->part_export_dsl_pull;
+ die "more than one DSL-pulling export attached to svcpart ".$part_svc->svcpart
+ if ( scalar(@exports) > 1 );
+
+ if ( scalar(@exports) == 1 ) {
+ my $cust_main = $cust_pkg->cust_main;
+ my $defsvctn = $cust_main->ship_daytime ? $cust_main->ship_daytime
+ : $cust_main->daytime;
+ $defsvctn =~ s/[^0-9]//g;
+
+ @fields = (
+ { field => 'first',
+ value => $cust_main->ship_first ? $cust_main->ship_first
+ : $cust_main->first,
+ },
+ { field => 'last',
+ value => $cust_main->ship_last ? $cust_main->ship_last
+ : $cust_main->last,
+ },
+ { field => 'company',
+ value => $cust_pkg->cust_main->ship_company,
+ value => $cust_main->ship_company ? $cust_main->ship_company
+ : $cust_main->company,
+ },
+ { field => 'svctn',
+ value => $defsvctn,
+ },
+ );
+
+ my $loop_type = { field => 'loop_type' };
+
+ my $export = @exports[0];
+ if($export->exporttype eq 'ikano') {
+ $cgi->param('vendor_qual_id') =~ /^(\d+)$/
+ or die 'unparsable vendor_qual_id';
+ my $vendor_qual_id = $1;
+
+ die "no start date set on customer package" if !$cust_pkg->start_date;
+
+ $loop_type = { field => 'loop_type',
+ type => 'select',
+ options => [ '', '0' ],
+ labels => { '' => 'Line-share', '0', => 'Standalone' },
+ # onchange => "document.getElementById('svctn').value = ''",
+ };
+ push @fields, { field => 'isp_chg', type => 'checkbox', };
+ push @fields, 'isp_prev';
+ push @fields, { field => 'vendor_qual_id',
+ type => 'fixed',
+ value => $vendor_qual_id,
+ };
+ }
+ else {
+ push @fields, 'username';
+ }
+
+ push @fields, 'password';
+
+ push @fields, $loop_type;
+
+ push @fields, { field => 'vendor_order_type',
+ type => 'hidden',
+ value => 'N' };
+ push @fields, { field => 'desired_dd',
+ type => 'fixed',
+ formatted_value =>
+ time2str($date_format,$cust_pkg->start_date),
+ value => $cust_pkg->start_date,
+ };
+ }
+ else {
+ # XXX
+ }
+};
+</%init>
diff --git a/httemplate/view/elements/svc_Common.html b/httemplate/view/elements/svc_Common.html
index 618d33e..25845dd 100644
--- a/httemplate/view/elements/svc_Common.html
+++ b/httemplate/view/elements/svc_Common.html
@@ -52,18 +52,22 @@ function areyousure(href) {
Service #<B><% $svcnum %></B>
% my $url = $opt{'edit_url'} || $p. 'edit/'. $opt{'table'}. '.cgi?';
| <A HREF="<%$url%><%$svcnum%>">Edit this <% $label %></A>
+
+% unless ( $opt{'disable_unprovision'} ) {
| <A HREF="javascript:areyousure('<%$p.'misc/unprovision.cgi?'.$svcnum%>')">
Unprovision this Service</A>
<BR>
+% }
<% ntable("#cccccc") %><TR><TD><% ntable("#cccccc",2) %>
% foreach my $f ( @$fields ) {
%
-% my($field, $type, $value);
+% my($field, $type, $value, $hack_strict_refs);
% if ( ref($f) ) {
% $field = $f->{'field'},
-% $value = $f->{'value'} ? &{ $f->{'value'} }($svc_x) : $svc_x->$field;
+% $hack_strict_refs = \&{ $f->{'value'} } if $f->{'value'};
+% $value = $f->{'value'} ? &$hack_strict_refs($svc_x) : $svc_x->$field;
% $type = $f->{'type'} || 'text',
% } else {
% $field = $f;
@@ -172,4 +176,6 @@ if ($pkgnum) {
$custnum = '';
}
+&{ $opt{'svc_callback'} }( $cgi, $svc_x, $part_svc, $cust_pkg, $fields, \%opt )
+ if $opt{'svc_callback'};
</%init>
diff --git a/httemplate/view/svc_dsl.cgi b/httemplate/view/svc_dsl.cgi
new file mode 100644
index 0000000..a4b2d43
--- /dev/null
+++ b/httemplate/view/svc_dsl.cgi
@@ -0,0 +1,62 @@
+<% include('elements/svc_Common.html',
+ 'table' => 'svc_dsl',
+ 'labels' => \%labels,
+ 'fields' => \@fields,
+ 'svc_callback' => $svc_cb,
+ 'html_foot' => $html_foot,
+ )
+%>
+<%init>
+my $conf = new FS::Conf;
+my $date_format = $conf->config('date_format') || '%m/%d/%Y';
+
+my $fields = FS::svc_dsl->table_info->{'fields'};
+my %labels = map { $_ => ( ref($fields->{$_})
+ ? $fields->{$_}{'label'}
+ : $fields->{$_}
+ );
+ } keys %$fields;
+my @fields = keys %$fields;
+
+my $footer;
+
+my $html_foot = sub {
+ return $footer;
+};
+
+my $svc_cb = sub {
+ my( $cgi,$svc_x, $part_svc,$cust_pkg, $fields1,$opt) = @_;
+
+ my @exports = $part_svc->part_export_dsl_pull;
+ die "more than one DSL-pulling export attached to svcpart ".$part_svc->svcpart
+ if ( scalar(@exports) > 1 );
+
+ # if no DSL-pulling exports, then just display everything, which is the
+ # default behaviour implemented above
+ return if ( scalar(@exports) == 0 );
+
+ $opt->{'disable_unprovision'} = 1;
+ my $exporttype = @exports[0]->exporttype;
+
+ # XXX: AJAX auto-pull
+
+ @fields = qw( svctn first last company username password );
+
+ if($exporttype eq 'ikano') {
+ push @fields, 'isp_chg';
+ push @fields, 'isp_prev';
+ push @fields, 'staticips';
+ }
+ else {
+ # XXX
+ }
+
+ # hack against "can't use string ... as a subroutine ref while 'strict refs' in use"
+ my $statusSub = \&{'FS::part_export::'.$exporttype.'::status_line'};
+ my $statusLine = &$statusSub($svc_x,$date_format,"<BR>");
+
+ $footer = "<B>$statusLine</B>";
+
+ # XXX: notes
+};
+</%init>