connection charge handling which comports with history of module
[freeside.git] / FS / FS / part_pkg / voip_cdr.pm
index eccf2c1..614ea82 100644 (file)
@@ -15,7 +15,12 @@ use FS::part_pkg::recur_Common;
 
 @ISA = qw(FS::part_pkg::recur_Common);
 
-$DEBUG = 0;
+$DEBUG = 1;
+
+tie my %cdr_svc_method, 'Tie::IxHash',
+  'svc_phone.phonenum' => 'Phone numbers (svc_phone.phonenum)',
+  'svc_pbx.title'      => 'PBX name (svc_pbx.title)',
+;
 
 tie my %rating_method, 'Tie::IxHash',
   'prefix' => 'Rate calls by using destination prefix to look up a region and rate according to the internal prefix and rate tables',
@@ -71,6 +76,11 @@ tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities();
                          'select_options' => \%FS::part_pkg::recur_Common::recur_method,
                        },
 
+    'cdr_svc_method' => { 'name' => 'CDR service matching method',
+                          'type' => 'radio',
+                          'options' => \%cdr_svc_method,
+                        },
+
     'rating_method' => { 'name' => 'Rating method',
                          'type' => 'radio',
                          'options' => \%rating_method,
@@ -143,6 +153,13 @@ tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities();
     'skip_dstchannel_prefix' => { 'name' => 'Do not charge for CDRs where the dstchannel starts with:',
                                 },
 
+    'skip_src_length_more' => { 'name' => 'Do not charge for CDRs where the source is more than this many digits:',
+                              },
+
+    'noskip_src_length_accountcode_tollfree' => { 'name' => 'Do charge for CDRs where source is equal or greater than the specified digits and accountcode is toll free',
+                                                  'type' => 'checkbox',
+                                                },
+
     'skip_dst_length_less' => { 'name' => 'Do not charge for CDRs where the destination is less than this many digits:',
                               },
 
@@ -210,6 +227,7 @@ tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities();
   'fieldorder' => [qw(
                        setup_fee recur_fee recur_temporality unused_credit
                        recur_method cutoff_day
+                       cdr_svc_method
                        rating_method ratenum min_charge sec_granularity
                        ignore_unrateable
                        default_prefix
@@ -219,6 +237,7 @@ tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities();
                        use_amaflags use_disposition
                        use_disposition_taqua use_carrierid use_cdrtypenum
                        skip_dcontext skip_dstchannel_prefix
+                       skip_src_length_more noskip_src_length_accountcode_tollfree
                        skip_dst_length_less skip_lastapp
                        use_duration
                        411_rewrite
@@ -278,6 +297,7 @@ sub calc_usage {
 
 #  my $downstream_cdr = '';
 
+  my $cdr_svc_method    = $self->option('cdr_svc_method')||'svc_phone.phonenum';
   my $rating_method     = $self->option('rating_method') || 'prefix';
   my $intl              = $self->option('international_prefix') || '011';
   my $domestic_prefix   = $self->option('domestic_prefix');
@@ -305,14 +325,19 @@ sub calc_usage {
   die $@ if $@;
   my $csv = new Text::CSV_XS;
 
+  my($svc_table, $svc_field) = split('.', $cdr_svc_method);
+
   foreach my $cust_svc (
-    grep { $_->part_svc->svcdb eq 'svc_phone' } $cust_pkg->cust_svc
+    grep { $_->part_svc->svcdb eq $svc_table } $cust_pkg->cust_svc
   ) {
 
+    my $svc_x = $cust_svc->svc_x;
     foreach my $cdr (
-      $cust_svc->get_cdrs_for_update(
+      $svc_x->get_cdrs(
         'disable_src'    => $self->option('disable_src'),
         'default_prefix' => $self->option('default_prefix'),
+        'status'         => '',
+        'for_update'     => 1,
       )  # $last_bill, $$sdate )
     ) {
       if ( $DEBUG > 1 ) {
@@ -324,6 +349,8 @@ sub calc_usage {
       my( $rate_region, $regionnum );
       my $pretty_destnum;
       my $charge = '';
+      my $seconds = '';
+      my $regionname = '';
       my $classnum = '';
       my @call_details = ();
       if ( $rating_method eq 'prefix' ) {
@@ -397,6 +424,8 @@ sub calc_usage {
 
           warn "rating call $to_or_from +$countrycode $number\n" if $DEBUG;
           $pretty_destnum = "+$countrycode $number";
+          #asterisks here causes inserting the detail to barf, so:
+          $pretty_destnum =~ s/\*//g;
 
           my $rate = qsearchs('rate', { 'ratenum' => $ratenum })
             or die "ratenum $ratenum not found!";
@@ -409,6 +438,7 @@ sub calc_usage {
 
             $rate_region = $rate_detail->dest_region;
             $regionnum = $rate_region->regionnum;
+            $regionname = $rate_region->regionname;
             warn "  found rate for regionnum $regionnum ".
                  "and rate detail $rate_detail\n"
               if $DEBUG;
@@ -447,6 +477,7 @@ sub calc_usage {
 #        } else { #pass upstream price through
 #
 #          $charge = sprintf('%.2f', $cdr->upstream_price);
+#          warn "Incrementing \$charges by $charge.  Now $charges\n" if $DEBUG;
 #          $charges += $charge;
 # 
 #          @call_details = (
@@ -465,6 +496,7 @@ sub calc_usage {
         #XXX $charge = sprintf('%.2f', $cdr->upstream_price);
         $charge = sprintf('%.3f', $cdr->upstream_price);
         $charges += $charge;
+        warn "Incrementing \$charges by $charge.  Now $charges\n" if $DEBUG;
 
         @call_details = ($cdr->downstream_csv( 'format' => $output_format,
                                                'charge' => $charge,
@@ -481,7 +513,7 @@ sub calc_usage {
                             : 60;
 
                     # length($cdr->billsec) ? $cdr->billsec : $cdr->duration;
-        my $seconds = $use_duration ? $cdr->duration : $cdr->billsec;
+        $seconds = $use_duration ? $cdr->duration : $cdr->billsec;
 
         $seconds += $granularity - ( $seconds % $granularity )
           if $seconds      # don't granular-ize 0 billsec calls (bills them)
@@ -495,6 +527,7 @@ sub calc_usage {
         $charge = sprintf('%.4f', ( $self->option('min_charge') * $minutes )
                                   + 0.0000000001 ); #so 1.00005 rounds to 1.0001
 
+        warn "Incrementing \$charges by $charge.  Now $charges\n" if $DEBUG;
         $charges += $charge;
 
         @call_details = ($cdr->downstream_csv( 'format' => $output_format,
@@ -530,7 +563,10 @@ sub calc_usage {
           my $granularity = $rate_detail->sec_granularity;
 
                       # length($cdr->billsec) ? $cdr->billsec : $cdr->duration;
-          my $seconds = $use_duration ? $cdr->duration : $cdr->billsec;
+          $seconds = $use_duration ? $cdr->duration : $cdr->billsec;
+
+          $seconds -= $rate_detail->conn_sec;
+          $seconds = 0 if $seconds < 0;
 
           $seconds += $granularity - ( $seconds % $granularity )
             if $seconds      # don't granular-ize 0 billsec calls (bills them)
@@ -543,14 +579,18 @@ sub calc_usage {
 
           $included_min{$regionnum} -= $minutes;
 
+          $charge = sprintf('%.2f', $rate_detail->conn_charge);
+
           if ( $included_min{$regionnum} < 0 ) {
             my $charge_min = 0 - $included_min{$regionnum}; #XXX should preserve
                                                             #(display?) this
             $included_min{$regionnum} = 0;
-            $charge = sprintf('%.2f', ( $rate_detail->min_charge * $charge_min )
-                                      + 0.00000001 ); #so 1.005 rounds to 1.01
-            $charges += $charge;
+            $charge += sprintf('%.2f', ($rate_detail->min_charge * $charge_min)
+                                       + 0.00000001 ); #so 1.005 rounds to 1.01
+            $charge = sprintf('%.2f', $charge);
           }
+          warn "Incrementing \$charges by $charge.  Now $charges\n" if $DEBUG;
+          $charges += $charge;
 
           # this is why we need regionnum/rate_region....
           warn "  (rate region $rate_region)\n" if $DEBUG;
@@ -561,7 +601,7 @@ sub calc_usage {
                                  'minutes'        => $minutes,
                                  'charge'         => $charge,
                                  'pretty_dst'     => $pretty_destnum,
-                                 'dst_regionname' => $rate_region->regionname,
+                                 'dst_regionname' => $regionname,
                                )
           );
 
@@ -577,11 +617,25 @@ sub calc_usage {
           #if ( $self->option('rating_method') eq 'upstream_simple' ) {
           if ( scalar(@call_details) == 1 ) {
             $call_details =
-              [ 'C', $call_details[0], $charge, $classnum, $phonenum ];
+              [ 'C',
+                $call_details[0],
+                $charge,
+                $classnum,
+                $phonenum,
+                $seconds,
+                $regionname,
+              ];
           } else { #only used for $rating_method eq 'upstream' now
             $csv->combine(@call_details);
             $call_details =
-              [ 'C', $csv->string, $charge, $classnum, $phonenum ];
+              [ 'C',
+                $csv->string,
+                $charge,
+                $classnum,
+                $phonenum,
+                $seconds,
+                $regionname,
+              ];
           }
           warn "  adding details on charge to invoice: [ ".
               join(', ', @{$call_details} ). " ]"
@@ -607,7 +661,14 @@ sub calc_usage {
 
   } # $cust_svc
 
-  unshift @$details, [ 'C', FS::cdr::invoice_header($output_format) ]
+  unshift @$details, [ 'C',
+                       FS::cdr::invoice_header($output_format),
+                       '',
+                       '',
+                       '',
+                       '',
+                       '',
+                     ]
     if @$details && $rating_method ne 'upstream';
 
 #  if ( $spool_cdr && length($downstream_cdr) ) {
@@ -655,6 +716,7 @@ sub check_chargable {
     use_cdrtypenum
     skip_dcontext
     skip_dstchannel_prefix
+    skip_src_length_more noskip_src_length_accountcode_tollfree
     skip_dst_length_less
     skip_lastapp
   );
@@ -697,6 +759,26 @@ sub check_chargable {
   return "lastapp is $opt{'skip_lastapp'}"
     if length($opt{'skip_lastapp'}) && $cdr->lastapp eq $opt{'skip_lastapp'};
 
+  my $src_length = $opt{'skip_src_length_more'};
+  if ( $src_length ) {
+
+    if ( $opt{'noskip_src_length_accountcode_tollfree'} ) {
+
+      if ( $cdr->is_tollfree('accountcode') ) {
+        return "source less than or equal to $src_length digits"
+          if length($cdr->src) <= $src_length;
+      } else {
+        return "source more than $src_length digits"
+          if length($cdr->src) > $src_length;
+      }
+
+    } else {
+      return "source more than $src_length digits"
+        if length($cdr->src) > $src_length;
+    }
+
+  }
+
   #all right then, rate it
   '';
 }