correctly handle percentage discounts with duration less than package billing cycle...
[freeside.git] / bin / cdr-voipnow.import
1 #!/usr/bin/perl
2
3 use strict;
4 use vars qw( $DEBUG );
5 use Date::Parse 'str2time';
6 use Date::Format 'time2str';
7 use FS::UID qw(adminsuidsetup dbh);
8 use FS::Record qw(qsearchs);
9 use FS::cdr;
10 use DBI;
11 use Getopt::Std;
12
13 my %opt;
14 getopts('H:U:P:D:T:vs:e:', \%opt);
15 my $user = shift or die &usage;
16
17 my $dsn = 'dbi:mysql';
18 $dsn .= ":database=$opt{D}" if $opt{D};
19 $dsn .= ":host=$opt{H}" if $opt{H};
20
21 my $mysql = DBI->connect($dsn, $opt{U}, $opt{P}) 
22   or die $DBI::errstr;
23
24 adminsuidsetup $user;
25 $FS::UID::AutoCommit = 0;
26 my $fsdbh = FS::UID::dbh;
27
28 # don't use freesidestatus
29
30 my $start_id;
31 if ( $opt{s} ) {
32   $start_id = $opt{s};
33 }
34 else {
35   my $last_cdr = qsearchs({
36       'table'   => 'cdr',
37       'hashref' => {},
38       'extra_sql' => 'ORDER BY cdrid DESC LIMIT 1',
39     });
40   $start_id = $last_cdr ? $last_cdr->cdrid + 1: 1;
41 }
42 my $end_id = $opt{e};
43 print "Selecting CDRs from $start_id to ".($end_id || 'end')."...\n";
44
45 my $table = $opt{T} || 'call_history';
46 # spelled "disposion" in the table
47 my @cols = ( qw( 
48   id extension_number flow channel partyid start answer duration disposion did
49   client_client_id ) );
50 my $sql = 'SELECT '.join(',', @cols). " FROM $table WHERE id >= $start_id";
51 $sql .= " AND id <= $end_id" if $end_id;
52 $sql .= " ORDER BY id";
53 my $sth = $mysql->prepare($sql);
54 $sth->execute;
55 print "Importing ".$sth->rows." records...\n";
56
57 my $cdr_batch = new FS::cdr_batch({ 
58     'cdrbatch' => 'mysql-import-'. time2str('%Y/%m/%d-%T',time),
59   });
60 my $error = $cdr_batch->insert;
61 die $error if $error;
62 my $cdrbatchnum = $cdr_batch->cdrbatchnum;
63 my $imported = 0;
64 my $skipped = 0;
65
66 my $row;
67 my ($first, $last);
68 while ( $row = $sth->fetchrow_hashref ) {
69   if ( $opt{s} # skip this check if the range doesn't overlap
70       and qsearchs('cdr', { cdrid => $row->{id} } ) ) {
71     $skipped++;
72     print $row->{id} ." (skipped)\n" if $opt{v};
73     next;
74   }
75   my $cdr = FS::cdr->new({
76       cdrid         => $row->{id},
77       channel       => $row->{channel},
78       duration      => $row->{duration},
79       billsec       => $row->{duration},
80       disposition   => $row->{disposion},
81       startdate     => str2time($row->{start}),
82       answerdate    => str2time($row->{answer}),
83       cdrbatchnum   => $cdrbatchnum,
84       accountcode   => $row->{client_client_id},
85     }
86   );
87   print $row->{id},"\n" if $opt{v};
88   if ( $row->{flow} eq 'out' ) {
89     $cdr->src($row->{'extension_number'});
90     $cdr->dst($row->{'partyid'});
91   }
92   elsif ( $row->{flow} eq 'in' ) {
93     $cdr->dst($row->{'did'});
94     $cdr->src($row->{'partyid'});
95   }
96   else {
97     $fsdbh->rollback;
98     die $row->{id} .": invalid flow value: '".$row->{flow}."'\n";
99   }
100   my $error = $cdr->insert;
101   if($error) {
102     $fsdbh->rollback;
103     die $row->{id} . ": failed import: $error\n";
104   }
105   $first ||= $row->{id};
106   $last = $row->{id};
107   $imported++;
108 }
109 $fsdbh->commit or die $fsdbh->errstr;
110 print "Done.\n";
111 print "Imported $imported CDRs ($first - $last).\n" if $imported;
112 print "Skipped $skipped duplicates.\n" if $skipped;
113 $mysql->disconnect;
114
115 sub usage {
116   "Usage: \n  cdr-voipnow.import\n\t[ -H host ]\n\t-D database\n\t-U user\n\t-P password\n\t[ -v ] [ -s start ] [ -e end ]\n\tfreesideuser\n";
117 }
118
119 =head1 NAME
120
121 cdr-voipnow.import - Import call data records (CDRs) from a 4psa VoipNow system
122
123 =head1 SYNOPSIS
124
125   cdr-voipnow.import [ -H host ] -D database -U user -P password 
126     [ -v ] [ -s start ] [ -e end ] freesideuser
127
128 =head1 DESCRIPTION
129
130 Connects to a MySQL database and downloads CDRs from the "call_history" table.
131 The "id" field maps to "cdrid" in Freeside.  Other than that, the following
132 fields are imported: channel, duration, billsec, startdate, answerdate,
133 disposition, src, dst.  src and dst are inferred from the "extension_number"
134 and "partyid" fields, with the value of the "flow" field (in or out) deciding
135 which is the source number and which is the destination.
136
137 Any import errors (except duplicates) will abort and roll back the 
138 transaction.
139
140 =head1 OPTIONS
141
142 -H, -D, -U, -P: parameters to connect to the database: host, database name
143 user, password.  Required, except -H, which defaults to localhost.
144
145 -s: set the lowest CDR id to import.  By default, the script will find 
146 the highest existing cdrid and import all CDRs with ids greater than that.
147 -s overrides this and turns on duplicate checking.
148
149 -e: set the highest CDR id to import.  By default, this is unlimited.
150
151 -v: report all CDR ids as they are imported.
152
153 =cut