From: Jonathan Prykop Date: Thu, 12 May 2016 22:57:12 +0000 (-0500) Subject: RT#39913 Conexiant API X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=350c6073bb6cf465b02ef373bf7bfde2a8a07500 RT#39913 Conexiant API --- diff --git a/FS/FS/cdr/conexiant.pm b/FS/FS/cdr/conexiant.pm new file mode 100644 index 000000000..852c2f60f --- /dev/null +++ b/FS/FS/cdr/conexiant.pm @@ -0,0 +1,43 @@ +package FS::cdr::conexiant; +use base qw( FS::cdr ); + +use strict; +use vars qw( %info ); +use FS::Record qw( qsearchs ); +use FS::cdr qw( _cdr_date_parser_maker _cdr_min_parser_maker ); + +%info = ( + 'name' => 'Conexiant', + 'weight' => 600, + 'header' => 1, + 'type' => 'csv', + 'import_fields' => [ + skip(3), #LookupError,Direction,LegType + sub { #CallId + my($cdr,$value,$conf,$param) = @_; + if (qsearchs('cdr',{'uniqueid' => $value})) { + $param->{'skiprow'} = 1; + $param->{'empty_ok'} = 1; + } else { + $cdr->uniqueid($value); + } + }, + 'upstream_rateplanid', #ClientRateSheetId + skip(1), #ClientRouteId + 'src', #SourceNumber + skip(1), #RawNumber + 'dst', #DestNumber + skip(1), #DestLRN + _cdr_date_parser_maker('startdate'), #CreatedOn + _cdr_date_parser_maker('answerdate'), #AnsweredOn + _cdr_date_parser_maker('enddate'), #HangupOn + skip(4), #CallCause,SipCode,Price,USFCharge + 'upstream_price', #TotalPrice + _cdr_min_parser_maker('billsec'), #PriceDurationMins + skip(2), #SipEndpointId, SipEndpointName + ], +); + +sub skip { map {''} (1..$_[0]) } + +1; diff --git a/FS/bin/freeside-cdr-conexiant-import b/FS/bin/freeside-cdr-conexiant-import new file mode 100755 index 000000000..a79477c51 --- /dev/null +++ b/FS/bin/freeside-cdr-conexiant-import @@ -0,0 +1,127 @@ +#!/usr/bin/perl + +use strict; + +use Cpanel::JSON::XS; +use Getopt::Long; +use LWP::UserAgent; +use MIME::Base64; +use Net::HTTPS::Any qw(https_post https_get); + +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearchs); +use FS::cdr; +use FS::cdr_batch; + +sub usage { +"Usage: +freeside-cdr-conexiant-import -h -u username -p apikey [-v] freesideuser + +Downloads any existing CDR files with the BilledCallsOnly flag and +imports records that have not been imported yet. Silently skips +records that have already been imported. +"; +} + +# should really be using a module for this +`which unzip` or die "can't find unzip executable"; + +my ($username,$password,$verbose); +GetOptions( + "password=s" => \$password, + "username=s" => \$username, + "verbose" => \$verbose, +); + +my $fsuser = $ARGV[-1]; + +die usage() unless $fsuser; + +adminsuidsetup($fsuser); + +my ( $page, $response, %reply_headers ) = https_post( + 'host' => 'api.conexiant.net', + 'port' => '443', + 'path' => '/v1/Cdrs/SearchCdrsDownloads', + 'headers' => { + 'Authorization' => 'Basic ' . MIME::Base64::encode("$username:$password",'') + }, + 'content' => '{}', +); + +die "Bad response from conexiant server: $response" + unless $response =~ /^200/; + +my $result = decode_json($page); + +die "Error from conexiant: " . ($result->{'ErrorInfo'} || 'No error message') + unless $result->{'Success'}; + +my $files = $result->{'Data'}->{'Result'}; + +die "Unexpected results from conexiant, not an array" + unless ref($files) eq 'ARRAY'; + +my $dir = $FS::UID::cache_dir. "/cache.". $FS::UID::datasrc; +my $ua = LWP::UserAgent->new; + +# Download files are created automatically at regular frequent intervals, +# but they contain overlapping data. +# +# FS::cdr::conexiant automatically skips previously imported cdrs, +# though if it does so for all records in a file, +# then batch_import thinks the file is empty +foreach my $file (@$files) { + next unless $file->{'BilledCallsOnly'}; + my $cdrbatch = 'conexiant-' . $file->{'Identifier'}; + # files that were "empty" will unfortunately be re-downloaded, + # but the alternative is to leave an excess of empty batches in system, + # and re-downloading is harmless (all files expire after 48 hours anyway) + if (qsearchs('cdr_batch',{ 'cdrbatch' => $cdrbatch })) { + print "$cdrbatch already imported\n" if $verbose; + next; + } + if ($verbose) { + print "Downloading $cdrbatch\n". + " Created ".$file->{'CreatedOn'}."\n". + " Start ".$file->{'QueryStart'}."\n". + " End ".$file->{'QueryEnd'}."\n". + " Link ".$file->{'ValidLink'}."\n"; + } + my $zfh = new File::Temp( TEMPLATE => 'conexiant.XXXXXXXX', + SUFFIX => '.zip', + DIR => $dir, + ) + or die "can't open temporary file to store download: $!\n"; + my $cfh = new File::Temp( TEMPLATE => 'conexiant.XXXXXXXX', + SUFFIX => '.csv', + DIR => $dir, + ) + or die "can't open temporary file to unzip download: $!\n"; + # yeah, these files ain't secured in any way + my $response = $ua->get($file->{'ValidLink'}, ':content_file' => $zfh->filename); + unless ($response->is_success) { + die "Error downloading $cdrbatch: ".$response->status_line; + } + my $zfilename = $zfh->filename; + print $cfh `unzip -p $zfilename 'Conexiant Cdrs.csv'`; + seek($cfh,0,0); + print "Importing batch $cdrbatch\n" if $verbose; + my $error = FS::cdr::batch_import({ + 'batch_namevalue' => $cdrbatch, + 'file' => $cfh->filename, + 'format' => 'conexiant' + }); + if ($error eq 'Empty file!') { + print "File contains no new cdrs, no batch created\n" if $verbose; + $error = ''; + } elsif ($verbose && !$error) { + print "File successfully imported\n"; + } + die "Error importing $cdrbatch: $error" if $error; +} + +exit; + + +