RT#39913: Conexiant API [distinguish all rows previously imported from truly empty...
[freeside.git] / FS / bin / freeside-cdr-conexiant-import
1 #!/usr/bin/perl
2
3 use strict;
4
5 use Cpanel::JSON::XS;
6 use Getopt::Long;
7 use LWP::UserAgent;
8 use MIME::Base64;
9 use Net::HTTPS::Any qw(https_post https_get);
10
11 use FS::UID qw(adminsuidsetup);
12 use FS::Record qw(qsearchs);
13 use FS::cdr;
14 use FS::cdr_batch;
15
16 sub usage {
17 "Usage:
18 freeside-cdr-conexiant-import -h -u username -p apikey [-v] freesideuser
19
20 Downloads any existing CDR files with the BilledCallsOnly flag and 
21 imports records that have not been imported yet.  Silently skips 
22 records that have already been imported.
23 ";
24 }
25
26 # should really be using a module for this
27 `which unzip` or die "can't find unzip executable";
28
29 my ($username,$password,$verbose);
30 GetOptions(
31   "password=s"  => \$password,
32   "username=s"  => \$username,
33   "verbose"     => \$verbose,
34 );
35
36 my $fsuser = $ARGV[-1];
37
38 die usage() unless $fsuser;
39
40 adminsuidsetup($fsuser);
41
42 my ( $page, $response, %reply_headers ) = https_post(
43   'host'    => 'api.conexiant.net',
44   'port'    => '443',
45   'path'    => '/v1/Cdrs/SearchCdrsDownloads',
46   'headers' => {
47     'Authorization' => 'Basic ' . MIME::Base64::encode("$username:$password",'')
48   },
49   'content' => '{}',
50 );
51
52 die "Bad response from conexiant server: $response"
53   unless $response =~ /^200/;
54
55 my $result = decode_json($page);
56
57 die "Error from conexiant: " . ($result->{'ErrorInfo'} || 'No error message')
58   unless $result->{'Success'};
59
60 my $files = $result->{'Data'}->{'Result'};
61
62 die "Unexpected results from conexiant, not an array"
63   unless ref($files) eq 'ARRAY';
64
65 my $dir = $FS::UID::cache_dir. "/cache.". $FS::UID::datasrc;
66 my $ua  = LWP::UserAgent->new;
67
68 # Download files are created automatically at regular frequent intervals,
69 # but they contain overlapping data.
70 #
71 # FS::cdr::conexiant automatically skips previously imported cdrs
72 foreach my $file (@$files) {
73   next unless $file->{'BilledCallsOnly'};
74   my $cdrbatch = 'conexiant-' . $file->{'Identifier'};
75   # files that contained no new records will unfortunately be re-downloaded,
76   # but the alternative is to leave an excess of empty batches in system,
77   # and re-downloading is harmless (all files expire after 48 hours anyway)
78   if (qsearchs('cdr_batch',{ 'cdrbatch' => $cdrbatch })) {
79     print "$cdrbatch already imported\n" if $verbose;
80     next;
81   }
82   if ($verbose) {
83     print "Downloading $cdrbatch\n".
84           "  Created ".$file->{'CreatedOn'}."\n".
85           "  Start   ".$file->{'QueryStart'}."\n".
86           "  End     ".$file->{'QueryEnd'}."\n".
87           "  Link    ".$file->{'ValidLink'}."\n";
88   }
89   my $zfh = new File::Temp( TEMPLATE => 'conexiant.XXXXXXXX',
90                            SUFFIX   => '.zip',
91                            DIR      => $dir,
92                          )
93     or die "can't open temporary file to store download: $!\n";
94   my $cfh = new File::Temp( TEMPLATE => 'conexiant.XXXXXXXX',
95                            SUFFIX   => '.csv',
96                            DIR      => $dir,
97                          )
98     or die "can't open temporary file to unzip download: $!\n";
99   # yeah, these files ain't secured in any way
100   my $response = $ua->get($file->{'ValidLink'}, ':content_file' => $zfh->filename);
101   unless ($response->is_success) {
102     die "Error downloading $cdrbatch: ".$response->status_line;
103   }
104   my $zfilename = $zfh->filename;
105   print $cfh `unzip -p $zfilename 'Conexiant Cdrs.csv'`;
106   seek($cfh,0,0);
107   print "Importing batch $cdrbatch\n" if $verbose;
108   my $error = FS::cdr::batch_import({
109     'batch_namevalue' => $cdrbatch,
110     'file'            => $cfh->filename,
111     'format'          => 'conexiant'
112   });
113   if ($error eq 'Empty file!') {
114     print "File contains no records\n" if $verbose;
115     $error = '';
116   } elsif ($error eq "All records in file were previously imported") {
117     print "File contains no new cdrs, no batch created\n" if $verbose;
118     $error = '';
119   } elsif ($verbose && !$error) {
120     print "File successfully imported\n";
121   }
122   die "Error importing $cdrbatch: $error" if $error;
123 }
124
125 exit;
126
127
128