Merge branch 'master' of git.freeside.biz:/home/git/freeside
authorIvan Kohler <ivan@freeside.biz>
Sun, 23 Sep 2012 21:57:08 +0000 (14:57 -0700)
committerIvan Kohler <ivan@freeside.biz>
Sun, 23 Sep 2012 21:57:08 +0000 (14:57 -0700)
FS/FS/cdr/taqua.pm
FS/FS/cdr/taqua62.pm [new file with mode: 0644]
FS/FS/part_pkg.pm

index 390152a..7ef6d76 100644 (file)
@@ -7,7 +7,7 @@ use FS::cdr qw(_cdr_date_parser_maker);
 @ISA = qw(FS::cdr);
 
 %info = (
-  'name'          => 'Taqua',
+  'name'          => 'Taqua v6.0',
   'weight'        => 130,
   'header'        => 1,
   'import_fields' => [  #some of these are kind arbitrary...
diff --git a/FS/FS/cdr/taqua62.pm b/FS/FS/cdr/taqua62.pm
new file mode 100644 (file)
index 0000000..862018e
--- /dev/null
@@ -0,0 +1,178 @@
+package FS::cdr::taqua62;
+
+use strict;
+use vars qw(@ISA %info $da_rewrite);
+use FS::cdr qw(_cdr_date_parser_maker);
+
+@ISA = qw(FS::cdr);
+
+%info = (
+  'name'          => 'Taqua v6.2',
+  'weight'        => 131,
+  'header'        => 1,
+  'import_fields' => [
+
+    #0
+    '', #Key 
+    '', #InsertTime, irrelevant
+    #RecordType
+    sub {
+      my($cdr, $field, $conf, $hashref) = @_;
+      $hashref->{skiprow} = 1
+        unless ($field == 0 && $cdr->disposition == 100       )  #regular CDR
+            || ($field == 1 && $cdr->lastapp     eq 'acctcode'); #accountcode
+      $cdr->cdrtypenum($field);
+    },
+
+    '',       #RecordVersion
+    '',       #OrigShelfNumber
+    '',       #OrigCardNumber
+    '',       #OrigCircuit
+    '',       #OrigCircuitType
+    'uniqueid',                           #SequenceNumber
+    'sessionnum',                         #SessionNumber
+    #10
+    'src',                                #CallingPartyNumber
+    #CalledPartyNumber
+    sub {
+      my( $cdr, $field, $conf ) = @_;
+      if ( $cdr->calltypenum == 6 && $cdr->cdrtypenum == 0 ) {
+        $cdr->dst("+$field");
+      } else {
+        $cdr->dst($field);
+      }
+    },
+
+    _cdr_date_parser_maker('startdate', 'gmt' => 1),  #CallArrivalTime
+    _cdr_date_parser_maker('enddate', 'gmt' => 1),    #CallCompletionTime
+
+    #Disposition
+    #sub { my($cdr, $d ) = @_; $cdr->disposition( $disposition{$d}): },
+    'disposition',
+                                          #  -1 => '',
+                                          #   0 => '',
+                                          # 100 => '', #regular cdr
+                                          # 101 => '',
+                                          # 102 => '',
+                                          # 103 => '',
+                                          # 104 => '',
+                                          # 105 => '',
+                                          # 201 => '',
+                                          # 203 => '',
+                                          # 204 => '',
+
+    _cdr_date_parser_maker('answerdate', 'gmt' => 1), #DispositionTime
+    '',       #TCAP
+    '',       #OutboundCarrierConnectTime
+    '',       #OutboundCarrierDisconnectTime
+
+    #TermTrunkGroup
+    #it appears channels are actually part of trunk groups, but this data
+    #is interesting and we need a source and destination place to put it
+    'dstchannel',                         #TermTrunkGroup
+
+    #20
+
+    '',       #TermShelfNumber
+    '',       #TermCardNumber
+    '',       #TermCircuit
+    '',       #TermCircuitType
+    'carrierid',                          #OutboundCarrierId
+
+    #BillingNumber
+    #'charged_party',                      
+    sub {
+      my( $cdr, $field, $conf ) = @_;
+
+      #could be more efficient for the no config case, if anyone ever needs that
+      $da_rewrite ||= $conf->config('cdr-taqua-da_rewrite');
+
+      if ( $da_rewrite && $field =~ /\d/ ) {
+        my $rewrite = $da_rewrite;
+        $rewrite =~ s/\s//g;
+        my @rewrite = split(',', $conf->config('cdr-taqua-da_rewrite') );
+        if ( grep { $field eq $_ } @rewrite ) {
+          $cdr->charged_party( $cdr->src() );
+          $cdr->calltypenum(12);
+          return;
+        }
+      }
+      if ( $cdr->is_tollfree ) {        # thankfully this is already available
+        $cdr->charged_party($cdr->dst); # and this
+      } else {
+        $cdr->charged_party($field);
+      }
+    },
+
+    'subscriber',                         #SubscriberName
+    'lastapp',                            #ServiceName
+    '',       #some weirdness #ChargeTime
+    'lastdata',                           #ServiceInformation
+
+    #30
+
+    '',       #FacilityInfo
+    '',             #all 1900-01-01 0#CallTraceTime
+    '',             #all-1#UniqueIndicator
+    '',             #all-1#PresentationIndicator
+    '',             #empty#Pin
+    'calltypenum',                        #CallType
+
+    #nothing below is used by QIS...
+
+    '',           #Balt/empty #OrigRateCenter
+    '',           #Balt/empty #TermRateCenter
+
+    #OrigTrunkGroup
+    #it appears channels are actually part of trunk groups, but this data
+    #is interesting and we need a source and destination place to put it
+    'channel',                            #OrigTrunkGroup
+    'userfield',                                #empty#UserDefined
+
+    #40
+
+    '',             #empty#PseudoDestinationNumber
+    '',             #all-1#PseudoCarrierCode
+    '',             #empty#PseudoANI
+    '',             #all-1#PseudoFacilityInfo
+    '',       #OrigDialedDigits
+    '',             #all-1#OrigOutboundCarrier
+    '',       #IncomingCarrierID
+    'dcontext',                           #JurisdictionInfo
+    '',       #OrigDestDigits
+    '',             #empty#AMALineNumber
+
+    #50
+
+    '',             #empty#AMAslpID
+    '',             #empty#AMADigitsDialedWC
+    '',       #OpxOffHook
+    '',       #OpxOnHook
+    '',       #OrigCalledNumber
+    '',       #RedirectingNumber
+    '',       #RouteAttempts
+    '',       #OrigMGCPTerm
+    '',       #TermMGCPTerm
+    '',       #ReasonCode
+
+    #60
+    
+    '',       #OrigIPCallID
+    '',       #ESAIPTrunkGroup
+    '',       #ESAReason
+    '',       #BearerlessCall
+    '',       #oCodec
+    '',       #tCodec
+    '',       #OrigTrunkGroupNumber
+    '',       #TermTrunkGroupNumber
+    '',       #TermRecord
+    '',       #OrigRoutingIndicator
+
+    #70
+
+    '',       #TermRoutingIndicator
+
+  ],
+);
+
+1;
index 91bcdc5..6e7f8f8 100644 (file)
@@ -1598,18 +1598,79 @@ sub _upgrade_data { # class method
 
   # set any package with FCC voice lines to the "VoIP with broadband" category
   # for backward compatibility
-  my $journal = 'part_pkg_fcc_voip_class';
-  if (!FS::upgrade_journal->is_done($journal)) {
-    @part_pkg = qsearch('part_pkg', { 
-        fcc_ds0s        => { op => '>', value => 0 },
-        fcc_voip_class  => ''
-    });
-    foreach my $part_pkg (@part_pkg) {
-      $part_pkg->set(fcc_voip_class => 2);
-      my $error = $part_pkg->replace;
-      die $error if $error;
+  #
+  # recover from a bad upgrade bug
+  my $upgrade = 'part_pkg_fcc_voip_class_FIX';
+  if (!FS::upgrade_journal->is_done($upgrade)) {
+    my $bad_upgrade = qsearchs('upgrade_journal', 
+      { upgrade => 'part_pkg_fcc_voip_class' }
+    );
+    if ( $bad_upgrade ) {
+      my $where = 'WHERE history_date <= '.$bad_upgrade->_date.
+                  ' AND  history_date >  '.($bad_upgrade->_date - 3600);
+      my @h_part_pkg_option = map { FS::part_pkg_option->new($_->hashref) }
+        qsearch({
+          'select'    => '*',
+          'table'     => 'h_part_pkg_option',
+          'hashref'   => {},
+          'extra_sql' => "$where AND history_action = 'delete'",
+          'order_by'  => 'ORDER BY history_date ASC',
+        });
+      my @h_pkg_svc = map { FS::pkg_svc->new($_->hashref) }
+        qsearch({
+          'select'    => '*',
+          'table'     => 'h_pkg_svc',
+          'hashref'   => {},
+          'extra_sql' => "$where AND history_action = 'replace_old'",
+          'order_by'  => 'ORDER BY history_date ASC',
+        });
+      my %opt;
+      foreach my $deleted (@h_part_pkg_option, @h_pkg_svc) {
+        my $pkgpart ||= $deleted->pkgpart;
+        $opt{$pkgpart} ||= {
+          options => {},
+          pkg_svc => {},
+          primary_svc => '',
+          hidden_svc => {},
+        };
+        if ( $deleted->isa('FS::part_pkg_option') ) {
+          $opt{$pkgpart}{options}{ $deleted->optionname } = $deleted->optionvalue;
+        } else { # pkg_svc
+          my $svcpart = $deleted->svcpart;
+          $opt{$pkgpart}{pkg_svc}{$svcpart} = $deleted->quantity;
+          $opt{$pkgpart}{hidden_svc}{$svcpart} ||= $deleted->hidden;
+          $opt{$pkgpart}{primary_svc} = $svcpart if $deleted->primary_svc;
+        }
+      }
+      foreach my $pkgpart (keys %opt) {
+        my $part_pkg = FS::part_pkg->by_key($pkgpart);
+        my $error = $part_pkg->replace( $part_pkg->replace_old, $opt{$pkgpart} );
+        if ( $error ) {
+          die "error recovering damaged pkgpart $pkgpart:\n$error\n";
+        }
+      }
+    } # $bad_upgrade exists
+    else { # do the original upgrade, but correctly this time
+      @part_pkg = qsearch('part_pkg', {
+          fcc_ds0s        => { op => '>', value => 0 },
+          fcc_voip_class  => ''
+      });
+      foreach my $part_pkg (@part_pkg) {
+        $part_pkg->set(fcc_voip_class => 2);
+        my @pkg_svc = $part_pkg->pkg_svc;
+        my %quantity = map {$_->svcpart, $_->quantity} @pkg_svc;
+        my %hidden   = map {$_->svcpart, $_->hidden  } @pkg_svc;
+        my $error = $part_pkg->replace(
+          $part_pkg->replace_old,
+          options     => { $part_pkg->options },
+          pkg_svc     => \%quantity,
+          hidden_svc  => \%hidden,
+          primary_svc => ($part_pkg->svcpart || ''),
+        );
+        die $error if $error;
+      }
     }
-    FS::upgrade_journal->set_done($journal);
+    FS::upgrade_journal->set_done($upgrade);
   }
 
 }