-change ikano.pm to use the new part_pkg_vendor, RT7111
authorlevinse <levinse>
Thu, 9 Dec 2010 19:26:20 +0000 (19:26 +0000)
committerlevinse <levinse>
Thu, 9 Dec 2010 19:26:20 +0000 (19:26 +0000)
-implement service expiry and add export expire to ikano, RT7111
-fix edit part_pkg bug, RT7111

FS/FS/cust_pkg.pm
FS/FS/cust_svc.pm
FS/FS/part_export/ikano.pm
FS/FS/part_pkg.pm
FS/FS/svc_Common.pm
FS/bin/freeside-pull-dsl

index e3f4777..b97bc93 100644 (file)
@@ -661,7 +661,25 @@ sub cancel {
   }
 
   my %svc;
-  unless ( $date ) {
+  if ( $date ) {
+       # copied from below
+       foreach my $cust_svc (
+         #schwartz
+         map  { $_->[0] }
+         sort { $a->[1] <=> $b->[1] }
+         map  { [ $_, $_->svc_x->table_info->{'cancel_weight'} ]; }
+         qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } )
+       ) {
+
+         my $error = $cust_svc->cancel( ('date' => $date) );
+
+         if ( $error ) {
+           $dbh->rollback if $oldAutoCommit;
+           return "Error expiring cust_svc: $error";
+         }
+       }
+
+  } else {
     foreach my $cust_svc (
       #schwartz
       map  { $_->[0] }
index 7b866fa..0a58d55 100644 (file)
@@ -109,7 +109,7 @@ If there is an error, returns the error, otherwise returns false.
 =cut
 
 sub cancel {
-  my $self = shift;
+  my($self,%opt) = @_;
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -133,19 +133,26 @@ sub cancel {
 
   my $svc = $self->svc_x;
   if ($svc) {
-
-    my $error = $svc->cancel;
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      return "Error canceling service: $error";
-    }
-    $error = $svc->delete; #this deletes this cust_svc record as well
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      return "Error deleting service: $error";
+    if ( %opt && $opt{'date'} ) {
+       my $error = $svc->expire($opt{'date'});
+       if ( $error ) {
+         $dbh->rollback if $oldAutoCommit;
+         return "Error expiring service: $error";
+       }
+    } else {
+       my $error = $svc->cancel;
+       if ( $error ) {
+         $dbh->rollback if $oldAutoCommit;
+         return "Error canceling service: $error";
+       }
+       $error = $svc->delete; #this deletes this cust_svc record as well
+       if ( $error ) {
+         $dbh->rollback if $oldAutoCommit;
+         return "Error deleting service: $error";
+       }
     }
 
-  } else {
+  } elsif ( !%opt ) {
 
     #huh?
     warn "WARNING: no svc_ record found for svcnum ". $self->svcnum.
index 30e2bac..ac1e578 100644 (file)
@@ -52,7 +52,6 @@ sub dsl_pull {
 # vendor_order_id, vendor_qual_id, vendor_order_type, pushed, monitored,
 # last_pull, address (from qual), contact info, ProductCustomId
     my($self, $svc_dsl, $threshold) = (shift, shift, shift);
-    $self->loadmod;
     my $result = $self->valid_order($svc_dsl,'pull');
     return $result unless $result eq '';
 
@@ -332,7 +331,9 @@ sub qual_html {
     my $list = "<B>Qualifying Packages:</B><UL>";
     my @part_pkgs = qsearch( 'part_pkg', { 'disabled' => '' } );
     foreach my $part_pkg ( @part_pkgs ) {
-       my $externalid = $part_pkg->option('externalid',1);
+       my %vendor_pkg_ids = $part_pkg->vendor_pkg_ids;
+       my $externalid = $vendor_pkg_ids{$self->exportnum} 
+           if defined $vendor_pkg_ids{$self->exportnum};
        if ( $externalid ) {
            $list .= "<LI>".$part_pkg->pkgpart.": ".$part_pkg->pkg." - "
                .$part_pkg->comment."</LI>" 
@@ -403,9 +404,10 @@ sub valid_order {
            &&  $svc_dsl->vendor_qual_id
            );
   return 'Missing or invalid order data' if $error;
-  
+  my %vendor_pkg_ids = $svc_dsl->cust_svc->cust_pkg->part_pkg->vendor_pkg_ids;
   return 'Package does not have an external id configured'
-    if $svc_dsl->cust_svc->cust_pkg->part_pkg->options('externalid',1) eq '';
+    unless defined $vendor_pkg_ids{$self->exportnum};
 
   return 'No valid qualification for this order' 
     unless qsearch( 'qual', { 'vendor_qual_id' => $svc_dsl->vendor_qual_id });
@@ -415,7 +417,7 @@ sub valid_order {
   if($svc_dsl->vendor_order_type eq 'NEW') {
     if($svc_dsl->pushed) {
        $error = !( ($action eq 'pull' || $action eq 'statuschg' 
-                       || $action eq 'delete')
+                       || $action eq 'delete' || $action eq 'expire')
            &&  length($svc_dsl->vendor_order_id) > 0
            &&  length($svc_dsl->vendor_order_status) > 0
                );
@@ -463,8 +465,6 @@ sub qual2termsid {
 sub _export_insert {
   my( $self, $svc_dsl ) = (shift, shift);
 
-  $self->loadmod;
-
   my $result = $self->valid_order($svc_dsl,'insert');
   return $result unless $result eq '';
 
@@ -472,7 +472,8 @@ sub _export_insert {
   my $contactTN = $svc_dsl->cust_svc->cust_pkg->cust_main->daytime;
   $contactTN =~ s/[^0-9]//g;
 
-  my $ProductCustomId = $svc_dsl->cust_svc->cust_pkg->part_pkg->option('externalid',1);
+  my %vendor_pkg_ids = $svc_dsl->cust_svc->cust_pkg->part_pkg->vendor_pkg_ids;
+  my $ProductCustomId = $vendor_pkg_ids{$self->exportnum};
 
   my $args = {
        orderType => 'NEW',
@@ -551,7 +552,7 @@ sub _export_delete {
   return $result unless $result eq '';
 
   # for now allow an immediate cancel only on New orders in New/Pending status
-  #XXX: add support for Chance and Cancel orders in New/Pending status later
+  #XXX: add support for Change and Cancel orders in New/Pending status later
 
   if($svc_dsl->vendor_order_type eq 'NEW') {
     if($svc_dsl->vendor_order_status eq 'NEW' 
@@ -572,6 +573,10 @@ sub _export_delete {
        return "Cannot cancel a NEW order unless it's in NEW or PENDING status";
     }
   }
+  elsif($svc_dsl->vendor_order_type eq 'CANCEL') {
+     return 'Cannot cancel a CANCEL order unless expire was set'
+       unless $svc_dsl->cust_svc->cust_pkg->expire > 0;
+  }
   else {
     return 'Canceling orders other than NEW orders is not currently implemented';
   }
@@ -579,6 +584,83 @@ sub _export_delete {
   '';
 }
 
+sub export_expire {
+  my($self, $svc_dsl, $date) = (shift, shift, shift);
+  
+  my $result = $self->valid_order($svc_dsl,'expire');
+  return $result unless $result eq '';
+  
+  # for now allow a proper cancel only on New orders in Completed status
+  #XXX: add support for some other cases in future
+  
+  if($svc_dsl->vendor_order_type eq 'NEW' 
+       && $svc_dsl->vendor_order_status eq 'COMPLETED') {
+    
+         my $contactTN = $svc_dsl->cust_svc->cust_pkg->cust_main->daytime;
+         $contactTN =~ s/[^0-9]//g;
+
+         my %vendor_pkg_ids = $svc_dsl->cust_svc->cust_pkg->part_pkg->vendor_pkg_ids;
+         my $ProductCustomId = $vendor_pkg_ids{$self->exportnum};
+
+         # we are now a cancel order
+         $svc_dsl->desired_due_date($date);
+         $svc_dsl->vendor_order_type('CANCEL');
+
+         my $args = {
+               orderType => 'CANCEL',
+               ProductCustomId => $ProductCustomId,
+               TermsId => $self->qual2termsid($svc_dsl->vendor_qual_id,$ProductCustomId),
+               DSLPhoneNumber => $svc_dsl->loop_type eq '0' ? 'STANDALONE'
+                                                           : $svc_dsl->phonenum,
+               Password => $svc_dsl->password,
+               PrequalId => $svc_dsl->vendor_qual_id,
+               CompanyName => $svc_dsl->company,
+               FirstName => $svc_dsl->first,
+               LastName => $svc_dsl->last,
+               MiddleName => '',
+               ContactMethod => 'PHONE',
+               ContactPhoneNumber => $contactTN,
+               ContactEmail => 'x@x.xx',
+               ContactFax => '',
+               DateToOrder => time2str("%Y-%m-%d",$date),
+               RequestClientIP => '127.0.0.1',
+               IspChange => 'NO',
+               IspPrevious => '',
+               CurrentProvider => '',
+         };
+
+         $args->{'VirtualPhoneNumber'} = $svc_dsl->phonenum 
+           if $svc_dsl->loop_type eq '0';
+
+         $result = $self->ikano_command('ORDER',$args); 
+         return $result unless ref($result); # scalar (string) is an error
+
+         # now we're getting an OrderResponse which should have one Order in it
+         warn "$me _export_insert OrderResponse hash:\n".Dumper($result)
+               if $self->option('debug');
+         
+         return 'Invalid order response' unless defined $result->{'Order'};
+         $result = $result->{'Order'};
+
+         return 'No/invalid order id or status returned' 
+           unless defined $result->{'Status'} && defined $result->{'OrderId'}
+               && grep($_ eq $result->{'Status'}, @Net::Ikano::orderStatus);
+
+         $svc_dsl->pushed(time);
+         $svc_dsl->last_pull((time)+1); 
+         $svc_dsl->vendor_order_id($result->{'OrderId'});
+         $svc_dsl->vendor_order_status($result->{'Status'});
+         local $FS::svc_Common::noexport_hack = 1;
+         $result = $svc_dsl->replace; 
+         return "Error setting DSL fields: $result" if $result;
+  }
+  else {
+    return "Cancelling anything other than NEW orders in COMPLETED status is "
+       . "not currently implemented";
+  }
+ '';
+}
+
 sub statuschg {
   my( $self, $svc_dsl, $type ) = (shift, shift, shift);
 
index 46067d1..5c67ed9 100644 (file)
@@ -21,6 +21,7 @@ use FS::part_pkg_taxoverride;
 use FS::part_pkg_taxproduct;
 use FS::part_pkg_link;
 use FS::part_pkg_discount;
+use FS::part_pkg_vendor;
 
 @ISA = qw( FS::m2m_Common FS::option_Common );
 $DEBUG = 0;
@@ -456,7 +457,7 @@ sub replace {
       my($exportnum,$vendor_pkg_id);
       while ( ($exportnum,$vendor_pkg_id) 
                                = each %{$options->{'part_pkg_vendor'}} ) {
-         my $replaced = 0;
+         my $noinsert = 0;
          foreach my $part_pkg_vendor ( @part_pkg_vendor ) {
            if($exportnum == $part_pkg_vendor->exportnum
                && $vendor_pkg_id ne $part_pkg_vendor->vendor_pkg_id) {
@@ -466,11 +467,16 @@ sub replace {
                  $dbh->rollback if $oldAutoCommit;
                  return "Error replacing part_pkg_vendor record: $error";
                }
-               $replaced = 1;
+               $noinsert = 1;
+               last;
+           }
+           elsif($exportnum == $part_pkg_vendor->exportnum
+               && $vendor_pkg_id eq $part_pkg_vendor->vendor_pkg_id) {
+               $noinsert = 1;
                last;
            }
          }
-         unless ( $replaced ) {
+         unless ( $noinsert ) {
            my $ppv = new FS::part_pkg_vendor( {
                    'pkgpart' => $new->pkgpart,
                    'exportnum' => $exportnum,
index b377642..3d8fe16 100644 (file)
@@ -375,6 +375,40 @@ sub delete {
   '';
 }
 
+=item expire DATE
+
+Currently this will only run expire exports if any are attached
+
+=cut
+
+sub expire {
+  my($self,$date) = (shift,shift);
+
+  return 'Expire date must be specified' unless $date;
+    
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $export_args = [$date];
+  my $error = $self->export('expire', @$export_args);
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+  '';
+}
+
 =item replace [ OLD_RECORD ] [ HASHREF | OPTION => VALUE ]
 
 Replaces OLD_RECORD with this one.  If there is an error, returns the error,
index d0aa921..e658407 100755 (executable)
@@ -40,7 +40,7 @@ sub untaint_argv {
 }
 
 sub usage {
-  die "Usage:\n\n  freeside-pull-dsl \n";
+  die "Usage:\n  freeside-pull-dsl user \n";
 }
 
 ###