basic CDR viewing from self-service, RT#4018
authorivan <ivan>
Mon, 18 May 2009 09:55:30 +0000 (09:55 +0000)
committerivan <ivan>
Mon, 18 May 2009 09:55:30 +0000 (09:55 +0000)
FS/FS/ClientAPI/MyAccount.pm
FS/FS/UI/bytecount.pm
FS/FS/cust_svc.pm
fs_selfservice/FS-SelfService/SelfService.pm
fs_selfservice/FS-SelfService/cgi/header.html [new file with mode: 0644]
fs_selfservice/FS-SelfService/cgi/selfservice.cgi
fs_selfservice/FS-SelfService/cgi/view_cdr_details.html [new file with mode: 0644]
fs_selfservice/FS-SelfService/cgi/view_usage.html

index d64c72c..ab50968 100644 (file)
@@ -10,7 +10,7 @@ use Business::CreditCard;
 use Time::Duration;
 use FS::UI::Web::small_custview qw(small_custview); #less doh
 use FS::UI::Web;
-use FS::UI::bytecount;
+use FS::UI::bytecount qw( display_bytecount );
 use FS::Conf;
 use FS::Record qw(qsearch qsearchs);
 use FS::Msgcat qw(gettext);
@@ -772,8 +772,14 @@ sub list_svcs {
                          : $cust_main->unsuspended_pkgs ) {
     push @cust_svc, @{[ $cust_pkg->cust_svc ]}; #@{[ ]} to force array context
   }
-  @cust_svc = grep { $_->part_svc->svcdb eq $p->{'svcdb'} } @cust_svc
-    if $p->{'svcdb'};
+  if ( $p->{'svcdb'} ) {
+    my $svcdb = ref($p->{'svcdb'}) eq 'HASH'
+                  ? $p->{'svcdb'}
+                  : ref($p->{'svcdb'}) eq 'ARRAY'
+                    ? { map { $_=>1 } @{ $p->{'svcdb'} } }
+                    : { $p->{'svcdb'} => 1 };
+    @cust_svc = grep $svcdb->{ $_->part_svc->svcdb }, @cust_svc
+  }
 
   #@svc_x = sort { $a->domain cmp $b->domain || $a->username cmp $b->username }
   #              @svc_x;
@@ -781,30 +787,51 @@ sub list_svcs {
   { 
     #no#'svcnum'   => $session->{'svcnum'},
     'custnum'  => $custnum,
-    'svcs'     => [ map { 
-                          my $svc_x = $_->svc_x;
-                          my($label, $value) = $_->label;
-                          my $part_pkg = $svc_x->cust_svc->cust_pkg->part_pkg;
-
-                          { 'svcnum'    => $_->svcnum,
-                            'label'     => $label,
-                            'value'     => $value,
-                            'username'  => $svc_x->username,
-                            'email'     => $svc_x->email,
-                            'seconds'   => $svc_x->seconds,
-                            'upbytes'   => FS::UI::bytecount::display_bytecount($svc_x->upbytes),
-                            'downbytes' => FS::UI::bytecount::display_bytecount($svc_x->downbytes),
-                            'totalbytes'=> FS::UI::bytecount::display_bytecount($svc_x->totalbytes),
-                            'recharge_amount' => $part_pkg->option('recharge_amount', 1),
-                            'recharge_seconds' => $part_pkg->option('recharge_seconds', 1),
-                            'recharge_upbytes' => FS::UI::bytecount::display_bytecount($part_pkg->option('recharge_upbytes', 1)),
-                            'recharge_downbytes' => FS::UI::bytecount::display_bytecount($part_pkg->option('recharge_downbytes', 1)),
-                            'recharge_totalbytes' => FS::UI::bytecount::display_bytecount($part_pkg->option('recharge_totalbytes', 1)),
-                            # more...
-                          };
-                        }
-                        @cust_svc
-                  ],
+    'svcs'     => [
+      map { 
+            my $svc_x = $_->svc_x;
+            my($label, $value) = $_->label;
+            my $svcdb = $_->part_svc->svcdb;
+            my $part_pkg = $_->cust_pkg->part_pkg;
+
+            my %hash = (
+              'svcnum' => $_->svcnum,
+              'svcdb'  => $svcdb,
+              'label'  => $label,
+              'value'  => $value,
+            );
+
+            if ( $svcdb eq 'svc_acct' ) {
+              %hash = (
+                %hash,
+                'username'   => $svc_x->username,
+                'email'      => $svc_x->email,
+                'seconds'    => $svc_x->seconds,
+                'upbytes'    => display_bytecount($svc_x->upbytes),
+                'downbytes'  => display_bytecount($svc_x->downbytes),
+                'totalbytes' => display_bytecount($svc_x->totalbytes),
+
+                'recharge_amount'  => $part_pkg->option('recharge_amount',1),
+                'recharge_seconds' => $part_pkg->option('recharge_seconds',1),
+                'recharge_upbytes'    =>
+                  display_bytecount($part_pkg->option('recharge_upbytes',1)),
+                'recharge_downbytes'  =>
+                  display_bytecount($part_pkg->option('recharge_downbytes',1)),
+                'recharge_totalbytes' =>
+                  display_bytecount($part_pkg->option('recharge_totalbytes',1)),
+                # more...
+              );
+
+            } elsif ( $svcdb eq 'svc_phone' ) {
+              %hash = (
+                %hash,
+              );
+            }
+
+            \%hash;
+          }
+          @cust_svc
+    ],
   };
 
 }
@@ -814,9 +841,8 @@ sub _list_svc_usage {
   my @usage = ();
   foreach my $part_export ( 
     map { qsearch ( 'part_export', { 'exporttype' => $_ } ) }
-    qw (sqlradius sqlradius_withdomain')
+    qw( sqlradius sqlradius_withdomain )
   ) {
-
     push @usage, @ { $part_export->usage_sessions($begin, $end, $svc_acct) };
   }
   (@usage);
@@ -849,29 +875,50 @@ sub list_support_usage {
   _usage_details(\&_list_support_usage, @_);
 }
 
+sub _list_cdr_usage {
+  my($svc_phone, $begin, $end) = @_;
+  map [ $_->downstream_csv('format' => 'default') ], #XXX config for format
+      $svc_phone->cust_svc->get_cdrs( 'begin'=>$begin, 'end'=>$end, );
+}
+
+sub list_cdr_usage {
+  my $p = shift;
+  _usage_details( \&_list_cdr_usage, $p,
+                  'svcdb' => 'svc_phone',
+                );
+}
+
 sub _usage_details {
-  my ($callback, $p) = (shift,shift);
+  my($callback, $p, %opt) = @_;
 
   my($context, $session, $custnum) = _custoragent_session_custnum($p);
   return { 'error' => $session } if $context eq 'error';
 
   my $search = { 'svcnum' => $p->{'svcnum'} };
   $search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent';
-  my $svc_acct = qsearchs ( 'svc_acct', $search );
+
+  my $svcdb = $opt{'svcdb'} || 'svc_acct';
+
+  my $svc_x = qsearchs( $svcdb, $search );
   return { 'error' => 'No service selected in list_svc_usage' } 
-    unless $svc_acct;
+    unless $svc_x;
 
-  my $freq   = $svc_acct->cust_svc->cust_pkg->part_pkg->freq;
-  my $start  = $svc_acct->cust_svc->cust_pkg->setup;
-  #my $end    = $svc_acct->cust_svc->cust_pkg->bill; # or time?
-  my $end    = time;
+  my $header = $svcdb eq 'svc_phone'
+                 ? [ split(',', FS::cdr::invoice_header('default') ) ]  #XXX
+                 : [];
 
-  unless($p->{beginning}){
-    $p->{beginning} = $svc_acct->cust_svc->cust_pkg->last_bill;
-    $p->{ending} = $end;
+  my $cust_pkg = $svc_x->cust_svc->cust_pkg;
+  my $freq     = $cust_pkg->part_pkg->freq;
+  my $start    = $cust_pkg->setup;
+  #my $end      = $cust_pkg->bill; # or time?
+  my $end      = time;
+
+  unless ( $p->{beginning} ) {
+    $p->{beginning} = $cust_pkg->last_bill;
+    $p->{ending}    = $end;
   }
 
-  my (@usage) = &$callback($svc_acct,$p->{beginning},$p->{ending});
+  my (@usage) = &$callback($svc_x, $p->{beginning}, $p->{ending});
 
   #kinda false laziness with FS::cust_main::bill, but perhaps
   #we should really change this bit to DateTime and DateTime::Duration
@@ -914,6 +961,7 @@ sub _usage_details {
     'ending'    => $p->{ending},
     'previous'  => ($previous > $start) ? $previous : $start,
     'next'      => ($next < $end) ? $next : $end,
+    'header'    => $header,
     'usage'     => \@usage,
   };
 }
index 0ddc754..7e78bf5 100644 (file)
@@ -1,10 +1,15 @@
 package FS::UI::bytecount;
 
 use strict;
-use vars qw($DEBUG $me);
+use vars qw($DEBUG $me @ISA @EXPORT_OK);
+use Exporter;
 use FS::Conf;
 use Number::Format 1.50;
 
+@ISA = qw( Exporter );
+
+@EXPORT_OK = qw( bytecount_unexact parse_bytecount display_bytecount );
+
 $DEBUG = 0;
 $me = '[FS::UID::bytecount]';
 
index c4a75f7..fe83138 100644 (file)
@@ -692,32 +692,56 @@ CDRs are associated with svc_phone services via svc_phone.phonenum
 =cut
 
 sub get_cdrs_for_update {
+  my $self = shift;
+  $self->get_cdrs( 'freesidestatus' => '',
+                   'for_update'     => 1,
+                   @_,
+                 );
+}
+
+sub get_cdrs {
   my($self, %options) = @_;
 
   my @fields = ( 'charged_party' );
   push @fields, 'src' unless $options{'disable_src'};
 
-  #CDRs are now associated with svc_phone services via svc_phone.phonenum
+  my $for_update = $options{'for_update'} ? 'FOR UPDATE' : '';
+
+  my %hash = ();
+  $hash{'freesidestatus'} = $options{'freesidestatus'}
+    if exists($options{'freesidestatus'});
+
+  #CDRs are associated with svc_phone services via svc_phone.phonenum
+
   #return () unless $self->svc_x->isa('FS::svc_phone');
   return () unless $self->part_svc->svcdb eq 'svc_phone';
   my $number = $self->svc_x->phonenum;
 
   my $prefix = $options{'default_prefix'};
 
-  my @where =  map " $_ = '$number'        ", @fields;
-  push @where, map " $_ = '$prefix$number' ", @fields
+  my @orwhere =  map " $_ = '$number'        ", @fields;
+  push @orwhere, map " $_ = '$prefix$number' ", @fields
     if length($prefix);
   if ( $prefix =~ /^\+(\d+)$/ ) {
-    push @where, map " $_ = '$1$number' ", @fields
+    push @orwhere, map " $_ = '$1$number' ", @fields
+  }
+
+  my @where = ( ' ( '. join(' OR ', @orwhere ). ' ) ' );
+
+  if ( $options{'begin'} ) {
+    push @where, 'startdate >= '. $options{'begin'};
+  }
+  if ( $options{'end'} ) {
+    push @where, 'startdate < '.  $options{'end'};
   }
 
-  my $extra_sql = ' AND ( '. join(' OR ', @where ). ' ) ';
+  my $extra_sql = ( keys(%hash) ? ' AND ' : ' WHERE ' ). join(' AND ', @where );
 
   my @cdrs =
     qsearch( {
       'table'      => 'cdr',
-      'hashref'    => { 'freesidestatus' => '', },
-      'extra_sql'  => "$extra_sql FOR UPDATE",
+      'hashref'    => \%hash,
+      'extra_sql'  => "$extra_sql $for_update",
     } );
 
   @cdrs;
index fef2115..47f312a 100644 (file)
@@ -45,6 +45,7 @@ $socket .= '.'.$tag if defined $tag && length($tag);
   'list_pkgs'                 => 'MyAccount/list_pkgs',     #add to ss (added?)
   'list_svcs'                 => 'MyAccount/list_svcs',     #add to ss (added?)
   'list_svc_usage'            => 'MyAccount/list_svc_usage',   
+  'list_cdr_usage'            => 'MyAccount/list_cdr_usage',   
   'list_support_usage'        => 'MyAccount/list_support_usage',   
   'order_pkg'                 => 'MyAccount/order_pkg',     #add to ss cgi!
   'change_pkg'                => 'MyAccount/change_pkg', 
diff --git a/fs_selfservice/FS-SelfService/cgi/header.html b/fs_selfservice/FS-SelfService/cgi/header.html
new file mode 100644 (file)
index 0000000..cf8fd2b
--- /dev/null
@@ -0,0 +1,9 @@
+<HTML>
+  <HEAD>
+    <TITLE>MyAccount</TITLE>
+  </HEAD>
+  <BODY BGCOLOR="#eeeeee">
+    <FONT SIZE=5>MyAccount</FONT>
+    <BR><BR>
+    <%= include('myaccount_menu') %>
+    <TD VALIGN="top">
index bb3db12..ecf2553 100644 (file)
@@ -15,7 +15,8 @@ use FS::SelfService qw( login_info login customer_info edit_info invoice
                         list_pkgs order_pkg signup_info order_recharge
                         part_svc_info provision_acct provision_external
                         unprovision_svc change_pkg domainselector
-                        list_svcs list_svc_usage list_support_usage
+                        list_svcs
+                        list_svc_usage list_cdr_usage list_support_usage
                         myaccount_passwd
                       );
 
@@ -72,7 +73,7 @@ $session_id = $cgi->param('session');
 
 #order|pw_list XXX ???
 $cgi->param('action') =~
-    /^(myaccount|view_invoice|make_payment|make_ach_payment|make_thirdparty_payment|payment_results|ach_payment_results|recharge_prepay|recharge_results|logout|change_bill|change_ship|change_pay|process_change_bill|process_change_ship|process_change_pay|customer_order_pkg|process_order_pkg|customer_change_pkg|process_change_pkg|process_order_recharge|provision|provision_svc|process_svc_acct|process_svc_external|delete_svc|view_usage|view_usage_details|view_support_details|change_password|process_change_password)$/
+    /^(myaccount|view_invoice|make_payment|make_ach_payment|make_thirdparty_payment|payment_results|ach_payment_results|recharge_prepay|recharge_results|logout|change_bill|change_ship|change_pay|process_change_bill|process_change_ship|process_change_pay|customer_order_pkg|process_order_pkg|customer_change_pkg|process_change_pkg|process_order_recharge|provision|provision_svc|process_svc_acct|process_svc_external|delete_svc|view_usage|view_usage_details|view_cdr_details|view_support_details|change_password|process_change_password)$/
   or die "unknown action ". $cgi->param('action');
 my $action = $1;
 
@@ -564,7 +565,7 @@ sub delete_svc {
 sub view_usage {
   list_svcs(
     'session_id'  => $session_id,
-    'svcdb'       => 'svc_acct',
+    'svcdb'       => [ 'svc_acct', 'svc_phone' ],
     'ncancelled'  => 1,
   );
 }
@@ -578,6 +579,15 @@ sub view_usage_details {
   );
 }
 
+sub view_cdr_details {
+  list_cdr_usage(
+    'session_id'  => $session_id,
+    'svcnum'      => $cgi->param('svcnum'),
+    'beginning'   => $cgi->param('beginning') || '',
+    'ending'      => $cgi->param('ending') || '',
+  );
+}
+
 sub view_support_details {
   list_support_usage(
     'session_id'  => $session_id,
diff --git a/fs_selfservice/FS-SelfService/cgi/view_cdr_details.html b/fs_selfservice/FS-SelfService/cgi/view_cdr_details.html
new file mode 100644 (file)
index 0000000..32bd632
--- /dev/null
@@ -0,0 +1,54 @@
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('header') %>
+
+<FONT SIZE=4>Call usage for
+<%= Date::Format::time2str('%b&nbsp;%o&nbsp;%Y', $beginning) %> -
+<%= Date::Format::time2str('%b&nbsp;%o&nbsp;%Y', $ending) %>
+</FONT><BR><BR>
+
+<%= if ( $error ) {
+  $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">$error</FONT><BR><BR>!;
+} ''; %>
+<TABLE WIDTH="100%">
+  <TR>
+    <TD WIDTH="50%">
+<%= if ($previous < $beginning) {
+    $OUT .= qq!<A HREF="${url}view_cdr_details;svcnum=$svcnum;beginning=!;
+    $OUT .= qq!$previous;ending=$beginning">Previous period</A>!;
+    }else{
+      '';
+    } %>
+    </TD>
+    <TD  WIDTH="50%" ALIGN="right">
+<%= if ($next > $ending) {
+    $OUT .= qq!<A HREF="${url}view_cdr_details;svcnum=$svcnum;beginning=!;
+    $OUT .= qq!$ending;ending=$next">Next period</A>!;
+    }else{
+      '';
+    }%>
+    </TD>
+  </TR>
+</TABLE>
+<TABLE BGCOLOR="#cccccc">
+  <TR>
+<%= foreach my $header (@header) {
+      $OUT .= qq(<TH ALIGN="right">$header</TH>);
+    }
+%>
+  </TR>
+<%= my $total = 0;
+    my $utotal = 0;
+    my $dtotal = 0;
+    foreach my $usage ( @usage ) {
+      $OUT .= '<TR>';
+      $OUT .= qq(<TD>$_</TD>) foreach @{$usage};
+      $OUT .= '</TR>';
+    }
+%>
+
+</TABLE>
+<BR>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
index b78f997..b492102 100644 (file)
@@ -1,24 +1,30 @@
-<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
-<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
-<%= $url = "$selfurl?session=$session_id;action="; ''; %>
-<%= include('myaccount_menu') %>
-<TD VALIGN="top">
-
-<FONT SIZE=4>Service usage</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action=";
+    @svc_acct  = grep { $_->{svcdb} eq 'svc_acct'  } @svcs;
+    @svc_phone = grep { $_->{svcdb} eq 'svc_phone' } @svcs;
+    '';
+%>
+<%= include('header') %>
 
 <%= if ( $error ) {
   $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">$error</FONT><BR><BR>!;
 } ''; %>
 
-<TABLE BGCOLOR="#cccccc">
-  <TR>
-    <TH ALIGN="left">Account</TH>
-    <TH ALIGN="right">Time remaining</TH>
-    <TH ALIGN="right">Upload remaining</TH>
-    <TH ALIGN="right">Download remaining</TH>
-    <TH ALIGN="right">Total remaining</TH>
-  </TR>
-<%= foreach my $svc ( @svcs ) {
+<%= if ( @svc_acct ) {
+      $OUT.= '<FONT SIZE="4">Account usage</FONT><BR><BR>
+              <TABLE BGCOLOR="#cccccc">
+                <TR>
+                  <TH ALIGN="left">Account</TH>
+                  <TH ALIGN="right">Time remaining</TH>
+                  <TH ALIGN="right">Upload remaining</TH>
+                  <TH ALIGN="right">Download remaining</TH>
+                  <TH ALIGN="right">Total remaining</TH>
+                </TR>';
+    } else {
+      $OUT .= '';
+    }
+%>
+
+<%= foreach my $svc ( @svc_acct ) {
       my $link = "${url}view_usage_details;".
         "svcnum=$svc->{'svcnum'};beginning=0;ending=0";
   $OUT .= '<TR><TD>';
       $OUT .= $svc->{'recharge_totalbytes'} if $svc->{'recharge_totalbytes'};
     $OUT .= '</TD></TR>';
     }
-  } %>
+  }
+%>
 
-</TABLE>
-<BR>
+<%= scalar(@svc_acct) ? '</TABLE><BR><BR>' : '' %>
 
-</TD></TR></TABLE>
+<%= if ( @svc_phone ) {
+      $OUT.= '<FONT SIZE="4">Call usage</FONT><BR><BR>
+              <TABLE BGCOLOR="#cccccc">
+                <TR>
+                  <TH ALIGN="left">Number</TH>'; #"Account" ?
+                                                 #what else?
+      $OUT .= '</TR>';
+    } else {
+      $OUT .= '';
+    }
+%>
 
+<%= 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>';
+  }
+%>
+
+<%= scalar(@svc_phone) ? '</TABLE><BR><BR>' : '' %>
+
+</TD></TR></TABLE>
 <%= include('footer') %>