add cdr-charged_party-truncate_{length,prefix} in order to trim charged_party to...
[freeside.git] / FS / FS / cdr.pm
index 3c806f4..2a235cc 100644 (file)
@@ -130,6 +130,8 @@ following fields are currently supported:
 
 =item freesidestatus - NULL, done (or something)
 
+=item freesiderewritestatus - NULL, done (or something)
+
 =item cdrbatch
 
 =back
@@ -228,6 +230,7 @@ sub check {
 #    || $self->ut_numbern('upstream_rateid')
 #    || $self->ut_numbern('svcnum')
 #    || $self->ut_textn('freesidestatus')
+#    || $self->ut_textn('freesiderewritestatus')
 #  ;
 #  return $error if $error;
 
@@ -243,6 +246,55 @@ sub check {
     $self->billsec(  $self->enddate - $self->answerdate );
   } 
 
+  $self->set_charged_party;
+
+  #check the foreign keys even?
+  #do we want to outright *reject* the CDR?
+  my $error =
+       $self->ut_numbern('acctid')
+
+  #add a config option to turn these back on if someone needs 'em
+  #
+  #  #Usage = 1, S&E = 7, OC&C = 8
+  #  || $self->ut_foreign_keyn('cdrtypenum',  'cdr_type',     'cdrtypenum' )
+  #
+  #  #the big list in appendix 2
+  #  || $self->ut_foreign_keyn('calltypenum', 'cdr_calltype', 'calltypenum' )
+  #
+  #  # Telstra =1, Optus = 2, RSL COM = 3
+  #  || $self->ut_foreign_keyn('carrierid', 'cdr_carrier', 'carrierid' )
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=item is_tollfree
+
+  Returns true when the cdr represents a toll free number and false otherwise.
+
+=cut
+
+sub is_tollfree {
+  my $self = shift;
+  ( $self->dst =~ /^(\+?1)?8(8|([02-7])\3)/ ) ? 1 : 0;
+}
+
+=item set_charged_party
+
+If the charged_party field is already set, does nothing.  Otherwise:
+
+If the cdr-charged_party-accountcode config option is enabled, sets the
+charged_party to the accountcode.
+
+Otherwise sets the charged_party normally: to the src field in most cases,
+or to the dst field if it is a toll free number.
+
+=cut
+
+sub set_charged_party {
+  my $self = shift;
+
   my $conf = new FS::Conf;
 
   unless ( $self->charged_party ) {
@@ -253,7 +305,7 @@ sub check {
 
     } else {
 
-      if ( $self->dst =~ /^(\+?1)?8[02-8]{2}/ ) {
+      if ( $self->is_tollfree ) {
         $self->charged_party($self->dst);
       } else {
         $self->charged_party($self->src);
@@ -263,25 +315,14 @@ sub check {
 
   }
 
-  #check the foreign keys even?
-  #do we want to outright *reject* the CDR?
-  my $error =
-       $self->ut_numbern('acctid')
+  my $prefix = $conf->config('cdr-charged_party-truncate_prefix');
+  my $prefix_len = length($prefix);
+  my $trunc_len = $conf->config('cdr-charged_party-truncate_length');
 
-  #add a config option to turn these back on if someone needs 'em
-  #
-  #  #Usage = 1, S&E = 7, OC&C = 8
-  #  || $self->ut_foreign_keyn('cdrtypenum',  'cdr_type',     'cdrtypenum' )
-  #
-  #  #the big list in appendix 2
-  #  || $self->ut_foreign_keyn('calltypenum', 'cdr_calltype', 'calltypenum' )
-  #
-  #  # Telstra =1, Optus = 2, RSL COM = 3
-  #  || $self->ut_foreign_keyn('carrierid', 'cdr_carrier', 'carrierid' )
-  ;
-  return $error if $error;
+  $self->charged_party( substr($self->charged_party, 0, $trunc_len) )
+    if $prefix_len && $trunc_len
+    && substr($self->charged_party, 0, $prefix_len) eq $prefix;
 
-  $self->SUPER::check;
 }
 
 =item set_status_and_rated_price STATUS [ RATED_PRICE ]
@@ -436,14 +477,27 @@ my %export_names = (
   },
   'default' => {
     'name'           => 'Default',
-    'invoice_header' => 'Date,Time,Duration,Price,Number,Destination',
+    'invoice_header' => 'Date,Time,Number,Destination,Duration,Price',
   },
   'source_default' => {
     'name'           => 'Default with source',
-    'invoice_header' => 'Caller,Date,Time,Duration,Number,Destination,Price',
+    'invoice_header' => 'Caller,Date,Time,Number,Destination,Duration,Price',
+  },
+  'accountcode_default' => {
+    'name'           => 'Default plus accountcode',
+    'invoice_header' => 'Date,Time,Account,Number,Destination,Duration,Price',
   },
 );
 
+my $duration_sub = sub {
+  my($cdr, %opt) = @_;
+  if ( $opt{minutes} ) {
+    $opt{minutes}. ( $opt{granularity} ? 'm' : ' call' );
+  } else {
+    sprintf('%.2fm', $cdr->billsec / 60 );
+  }
+};
+
 my %export_formats = (
   'convergent' => [
     'carriername', #CARRIER
@@ -465,8 +519,9 @@ my %export_formats = (
     sub { time2str('%r', shift->calldate_unix ) },   #TIME
     'userfield',                                     #USER
     'dst',                                           #NUMBER_DIALED
-    sub { sprintf('%.2fm', shift->billsec / 60 ) },  #DURATION
-    sub { sprintf('%.3f', shift->upstream_price ) }, #PRICE
+    $duration_sub,                                   #DURATION
+    #sub { sprintf('%.3f', shift->upstream_price ) }, #PRICE
+    sub { my($cdr, %opt) = @_; $opt{money_char}. $opt{charge}; }, #PRICE
   ],
   'simple2' => [
     sub { time2str('%D', shift->calldate_unix ) },   #DATE
@@ -474,8 +529,9 @@ my %export_formats = (
     #'userfield',                                     #USER
     'dst',                                           #NUMBER_DIALED
     'src',                                           #called from
-    sub { sprintf('%.2fm', shift->billsec / 60 ) },  #DURATION
-    sub { sprintf('%.3f', shift->upstream_price ) }, #PRICE
+    $duration_sub,                                   #DURATION
+    #sub { sprintf('%.3f', shift->upstream_price ) }, #PRICE
+    sub { my($cdr, %opt) = @_; $opt{money_char}. $opt{charge}; }, #PRICE
   ],
   'default' => [
 
@@ -487,27 +543,26 @@ my %export_formats = (
     sub { time2str('%r', shift->calldate_unix ) },
           # time2str("%c", $cdr->calldate_unix),  #XXX this should probably be a config option dropdown so they can select US vs- rest of world dates or whatnot
 
-    #DURATION
-    sub { my($cdr, %opt) = @_;
-          $opt{minutes}. ( $opt{granularity} ? 'm' : ' call' );
-        },
-
-    #PRICE
-    sub { my($cdr, %opt) = @_; $opt{money_char}. $opt{charge}; },
-
     #DEST ("Number")
     sub { my($cdr, %opt) = @_; $opt{pretty_dst} || $cdr->dst; },
 
     #REGIONNAME ("Destination")
     sub { my($cdr, %opt) = @_; $opt{dst_regionname}; },
 
+    #DURATION
+    $duration_sub,
+
+    #PRICE
+    sub { my($cdr, %opt) = @_; $opt{money_char}. $opt{charge}; },
+
   ],
 );
-$export_formats{'source_default'} = [ 'src',
-                                      @{ $export_formats{'default'} }[0..2],
-                                      @{ $export_formats{'default'} }[4..5],
-                                      @{ $export_formats{'default'} }[3],
-                                    ];
+$export_formats{'source_default'} = [ 'src', @{ $export_formats{'default'} }, ];
+$export_formats{'accountcode_default'} =
+  [ @{ $export_formats{'default'} }[0,1],
+    'accountcode',
+    @{ $export_formats{'default'} }[2..5],
+  ];
 
 sub downstream_csv {
   my( $self, %opt ) = @_;
@@ -634,10 +689,11 @@ sub _cdr_min_parse {
 
 sub _cdr_date_parser_maker {
   my $field = shift;
+  my %options = @_;
   my @fields = ref($field) ? @$field : ($field);
   return sub {
     my( $cdr, $datestring ) = @_;
-    my $unixdate = eval { _cdr_date_parse($datestring) };
+    my $unixdate = eval { _cdr_date_parse($datestring, %options) };
     die "error parsing date for @fields from $datestring: $@\n" if $@;
     $cdr->$_($unixdate) foreach @fields;
   };
@@ -645,6 +701,7 @@ sub _cdr_date_parser_maker {
 
 sub _cdr_date_parse {
   my $date = shift;
+  my %options = @_;
 
   return '' unless length($date); #that's okay, it becomes NULL
 
@@ -664,7 +721,11 @@ sub _cdr_date_parse {
   return '' if $year == 1900 && $mon == 1 && $day == 1
             && $hour == 0    && $min == 0 && $sec == 0;
 
-  timelocal($sec, $min, $hour, $day, $mon-1, $year);
+  if ($options{gmt}) {
+    timegm($sec, $min, $hour, $day, $mon-1, $year);
+  } else {
+    timelocal($sec, $min, $hour, $day, $mon-1, $year);
+  }
 }
 
 =item batch_import HASHREF