[freeside-commits] freeside/FS/FS/part_pkg voip_tiered.pm, NONE, 1.1.2.2 voip_inbound.pm, 1.12.2.4, 1.12.2.5

Ivan,,, ivan at wavetail.420.am
Sun Nov 13 20:28:52 PST 2011


Update of /home/cvs/cvsroot/freeside/FS/FS/part_pkg
In directory wavetail.420.am:/tmp/cvs-serv30904/FS/FS/part_pkg

Modified Files:
      Tag: FREESIDE_2_3_BRANCH
	voip_inbound.pm 
Added Files:
      Tag: FREESIDE_2_3_BRANCH
	voip_tiered.pm 
Log Message:
rate tiers for vnes, RT#14903

Index: voip_inbound.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/part_pkg/voip_inbound.pm,v
retrieving revision 1.12.2.4
retrieving revision 1.12.2.5
diff -u -w -d -r1.12.2.4 -r1.12.2.5
--- voip_inbound.pm	24 Oct 2011 21:21:05 -0000	1.12.2.4
+++ voip_inbound.pm	14 Nov 2011 04:28:50 -0000	1.12.2.5
@@ -1,16 +1,15 @@
 package FS::part_pkg::voip_inbound;
+use base qw( FS::part_pkg::recur_Common );
 
 use strict;
-use vars qw(@ISA $DEBUG %info);
+use vars qw($DEBUG %info);
 use Date::Format;
 use Tie::IxHash;
+use Text::CSV_XS;
 use FS::Conf;
 use FS::Record qw(qsearchs qsearch);
-use FS::part_pkg::recur_Common;
 use FS::cdr;
-use FS::part_pkg::recur_Common;
-
- at ISA = qw(FS::part_pkg::recur_Common);
+use FS::rate_detail;
 
 $DEBUG = 0;
 
@@ -56,10 +55,6 @@
                           'default' => '+1',
                         },
 
-    'disable_tollfree' => { 'name' => 'Disable automatic toll-free processing',
-                            'type' => 'checkbox',
-                          },
-
     'use_amaflags' => { 'name' => 'Only charge for CDRs where the amaflags field is set to "2" ("BILL"/"BILLING").',
                         'type' => 'checkbox',
                       },
@@ -148,7 +143,6 @@
                        FS::part_pkg::prorate_Mixin::fieldorder,
                    qw( min_charge min_included sec_granularity
                        default_prefix
-                       disable_tollfree
                        use_amaflags
                        use_carrierid
                        use_cdrtypenum ignore_cdrtypenum
@@ -160,7 +154,7 @@
                        bill_every_call
                      )
                   ],
-  'weight' => 40,
+  'weight' => 42,
 );
 
 sub price_info {
@@ -205,25 +199,21 @@
 
   my $spool_cdr = $cust_pkg->cust_main->spool_cdr;
 
-  my $included_min = ($self->option('min_included') 
-                        && $self->option('min_included') > 0) 
-                                        ? $self->option('min_included') : 0;
 
   my $charges = 0;
 
 #  my $downstream_cdr = '';
 
-  my $disable_tollfree  = $self->option('disable_tollfree');
-  my $ignore_unrateable = $self->option('ignore_unrateable', 'Hush!');
+  my $included_min  = $self->option('min_included', 1) || 0;
   my $use_duration      = $self->option('use_duration');
-
-  my $output_format     = $self->option('output_format', 'Hush!') || 'default';
+  my $output_format = $self->option('output_format', 1) || 'default';
+  my $granularity   = length($self->option('sec_granularity'))
+                        ? $self->option('sec_granularity')
+                        : 60;
 
   #for check_chargable, so we don't keep looking up options inside the loop
   my %opt_cache = ();
 
-  eval "use Text::CSV_XS;";
-  die $@ if $@;
   my $csv = new Text::CSV_XS;
 
   foreach my $cust_svc (
@@ -232,19 +222,25 @@
     my $svc_phone = $cust_svc->svc_x;
 
     foreach my $cdr ( $svc_phone->get_cdrs(
-      'for_update'     => 1,
-      'status'         => '', # unprocessed only
-      'default_prefix' => $self->option('default_prefix'),
       'inbound'        => 1,
+      'default_prefix' => $self->option('default_prefix'),
+      'status'         => '', # unprocessed only
+      'for_update'     => 1,
       )
     ) {
+
+      my $reason = $self->check_chargable( $cdr,
+                                           'option_cache' => \%opt_cache,
+                                         );
+      if ( $reason ) {
+        warn "not charging for CDR ($reason)\n" if $DEBUG;
+        next;
+      }
+
       if ( $DEBUG > 1 ) {
         warn "rating inbound CDR $cdr\n".
              join('', map { "  $_ => ". $cdr->{$_}. "\n" } keys %$cdr );
       }
-      my $granularity = length($self->option('sec_granularity'))
-                          ? $self->option('sec_granularity')
-                          : 60;
 
       my $seconds = $use_duration ? $cdr->duration : $cdr->billsec;
 
@@ -287,7 +283,7 @@
               $call_details[0],
               $charge,
               $cdr->calltypenum, #classnum
-              $self->phonenum,
+              '', #phonenum,
               $cdr->accountcode,
               $cdr->startdate,
               $seconds,
@@ -353,8 +349,7 @@
 
   return "carrierid != $opt{'use_carrierid'}"
     if length($opt{'use_carrierid'})
-    && $cdr->carrierid ne $opt{'use_carrierid'} #ne otherwise 0 matches ''
-    && ! $flags{'da_rewrote'};
+    && $cdr->carrierid ne $opt{'use_carrierid'}; #ne otherwise 0 matches ''
 
   return "cdrtypenum != $opt{'use_cdrtypenum'}"
     if length($opt{'use_cdrtypenum'})

--- NEW FILE: voip_tiered.pm ---
package FS::part_pkg::voip_tiered;
use base qw( FS::part_pkg::voip_cdr );

use strict;
use vars qw( $DEBUG %info );
use Tie::IxHash;
use Date::Format;
use Text::CSV_XS;
use FS::Conf;
use FS::Record qw(qsearchs); # qsearch);
use FS::cdr;
use FS::rate_tier;
use FS::rate_detail;

use Data::Dumper;

$DEBUG = 0;

tie my %cdr_inout, 'Tie::IxHash',
  'outbound'         => 'Outbound',
  'inbound'          => 'Inbound',
  'outbound_inbound' => 'Outbound and Inbound',
;

tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities();

%info = (
  'name' => 'VoIP tiered rate pricing of CDRs',
  'shortname' => 'VoIP/telco CDR tiered rating',
  'inherit_fields' => [ 'voip_cdr', 'prorate_Mixin', 'global_Mixin' ],
  'fields' => {
    'tiernum' => { 'name' => 'Tier plan',
                   'type' => 'select',
                   'select_table' => 'rate_tier',
                   'select_key'   => 'tiernum',
                   'select_label' => 'tiername',
                 },
    'cdr_inout' => { 'name'=> 'Call direction when using phone number matching',
                     'type'=> 'select',
                     'select_options' => \%cdr_inout,
                   },
    'min_included' => { 'name' => 'Minutes included',
                    },
    'sec_granularity' => { 'name' => 'Granularity',
                           'type' => 'select',
                           'select_options' => \%granularity,
                         },
    'rating_method'                          => { 'disabled' => 1 },
    'ratenum'                                => { 'disabled' => 1 },
    'intrastate_ratenum'                     => { 'disabled' => 1 },
    'min_charge'                             => { 'disabled' => 1 },
    'ignore_unrateable'                      => { 'disabled' => 1 },
    'domestic_prefix'                        => { 'disabled' => 1 },
    'international_prefix'                   => { 'disabled' => 1 },
    'disable_tollfree'                       => { 'disabled' => 1 },
    'noskip_src_length_accountcode_tollfree' => { 'disabled' => 1 },
    'accountcode_tollfree_ratenum'           => { 'disabled' => 1 },
    'noskip_dst_length_accountcode_tollfree' => { 'disabled' => 1 },
  },
  'fieldorder' => [qw(
                       recur_temporality
                       recur_method cutoff_day ),
                       FS::part_pkg::prorate_Mixin::fieldorder,
                   qw(
                       cdr_svc_method cdr_inout
                       tiernum
                     )
                  ],
  'weight' => 44,
);

sub calc_usage {
  my $self = shift;
  my($cust_pkg, $sdate, $details, $param ) = @_;

  #my $last_bill = $cust_pkg->last_bill;
  my $last_bill = $cust_pkg->get('last_bill'); #->last_bill falls back to setup

  return 0
    if $self->recur_temporality eq 'preceding'
    && ( $last_bill eq '' || $last_bill == 0 );

  my $included_min    = $self->option('min_included', 1) || 0;
  my $cdr_svc_method  = $self->option('cdr_svc_method',1)||'svc_phone.phonenum';
  my $cdr_inout       = ($cdr_svc_method eq 'svc_phone.phonenum')
                          && $self->option('cdr_inout',1)
                          || 'outbound';
  my $use_duration    = $self->option('use_duration');
  my $granularity     = length($self->option('sec_granularity'))
                          ? $self->option('sec_granularity')
                          : 60;

  #for check_chargable, so we don't keep looking up options inside the loop
  my %opt_cache = ();

  my($svc_table, $svc_field) = split('\.', $cdr_svc_method);

  my %options = (
    'disable_src'    => $self->option('disable_src'),
    'default_prefix' => $self->option('default_prefix'),
    'status'         => '',
    'for_update'     => 1,
  );  # $last_bill, $$sdate )
  $options{'by_svcnum'} = 1 if $svc_field eq 'svcnum';

  ###
  # pass one: find the total minutes/calls and store the CDRs
  ###
  my $total = 0;
  my @cdrs = ();

  my @cust_svc;
  if( $self->option('bill_inactive_svcs',1) ) {
    #XXX in this mode do we need to restrict the set of CDRs by date also?
    @cust_svc = $cust_pkg->h_cust_svc($$sdate, $last_bill);
  } else {
    @cust_svc = $cust_pkg->cust_svc;
  }
  @cust_svc = grep { $_->part_svc->svcdb eq $svc_table } @cust_svc;

  foreach my $cust_svc (@cust_svc) {

    my $svc_x;
    if( $self->option('bill_inactive_svcs',1) ) {
      $svc_x = $cust_svc->h_svc_x($$sdate, $last_bill);
    }
    else {
      $svc_x = $cust_svc->svc_x;
    }

    foreach my $pass (split('_', $cdr_inout)) {

      $options{'inbound'} = ( $pass eq 'inbound' );

      foreach my $cdr (
        $svc_x->get_cdrs( %options )
      ) {
        if ( $DEBUG > 1 ) {
          warn "rating CDR $cdr\n".
               join('', map { "  $_ => ". $cdr->{$_}. "\n" } keys %$cdr );
        }

        my $charge = '';
        my $seconds = '';

        $seconds = $use_duration ? $cdr->duration : $cdr->billsec;

        $seconds += $granularity - ( $seconds % $granularity )
          if $seconds      # don't granular-ize 0 billsec calls (bills them)
          && $granularity  # 0 is per call
          && $seconds % $granularity;
        my $minutes = $granularity ? ($seconds / 60) : 1;

        my $charge_min = $minutes;

        $included_min -= $minutes;
        if ( $included_min > 0 ) {
          $charge_min = 0;
        } else {
           $charge_min = 0 - $included_min;
           $included_min = 0;
        }

        $cdr->tmp_inout( $pass );
        $cdr->tmp_rated_seconds( $seconds );
        $cdr->tmp_rated_minutes( $charge_min );
        $cdr->tmp_svcnum( $cust_svc->svcnum );
        push @cdrs, $cdr;
        $total += $charge_min;

      } # $cdr

    } # $pass
 
  } # $cust_svc

  ###
  # pass two: find a tiered rate and do the rest
  ###

  my $rate_tier = qsearchs('rate_tier', { tiernum=>$self->option('tiernum') } )
    or die "unknown tiernum ". $self->option('tiernum');
  my $rate_tier_detail = $rate_tier->rate_tier_detail( $total )
    or die "no base rate for tier? ($total)";
  my $min_charge = $rate_tier_detail->min_charge;

  my $output_format = $self->option('output_format', 'Hush!') || 'default';

  my $csv = new Text::CSV_XS;

  my $charges = 0;
  my @invoice_details_sort;

  foreach my $cdr (@cdrs) {

    my $charge_min = $cdr->tmp_rated_minutes;

    my $charge = sprintf('%.4f', ( $min_charge * $charge_min )
                                 + 0.0000000001 ); #so 1.00005 rounds to 1.0001


    if ( $charge > 0 ) {
      $charges += $charge;

      my $detail = 
        $cdr->downstream_csv( 'format'  => $output_format,
                              'charge'  => $charge,
                              'seconds' => ($use_duration ? 
                                              $cdr->duration : 
                                              $cdr->billsec),
                              'granularity' => $granularity,
                            );

      my $call_details =
        { format      => 'C',
          detail      => $detail,
          amount      => $charge,
          #classnum    => $cdr->calltypenum, #classnum
          #phonenum    => $phonenum, #XXX need this to sort on them
          accountcode => $cdr->accountcode,
          startdate   => $cdr->startdate,
          duration    => $cdr->tmp_rated_seconds,
        };

       #warn "  adding details on charge to invoice: [ ".
      #    join(', ', @{$call_details} ). " ]"
      #  if ( $DEBUG && ref($call_details) );
      push @invoice_details_sort, [ $call_details, $cdr->calldate_unix ];
    }

    my $error = $cdr->set_status_and_rated_price(
      'done',
      $charge,
      $cdr->tmp_svcnum,
      'inbound'       => ($cdr->tmp_inout eq 'inbound'),
      'rated_minutes' => $charge_min,
      'rated_seconds' => $cdr->tmp_rated_seconds,
    );
    die $error if $error;


  }

  my @sorted_invoice_details = sort { ${$a}[1] <=> ${$b}[1] } @invoice_details_sort;
  foreach my $sorted_call_detail ( @sorted_invoice_details ) {
      push @$details, ${$sorted_call_detail}[0];
  }

  unshift @$details, { format => 'C',
                       detail => FS::cdr::invoice_header($output_format),
                     }
    if @$details;

  $charges;
}

1;




More information about the freeside-commits mailing list