[freeside-commits] branch master updated. db5e7f34b1e17ae6ce8909062537cc2fb98ca30d

Mark Wells mark at 420.am
Mon Feb 25 17:11:27 PST 2013


The branch, master has been updated
       via  db5e7f34b1e17ae6ce8909062537cc2fb98ca30d (commit)
      from  2fc12e6b5a376fef9b5f5bf0301aab8497c6a412 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit db5e7f34b1e17ae6ce8909062537cc2fb98ca30d
Author: Mark Wells <mark at freeside.biz>
Date:   Mon Feb 25 17:10:46 2013 -0800

    display inbound CDRs in selfservice, #18316; Taqua caller ID, #18574

diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm
index faf3778..38139e1 100644
--- a/FS/FS/ClientAPI/MyAccount.pm
+++ b/FS/FS/ClientAPI/MyAccount.pm
@@ -1723,7 +1723,34 @@ sub list_svcs {
               } else {
                 $hash{'name'} = $cust_main->name;
               }
+            } elsif ( $svcdb eq 'svc_phone' ) {
+              # could potentially show lots of things...
+              $hash{'outbound'} = 1;
+              $hash{'inbound'}  = 0;
+              if ( $part_pkg->plan eq 'voip_inbound' ) {
+                $hash{'outbound'} = 0;
+                $hash{'inbound'}  = 1;
+              } elsif ( $part_pkg->option('selfservice_inbound_format')
+                    or  $conf->config('selfservice-default_inbound_cdr_format')
+              ) {
+                $hash{'inbound'}  = 1;
+              }
+              foreach (qw(inbound outbound)) {
+                # hmm...we can't filter by status here, because there might
+                # not be cdr_terminations at all.  have to go by date.
+                # find all since the last bill date.
+                # XXX cdr types?  we are going to need them.
+                if ( $hash{$_} ) {
+                  my $sum_cdr = $svc_x->sum_cdrs(
+                    'inbound' => ( $_ eq 'inbound' ? 1 : 0 ),
+                    'begin'   => ($cust_pkg->last_bill || 0),
+                    'nonzero' => 1,
+                  );
+                  $hash{$_} = $sum_cdr->hashref;
+                }
+              }
             }
+
             # elsif ( $svcdb eq 'svc_phone' || $svcdb eq 'svc_port' ) {
             #  %hash = (
             #    %hash,
@@ -1996,7 +2023,7 @@ sub _list_cdr_usage {
   # we have to return the results all at once...
   my($svc_phone, $begin, $end, %opt) = @_;
   map [ $_->downstream_csv(%opt, 'keeparray' => 1) ],
-    $svc_phone->get_cdrs( 'begin'=>$begin, 'end'=>$end, );
+    $svc_phone->get_cdrs( 'begin'=>$begin, 'end'=>$end, %opt );
 }
 
 sub list_cdr_usage {
@@ -2026,18 +2053,21 @@ sub _usage_details {
   my %callback_opt;
   my $header = [];
   if ( $svcdb eq 'svc_phone' ) {
-    my $format   = $cust_pkg->part_pkg->option('output_format') || '';
-    $format = '' if $format =~ /^sum_/;
-    # sensible default if there is no format or it's a summary format
-    if ( $cust_pkg->part_pkg->plan eq 'voip_inbound' ) {
-      $format ||= 'source_default';
+    my $conf = FS::Conf->new;
+    my $format = '';
+    if ( $p->{inbound} ) {
+      $format = $cust_pkg->part_pkg->option('selfservice_inbound_format') 
+                || $conf->config('selfservice-default_inbound_cdr_format')
+                || 'source_default';
       $callback_opt{inbound} = 1;
+    } else {
+      $format = $cust_pkg->part_pkg->option('selfservice_format')
+                || $conf->config('selfservice-default_cdr_format')
+                || 'default';
     }
-    else {
-      $format ||= 'default';
-    }
-    
+
     $callback_opt{format} = $format;
+    $callback_opt{use_clid} = 1;
     $header = [ split(',', FS::cdr::invoice_header($format) ) ];
   }
 
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index 93aa84b..71b7ddf 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -717,6 +717,18 @@ my %batch_gateway_options = (
   },
 );
 
+my @cdr_formats = (
+  '' => '',
+  'default' => 'Default',
+  'source_default' => 'Default with source',
+  'accountcode_default' => 'Default plus accountcode',
+  'description_default' => 'Default with description field as destination',
+  'basic' => 'Basic',
+  'simple' => 'Simple',
+  'simple2' => 'Simple with source',
+  'accountcode_simple' => 'Simple with accountcode',
+);
+
 # takes the reason class (C, R, S) as an argument
 sub reason_type_options {
   my $reason_class = shift;
@@ -4760,6 +4772,13 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'cdr-taqua-callerid_rewrite',
+    'section'     => 'telephony',
+    'description' => 'For the Taqua CDR format, pull Caller ID blocking information from secondary CDRs.',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'cdr-asterisk_australia_rewrite',
     'section'     => 'telephony',
     'description' => 'For Asterisk CDRs, assign CDR type numbers based on Australian conventions.',
@@ -5351,6 +5370,22 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'selfservice-default_cdr_format',
+    'section'     => 'self-service',
+    'description' => 'Format for showing outbound CDRs in self-service.  The per-package option overrides this.',
+    'type'        => 'select',
+    'select_hash' => \@cdr_formats,
+  },
+
+  {
+    'key'         => 'selfservice-default_inbound_cdr_format',
+    'section'     => 'self-service',
+    'description' => 'Format for showing inbound CDRs in self-service.  The per-package option overrides this.  Leave blank to avoid showing these CDRs.',
+    'type'        => 'select',
+    'select_hash' => \@cdr_formats,
+  },
+
+  {
     'key'         => 'logout-timeout',
     'section'     => 'UI',
     'description' => 'If set, automatically log users out of the backoffice after this many minutes.',
diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm
index fedf28a..5e986ab 100644
--- a/FS/FS/cdr.pm
+++ b/FS/FS/cdr.pm
@@ -1173,6 +1173,8 @@ sub export_formats {
     length($price) ? ($opt{money_char} . $price) : '';
   };
 
+  my $src_sub = sub { $_[0]->clid || $_[0]->src };
+
   %export_formats = (
     'simple' => [
       sub { time2str($date_format, shift->calldate_unix ) },   #DATE
@@ -1187,7 +1189,7 @@ sub export_formats {
       sub { time2str($date_format, shift->calldate_unix ) },   #DATE
       sub { time2str('%r', shift->calldate_unix ) },   #TIME
       #'userfield',                                     #USER
-      'src',                                           #called from
+      $src_sub,                                           #called from
       'dst',                                           #NUMBER_DIALED
       $duration_sub,                                   #DURATION
       #sub { sprintf('%.3f', shift->upstream_price ) }, #PRICE
@@ -1196,7 +1198,7 @@ sub export_formats {
     'accountcode_simple' => [
       sub { time2str($date_format, shift->calldate_unix ) },   #DATE
       sub { time2str('%r', shift->calldate_unix ) },   #TIME
-      'src',                                           #called from
+      $src_sub,                                           #called from
       'accountcode',                                   #NUMBER_DIALED
       $duration_sub,                                   #DURATION
       $price_sub,
@@ -1204,14 +1206,14 @@ sub export_formats {
     'sum_duration' => [ 
       # for summary formats, the CDR is a fictitious object containing the 
       # total billsec and the phone number of the service
-      'src',
+      $src_sub,
       sub { my($cdr, %opt) = @_; $opt{ratename} },
       sub { my($cdr, %opt) = @_; $opt{count} },
       sub { my($cdr, %opt) = @_; int($opt{seconds}/60).'m' },
       $price_sub,
     ],
     'sum_count' => [
-      'src',
+      $src_sub,
       sub { my($cdr, %opt) = @_; $opt{ratename} },
       sub { my($cdr, %opt) = @_; $opt{count} },
       $price_sub,
@@ -1245,7 +1247,7 @@ sub export_formats {
       $price_sub,
     ],
   );
-  $export_formats{'source_default'} = [ 'src', @{ $export_formats{'default'} }, ];
+  $export_formats{'source_default'} = [ $src_sub, @{ $export_formats{'default'} }, ];
   $export_formats{'accountcode_default'} =
     [ @{ $export_formats{'default'} }[0,1],
       'accountcode',
@@ -1253,7 +1255,7 @@ sub export_formats {
     ];
   my @default = @{ $export_formats{'default'} };
   $export_formats{'description_default'} = 
-    [ 'src', @default[0..2], 
+    [ $src_sub, @default[0..2], 
       sub { my($cdr, %opt) = @_; $cdr->description },
       @default[4,5] ];
 
diff --git a/FS/FS/cdr/taqua62.pm b/FS/FS/cdr/taqua62.pm
index 862018e..aa94630 100644
--- a/FS/FS/cdr/taqua62.pm
+++ b/FS/FS/cdr/taqua62.pm
@@ -20,7 +20,9 @@ use FS::cdr qw(_cdr_date_parser_maker);
       my($cdr, $field, $conf, $hashref) = @_;
       $hashref->{skiprow} = 1
         unless ($field == 0 && $cdr->disposition == 100       )  #regular CDR
-            || ($field == 1 && $cdr->lastapp     eq 'acctcode'); #accountcode
+            || ($field == 1 && $cdr->lastapp     eq 'acctcode')  #accountcode
+            || ($field == 1 && $cdr->lastapp     eq 'CallerId')  #CID blocking
+            ;
       $cdr->cdrtypenum($field);
     },
 
diff --git a/FS/FS/part_pkg/voip_cdr.pm b/FS/FS/part_pkg/voip_cdr.pm
index aae51e9..04098a8 100644
--- a/FS/FS/part_pkg/voip_cdr.pm
+++ b/FS/FS/part_pkg/voip_cdr.pm
@@ -51,6 +51,11 @@ tie my %unrateable_opts, 'Tie::IxHash',
   2  => 'Flag for later review',
 ;
 
+tie my %detail_formats, 'Tie::IxHash',
+  '' => '',
+  FS::cdr::invoice_formats()
+;
+
 %info = (
   'name' => 'VoIP rating by plan of CDR records in an internal (or external) SQL table',
   'shortname' => 'VoIP/telco CDR rating (standard)',
@@ -211,12 +216,25 @@ tie my %unrateable_opts, 'Tie::IxHash',
                       },
 
     #false laziness w/cdr_termination.pm
-    'output_format' => { 'name' => 'CDR invoice display format',
+    'output_format' => { 'name' => 'CDR display format for invoices',
                          'type' => 'select',
-                         'select_options' => { FS::cdr::invoice_formats() },
+                         'select_options' => \%detail_formats,
                          'default'        => 'default', #XXX test
                        },
 
+    'selfservice_format' => 
+      { 'name' => 'CDR display format for selfservice',
+        'type' => 'select',
+        'select_options' => \%detail_formats,
+        'default' => 'default'
+      },
+    'selfservice_inbound_format' =>
+      { 'name' => 'Inbound CDR display format for selfservice',
+        'type' => 'select',
+        'select_options' => \%detail_formats,
+        'default' => ''
+      },
+
     'usage_section' => { 'name' => 'Section in which to place usage charges (whether separated or not): ',
                        },
 
@@ -297,7 +315,9 @@ tie my %unrateable_opts, 'Tie::IxHash',
                        skip_max_callers
                        use_duration
                        411_rewrite
-                       output_format usage_mandate summarize_usage usage_section
+                       output_format 
+                       selfservice_format selfservice_inbound_format
+                       usage_mandate summarize_usage usage_section
                        bill_every_call bill_inactive_svcs
                        count_available_phones suspend_bill 
                      )
diff --git a/FS/FS/svc_phone.pm b/FS/FS/svc_phone.pm
index bf610c6..f28002c 100644
--- a/FS/FS/svc_phone.pm
+++ b/FS/FS/svc_phone.pm
@@ -688,6 +688,8 @@ with the chosen prefix.
 
 =item disable_src => 1: Only match on "charged_party", not "src".
 
+=item nonzero: Only return CDRs where duration > 0.
+
 =item by_svcnum: not supported for svc_phone
 
 =item billsec_sum: Instead of returning all of the CDRs, return a single
@@ -755,6 +757,9 @@ sub psearch_cdrs {
   if ( $options{'end'} ) {
     push @where, 'startdate < '.  $options{'end'};
   }
+  if ( $options{'nonzero'} ) {
+    push @where, 'duration > 0';
+  }
 
   my $extra_sql = ( keys(%hash) ? ' AND ' : ' WHERE ' ). join(' AND ', @where );
 
@@ -781,6 +786,30 @@ sub get_cdrs {
   qsearch ( $psearch->{query} )
 }
 
+=item sum_cdrs
+
+Takes the same options as psearch_cdrs, but returns a single row containing
+"count" (the number of CDRs) and the sums of the following fields: duration,
+billsec, rated_price, rated_seconds, rated_minutes.
+
+Note that if any calls are not rated, their rated_* fields will be null.
+If you want to use those fields, pass the 'status' option to limit to 
+calls that have been rated.  This is intentional; please don't "fix" it.
+
+=cut
+
+sub sum_cdrs {
+  my $self = shift;
+  my $psearch = $self->psearch_cdrs(@_);
+  $psearch->{query}->{'select'} = join(',',
+    'COUNT(*) AS count',
+    map { "SUM($_) AS $_" }
+      qw(duration billsec rated_price rated_seconds rated_minutes)
+  );
+  # hack
+  $psearch->{query}->{'extra_sql'} =~ s/ ORDER BY.*$//;
+  qsearchs ( $psearch->{query} );
+}
 
 =back
 
diff --git a/FS/bin/freeside-cdrrewrited b/FS/bin/freeside-cdrrewrited
index f2c3926..16f931f 100644
--- a/FS/bin/freeside-cdrrewrited
+++ b/FS/bin/freeside-cdrrewrited
@@ -30,9 +30,9 @@ die "not running; cdr-asterisk_forward_rewrite, cdr-charged_party_rewrite ".
 
 #--
 
-my %accountcode_unmatch = ();
-my $accountcode_retry = 4 * 60 * 60; # 4 hours
-my $accountcode_giveup = 4 * 24 * 60 * 60; # 4 days
+my %sessionnum_unmatch = ();
+my $sessionnum_retry = 4 * 60 * 60; # 4 hours
+my $sessionnum_giveup = 4 * 24 * 60 * 60; # 4 days
 
 my %cdr_type = map { lc($_->cdrtypename) => $_->cdrtypenum } 
   qsearch('cdr_type',{});
@@ -45,8 +45,8 @@ while (1) {
   # instead of just doing this search like normal CDRs
 
   #hmm :/
-  my @recent = grep { ($accountcode_unmatch{$_} + $accountcode_retry) > time }
-                 keys %accountcode_unmatch;
+  my @recent = grep { ($sessionnum_unmatch{$_} + $sessionnum_retry) > time }
+                 keys %sessionnum_unmatch;
   my $extra_sql = scalar(@recent)
                     ? ' AND acctid NOT IN ('. join(',', @recent). ') '
                     : '';
@@ -136,45 +136,62 @@ while (1) {
 
     }
 
-    if ( $conf->exists('cdr-taqua-accountcode_rewrite')
-         && $cdr->lastapp eq 'acctcode' && $cdr->cdrtypenum == 1
+    if (     $cdr->cdrtypenum == 1
+         and $cdr->lastapp
+         and (
+            $conf->exists('cdr-taqua-accountcode_rewrite') or
+            $conf->exists('cdr-taqua-callerid_rewrite') )
        )
     {
 
       #find the matching CDR
-      my $primary = qsearchs('cdr', {
-        'sessionnum'  => $cdr->sessionnum,
-        'src'         => $cdr->subscriber,
-        #'accountcode' => '',
-      });
+      my %search = ( 'sessionnum' => $cdr->sessionnum );
+      if ( $cdr->lastapp eq 'acctcode' ) {
+        $search{'src'} = $cdr->subscriber;
+      } elsif ( $cdr->lastapp eq 'CallerId' ) {
+        $search{'dst'} = $cdr->subscriber;
+      }
+      my $primary = qsearchs('cdr', \%search);
 
       unless ( $primary ) {
 
         my $cantfind = "can't find primary CDR with session ". $cdr->sessionnum.
                        ", src ". $cdr->subscriber;
-        if ( $cdr->calldate_unix + $accountcode_giveup < time ) {
+        if ( $cdr->calldate_unix + $sessionnum_giveup < time ) {
           warn "ERROR: $cantfind; giving up\n";
-          push @status, 'taqua-accountcode-NOTFOUND';
+          push @status, 'taqua-sessionnum-NOTFOUND';
           $cdr->status('done'); #so it doesn't try to rate
-          delete $accountcode_unmatch{$cdr->acctid}; #so it doesn't suck mem
+          delete $sessionnum_unmatch{$cdr->acctid}; #so it doesn't suck mem
         } else {
           warn "WARNING: $cantfind; will keep trying\n";
-          $accountcode_unmatch{$cdr->acctid} = time;
+          $sessionnum_unmatch{$cdr->acctid} = time;
           next;
         }
 
       } else {
 
-        $primary->accountcode( $cdr->lastdata );
+        if ( $cdr->lastapp eq 'acctcode' ) {
+          # lastdata contains the dialed account code
+          $primary->accountcode( $cdr->lastdata );
+          push @status, 'taqua-accountcode';
+        } elsif ( $cdr->lastapp eq 'CallerId' ) {
+          # lastdata contains "allowed" or "restricted"
+          # or case variants thereof
+          if ( lc($cdr->lastdata) eq 'restricted' ) {
+            $primary->clid( 'PRIVATE' );
+          }
+          push @status, 'taqua-callerid';
+        } else {
+          warn "unknown Taqua service name: ".$cdr->lastapp."\n";
+        }
         #$primary->freesiderewritestatus( 'taqua-accountcode-primary' );
-        my $error = $primary->replace;
+        my $error = $primary->replace if $primary->modified;
         if ( $error ) {
           warn "WARNING: error rewriting primary CDR (will retry): $error\n";
           next;
         }
         $skip{$primary->acctid} = 1;
 
-        push @status, 'taqua-accountcode';
         $cdr->status('done'); #so it doesn't try to rate
 
       }
@@ -214,7 +231,10 @@ sub _shouldrun {
      $conf->exists('cdr-asterisk_forward_rewrite')
   || $conf->exists('cdr-asterisk_australia_rewrite')
   || $conf->exists('cdr-charged_party_rewrite')
-  || $conf->exists('cdr-taqua-accountcode_rewrite');
+  || $conf->exists('cdr-taqua-accountcode_rewrite')
+  || $conf->exists('cdr-taqua-callerid_rewrite')
+  || 0
+  ;
 }
 
 sub usage { 
diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
index de0ab1a..f7fe308 100755
--- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
+++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
@@ -873,6 +873,7 @@ sub view_cdr_details {
     'svcnum'      => $cgi->param('svcnum'),
     'beginning'   => $cgi->param('beginning') || '',
     'ending'      => $cgi->param('ending') || '',
+    'inbound'     => $cgi->param('inbound') || 0,
   );
 }
 
diff --git a/fs_selfservice/FS-SelfService/cgi/view_cdr_details.html b/fs_selfservice/FS-SelfService/cgi/view_cdr_details.html
index b0205ec..1342c08 100644
--- a/fs_selfservice/FS-SelfService/cgi/view_cdr_details.html
+++ b/fs_selfservice/FS-SelfService/cgi/view_cdr_details.html
@@ -1,5 +1,6 @@
 <%= $url = "$selfurl?session=$session_id;action="; ''; %>
-<%= include('header', 'Call usage for '.
+<%= include('header', ($inbound ? 'Dialed calls ' : 'Received calls ') . 
+                       ' for '.
                        Date::Format::time2str('%b %o %Y', $beginning).
                        ' - '.
                        Date::Format::time2str('%b %o %Y', $ending)
diff --git a/fs_selfservice/FS-SelfService/cgi/view_usage.html b/fs_selfservice/FS-SelfService/cgi/view_usage.html
index fd5426a..f707668 100644
--- a/fs_selfservice/FS-SelfService/cgi/view_usage.html
+++ b/fs_selfservice/FS-SelfService/cgi/view_usage.html
@@ -62,11 +62,22 @@
 <%= scalar(@svc_acct) ? '</TABLE><BR><BR>' : '' %>
 
 <%= if ( @svc_phone ) {
+      %any = ();
+      for my $dir (qw(outbound inbound)) {
+        $any{$dir} = grep { $_->{$dir} } @svc_phone;
+      }
       $OUT.= '<FONT SIZE="4">Call usage</FONT><BR><BR>
               <TABLE BGCOLOR="#cccccc">
                 <TR>
-                  <TH ALIGN="left">Number</TH>'; #"Account" ?
-                                                 #what else?
+                  <TH ALIGN="left">Number</TH>';
+      if ( $any{outbound} ) {
+        $OUT .= '
+                  <TH>Dialed</TH>';
+      }
+      if ( $any{inbound} ) {
+        $OUT .= '
+                  <TH>Received</TH>';
+      }
       $OUT .= '</TR>';
     } else {
       $OUT .= '';
@@ -76,10 +87,27 @@
 <%= foreach my $svc_phone ( @svc_phone ) {
       my $link = "${url}view_cdr_details;".
         "svcnum=$svc_phone->{'svcnum'};beginning=0;ending=0";
-  $OUT .= '<TR><TD>';
-    $OUT .= qq!<A HREF="$link">!. $svc_phone->{'label'}. ': '. $svc_phone->{'value'}.'</A>';
-  $OUT .= '</TD></TR>';
+  $OUT .= '<TR><TD>'. $svc_phone->{'label'}. ': '. $svc_phone->{'value'};
+  $OUT .= '</TD>';
+  # usage summary w/ links
+  for my $dir (qw(outbound inbound)) {
+    if ( $dir eq 'inbound' ) {
+      $link .= ';inbound=1';
+    }
+    if ( $svc_phone->{$dir} ) {
+      $OUT .= '<TD ALIGN="right">'.qq!<A HREF="$link">! .
+        sprintf('%d calls (%.0f minutes)',
+          $svc_phone->{$dir}->{'count'},
+          $svc_phone->{$dir}->{'duration'} / 60
+        ) .
+        '</A></TD>';
+    } elsif ( $any{$dir} )  {
+      $OUT .= '<TD></TD>';
+    }
   }
+  $OUT .= '</TR>';
+}
+'';
 %>
 
 <%= scalar(@svc_phone) ? '</TABLE><BR><BR>' : '' %>

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/ClientAPI/MyAccount.pm                       |   50 +++++++++++++---
 FS/FS/Conf.pm                                      |   35 +++++++++++
 FS/FS/cdr.pm                                       |   14 +++--
 FS/FS/cdr/taqua62.pm                               |    4 +-
 FS/FS/part_pkg/voip_cdr.pm                         |   26 ++++++++-
 FS/FS/svc_phone.pm                                 |   29 ++++++++++
 FS/bin/freeside-cdrrewrited                        |   60 +++++++++++++-------
 fs_selfservice/FS-SelfService/cgi/selfservice.cgi  |    1 +
 .../FS-SelfService/cgi/view_cdr_details.html       |    3 +-
 fs_selfservice/FS-SelfService/cgi/view_usage.html  |   38 +++++++++++--
 10 files changed, 214 insertions(+), 46 deletions(-)




More information about the freeside-commits mailing list