1 package FS::part_export::prizm;
3 use vars qw(@ISA %info %options $DEBUG $me);
5 use FS::Record qw(fields dbh);
8 @ISA = qw(FS::part_export);
10 $me = '[' . __PACKAGE__ . ']';
12 tie %options, 'Tie::IxHash',
13 'url' => { label => 'Northbound url', default=>'https://localhost:8443/prizm/nbi' },
14 'user' => { label => 'Northbound username', default=>'nbi' },
15 'password' => { label => 'Password', default => '' },
16 'ems' => { label => 'Full EMS', type => 'checkbox' },
17 'always_bam' => { label => 'Always activate/suspend authentication', type => 'checkbox' },
18 'element_name_length' => { label => 'Size of siteName (best left blank)' },
22 Real-time export of <b>svc_broadband</b>, <b>cust_pkg</b>, and <b>cust_main</b>
23 record data to Motorola
24 <a href="http://motorola.canopywireless.com/products/prizm/">Canopy Prizm
25 software</a> via the Northbound interface.<br><br>
27 Freeside will attempt to create an element in an existing network with the
28 values provided in svc_broadband. Of particular interest are
30 <li> mac address - used to identify the element
31 <li> vlan profile - an exact match for a vlan profiles defined in prizm
32 <li> ip address - defines the management ip address of the prizm element
33 <li> latitude - GPS latitude
34 <li> longitude - GPS longitude
35 <li> altitude - GPS altitude
38 In addition freeside attempts to set the service plan name in prizm to the
39 name of the package in which the service resides.
41 The service is associated with a customer in prizm as well, and freeside
42 will create the customer should none already exist with import id matching
43 the freeside customer number. The following fields are set.
46 <li> importId - the freeside customer number
47 <li> customerType - freeside
48 <li> customerName - the name associated with the freeside shipping address
49 <li> address1 - the shipping address
55 <li> workPhone - the daytime phone number
56 <li> homePhone - the night phone number
57 <li> freesideId - the freeside customer number
60 Additionally set on the element are
62 <li> Site Name - The shipping name followed by the service broadband description field
63 <li> Site Location - the shipping address
64 <li> Site Contact - the daytime and night phone numbers
67 Freeside provisions, suspends, and unsuspends elements BAM only unless the
68 'Full EMS' checkbox is checked.<br><br>
70 When freeside provisions an element the siteName is copied internally by
71 prizm in such a manner that it is possible for the value to exceed the size
72 of the column used in the prizm database. Therefore freeside truncates
73 by default this value to 50 characters. It is thought that this
74 column is the account_name column of the element_user_account table. It
75 may be possible to lift this limit by modifying the prizm database and
76 setting a new appropriate value on this export. This is untested and
82 'svc' => 'svc_broadband',
83 'desc' => 'Real-time export to Northbound Interface',
84 'options' => \%options,
90 my ($self,$namespace,$method) = (shift,shift,shift);
92 eval "use Net::Prizm 0.04 qw(CustomerInfo PrizmElement);";
95 my $prizm = new Net::Prizm (
96 namespace => $namespace,
97 url => $self->option('url'),
98 user => $self->option('user'),
99 password => $self->option('password'),
105 sub queued_prizm_command { # subroutine
106 my( $url, $user, $password, $namespace, $method, @args ) = @_;
108 eval "use Net::Prizm 0.04 qw(CustomerInfo PrizmElement);";
111 my $prizm = new Net::Prizm (
112 namespace => $namespace,
115 password => $password,
118 $err_or_som = $prizm->$method( @args);
121 unless ref($err_or_som);
128 my( $self, $svc ) = ( shift, shift );
129 warn "$me: _export_insert called for export ". $self->exportnum.
130 " on service ". $svc->svcnum. "\n"
133 my $cust_main = $svc->cust_svc->cust_pkg->cust_main;
135 my $err_or_som = $self->prizm_command('CustomerIfService', 'getCustomers',
137 [$cust_main->custnum],
141 unless ref($err_or_som);
144 if ( defined $cust_main->dbdef_table->column('ship_last') ) {
145 $pre = $cust_main->ship_last ? 'ship_' : '';
147 my $name = $pre ? $cust_main->ship_name : $cust_main->name;
148 my $location = join(" ", map { my $method = "$pre$_"; $cust_main->$method }
149 qw (address1 address2 city state zip)
151 my $contact = join(" ", map { my $method = "$pre$_"; $cust_main->$method }
156 if ($err_or_som->result->[0]) {
157 $pcustomer = $err_or_som->result->[0]->customerId;
158 warn "$me: found customer $pcustomer in prizm\n" if $DEBUG;
160 my $chashref = $cust_main->hashref;
162 importId => $cust_main->custnum,
163 customerName => $name,
164 customerType => 'freeside',
165 address1 => $chashref->{"${pre}address1"},
166 address2 => $chashref->{"${pre}address2"},
167 city => $chashref->{"${pre}city"},
168 state => $chashref->{"${pre}state"},
169 zipCode => $chashref->{"${pre}zip"},
170 workPhone => $chashref->{"${pre}daytime"},
171 homePhone => $chashref->{"${pre}night"},
172 email => @{[$cust_main->invoicing_list_emailonly]}[0],
173 extraFieldNames => [ 'country', 'freesideId',
175 extraFieldValues => [ $chashref->{"${pre}country"}, $cust_main->custnum,
179 $err_or_som = $self->prizm_command('CustomerIfService', 'addCustomer',
182 unless ref($err_or_som);
184 $pcustomer = $err_or_som->result;
185 warn "$me: added customer $pcustomer to prizm\n" if $DEBUG;
187 warn "multiple prizm customers found for $cust_main->custnum"
188 if scalar(@$pcustomer) > 1;
190 # #kinda big question/expensive
191 # $err_or_som = $self->prizm_command('NetworkIfService', 'getPrizmElements',
192 # ['Network Default Gateway Address'],
193 # [$svc->addr_block->ip_gateway],
197 # unless ref($err_or_som);
199 # return "No elements in network" unless exists $err_or_som->result->[0];
202 # for (my $i = 0; $i < $err_or_som->result->[0]->attributeNames; $i++) {
203 # if ($err_or_som->result->[0]->attributeNames->[$i] eq "Network.ID"){
204 # $networkid = $err_or_som->result->[0]->attributeValues->[$i];
209 my $performance_profile = $svc->performance_profile;
210 $performance_profile ||= $svc->cust_svc->cust_pkg->part_pkg->pkg;
212 my $element_name_length = 50;
213 $element_name_length = $1
214 if $self->option('element_name_length') =~ /^\s*(\d+)\s*$/;
215 $err_or_som = $self->prizm_command('NetworkIfService', 'addProvisionedElement',
218 substr($name . " " . $svc->description,
219 0, $element_name_length),
222 sprintf("%032X", $svc->authkey || 0),
223 $performance_profile,
225 ($self->option('ems') ? 1 : 0 ),
228 unless ref($err_or_som);
229 warn "$me: added provisioned element to prizm\n" if $DEBUG;
231 my (@names) = ('Management IP',
239 my (@values) = ($svc->ip_addr,
243 $name . " " . $svc->description,
247 $element = $err_or_som->result->elementId;
248 $err_or_som = $self->prizm_command('NetworkIfService', 'setElementConfig',
256 unless ref($err_or_som);
257 warn "$me: set element configuration\n" if $DEBUG;
259 $err_or_som = $self->prizm_command('NetworkIfService', 'setElementConfigSet',
266 unless ref($err_or_som);
267 warn "$me: set element vlan profile\n" if $DEBUG;
269 $err_or_som = $self->prizm_command('NetworkIfService', 'setElementConfigSet',
271 $performance_profile,
276 unless ref($err_or_som);
277 warn "$me: set element configset (performance profile)\n" if $DEBUG;
279 $err_or_som = $self->prizm_command('NetworkIfService',
280 'activateNetworkElements',
283 ( $self->option('ems') ? 1 : 0 ),
287 unless ref($err_or_som);
288 warn "$me: activated element\n" if $DEBUG;
290 $err_or_som = $self->prizm_command('CustomerIfService',
291 'addElementToCustomer',
299 unless ref($err_or_som);
300 warn "$me: added element to customer\n" if $DEBUG;
306 my( $self, $svc ) = ( shift, shift );
308 my $oldAutoCommit = $FS::UID::AutoCommit;
309 local $FS::UID::AutoCommit = 0;
312 my $cust_pkg = $svc->cust_svc->cust_pkg;
317 my $queue = new FS::queue {
318 'svcnum' => $svc->svcnum,
319 'job' => 'FS::part_export::prizm::queued_prizm_command',
321 my $error = $queue->insert(
322 ( map { $self->option($_) }
323 qw( url user password ) ),
325 'removeElementFromCustomer',
333 $dbh->rollback if $oldAutoCommit;
337 push @$depend, $queue->jobnum;
341 $self->queue_statuschange('deleteElement', $depend, $svc, 1);
343 unless (ref($err_or_queue)) {
344 $dbh->rollback if $oldAutoCommit;
345 return $err_or_queue;
348 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
353 sub _export_replace {
354 my( $self, $new, $old ) = ( shift, shift, shift );
356 my $err_or_som = $self->prizm_command('NetworkIfService', 'getPrizmElements',
362 unless ref($err_or_som);
364 return "Can't find prizm element for " . $old->mac_addr
365 unless $err_or_som->result->[0];
367 my %freeside2prizm = ( mac_addr => 'MAC Address',
368 ip_addr => 'Management IP',
369 latitude => 'GPS Latitude',
370 longitude => 'GPS Longitude',
371 altitude => 'GPS Altitude',
372 authkey => 'Authentication Key',
376 my (@names) = map { push @values, $new->$_; $freeside2prizm{$_} }
377 grep { $old->$_ ne $new->$_ }
378 grep { exists($freeside2prizm{$_}) }
379 fields( 'svc_broadband' );
381 if ($old->description ne $new->description) {
382 my $cust_main = $old->cust_svc->cust_pkg->cust_main;
383 my $name = defined($cust_main->dbdef_table->column('ship_last'))
384 ? $cust_main->ship_name
386 push @values, $name . " " . $new->description;
387 push @names, "Site Name";
390 my $element = $err_or_som->result->[0]->elementId;
392 $err_or_som = $self->prizm_command('NetworkIfService', 'setElementConfig',
400 unless ref($err_or_som);
402 $err_or_som = $self->prizm_command('NetworkIfService', 'setElementConfigSet',
408 if $old->vlan_profile ne $new->vlan_profile;
411 unless ref($err_or_som);
413 my $performance_profile = $new->performance_profile;
414 $performance_profile ||= $new->cust_svc->cust_pkg->part_pkg->pkg;
416 $err_or_som = $self->prizm_command('NetworkIfService', 'setElementConfigSet',
418 $performance_profile,
423 unless ref($err_or_som);
429 sub _export_suspend {
430 my( $self, $svc ) = ( shift, shift );
432 my $ems = $self->option('ems') ? 1 : 0;
433 my $err_or_queue = '';
435 my $oldAutoCommit = $FS::UID::AutoCommit;
436 local $FS::UID::AutoCommit = 0;
440 $self->queue_statuschange('suspendNetworkElements', [], $svc, 1, $ems);
441 unless (ref($err_or_queue)) {
442 $dbh->rollback if $oldAutoCommit;
443 return $err_or_queue;
445 push @$depend, $err_or_queue->jobnum;
447 if ($ems && $self->option('always_bam')) {
449 $self->queue_statuschange('suspendNetworkElements', $depend, $svc, 1, 0);
450 unless (ref($err_or_queue)) {
451 $dbh->rollback if $oldAutoCommit;
452 return $err_or_queue;
456 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
461 sub _export_unsuspend {
462 my( $self, $svc ) = ( shift, shift );
464 my $ems = $self->option('ems') ? 1 : 0;
465 my $err_or_queue = '';
467 my $oldAutoCommit = $FS::UID::AutoCommit;
468 local $FS::UID::AutoCommit = 0;
471 if ($ems && $self->option('always_bam')) {
473 $self->queue_statuschange('activateNetworkElements', [], $svc, 1, 0);
474 unless (ref($err_or_queue)) {
475 $dbh->rollback if $oldAutoCommit;
476 return $err_or_queue;
478 push @$depend, $err_or_queue->jobnum;
482 $self->queue_statuschange('activateNetworkElements', $depend, $svc, 1, $ems);
483 unless (ref($err_or_queue)) {
484 $dbh->rollback if $oldAutoCommit;
485 return $err_or_queue;
488 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
494 my( $self, $svc, $arrayref ) = ( shift, shift, shift );
497 '<A HREF="http://'. $svc->ip_addr. '" target="_blank">SM</A>';
502 sub queue_statuschange {
503 my( $self, $method, $jobs, $svc, @args ) = @_;
505 # already in a transaction and can't die here
507 my $queue = new FS::queue {
508 'svcnum' => $svc->svcnum,
509 'job' => 'FS::part_export::prizm::statuschange',
511 my $error = $queue->insert(
512 ( map { $self->option($_) }
513 qw( url user password ) ),
519 unless ($error) { # successful insertion
520 foreach my $job ( @$jobs ) {
521 $error ||= $queue->depend_insert($job);
528 sub statuschange { # subroutine
529 my( $url, $user, $password, $method, $mac_addr, @args) = @_;
531 eval "use Net::Prizm 0.04 qw(CustomerInfo PrizmElement);";
534 my $prizm = new Net::Prizm (
535 namespace => 'NetworkIfService',
538 password => $password,
541 my $err_or_som = $prizm->getPrizmElements( [ 'MAC Address' ],
546 unless ref($err_or_som);
548 die "Can't find prizm element for " . $mac_addr
549 unless $err_or_som->result->[0];
553 if ($method =~ /suspendNetworkElements/ || $method =~ /activateNetworkElements/) {
554 $arg1 = [ $err_or_som->result->[0]->elementId ];
556 $arg1 = $err_or_som->result->[0]->elementId;
558 $err_or_som = $prizm->$method( $arg1, @args );
561 unless ref($err_or_som);