1 package FS::part_export::soma;
3 use vars qw(@ISA %info %options $DEBUG);
5 use FS::Record qw(fields dbh);
8 @ISA = qw(FS::part_export);
11 tie %options, 'Tie::IxHash',
12 'url' => { label => 'Soma OSS-API url', default=>'https://localhost:8088/ossapi/services' },
13 'data_app_id' => { label => 'SOMA Data Application Id', default => '' },
17 Real-time export of <b>svc_external</b> and <b>svc_broadband</b> record data
18 to SOMA Networks <a href="http://www.somanetworks.com">platform</a> via the
21 Freeside will attempt to create/delete a cpe for the ESN provided in
22 svc_external. If a data application id is provided then freeside will
23 use the values provided in svc_broadband to manage the attributes and
29 'svc' => [ qw ( svc_broadband svc_external ) ],
30 'desc' => 'Real-time export to SOMA platform',
31 'options' => \%options,
37 my( $self, $svc ) = ( shift, shift );
39 warn "_export_insert called for service ". $svc->svcnum
42 my %args = ( url => $self->option('url'), method => '_queueable_insert' );
44 $args{esn} = $self->esn($svc) or return 'No ESN found!';
46 my $svcdb = $svc->cust_svc->part_svc->svcdb;
47 $args{svcdb} = $svcdb;
48 if ( $svcdb eq 'svc_external' ) {
50 } elsif ( $svcdb eq 'svc_broadband' ){
51 $args{data_app_id} = $self->option('data_app_id')
53 return "Don't know how to provision $svcdb";
56 warn "dispatching statuschange" if $DEBUG;
58 eval { statuschange(%args) };
65 my( $self, $svc ) = ( shift, shift );
67 my %args = ( url => $self->option('url'), method => '_queueable_delete' );
69 $args{esn} = $self->esn($svc) or return 'No ESN found!';
71 my $svcdb = $svc->cust_svc->part_svc->svcdb;
72 $args{svcdb} = $svcdb;
73 if ( $svcdb eq 'svc_external' ) {
75 } elsif ( $svcdb eq 'svc_broadband' ){
76 $args{data_app_id} = $self->option('data_app_id')
78 return "Don't know how to provision $svcdb";
81 eval { statuschange(%args) };
88 my( $self, $new, $old ) = ( shift, shift, shift );
90 my %args = ( url => $self->option('url'), method => '_queueable_replace' );
92 $args{esn} = $self->esn($old) or return 'No old ESN found!';
93 $args{new_esn} = $self->esn($new) or return 'No new ESN found!';
95 my $svcdb = $old->cust_svc->part_svc->svcdb;
96 $args{svcdb} = $svcdb;
97 if ( $svcdb eq 'svc_external' ) {
99 } elsif ( $svcdb eq 'svc_broadband' ){
100 $args{data_app_id} = $self->option('data_app_id')
102 return "Don't know how to provision $svcdb";
105 eval { statuschange(%args) };
111 sub _export_suspend {
112 my( $self, $svc ) = ( shift, shift );
114 $self->queue_statuschange('_queueable_suspend', $svc);
117 sub _export_unsuspend {
118 my( $self, $svc ) = ( shift, shift );
120 $self->queue_statuschange('_queueable_unsuspend', $svc);
123 sub queue_statuschange {
124 my( $self, $method, $svc ) = @_;
126 my %args = ( url => $self->option('url'), method => $method );
128 my $svcdb = $svc->cust_svc->part_svc->svcdb;
129 $args{svcdb} = $svcdb;
130 if ( $svcdb eq 'svc_external' ) {
131 #do absolutely nothing
133 } elsif ( $svcdb eq 'svc_broadband' ){
134 $args{data_app_id} = $self->option('data_app_id')
136 return "Don't know how to provision $svcdb";
139 $args{esn} = $self->esn($svc);
141 my $queue = new FS::queue {
142 'svcnum' => $svc->svcnum,
143 'job' => 'FS::part_export::soma::statuschange',
145 my $error = $queue->insert( %args );
147 return $error if $error;
153 sub statuschange { # subroutine
156 warn "statuschange called with options ".
157 join (', ', map { "$_ => $options{$_}" } keys(%options))
160 my $method = $options{method};
162 eval "use Net::Soma 0.01 qw(ApplicationDef ApplicationInstance
163 AttributeDef AttributeInstance);";
166 my %soma_objects = ();
167 foreach my $service ( qw ( CPECollection CPEAccess AppCatalog Applications ) )
169 $soma_objects{$service} = new Net::Soma ( namespace => $service."Service",
170 url => $options{'url'},
175 my $cpeid = eval {$soma_objects{CPECollection}->getCPEByESN( $options{esn} )};
176 warn "failed to find CPE with ESN $options{esn}"
177 if ($DEBUG && !$cpeid);
179 if ( $method eq '_queueable_insert' && $options{svcdb} eq 'svc_external' ) {
181 # only type 1 is used at this time
182 $cpeid = $soma_objects{CPECollection}->createCPE( $options{esn}, 1 );
184 $soma_objects{CPECollection}->releaseCPE( $cpeid );
185 die "Soma element for $options{esn} already exists";
189 die "Can't find soma element for $options{esn}"
192 warn "dispatching $method from statuschange" if $DEBUG;
193 &{$method}( \%soma_objects, $cpeid, %options );
197 sub _queueable_insert {
198 my( $soma_objects, $cpeid, %options ) = @_;
200 warn "_queueable_insert called for $cpeid with options ".
201 join (', ', map { "$_ => $options{$_}" } keys(%options))
204 my $appid = $options{data_app_id};
207 $soma_objects->{AppCatalog}
208 ->getDefaultApplicationInstance($appid, $cpeid);
211 $soma_objects->{AppCatalog}
212 ->getDefaultApplicationAttributeInstance(2, 1, $cpeid);
213 $attribute->value('G');
216 foreach my $instance (@{$application->attributes}) {
217 unless ($instance->definitionId == $attribute->definitionId) {
220 $application->attributes->[$i] = $attribute;
224 $soma_objects->{Applications}->subscribeApp( $cpeid, $application );
227 $soma_objects->{CPECollection}->releaseCPE( $cpeid );
232 sub _queueable_delete {
233 my( $soma_objects, $cpeid, %options ) = @_;
235 my $appid = $options{data_app_id};
240 $soma_objects->{Applications}->getSubscribedApplications( $cpeid );
243 foreach $application (@$applications) {
244 next unless $application->definitionId == $appid;
245 $instance_id = $application->instanceId;
248 $soma_objects->{Applications}->unsubscribeApp( $cpeid, $instance_id );
252 $soma_objects->{CPECollection}->deleteCPE($cpeid);
257 $soma_objects->{CPECollection}->releaseCPE( $cpeid ) unless $norelease;
262 sub _queueable_replace {
263 my( $soma_objects, $cpeid, %options ) = @_;
265 my $appid = $options{data_app_id} || '';
267 if (exists($options{data_app_id})) {
269 $soma_objects->{Applications}->getSubscribedApplications( $cpeid );
272 foreach $application (@$applications) {
273 next unless $application->internalName eq 'dataApplication';
274 if ($application->definitionId != $options{data_app_id}) {
275 $instance_id = $application->instanceId;
276 $soma_objects->{Applications}->unsubscribeApp( $cpeid, $instance_id );
280 if ($appid && !$instance_id ) {
282 $soma_objects->{AppCatalog}
283 ->getDefaultApplicationInstance($appid, $cpeid);
285 $soma_objects->{Applications}->subscribeApp( $cpeid, $application );
290 $soma_objects->{CPEAccess}->switchCPE($cpeid, $options{new_esn})
291 unless( $options{new_esn} eq $options{esn});
295 $soma_objects->{CPECollection}->releaseCPE( $cpeid );
300 sub _queueable_suspend {
301 my( $soma_objects, $cpeid, %options ) = @_;
303 my $appid = $options{data_app_id};
307 $soma_objects->{Applications}->getSubscribedApplications( $cpeid );
310 foreach $application (@$applications) {
311 next unless $application->definitionId == $appid;
313 $instance_id = $application->instanceId;
315 $soma_objects->{AppCatalog}->getApplicationDef($appid, $cpeid);
316 my @attr_def = grep { $_->internalName eq 'status' }
317 @{$app_def->attributes};
319 foreach my $attribute ( @{$application->attributes} ) {
320 next unless $attribute->definitionId == $attr_def[0]->definitionId;
321 $attribute->{value} = 'S';
323 $soma_objects->{Applications}->setAppAttribute( $cpeid,
337 $soma_objects->{CPECollection}->releaseCPE( $cpeid );
342 sub _queueable_unsuspend {
343 my( $soma_objects, $cpeid, %options ) = @_;
345 my $appid = $options{data_app_id};
349 $soma_objects->{Applications}->getSubscribedApplications( $cpeid );
352 foreach $application (@$applications) {
353 next unless $application->definitionId == $appid;
355 $instance_id = $application->instanceId;
357 $soma_objects->{AppCatalog}->getApplicationDef($appid, $cpeid);
358 my @attr_def = grep { $_->internalName eq 'status' }
359 @{$app_def->attributes};
361 foreach my $attribute ( @{$application->attributes} ) {
362 next unless $attribute->definitionId == $attr_def[0]->definitionId;
363 $attribute->{value} = 'E';
365 $soma_objects->{Applications}->setAppAttribute( $cpeid,
379 $soma_objects->{CPECollection}->releaseCPE( $cpeid );
385 my ( $self, $svc ) = @_;
386 my $svcdb = $svc->cust_svc->part_svc->svcdb;
388 if ($svcdb eq 'svc_external') {
389 my $esn = $svc->title;
390 $esn =~ /^\s*([\da-fA-F]{1,16})\s*$/ && ($esn = $1);
391 return sprintf( '%016s', $esn );
394 my $cust_pkg = $svc->cust_svc->cust_pkg;
395 return '' unless $cust_pkg;
397 my @cust_svc = grep { $_->part_svc->svcdb eq 'svc_external' &&
398 scalar( $_->part_svc->part_export('soma') )
401 return '' unless scalar(@cust_svc);
402 warn "part_export::soma found multiple ESNs for cust_svc ". $svc->svcnum
403 if scalar( @cust_svc ) > 1;
405 my $esn = $cust_svc[0]->svc_x->title;
406 $esn =~ /^\s*([\da-fA-F]{1,16})\s*$/ && ($esn = $1);
408 sprintf( '%016s', $esn );