RT#37901: Galactic Telecom CDRs [field mappings]
[freeside.git] / FS / bin / freeside-cdr-portaone-import
1 #!/usr/bin/perl
2
3 use strict;
4
5 use Date::Format 'time2str';
6 use Date::Parse 'str2time';
7 use Getopt::Long;
8 use JSON;
9 use Net::HTTPS::Any qw(https_post);
10
11 use FS::Record qw(qsearchs dbh);
12 use FS::UID qw(adminsuidsetup);
13
14 sub usage {
15   "Usage:
16 freeside-cdr-portaone-import -h 'your.domain.com:443' -u switchusername -p switchpass 
17   [-s startdate] [-e enddate] [-v] freesideuser
18 ";
19 }
20
21 my ($host,$username,$password,$startdate,$enddate,$verbose);
22 GetOptions(
23   "enddate=s"   => \$enddate,
24   "host=s"      => \$host,
25   "password=s"  => \$password,
26   "startdate=s" => \$startdate,
27   "username=s"  => \$username,
28   "verbose"     => \$verbose,
29 );
30
31 my $fsuser = $ARGV[-1];
32
33 die usage() unless $host && $password && $username && $fsuser;
34
35 adminsuidsetup($fsuser);
36
37 my $port = 443;
38 if ($host =~ /^(.*)\:(.*)$/) {
39   $host = $1;
40   $port = $2;
41 }
42
43 if ($startdate) {
44   $startdate = str2time($startdate) or die "Can't parse startdate $startdate";
45   $startdate = time2str("%Y-%m-%d %H:%M:%S",$startdate);
46 }
47 unless ($startdate) {
48   my $lastbatch = qsearchs({
49     'table'     => 'cdr_batch',
50     'hashref'   => { 'cdrbatch' => {op=>'like', value=>'portaone-import%'}},
51     'order_by'  => 'ORDER BY _date DESC LIMIT 1',
52   });
53   $startdate = time2str("%Y-%m-%d %H:%M:%S", $lastbatch->_date + 1) if $lastbatch;
54 }
55 $startdate ||= '2010-01-01 00:00:00'; #seems decently in the past
56
57 my $now = time;
58 if ($enddate) {
59   $enddate = str2time($enddate) or die "Can't parse enddate $enddate";
60   $now = $enddate;
61   $enddate = time2str("%Y-%m-%d %H:%M:%S",$enddate);
62 }
63 $enddate ||= time2str("%Y-%m-%d %H:%M:%S",$now);
64
65
66 $FS::UID::AutoCommit = 0;
67
68 my $cdr_batch = new FS::cdr_batch({ 
69   'cdrbatch' => 'portaone-import-'. time2str('%Y/%m/%d-%T',$now),
70   '_date'    => $now,
71 });
72 my $error = $cdr_batch->insert;
73 if ($error) {
74   dbh->rollback;
75   die "Error creating batch: $error";
76 }
77
78 print "Downloading records from $startdate to $enddate\n" if $verbose;
79
80 my $auth_info; # needs to be declared undef for call_api
81 $auth_info = call_api('Session','login',{
82   'login'    => $username,
83   'password' => $password,
84 });
85
86 my $results = {};
87 my $custlist = call_api('Customer','get_customer_list');
88 my @custnum = map { $_->{'i_customer'} } @{$custlist->{'customer_list'}};
89 foreach my $custnum (@custnum) {
90   print "Retrieving for customer $custnum\n" if $verbose;
91   my $step = 500; # too many records was crashing server, so we request in chunks
92   my $lastcount = $step; # to get the while loop rolling
93   my $totalcount = 0; # for verbose display only
94   my $offset = 0;
95   while ($lastcount == $step) {
96     my $xdrs = call_api('Customer','get_customer_xdrs',{
97       'i_customer' => $custnum,
98       'from_date'  => $startdate,
99       'to_date'    => $enddate,
100       'cdr_entity' => 'A',
101       'limit'      => $step,
102       'offset'     => $offset,
103     });
104     my @xdrs = @{$xdrs->{'xdr_list'}};
105     print "Inserting ".@xdrs." records\n" if $verbose && @xdrs;
106     foreach my $xdr (@xdrs) {
107       my $desc = $xdr->{'country'};
108       if ($xdr->{'subdivision'}) {
109         $desc = ', ' . $desc if $desc;
110         $desc = $xdr->{'subdivision'} . $desc;
111       }
112       if ($xdr->{'description'}) {
113         $desc = ' (' . $desc . ')' if $desc;
114         $desc = $xdr->{'description'} . $desc;
115       }
116       my $cdr = FS::cdr->new ({
117         'cdrbatchnum'             => $cdr_batch->cdrbatchnum,
118         'uniqueid'                => $xdr->{'i_xdr'},
119         'src'                     => $xdr->{'CLI'},
120         'dst'                     => $xdr->{'CLD'},
121         'upstream_price'          => $xdr->{'charged_amount'},
122         'startdate'               => $xdr->{'unix_connect_time'},
123         'enddate'                 => $xdr->{'unix_disconnect_time'},
124         'accountcode'             => $xdr->{'account_id'},
125         'billsec'                 => $xdr->{'charged_quantity'},
126         'upstream_dst_regionname' => $desc,
127       });
128       $error = $cdr->insert;
129       if ($error) {
130         dbh->rollback;
131         die "Error inserting cdr: $error";
132       }
133     } #foreach $xdr
134     $totalcount += @xdrs;
135     $lastcount = @xdrs;
136     $offset += $step;
137   } #while $lastcount == $step
138   print scalar($totalcount) . " xdrs retrieved\n" if $verbose;
139 } #foreach $custnum
140
141 call_api('Session','logout',$auth_info);
142
143 ### Full list of fields returned by API:
144 #i_xdr                     int      The unique ID of the xdr record
145 #account_id                   int      The unique ID of the account database record
146 #CLI                       string   Calling Line Identification
147 #CLD                       string   Called Line Identification
148 #charged_amount            float    Amount charged
149 #charged_quantity          int      Units charged
150 #country                   string   Country
151 #subdivision               string   Country subdivision
152 #description               string   Destination description
153 #disconnect_cause          string   The code of disconnect cause
154 #bill_status               string   Call bill status
155 #disconnect_reason         string   Call disconnect reason
156 #connect_time              dateTime Call connect time
157 #unix_connect_time         int      Call connect time (expressed in Unix time format - seconds since epoch)
158 #disconnect_time           dateTime Call disconnect time 
159 #unix_disconnect_time      int      Call disconnect time (expressed in Unix time format - seconds since epoch)
160 #bill_time                 dateTime Call bill time 
161 #bit_flags                 int      Extended information how the service was used; the integer field that should be treated as a bit-map. Each currently used bit is listed in the Transaction_Flag_Types table (bit_offset indicates position)
162 #call_recording_url        string   Path to recorded .wav files
163 #call_recording_server_url string   URL to the recording server 
164
165 dbh->commit;
166
167 exit;
168
169 sub call_api {
170   my ($service,$method,$params) = @_;
171   my %auth_info = $auth_info ? ('auth_info' => encode_json($auth_info)) : ();
172   $params ||= {};
173   print "Calling $service/$method\n" if $verbose;
174   my ( $page, $response, %reply_headers ) = https_post(
175     'host'    => $host,
176     'port'    => $port,
177     'path'    => '/rest/'.$service.'/'.$method.'/',
178     'args'    => [ %auth_info, 'params' => encode_json($params) ],
179   );
180   return decode_json($page) if $response eq '200 OK';
181   dbh->rollback;
182   if ($response =~ /^500/) {
183     my $error = decode_json($page);
184     die "Server returned error during $service/$method: ".$error->{'faultstring'}
185       if $error->{'faultcode'};
186   }
187   die "Bad response from server during $service/$method: $response";
188 }
189
190