[freeside-commits] freeside/FS/FS cdr.pm, 1.1, 1.2 Schema.pm, 1.13, 1.14 svc_acct.pm, 1.191, 1.192 cdr_upstream_rate.pm, NONE, 1.1 cust_svc.pm, 1.62, 1.63 rate_detail.pm, 1.4, 1.5 cust_main.pm, 1.208, 1.209 Conf.pm, 1.149, 1.150

Ivan,,, ivan at wavetail.420.am
Mon Mar 20 11:13:28 PST 2006


Update of /home/cvs/cvsroot/freeside/FS/FS
In directory wavetail:/tmp/cvs-serv20016/FS/FS

Modified Files:
	cdr.pm Schema.pm svc_acct.pm cust_svc.pm rate_detail.pm 
	cust_main.pm Conf.pm 
Added Files:
	cdr_upstream_rate.pm 
Log Message:
add price plan to bill on internal or external CDRs directly, add option to export CDRs to a per-customer downstream file

Index: Conf.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Conf.pm,v
retrieving revision 1.149
retrieving revision 1.150
diff -u -d -r1.149 -r1.150
--- Conf.pm	22 Feb 2006 13:07:47 -0000	1.149
+++ Conf.pm	20 Mar 2006 19:13:26 -0000	1.150
@@ -1681,6 +1681,20 @@
     'type'        => 'text',
   },
 
+  {
+    'key'         => 'echeck-nonus',
+    'section'     => 'billing',
+    'description' => 'Disable ABA-format account checking for Electronic Check payment info',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'voip-cust_cdr_spools',
+    'section'     => '',
+    'description' => 'Enable the per-customer option for individual CDR spools.',
+    'type'        => 'checkbox',
+  },
+
 );
 
 1;

Index: cust_svc.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_svc.pm,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -d -r1.62 -r1.63
--- cust_svc.pm	30 Dec 2005 02:41:22 -0000	1.62
+++ cust_svc.pm	20 Mar 2006 19:13:26 -0000	1.63
@@ -16,6 +16,7 @@
 use FS::svc_external;
 use FS::domain_record;
 use FS::part_export;
+use FS::cdr;
 
 @ISA = qw( FS::Record );
 
@@ -570,6 +571,50 @@
 
 }
 
+=item get_cdrs_for_update
+
+Returns (and SELECTs "FOR UPDATE") all unprocessed (freesidestatus NULL) CDR
+objects (see L<FS::cdr>) associated with this service.
+
+Currently CDRs are associated with svc_acct services via a DID in the
+username.  This part is rather tenative and still subject to change...
+
+=cut
+
+sub get_cdrs_for_update {
+  my($self, %options) = @_;
+
+  my $default_prefix = $options{'default_prefix'};
+
+  #Currently CDRs are associated with svc_acct services via a DID in the
+  #username.  This part is rather tenative and still subject to change...
+  #return () unless $self->svc_x->isa('FS::svc_acct');
+  return () unless $self->part_svc->svcdb eq 'svc_acct';
+  my $number = $self->svc_x->username;
+
+  my @cdrs = 
+    qsearch(
+      'table'      => 'cdr',
+      'hashref'    => { 'freesidestatus' => '',
+                        'charged_party'  => $number
+                      },
+      'extra_sql'  => 'FOR UPDATE',
+    );
+
+  if ( length($default_prefix) ) {
+    push @cdrs,
+      qsearch(
+        'table'      => 'cdr',
+        'hashref'    => { 'freesidestatus' => '',
+                          'charged_party'  => "$default_prefix$number",
+                        },
+        'extra_sql'  => 'FOR UPDATE',
+      );
+  }
+
+  @cdrs;
+}
+
 =item pkg_svc
 
 Returns the pkg_svc record for for this service, if applicable.

Index: rate_detail.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/rate_detail.pm,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- rate_detail.pm	18 Feb 2006 02:11:44 -0000	1.4
+++ rate_detail.pm	20 Mar 2006 19:13:26 -0000	1.5
@@ -114,7 +114,11 @@
     || $self->ut_foreign_keyn('orig_regionnum', 'rate_region', 'regionnum' )
     || $self->ut_foreign_key('dest_regionnum', 'rate_region', 'regionnum' )
     || $self->ut_number('min_included')
-    || $self->ut_money('min_charge')
+
+    #|| $self->ut_money('min_charge')
+    #good enough for now...
+    || $self->ut_float('min_charge')
+
     || $self->ut_number('sec_granularity')
   ;
   return $error if $error;
@@ -122,6 +126,30 @@
   $self->SUPER::check;
 }
 
+=item orig_region 
+
+Returns the origination region (see L<FS::rate_region>) associated with this
+call plan rate.
+
+=cut
+
+sub orig_region {
+  my $self = shift;
+  qsearchs('rate_region', { 'regionnum' => $self->orig_regionnum } );
+}
+
+=item dest_region 
+
+Returns the destination region (see L<FS::rate_region>) associated with this
+call plan rate.
+
+=cut
+
+sub dest_region {
+  my $self = shift;
+  qsearchs('rate_region', { 'regionnum' => $self->dest_regionnum } );
+}
+
 =back
 
 =head1 BUGS

Index: svc_acct.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/svc_acct.pm,v
retrieving revision 1.191
retrieving revision 1.192
diff -u -d -r1.191 -r1.192
--- svc_acct.pm	7 Feb 2006 13:49:44 -0000	1.191
+++ svc_acct.pm	20 Mar 2006 19:13:26 -0000	1.192
@@ -20,6 +20,7 @@
 use FS::UID qw( datasrc );
 use FS::Conf;
 use FS::Record qw( qsearch qsearchs fields dbh dbdef );
+use FS::Msgcat qw(gettext);
 use FS::svc_Common;
 use FS::cust_svc;
 use FS::part_svc;
@@ -31,9 +32,9 @@
 use FS::radius_usergroup;
 use FS::export_svc;
 use FS::part_export;
-use FS::Msgcat qw(gettext);
 use FS::svc_forward;
 use FS::svc_www;
+use FS::cdr;
 
 @ISA = qw( FS::svc_Common );
 
@@ -1344,6 +1345,67 @@
   $self->cust_svc->get_session_history(@_);
 }
 
+=item get_cdrs TIMESTAMP_START TIMESTAMP_END [ 'OPTION' => 'VALUE ... ]
+
+=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'
+                 )
+            )
+      ";
+
+  }
+
+  qsearch(
+    'select'    => "$for_update *",
+    'table'     => 'cdr',
+    'hashref'   => {
+                     #( freesidestatus IS NULL OR freesidestatus = '' )
+                     'freesidestatus' => '',
+                   },
+    'extra_sql' => $charged_or_src,
+
+  );
+
+}
+
 =item radius_groups
 
 Returns all RADIUS groups for this account (see L<FS::radius_usergroup>).

Index: cdr.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cdr.pm,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cdr.pm	18 Feb 2006 11:14:19 -0000	1.1
+++ cdr.pm	20 Mar 2006 19:13:26 -0000	1.2
@@ -3,11 +3,13 @@
 use strict;
 use vars qw( @ISA );
 use Date::Parse;
+use Date::Format;
 use FS::UID qw( dbh );
 use FS::Record qw( qsearch qsearchs );
 use FS::cdr_type;
 use FS::cdr_calltype;
 use FS::cdr_carrier;
+use FS::cdr_upstream_rate;
 
 @ISA = qw(FS::Record);
 
@@ -99,6 +101,8 @@
 
 =item upstream_rateplanid - Upstream rate plan ID
 
+=item rated_price - Rated (or re-rated) price
+
 =item distance - km (need units field?)
 
 =item islocal - Local - 1, Non Local = 0
@@ -121,7 +125,7 @@
 
 =item svcnum - Link to customer service (see L<FS::cust_svc>)
 
-=item freesidestatus - NULL, done, skipped, pushed_downstream (or something)
+=item freesidestatus - NULL, done (or something)
 
 =back
 
@@ -241,7 +245,184 @@
   $self->SUPER::check;
 }
 
-my %formats = (
+=item set_status_and_rated_price STATUS [ RATED_PRICE ]
+
+Sets the status to the provided string.  If there is an error, returns the
+error, otherwise returns false.
+
+=cut
+
+sub set_status_and_rated_price {
+  my($self, $status, $rated_price) = @_;
+  $self->status($status);
+  $self->rated_price($rated_price);
+  $self->replace();
+}
+
+=item calldate_unix 
+
+Parses the calldate in SQL string format and returns a UNIX timestamp.
+
+=cut
+
+sub calldate_unix {
+  str2time(shift->calldate);
+}
+
+=item cdr_carrier
+
+Returns the FS::cdr_carrier object associated with this CDR, or false if no
+carrierid is defined.
+
+=cut
+
+my %carrier_cache = ();
+
+sub cdr_carrier {
+  my $self = shift;
+  return '' unless $self->carrierid;
+  $carrier_cache{$self->carrierid} ||=
+    qsearchs('cdr_carrier', { 'carrierid' => $self->carrierid } );
+}
+
+=item carriername 
+
+Returns the carrier name (see L<FS::cdr_carrier>), or the empty string if
+no FS::cdr_carrier object is assocated with this CDR.
+
+=cut
+
+sub carriername {
+  my $self = shift;
+  my $cdr_carrier = $self->cdr_carrier;
+  $cdr_carrier ? $cdr_carrier->carriername : '';
+}
+
+=item cdr_calltype
+
+Returns the FS::cdr_calltype object associated with this CDR, or false if no
+calltypenum is defined.
+
+=cut
+
+my %calltype_cache = ();
+
+sub cdr_calltype {
+  my $self = shift;
+  return '' unless $self->calltypenum;
+  $calltype_cache{$self->calltypenum} ||=
+    qsearchs('cdr_calltype', { 'calltypenum' => $self->calltypenum } );
+}
+
+=item calltypename 
+
+Returns the call type name (see L<FS::cdr_calltype>), or the empty string if
+no FS::cdr_calltype object is assocated with this CDR.
+
+=cut
+
+sub calltypename {
+  my $self = shift;
+  my $cdr_calltype = $self->cdr_calltype;
+  $cdr_calltype ? $cdr_calltype->calltypename : '';
+}
+
+=item cdr_upstream_rate
+
+Returns the upstream rate mapping (see L<FS::cdr_upstream_rate>), or the empty
+string if no FS::cdr_upstream_rate object is associated with this CDR.
+
+=cut
+
+sub cdr_upstream_rate {
+  my $self = shift;
+  return '' unless $self->upstream_rateid;
+  qsearchs('cdr_upstream_rate', { 'upstream_rateid' => $self->upstream_rateid })
+    or '';
+}
+
+=item _convergent_format COLUMN [ COUNTRYCODE ]
+
+Returns the number in COLUMN formatted as follows:
+
+If the country code does not match COUNTRYCODE (default "61"), it is returned
+unchanged.
+
+If the country code does match COUNTRYCODE (default "61"), it is removed.  In
+addiiton, "0" is prepended unless the number starts with 13, 18 or 19. (???)
+
+=cut
+
+sub _convergent_format {
+  my( $self, $field ) = ( shift, shift );
+  my $countrycode = scalar(@_) ? shift : '61'; #+61 = australia
+  #my $number = $self->$field();
+  my $number = $self->get($field);
+  #if ( $number =~ s/^(\+|011)$countrycode// ) {
+  if ( $number =~ s/^\+$countrycode// ) {
+    $number = "0$number"
+      unless $number =~ /^1[389]/; #???
+  }
+  $number;
+}
+
+=item downstream_csv [ OPTION => VALUE, ... ]
+
+=cut
+
+my %export_formats = (
+  'convergent' => [
+    'carriername', #CARRIER
+    sub { shift->_convergent_format('src') }, #SERVICE_NUMBER
+    sub { shift->_convergent_format('charged_party') }, #CHARGED_NUMBER
+    sub { time2str('%Y-%m-%d', shift->calldate_unix ) }, #DATE
+    sub { time2str('%T',       shift->calldate_unix ) }, #TIME
+    'billsec', #'duration', #DURATION
+    sub { shift->_convergent_format('dst') }, #NUMBER_DIALED
+    '', #XXX add (from prefixes in most recent email) #FROM_DESC
+    '', #XXX add (from prefixes in most recent email) #TO_DESC
+    'calltypename', #CLASS_CODE
+    'rated_price', #PRICE
+    sub { shift->rated_price ? 'Y' : 'N' }, #RATED
+    '', #OTHER_INFO
+  ],
+);
+
+sub downstream_csv {
+  my( $self, %opt ) = @_;
+
+  my $format = $opt{'format'}; # 'convergent';
+  return "Unknown format $format" unless exists $export_formats{$format};
+
+  eval "use Text::CSV_XS;";
+  die $@ if $@;
+  my $csv = new Text::CSV_XS;
+
+  my @columns =
+    map {
+          ref($_) ? &{$_}($self) : $self->$_();
+        }
+    @{ $export_formats{$format} };
+
+  my $status = $csv->combine(@columns);
+  die "FS::CDR: error combining ". $csv->error_input(). "into downstream CSV"
+    unless $status;
+
+  $csv->string;
+
+}
+
+=back
+
+=head1 CLASS METHODS
+
+=over 4
+
+=item batch_import
+
+=cut
+
+my %import_formats = (
   'asterisk' => [
     'accountcode',
     'src',
@@ -264,14 +445,15 @@
   ],
   'unitel' => [
     'uniqueid',
-    'cdr_type',
-    'calldate', # XXX may need massaging
-    'billsec', #XXX duration and billsec?
-               # sub { $_[0]->billsec(  $_[1] );
-               #       $_[0]->duration( $_[1] );
-               #     },
+    #'cdr_type',
+    'cdrtypenum',
+    'calldate', # may need massaging?  huh maybe not...
+    #'billsec', #XXX duration and billsec?
+                sub { $_[0]->billsec(  $_[1] );
+                      $_[0]->duration( $_[1] );
+                    },
     'src',
-    'dst',
+    'dst', # XXX needs to have "+61" prepended unless /^\+/ ???
     'charged_party',
     'upstream_currency',
     'upstream_price',
@@ -279,8 +461,8 @@
     'distance',
     'islocal',
     'calltypenum',
-    'startdate', # XXX will definitely need massaging
-    'enddate',   # XXX same
+    'startdate',  #XXX needs massaging
+    'enddate',    #XXX same
     'description',
     'quantity',
     'carrierid',
@@ -294,7 +476,7 @@
   my $fh = $param->{filehandle};
   my $format = $param->{format};
 
-  return "Unknown format $format" unless exists $formats{$format};
+  return "Unknown format $format" unless exists $import_formats{$format};
 
   eval "use Text::CSV_XS;";
   die $@ if $@;
@@ -339,7 +521,7 @@
         }
 
       }
-      @{ $formats{$format} }
+      @{ $import_formats{$format} }
     ;
 
     my $cdr = new FS::cdr ( \%cdr );

--- NEW FILE: cdr_upstream_rate.pm ---
package FS::cdr_upstream_rate;

use strict;
use vars qw( @ISA );
use FS::Record qw( qsearch qsearchs );
use FS::rate_detail;

@ISA = qw(FS::Record);

=head1 NAME

FS::cdr_upstream_rate - Object methods for cdr_upstream_rate records

=head1 SYNOPSIS

  use FS::cdr_upstream_rate;

  $record = new FS::cdr_upstream_rate \%hash;
  $record = new FS::cdr_upstream_rate { 'column' => 'value' };

  $error = $record->insert;

  $error = $new_record->replace($old_record);

  $error = $record->delete;

  $error = $record->check;

=head1 DESCRIPTION

An FS::cdr_upstream_rate object represents an upstream rate mapping to 
internal rate detail (see L<FS::rate_detail>).  FS::cdr_upstream_rate inherits
from FS::Record.  The following fields are currently supported:

=over 4

=item upstreamratenum - primary key

=item upstream_rateid - CDR upstream Rate ID (cdr.upstream_rateid - see L<FS::cdr>)

=item ratedetailnum - Rate detail - see L<FS::rate_detail>

=back

=head1 METHODS

=over 4

=item new HASHREF

Creates a new upstream rate mapping.  To add the upstream rate to the database,
see L<"insert">.

Note that this stores the hash reference, not a distinct copy of the hash it
points to.  You can ask the object for a copy with the I<hash> method.

=cut

# the new method can be inherited from FS::Record, if a table method is defined

sub table { 'cdr_upstream_rate'; }

=item insert

Adds this record to the database.  If there is an error, returns the error,
otherwise returns false.

=cut

# the insert method can be inherited from FS::Record

=item delete

Delete this record from the database.

=cut

# the delete method can be inherited from FS::Record

=item replace OLD_RECORD

Replaces the OLD_RECORD with this one in the database.  If there is an error,
returns the error, otherwise returns false.

=cut

# the replace method can be inherited from FS::Record

=item check

Checks all fields to make sure this is a valid upstream rate.  If there is
an error, returns the error, otherwise returns false.  Called by the insert
and replace methods.

=cut

# the check method should currently be supplied - FS::Record contains some
# data checking routines

sub check {
  my $self = shift;

  my $error = 
    $self->ut_numbern('upstreamratenum')
    #|| $self->ut_number('upstream_rateid')
    || $self->ut_alpha('upstream_rateid')
    #|| $self->ut_text('upstream_rateid')
    || $self->ut_foreign_key('ratedetailnum', 'rate_detail', 'ratedetailnum' )
  ;
  return $error if $error;

  $self->SUPER::check;
}

=item rate_detail

Returns the internal rate detail object for this upstream rate (see
L<FS::rate_detail>).

=cut

sub rate_detail {
  my $self = shift;
  qsearchs('rate_detail', { 'ratedetailnum' => $self->ratedetailnum } );
}

=back

=head1 BUGS

=head1 SEE ALSO

L<FS::Record>, schema.html from the base documentation.

=cut

1;


Index: cust_main.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_main.pm,v
retrieving revision 1.208
retrieving revision 1.209
diff -u -d -r1.208 -r1.209
--- cust_main.pm	18 Feb 2006 11:14:19 -0000	1.208
+++ cust_main.pm	20 Mar 2006 19:13:26 -0000	1.209
@@ -284,6 +284,8 @@
 
 =item referral_custnum - referring customer number
 
+=item spool_cdr - Enable individual CDR spooling, empty or `Y'
+
 =back
 
 =head1 METHODS
@@ -1257,7 +1259,11 @@
 
     my $payinfo = $self->payinfo;
     $payinfo =~ s/[^\d\@]//g;
-    $payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account at aba';
+    if ( $conf->exists('echeck-nonus') ) {
+      $payinfo =~ /^(\d+)\@(\d+)$/ or return 'invalid echeck account at aba';
+    } else {
+      $payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account at aba';
+    }
     $payinfo = "$1\@$2";
     $self->payinfo($payinfo);
     $self->paycvv('') if $self->dbdef_table->column('paycvv');
@@ -1336,8 +1342,10 @@
     $self->payname($1);
   }
 
-  $self->tax =~ /^(Y?)$/ or return "Illegal tax: ". $self->tax;
-  $self->tax($1);
+  foreach my $flag (qw( tax spool_cdr )) {
+    $self->$flag() =~ /^(Y?)$/ or return "Illegal $flag: ". $self->$flag();
+    $self->$flag($1);
+  }
 
   $self->otaker(getotaker) unless $self->otaker;
 
@@ -1640,6 +1648,7 @@
 
   my( $total_setup, $total_recur ) = ( 0, 0 );
   my %tax;
+  my @precommit_hooks = ();
 
   foreach my $cust_pkg (
     qsearch('cust_pkg', { 'custnum' => $self->custnum } )
@@ -1673,7 +1682,7 @@
       $setup = eval { $cust_pkg->calc_setup( $time ) };
       if ( $@ ) {
         $dbh->rollback if $oldAutoCommit;
-        return $@;
+        return "$@ running calc_setup for $cust_pkg\n";
       }
 
       $cust_pkg->setfield('setup', $time) unless $cust_pkg->setup;
@@ -1695,10 +1704,13 @@
       # XXX shared with $recur_prog
       $sdate = $cust_pkg->bill || $cust_pkg->setup || $time;
 
-      $recur = eval { $cust_pkg->calc_recur( \$sdate, \@details ) };
+      #over two params!  lets at least switch to a hashref for the rest...
+      my %param = ( 'precommit_hooks' => \@precommit_hooks, );
+
+      $recur = eval { $cust_pkg->calc_recur( \$sdate, \@details, \%param ) };
       if ( $@ ) {
         $dbh->rollback if $oldAutoCommit;
-        return $@;
+        return "$@ running calc_recur for $cust_pkg\n";
       }
 
       #change this bit to use Date::Manip? CAREFUL with timezones (see
@@ -1970,6 +1982,16 @@
     $dbh->rollback if $oldAutoCommit;
     return "can't update charged for invoice #$invnum: $error";
   }
+
+  foreach my $hook ( @precommit_hooks ) { 
+    eval {
+      &{$hook}; #($self) ?
+    };
+    if ( $@ ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "$@ running precommit hook $hook\n";
+    }
+  }
   
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   ''; #no error

Index: Schema.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Schema.pm,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- Schema.pm	8 Mar 2006 10:05:00 -0000	1.13
+++ Schema.pm	20 Mar 2006 19:13:26 -0000	1.14
@@ -437,6 +437,7 @@
         'refnum',   'int',  '',     '', '', '', 
         'referral_custnum', 'int',  'NULL', '', '', '', 
         'comments', 'text', 'NULL', '', '', '', 
+        'spool_cdr','char', 'NULL', 1, '', '', 
       ],
       'primary_key' => 'custnum',
       'unique' => [],
@@ -1146,7 +1147,8 @@
         'orig_regionnum',  'int', 'NULL', '', '', '', 
         'dest_regionnum',  'int',     '', '', '', '', 
         'min_included',    'int',     '', '', '', '', 
-        'min_charge',      @money_type, '', '', 
+        #'min_charge',      @money_type, '', '', 
+        'min_charge',      'decimal', '', '10,5', '', '', 
         'sec_granularity', 'int',     '', '', '', '', 
         #time period (link to table of periods)?
       ],
@@ -1416,14 +1418,14 @@
       'index'       => [],
     },
 
-    #map upstream rateid (XXX or rateplanid?) to ours...
-    'cdr_upstream_rate' => { # XXX or 'cdr_upstream_rateplan' ??
+    #map upstream rateid to ours...
+    'cdr_upstream_rate' => {
       'columns' => [
-        # XXX or 'upstream_rateplanid' ??
-        'upstream_rateid', 'int', 'NULL', '', '', '',
+        'upstreamratenum', 'serial',  '', '', '', '',
+        'upstream_rateid', 'varchar', '', $char_d, '', '', 
         'ratedetailnum',   'int', 'NULL', '', '', '',
       ],
-      'primary_key' => '', #XXX need a primary key
+      'primary_key' => 'upstreamratenum', #XXX need a primary key
       'unique' => [ [ 'upstream_rateid' ] ], #unless we add another field, yeah
       'index'  => [],
     },



More information about the freeside-commits mailing list