start of Enswitch CDR import, RT#11613
[freeside.git] / FS / FS / cdr.pm
index bf002f6..478dcff 100644 (file)
@@ -285,6 +285,10 @@ sub check {
 #  ;
 #  return $error if $error;
 
+  for my $f ( grep { $self->$_ =~ /\D/ } qw(startdate answerdate enddate)){
+    $self->$f( str2time($self->$f) );
+  }
+
   $self->calldate( $self->startdate_sql )
     if !$self->calldate && $self->startdate;
 
@@ -320,15 +324,19 @@ sub check {
   $self->SUPER::check;
 }
 
-=item is_tollfree
+=item is_tollfree [ COLUMN ]
 
-  Returns true when the cdr represents a toll free number and false otherwise.
+Returns true when the cdr represents a toll free number and false otherwise.
+
+By default, inspects the dst field, but an optional column name can be passed
+to inspect other field.
 
 =cut
 
 sub is_tollfree {
   my $self = shift;
-  ( $self->dst =~ /^(\+?1)?8(8|([02-7])\3)/ ) ? 1 : 0;
+  my $field = scalar(@_) ? shift : 'dst';
+  ( $self->$field() =~ /^(\+?1)?8(8|([02-7])\3)/ ) ? 1 : 0;
 }
 
 =item set_charged_party
@@ -357,6 +365,11 @@ sub set_charged_party {
         if $conf->exists('cdr-charged_party-accountcode-trim_leading_0s');
       $self->charged_party( $charged_party );
 
+    } elsif ( $conf->exists('cdr-charged_party-field') ) {
+
+      my $field = $conf->config('cdr-charged_party-field');
+      $self->charged_party( $self->$field() );
+
     } else {
 
       if ( $self->is_tollfree ) {
@@ -535,14 +548,20 @@ sub export_formats {
   my $conf = new FS::Conf;
   my $date_format = $conf->config('date_format') || '%m/%d/%Y';
 
+  # This is now smarter, and shows the call duration in the 
+  # largest units that accurately reflect the granularity.
   my $duration_sub = sub {
     my($cdr, %opt) = @_;
-    if ( $opt{minutes} ) {
-      $opt{minutes}. ( $opt{granularity} ? 'm' : ' call' );
-    } else {
-      #config if anyone really wants decimal minutes back
-      #sprintf('%.2fm', $cdr->billsec / 60 );
-      int($cdr->billsec / 60).'m '. ($cdr->billsec % 60).'s';
+    my $sec = $opt{seconds} || $cdr->billsec;
+    if ( length($opt{granularity}) && 
+         $opt{granularity} == 0 ) { #per call
+      return '1 call';
+    }
+    elsif ( $opt{granularity} == 60 ) {#full minutes
+      return sprintf("%.0fm",$sec/60);
+    }
+    else { #anything else
+      return sprintf("%dm %ds", $sec/60, $sec%60);
     }
   };
 
@@ -659,6 +678,50 @@ sub invoice_header {
   $export_names{$format}->{'invoice_header'};
 }
 
+=item clear_status 
+
+Clears cdr and any associated cdr_termination statuses - used for 
+CDR reprocessing.
+
+=cut
+
+sub clear_status {
+  my $self = shift;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  $self->freesidestatus('');
+  my $error = $self->replace;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  } 
+
+  my @cdr_termination = qsearch('cdr_termination', 
+                               { 'acctid' => $self->acctid } );
+  foreach my $cdr_termination ( @cdr_termination ) {
+      $cdr_termination->status('');
+      $error = $cdr_termination->replace;
+      if ( $error ) {
+       $dbh->rollback if $oldAutoCommit;
+       return $error;
+      } 
+  }
+  
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+  '';
+}
+
 =item import_formats
 
 Returns an ordered list of key value pairs containing import format names
@@ -755,14 +818,24 @@ sub _cdr_date_parse {
 
   if ( $date =~ /^\s*(\d{4})\D(\d{1,2})\D(\d{1,2})\D+(\d{1,2})\D(\d{1,2})\D(\d{1,2})(\D|$)/ ) {
     ($year, $mon, $day, $hour, $min, $sec) = ( $1, $2, $3, $4, $5, $6 );
-  } elsif ( $date  =~ /^\s*(\d{1,2})\D(\d{1,2})\D(\d{4})\s+(\d{1,2})\D(\d{1,2})\D(\d{1,2})(\D|$)/ ) {
+  } elsif ( $date  =~ /^\s*(\d{1,2})\D(\d{1,2})\D(\d{4})\s+(\d{1,2})\D(\d{1,2})(?:\D(\d{1,2}))?(\D|$)/ ) {
+    # 8/26/2010 12:20:01
+    # optionally without seconds
     ($mon, $day, $year, $hour, $min, $sec) = ( $1, $2, $3, $4, $5, $6 );
+    $sec = 0 if !defined($sec);
   } elsif ( $date  =~ /^\s*(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d+\.\d+)(\D|$)/ ) {
     # broadsoft: 20081223201938.314
     ($year, $mon, $day, $hour, $min, $sec) = ( $1, $2, $3, $4, $5, $6 );
+  } elsif ( $date  =~ /^\s*(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\d+(\D|$)/ ) {
+    # Taqua OM:  20050422203450943
+    ($year, $mon, $day, $hour, $min, $sec) = ( $1, $2, $3, $4, $5, $6 );
   } elsif ( $date  =~ /^\s*(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/ ) {
     # WIP: 20100329121420
     ($year, $mon, $day, $hour, $min, $sec) = ( $1, $2, $3, $4, $5, $6 );
+  } elsif ( $date =~ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/) {
+    # Telos
+    ($year, $mon, $day, $hour, $min, $sec) = ( $1, $2, $3, $4, $5, $6 );
+    $options{gmt} = 1;
   } else {
      die "unparsable date: $date"; #maybe we shouldn't die...
   }
@@ -829,6 +902,15 @@ my %import_options = (
     { map { $_ => $cdr_info{$_}->{'fixedlength_format'}; }
           keys %cdr_info
     },
+
+  'format_xml_formats' =>
+    { map { $_ => $cdr_info{$_}->{'xml_format'}; }
+          keys %cdr_info
+    },
+
+  'format_row_callbacks' => { map { $_ => $cdr_info{$_}->{'row_callback'}; }
+                                  keys %cdr_info
+                            },
 );
 
 sub _import_options {
@@ -879,9 +961,14 @@ sub _upgrade_data {
 
   my %cdrbatchnum = ();
   while (my $row = $sth->fetchrow_arrayref) {
-    my $cdr_batch = new FS::cdr_batch { 'cdrbatch' => $row->[0] };
-    my $error = $cdr_batch->insert;
-    die $error if $error;
+
+    my $cdr_batch = qsearchs( 'cdr_batch', { 'cdrbatch' => $row->[0] } );
+    unless ( $cdr_batch ) {
+      $cdr_batch = new FS::cdr_batch { 'cdrbatch' => $row->[0] };
+      my $error = $cdr_batch->insert;
+      die $error if $error;
+    }
+
     $cdrbatchnum{$row->[0]} = $cdr_batch->cdrbatchnum;
   }