[freeside-commits] branch master updated. 29a34baf1ce240da8e012a7147c4a88d48242260

Christopher Burger burgerc at freeside.biz
Thu Feb 15 08:48:54 PST 2018


The branch, master has been updated
       via  29a34baf1ce240da8e012a7147c4a88d48242260 (commit)
      from  e4829d1025798f30b0af30d1e22da2f7c769df31 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 29a34baf1ce240da8e012a7147c4a88d48242260
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Thu Feb 15 11:47:39 2018 -0500

    RT# 78356 - broadband svc export to saisei

diff --git a/FS/FS/part_export/saisei.pm b/FS/FS/part_export/saisei.pm
new file mode 100644
index 000000000..799220ef2
--- /dev/null
+++ b/FS/FS/part_export/saisei.pm
@@ -0,0 +1,453 @@
+package FS::part_export::saisei;
+
+use strict;
+use base qw( FS::part_export );
+use vars qw( @ISA %info );
+use Date::Format 'time2str';
+use Cpanel::JSON::XS;
+use Net::HTTPS::Any qw(https_post);
+use MIME::Base64;
+use REST::Client;
+use Data::Dumper;
+
+use FS::Conf;
+
+#@ISA = qw( FS::part_export::http );
+
+=pod
+
+=head1 NAME
+
+FS::part_export::saisei
+
+=head1 SYNOPSIS
+
+Saisei integration for Freeside
+
+=head1 DESCRIPTION
+
+This export offers basic svc_broadband provisioning for Saisei.
+
+This module also provides generic methods for working through the L</Saisei API>.
+
+=cut
+
+tie my %options, 'Tie::IxHash',
+  'username'         => { label => 'User Name',
+                          default => '' },
+  'password'         => { label => 'Password',
+                          default => '' },
+  'host'             => { label => 'Host',
+                          default => 'STM IP ADDRESS' },
+  'port'             => { label => 'Port',
+                          default => 5000 },
+  'customer_name'    => { label => 'Customer Name',
+                          default => 'FREESIDE CUST $custnum' },
+  'account_id'       => { label => 'Account ID',
+                          default => 'SVC$svcnum' },
+  'product_id'       => { label => 'Account Product ID' },
+  'debug'            => { type => 'checkbox',
+                          label => 'Enable debug warnings' },
+;
+
+%info = (
+  'svc'             => 'svc_broadband',
+  'desc'            => 'Export broadband service/account to Saisei',
+  'options'         => \%options,
+  'notes'           => <<'END',
+This is customer integration with Saisei.
+END
+);
+
+#"/STM_IP:5000/rest/top/configurations/running/" is for http 5029 for https
+
+#Creating User Names
+#Users are tracked by their name which gives access to the internal slice data which in turn allows the viewing of  Applications and Geo-Locations.
+#Creating a user name requires a command of the following format: -
+#'put', 'users/USER_NAME', {'description':description}
+#When creating a user name it is usual to add a description and since a user attribute set does not normally contain the users plan name it is best to encode it into the description field.
+
+sub _export_insert {
+  my ($self, $svc_broadband) = @_;
+  my $rateplan_name = $svc_broadband->{Hash}->{description};
+   $rateplan_name =~ s/\s/_/g;
+
+
+  # load needed info from our end
+  my $cust_main = $svc_broadband->cust_main;
+  return "Could not load service customer" unless $cust_main;
+  my $conf = new FS::Conf;
+
+  # get policy list
+  my $policies = $self->api_get_policies();
+
+  # check for existing rate plan
+  my $existing_rateplan;
+  $existing_rateplan = $self->api_get_rateplan($rateplan_name) unless $self->{'__saisei_error'};
+
+  # if no existing rate plan create one and modify it.
+  $self->api_create_rateplan($svc_broadband, $rateplan_name) unless $existing_rateplan;
+  $self->api_modify_rateplan($policies->{collection}, $svc_broadband, $rateplan_name) unless ($self->{'__saisei_error'} || $existing_rateplan);
+
+  # set rateplan to existing one or newly created one.
+  my $rateplan = $existing_rateplan ? $existing_rateplan : $self->api_get_rateplan($rateplan_name);
+
+  my @email = map { $_->emailaddress } FS::Record::qsearch({
+        'table'     => 'cust_contact',
+        'select'    => 'emailaddress',
+        'addl_from' => ' JOIN contact_email USING (contactnum)',
+        'hashref'   => { 'custnum' => $cust_main->{Hash}->{custnum}, },
+    });
+  my $username = $email[0];
+  my $description = $cust_main->{Hash}->{first}." ".$cust_main->{Hash}->{last};
+
+  # check for existing user.
+  my $existing_user;
+  $existing_user = $self->api_get_user($username) unless ( $self->{'__saisei_error'} || !$username);
+ 
+  # if no existing user create one.
+  $self->api_create_user($username, $description) unless $existing_user;
+
+  # set user to existing one or newly created one.
+  my $user = $existing_user ? $existing_user : $self->api_get_user($username);
+
+  ## add access point ?
+ 
+  ## tie host to user
+  $self->api_add_host_to_user($user->{collection}->[0]->{name}, $rateplan->{collection}->[0]->{name}, $svc_broadband->{Hash}->{ip_addr}) unless $self->{'__saisei_error'};
+
+  #die('ending for testing');
+  return '';
+
+}
+
+sub _export_replace {
+  my ($self, $svc_phone) = @_;
+  return '';
+}
+
+sub _export_delete {
+  my ($self, $svc_broadband) = @_;
+
+  my $cust_main = $svc_broadband->cust_main;
+  return "Could not load service customer" unless $cust_main;
+  my $conf = new FS::Conf;
+
+  my $rateplan_name = $svc_broadband->{Hash}->{description};
+  $rateplan_name =~ s/\s/_/g;
+
+  my @email = map { $_->emailaddress } FS::Record::qsearch({
+        'table'     => 'cust_contact',
+        'select'    => 'emailaddress',
+        'addl_from' => ' JOIN contact_email USING (contactnum)',
+        'hashref'   => { 'custnum' => $cust_main->{Hash}->{custnum}, },
+    });
+  my $username = $email[0]; 
+
+  ## tie host to user
+  $self->api_delete_host_to_user($username, $rateplan_name, $svc_broadband->{Hash}->{ip_addr}) unless $self->{'__saisei_error'};
+
+  return '';
+}
+
+sub _export_suspend {
+  my ($self, $svc_phone) = @_;
+  return '';
+}
+
+sub _export_unsuspend {
+  my ($self, $svc_phone) = @_;
+  return '';
+}
+
+=head1 Saisei API
+
+These methods allow access to the Saisei API using the credentials
+set in the export options.
+
+=cut
+
+=head2 api_call
+
+Accepts I<$service>, I<$method>, I<$params> hashref and optional
+I<$returnfield>.  Places an api call to the specified service
+and method with the specified params.  Returns the decoded json
+object returned by the api call.  If I<$returnfield> is specified,
+returns only that field of the decoded object, and errors out if
+that field does not exist.  Returns empty on failure;  retrieve
+error messages using L</api_error>.
+
+Must run L</api_login> first.
+
+=cut
+
+sub api_call {
+  my ($self,$method,$path,$params) = @_;
+  $self->{'__saisei_error'} = '';
+  my $auth_info = $self->option('username') . ':' . $self->option('password');
+  $params ||= {};
+
+  print "Calling /$method\n" if $self->option('debug');
+
+  my $data = encode_json($params) if keys %{ $params };
+
+  my $client = REST::Client->new();
+  $client->addHeader("Authorization", "Basic ".encode_base64($auth_info));
+  $client->setHost('http://'.$self->option('host').':'.$self->option('port'));
+  $client->$method('/rest/stm/configurations/running/'.$path, $data, { "Content-type" => 'application/json'});
+
+  my $result;
+
+  if ($client->responseCode() eq '200' || $client->responseCode() eq '201') {
+    eval { $result = decode_json($client->responseContent()) };
+    unless ($result) {
+      $self->{'__saisei_error'} = "Error decoding json: $@";
+      return;
+    }
+  }
+  else {
+    $self->{'__saisei_error'} = "Bad response from server during $method: " . $client->responseContent();
+    print "My response content fo /$method\n". Dumper($client->responseContent) if $self->option('debug');
+    return; 
+  }
+
+  return $result;
+  
+}
+
+=head2 api_error
+
+Returns the error string set by L</PortaOne API> methods,
+or a blank string if most recent call produced no errors.
+
+=cut
+
+sub api_error {
+  my $self = shift;
+  return $self->{'__saisei_error'} || '';
+}
+
+=head2 api_get_policies
+
+Gets a list of global policies.
+
+=cut
+
+sub api_get_policies {
+  my $self = shift;
+
+  my $get_policies = $self->api_call("GET", 'policies/?token=1&order=name&start=0&limit=20&select=name%2Cpercent_rate%2Cassured%2C');
+  return if $self->api_error;
+  $self->{'__saisei_error'} = "Did not receive any global policies"
+    unless $get_policies;
+
+  return $get_policies;
+}
+
+=head2 api_get_rateplan
+
+Gets rateplan info for specific rateplan.
+
+=cut
+
+sub api_get_rateplan {
+  my $self = shift;
+  my $rateplan = shift;
+
+  my $get_rateplan = $self->api_call("GET", "rate_plans/$rateplan");
+  return if $self->api_error;
+  $self->{'__saisei_error'} = "Did not receive any rateplan info"
+    unless $get_rateplan;
+
+  return $get_rateplan;
+}
+
+=head2 api_get_user
+
+Gets user info for specific user.
+
+=cut
+
+sub api_get_user {
+  my $self = shift;
+  my $user = shift;
+
+  my $get_user = $self->api_call("GET", "users/$user");
+  return if $self->api_error;
+  $self->{'__saisei_error'} = "Did not receive any user info"
+    unless $get_user;
+
+  return $get_user;
+}
+
+=head2 api_get_accesspoint
+
+Gets user info for specific access point.
+
+=cut
+
+sub api_get_accesspoint {
+  my $self = shift;
+  my $accesspoint;
+
+  my $get_accesspoint = $self->api_call("GET", "access_points/$accesspoint");
+  return if $self->api_error;
+  $self->{'__saisei_error'} = "Did not receive any user info"
+    unless $get_accesspoint;
+
+  return;
+}
+
+=head2 api_create_rateplan
+
+Creates a rateplan.
+
+=cut
+
+sub api_create_rateplan {
+  my ($self, $svc, $rateplan) = @_;
+
+  my $new_rateplan = $self->api_call(
+      "PUT", 
+      "rate_plans/$rateplan",
+      {
+        'downstream_rate' => $svc->{Hash}->{speed_down},
+        'upstream_rate' => $svc->{Hash}->{speed_up},
+      },
+  );
+
+  $self->{'__saisei_error'} = "Rate Plan not created"
+    unless $new_rateplan; # should never happen
+  return $new_rateplan;
+
+}
+
+=head2 api_modify_rateplan
+
+Modify a rateplan.
+
+=cut
+
+sub api_modify_rateplan {
+  my ($self,$policies,$svc,$rateplan_name) = @_;
+
+  foreach my $policy (@$policies) {
+    my $policyname = $policy->{name};
+    my $rate_multiplier = '';
+    if ($policy->{background}) { $rate_multiplier = ".01"; }
+    my $modified_rateplan = $self->api_call(
+      "PUT", 
+      "rate_plans/$rateplan_name/partitions/$policyname",
+      {
+        'restricted'      =>  $policy->{assured},         # policy_assured_flag
+        'rate_multiplier' => $rate_multiplier,           # policy_background 0.1
+        'rate'            =>  $policy->{percent_rate}, # policy_percent_rate
+      },
+    );
+
+    $self->{'__saisei_error'} = "Rate Plan not modified"
+      unless $modified_rateplan; # should never happen
+    
+  }
+
+  return;
+ 
+}
+
+=head2 api_create_user
+
+Creates a rateplan.
+
+=cut
+
+sub api_create_user {
+  my ($self,$user, $description) = @_;
+
+  my $new_user = $self->api_call(
+      "PUT", 
+      "users/$user",
+      {
+        'description' => $description,
+      },
+  );
+
+  $self->{'__saisei_error'} = "User not created"
+    unless $new_user; # should never happen
+
+  return $new_user;
+
+}
+
+=head2 api_create_accesspoint
+
+Creates a access point.
+
+=cut
+
+sub api_create_accesspoint {
+  my ($self,$accesspoint) = @_;
+
+  my $new_accesspoint = $self->api_call(
+      "PUT", 
+      "access_points/$accesspoint",
+      {
+        'description' => 'my description',
+      },
+  );
+
+  $self->{'__saisei_error'} = "Access point not created"
+    unless $new_accesspoint; # should never happen
+  return;
+
+}
+
+=head2 api_add_host_to_user
+
+ties host to user and rateplan.
+
+=cut
+
+sub api_add_host_to_user {
+  my ($self,$user, $rateplan, $ip) = @_;
+
+  my $new_host = $self->api_call(
+      "PUT", 
+      "hosts/$ip",
+      {
+        'user'      => $user,
+        'rate_plan' => $rateplan,
+      },
+  );
+
+  $self->{'__saisei_error'} = "Host not created"
+    unless $new_host; # should never happen
+
+  return $new_host;
+
+}
+
+=head2 api_add_host_to_user
+
+ties host to user and rateplan.
+
+=cut
+
+sub api_delete_host_to_user {
+  my ($self,$user, $rateplan, $ip) = @_;
+
+  my $delete_host = $self->api_call("DELETE", "hosts/$ip");
+
+  $self->{'__saisei_error'} = "Host not created"
+    unless $delete_host; # should never happen
+
+  return $delete_host;
+
+}
+
+=head1 SEE ALSO
+
+L<FS::part_export>
+
+=cut
+
+1;
\ No newline at end of file

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/part_export/saisei.pm | 453 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 453 insertions(+)
 create mode 100644 FS/FS/part_export/saisei.pm




More information about the freeside-commits mailing list