1 package FS::part_export::ikano;
3 use vars qw(@ISA %info %orderType %orderStatus %loopType $DEBUG $me);
5 use Date::Format qw( time2str );
6 use FS::Record qw(qsearch qsearchs);
11 @ISA = qw(FS::part_export);
13 $me= '[' . __PACKAGE__ . ']';
15 tie my %options, 'Tie::IxHash',
16 'keyid' => { label=>'Ikano keyid' },
17 'username' => { label=>'Ikano username',
20 'password' => { label=>'Ikano password' },
21 'check_networks' => { label => 'Check Networks',
22 default => 'ATT,BELLCA',
28 'desc' => 'Provision DSL to Ikano',
29 'options' => \%options,
31 Requires installation of
32 <a href="http://search.cpan.org/dist/Net-Ikano">Net::Ikano</a> from CPAN.
36 %orderType = ( 'N' => 'New', 'X' => 'Cancel', 'C' => 'Change' );
37 %orderStatus = ('N' => 'New',
42 %loopType = ( '' => 'Line-share', '0' => 'Standalone' );
44 sub rebless { shift; }
58 sub loop_type_long { # sub, not a method
59 my($svc_dsl) = (shift);
60 return $loopType{$svc_dsl->loop_type};
64 my($self,$svc_dsl) = (shift,shift);
65 return "Ikano ".$orderType{$svc_dsl->vendor_order_type}." order #"
66 . $svc_dsl->vendor_order_id . " (Status: "
67 . $orderStatus{$svc_dsl->vendor_order_status} . ")";
71 my( $self, $command, $args ) = @_;
73 eval "use Net::Ikano;";
76 my $ikano = Net::Ikano->new(
77 'keyid' => $self->option('keyid'),
78 'username' => $self->option('username'),
79 'password' => $self->option('password'),
81 #'reqpreviewonly' => 1,
84 $ikano->$command($args);
88 my( $self, $svc_dsl, $action ) = (shift, shift, shift);
90 warn "$me valid_order action=$action svc_dsl: ". Dumper($svc_dsl) if $DEBUG;
92 # common to all order types/status/loop_type
93 my $error = !($svc_dsl->desired_dd
94 && defined $orderType{$svc_dsl->vendor_order_type}
97 && defined $svc_dsl->loop_type
98 && $svc_dsl->vendor_qual_id
100 return 'Missing or invalid order data' if $error;
102 return 'Package does not have an external id configured'
103 if $svc_dsl->cust_svc->cust_pkg->part_pkg->options('externalid',1) eq '';
105 return 'No valid qualification for this order'
106 unless qsearch( 'qual', { 'vendor_qual_id' => $svc_dsl->vendor_qual_id });
108 # now go by order type
109 # weird ifs & long lines for readability and ease of understanding - don't change
110 if($svc_dsl->vendor_order_type eq 'N') {
111 if($svc_dsl->pushed) {
113 else { # unpushed New order - cannot do anything other than push it
114 $error = !($action eq 'insert'
115 && length($svc_dsl->vendor_order_id) < 1
116 && length($svc_dsl->vendor_order_status) < 1
117 && ( ($svc_dsl->svctn eq '' && $svc_dsl->loop_type eq '0') # dry
118 || ($svc_dsl->svctn ne '' && $svc_dsl->loop_type eq '') # line-share
121 return 'Invalid order data' if $error;
124 elsif($svc_dsl->vendor_order_type eq 'X') {
126 elsif($svc_dsl->vendor_order_type eq 'C') {
133 my ($self,$vendor_qual_id) = (shift,shift);
134 my $qual = qsearchs( 'qual', { 'vendor_qual_id' => $vendor_qual_id });
135 return '' unless $qual;
136 my %qual_options = $qual->options;
137 foreach my $optionname ( keys %qual_options ) {
138 if ( $optionname =~ /^ikano_network_(\d+)_productgroup_(\d+)_termsid$/ ) {
139 return $qual_options{$optionname};
141 # XXX finish this properly - the above is wrong
147 my( $self, $svc_dsl ) = (shift, shift);
149 my $result = $self->valid_order($svc_dsl,'insert');
150 return $result unless $result eq '';
152 my $isp_chg = $svc_dsl->isp_chg eq 'Y' ? 'YES' : 'NO';
153 my $contactTN = $svc_dsl->cust_svc->cust_pkg->cust_main->daytime;
154 $contactTN =~ s/[^0-9]//g;
159 $svc_dsl->cust_svc->cust_pkg->part_pkg->option('externalid',1),
160 TermsId => $self->qual2termsid($svc_dsl->vendor_qual_id),
161 DSLPhoneNumber => $svc_dsl->loop_type eq '0' ? 'STANDALONE'
163 Password => $svc_dsl->password,
164 PrequalId => $svc_dsl->vendor_qual_id,
165 CompanyName => $svc_dsl->company,
166 FirstName => $svc_dsl->first,
167 LastName => $svc_dsl->last,
169 ContactMethod => 'PHONE',
170 ContactPhoneNumber => $contactTN,
171 ContactEmail => 'x@x.xx',
173 DateToOrder => time2str("%Y-%m-%d",$svc_dsl->desired_dd),
174 RequestClientIP => '127.0.0.1',
175 IspChange => $isp_chg,
176 IspPrevious => $isp_chg eq 'YES' ? $svc_dsl->isp_prev : '',
177 CurrentProvider => $isp_chg eq 'NO' ? $svc_dsl->isp_prev : '',
180 $result = $self->ikano_command('ORDER',$args);
181 return $result unless ref($result); # scalar (string) is an error
183 # now we're getting an OrderResponse which should have one Order in it
184 warn Dumper($result) if $DEBUG;
185 my ($pushed,$vendor_order_id,$vendor_order_status,$last_pull);
190 return 'Invalid order response' unless defined $result->{'Order'};
191 $result = $result->{'Order'};
193 return 'No order id or status returned'
194 unless defined $result->{'Status'} && defined $result->{'OrderId'};
196 $vendor_order_id = $result->{'OrderId'};
197 $vendor_order_status = $result->{'Status'};
199 # XXX we need to set all of these values (everything in the last my statement
200 # above) in the svc without:
201 # a. re-triggering exports
202 # b. committing the svc into the db now (because other things in the caller
203 # and further up the stack may decide that the svc shouldn't be inserted)
208 sub _export_replace {
209 my( $self, $new, $old ) = (shift, shift, shift);
214 my( $self, $svc_dsl ) = (shift, shift);
218 sub _export_suspend {
219 my( $self, $svc_dsl ) = (shift, shift);
223 sub _export_unsuspend {
224 my( $self, $svc_dsl ) = (shift, shift);