Merge branch 'master' of git.freeside.biz:/home/git/freeside
authorIvan Kohler <ivan@freeside.biz>
Sat, 17 Jan 2015 02:37:43 +0000 (18:37 -0800)
committerIvan Kohler <ivan@freeside.biz>
Sat, 17 Jan 2015 02:37:43 +0000 (18:37 -0800)
1  2 
FS/FS/part_pkg/voip_cdr.pm
FS/FS/svc_acct.pm

@@@ -19,6 -19,7 +19,7 @@@ tie my %cdr_svc_method, 'Tie::IxHash'
    'svc_pbx.svcnum'     => 'Freeside service # (svc_pbx.svcnum)',
    'svc_pbx.ip.src'     => 'PBX name to source IP address',
    'svc_pbx.ip.dst'     => 'PBX name to destination IP address',
+   'svc_acct.username'  => 'Username (svc_acct.username)',
  ;
  
  tie my %rating_method, 'Tie::IxHash',
@@@ -463,16 -464,20 +464,20 @@@ sub calc_usage 
      #my @invoice_details_sort;
  
      # for tagging invoice details
+     # (unfortunate; should be a svc_x class method or table_info item or 
+     # something)
      my $phonenum;
      if ( $svc_table eq 'svc_phone' ) {
        $phonenum = $svc_x->phonenum;
      } elsif ( $svc_table eq 'svc_pbx' ) {
        $phonenum = $svc_x->title;
+     } elsif ( $svc_table eq 'svc_acct' ) {
+       $phonenum = $svc_x->username;
      }
      $formatter->phonenum($phonenum);
  
      #first rate any outstanding CDRs not yet rated
-     # XXX eventually use an FS::Cursor for this
+     # use FS::Cursor for this starting in 4.x
      my $cdr_search = $svc_x->psearch_cdrs(%options);
      $cdr_search->limit(1000);
      $cdr_search->increment(0); # because we're changing their status as we go
@@@ -678,7 -683,6 +683,7 @@@ sub reset_usage 
  
  # tells whether cust_bill_pkg_detail should return a single line for 
  # each phonenum
 +# i think this is currently unused?
  sub sum_usage {
    my $self = shift;
    $self->option('output_format') =~ /^sum_/;
diff --combined FS/FS/svc_acct.pm
@@@ -40,6 -40,7 +40,7 @@@ use FS::Record qw( qsearch qsearchs fie
  use FS::Msgcat qw(gettext);
  use FS::UI::bytecount;
  use FS::UI::Web;
+ use FS::PagedSearch qw( psearch ); # XXX in v4, replace with FS::Cursor
  use FS::part_pkg;
  use FS::part_svc;
  use FS::svc_acct_pop;
@@@ -293,21 -294,25 +294,21 @@@ sub table_info 
                           label => 'Quota', #Mail storage limit
                           type => 'text',
                           disable_inventory => 1,
 -                         disable_select => 1,
                         },
          'file_quota'=> { 
                           label => 'File storage limit',
                           type => 'text',
                           disable_inventory => 1,
 -                         disable_select => 1,
                         },
          'file_maxnum'=> { 
                           label => 'Number of files limit',
                           type => 'text',
                           disable_inventory => 1,
 -                         disable_select => 1,
                         },
          'file_maxsize'=> { 
                           label => 'File size limit',
                           type => 'text',
                           disable_inventory => 1,
 -                         disable_select => 1,
                         },
          '_password' => 'Password',
          'gid'       => {
@@@ -2367,65 -2372,94 +2368,94 @@@ sub last_login_text 
    $self->last_login ? ctime($self->last_login) : 'unknown';
  }
  
- =item get_cdrs TIMESTAMP_START TIMESTAMP_END [ 'OPTION' => 'VALUE ... ]
+ =item psearch_cdrs OPTIONS
+ Returns a paged search (L<FS::PagedSearch>) for Call Detail Records
+ associated with this service. For svc_acct, "associated with" means that
+ either the "src" or the "charged_party" field of the CDR matches the
+ "username" field of the service.
  
  =cut
  
- sub get_cdrs {
-   my($self, $start, $end, %opt ) = @_;
-   my $did = $self->username; #yup
-   my $prefix = $opt{'default_prefix'}; #convergent.au '+61'
-   my $for_update = $opt{'for_update'} ? 'FOR UPDATE' : '';
-   #SELECT $for_update * FROM cdr
-   #  WHERE calldate >= $start #need a conversion
-   #    AND calldate <  $end   #ditto
-   #    AND (    charged_party = "$did"
-   #          OR charged_party = "$prefix$did" #if length($prefix);
-   #          OR ( ( charged_party IS NULL OR charged_party = '' )
-   #               AND
-   #               ( src = "$did" OR src = "$prefix$did" ) # if length($prefix)
-   #             )
-   #        )
-   #    AND ( freesidestatus IS NULL OR freesidestatus = '' )
-   my $charged_or_src;
-   if ( length($prefix) ) {
-     $charged_or_src =
-       " AND (    charged_party = '$did' 
-               OR charged_party = '$prefix$did'
-               OR ( ( charged_party IS NULL OR charged_party = '' )
-                    AND
-                    ( src = '$did' OR src = '$prefix$did' )
-                  )
-             )
-       ";
-   } else {
-     $charged_or_src = 
-       " AND (    charged_party = '$did' 
-               OR ( ( charged_party IS NULL OR charged_party = '' )
-                    AND
-                    src = '$did'
-                  )
-             )
-       ";
+ sub psearch_cdrs {
+   my($self, %options) = @_;
+   my @fields;
+   my %hash;
+   my @where;
+   my $did = dbh->quote($self->username);
+   my $prefix = $options{'default_prefix'} || ''; #convergent.au '+61'
+   my $prefixdid = dbh->quote($prefix . $self->username);
+   my $for_update = $options{'for_update'} ? 'FOR UPDATE' : '';
  
+   if ( $options{inbound} ) {
+     # these will be selected under their DIDs
+     push @where, "FALSE";
    }
  
-   qsearch(
-     'select'    => "$for_update *",
+   my @orwhere;
+   if (!$options{'disable_charged_party'}) {
+     push @orwhere,
+       "charged_party = $did",
+       "charged_party = $prefixdid";
+   }
+   if (!$options{'disable_src'}) {
+     push @orwhere,
+       "src = $did AND charged_party IS NULL",
+       "src = $prefixdid AND charged_party IS NULL";
+   }
+   push @where, '(' . join(' OR ', @orwhere) . ')';
+   # $options{'status'} = '' is meaningful; for the rest of them it's not
+   if ( exists $options{'status'} ) {
+     $hash{'freesidestatus'} = $options{'status'};
+   }
+   if ( $options{'cdrtypenum'} ) {
+     $hash{'cdrtypenum'} = $options{'cdrtypenum'};
+   }
+   if ( $options{'calltypenum'} ) {
+     $hash{'calltypenum'} = $options{'calltypenum'};
+   }
+   if ( $options{'begin'} ) {
+     push @where, 'startdate >= '. $options{'begin'};
+   } 
+   if ( $options{'end'} ) {
+     push @where, 'startdate < '.  $options{'end'};
+   } 
+   if ( $options{'nonzero'} ) {
+     push @where, 'duration > 0';
+   } 
+   my $extra_sql = join(' AND ', @where);
+   if ($extra_sql) {
+     if (keys %hash) {
+       $extra_sql = " AND ".$extra_sql;
+     } else {
+       $extra_sql = " WHERE ".$extra_sql;
+     }
+   }
+   return psearch({
+     'select'    => '*',
      'table'     => 'cdr',
-     'hashref'   => {
-                      #( freesidestatus IS NULL OR freesidestatus = '' )
-                      'freesidestatus' => '',
-                    },
-     'extra_sql' => $charged_or_src,
+     'hashref'   => \%hash,
+     'extra_sql' => $extra_sql,
+     'order_by'  => "ORDER BY startdate $for_update",
+   });
+ }
  
-   );
+ =item get_cdrs (DEPRECATED)
  
+ Like psearch_cdrs, but returns all the L<FS::cdr> objects at once, in a 
+ single list. Arguments are the same as for psearch_cdrs.
+ =cut
+ sub get_cdrs {
+   my $self = shift;
+   my $psearch = $self->psearch_cdrs(@_);
+   qsearch ( $psearch->{query} )
  }
  
  # sub radius_groups has moved to svc_Radius_Mixin