RT#29296: API stuff: Add new locations [package location export]
authorJonathan Prykop <jonathan@freeside.biz>
Mon, 18 Apr 2016 19:33:02 +0000 (14:33 -0500)
committerJonathan Prykop <jonathan@freeside.biz>
Mon, 18 Apr 2016 19:33:02 +0000 (14:33 -0500)
FS/FS/Conf.pm
FS/FS/cust_location.pm
FS/FS/cust_pkg.pm
FS/FS/part_export/cust_location_http.pm

index 24d1056..7453158 100644 (file)
@@ -5306,7 +5306,7 @@ and customer address. Include units.',
       my @part_export =
         map { qsearch( 'part_export', {exporttype => $_ } ) }
           keys %{FS::part_export::export_info('cust_main')};
-      map { $_->exportnum => $_->exporttype.' to '.$_->machine } @part_export;
+      map { $_->exportnum => $_->exportname } @part_export;
     },
     'option_sub'  => sub {
       require FS::Record;
@@ -5315,7 +5315,7 @@ and customer address. Include units.',
         'part_export', { 'exportnum' => shift }
       );
       $part_export
-        ? $part_export->exporttype.' to '.$part_export->machine
+        ? $part_export->exportname
         : '';
     },
   },
@@ -5324,7 +5324,7 @@ and customer address. Include units.',
   {
     'key'         => 'cust_location-exports',
     'section'     => '',
-    'description' => 'Export(s) to call on cust_location insert, modification and deletion.',
+    'description' => 'Export(s) to call on cust_location insert or modification',
     'type'        => 'select-sub',
     'multiple'    => 1,
     'options_sub' => sub {
index 2b8a5c8..3588cee 100644 (file)
@@ -249,20 +249,22 @@ sub insert {
   # cust_location exports
   #my $export_args = $options{'export_args'} || [];
 
-  my @part_export =
-    map qsearch( 'part_export', {exportnum=>$_} ),
-      $conf->config('cust_location-exports'); #, $agentnum
-
-  foreach my $part_export ( @part_export ) {
-    my $error = $part_export->export_insert($self); #, @$export_args);
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      return "exporting to ". $part_export->exporttype.
-             " (transaction rolled back): $error";
+  # don't export custnum_pending cases, let follow-up replace handle that
+  if ($self->custnum || $self->prospectnum) {
+    my @part_export =
+      map qsearch( 'part_export', {exportnum=>$_} ),
+        $conf->config('cust_location-exports'); #, $agentnum
+
+    foreach my $part_export ( @part_export ) {
+      my $error = $part_export->export_insert($self); #, @$export_args);
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return "exporting to ". $part_export->exporttype.
+               " (transaction rolled back): $error";
+      }
     }
   }
 
-
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   '';
 }
@@ -311,20 +313,22 @@ sub replace {
   # cust_location exports
   #my $export_args = $options{'export_args'} || [];
 
-  my @part_export =
-    map qsearch( 'part_export', {exportnum=>$_} ),
-      $conf->config('cust_location-exports'); #, $agentnum
-
-  foreach my $part_export ( @part_export ) {
-    my $error = $part_export->export_replace($self, $old); #, @$export_args);
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      return "exporting to ". $part_export->exporttype.
-             " (transaction rolled back): $error";
+  # don't export custnum_pending cases, let follow-up replace handle that
+  if ($self->custnum || $self->prospectnum) {
+    my @part_export =
+      map qsearch( 'part_export', {exportnum=>$_} ),
+        $conf->config('cust_location-exports'); #, $agentnum
+
+    foreach my $part_export ( @part_export ) {
+      my $error = $part_export->export_replace($self, $old); #, @$export_args);
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return "exporting to ". $part_export->exporttype.
+               " (transaction rolled back): $error";
+      }
     }
   }
 
-
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   '';
 }
index 074a58c..1cc8235 100644 (file)
@@ -442,6 +442,21 @@ sub insert {
 
   my $conf = new FS::Conf;
 
+  if ($self->locationnum) {
+    my @part_export =
+      map qsearch( 'part_export', {exportnum=>$_} ),
+        $conf->config('cust_location-exports'); #, $agentnum
+
+    foreach my $part_export ( @part_export ) {
+      my $error = $part_export->export_pkg_location($self); #, @$export_args);
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return "exporting to ". $part_export->exporttype.
+               " (transaction rolled back): $error";
+      }
+    }
+  }
+
   if ( ! $import && $conf->config('ticket_system') && $options{ticket_subject} ) {
 
     #this init stuff is still inefficient, but at least its limited to 
@@ -696,6 +711,24 @@ sub replace {
     }
   }
 
+  # also run exports if removing locationnum?
+  #   doesn't seem to happen, and we don't export blank locationnum on insert...
+  if ($new->locationnum and ($new->locationnum != $old->locationnum)) {
+    my $conf = new FS::Conf;
+    my @part_export =
+      map qsearch( 'part_export', {exportnum=>$_} ),
+        $conf->config('cust_location-exports'); #, $agentnum
+
+    foreach my $part_export ( @part_export ) {
+      my $error = $part_export->export_pkg_location($new); #, @$export_args);
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return "exporting to ". $part_export->exporttype.
+               " (transaction rolled back): $error";
+      }
+    }
+  }
+
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   '';
 
index 460080c..e2830db 100644 (file)
@@ -4,27 +4,9 @@ use strict;
 use base qw( FS::part_export::http );
 use vars qw( %options %info );
 
-my @location_fields = qw(
-  custnum
-  address1
-  address2
-  city
-  state
-  zip
-  country
-  locationname
-  county
-  latitude
-  longitude
-  prospectnum
-  location_type
-  location_number
-  location_kind
-  geocode
-  district
-  censusyear
-  incorporated
-);
+use FS::cust_main::Location;
+
+my @location_fields = ( qw( custnum prospectnum ), FS::cust_main::Location->location_fields );
 
 tie %options, 'Tie::IxHash',
   'method' => { label   =>'Method',
@@ -32,10 +14,11 @@ tie %options, 'Tie::IxHash',
                 #options =>[qw(POST GET)],
                 options =>[qw(POST)],
                 default =>'POST' },
-  'url'    => { label   => 'URL', default => 'http://', },
-  'ssl_no_verify' => { label => 'Skip SSL certificate validation',
-                       type  => 'checkbox',
-                     },
+  'location_url'   => { label   => 'Location URL' },
+  'package_url'    => { label   => 'Package URL' },
+  'ssl_no_verify'  => { label => 'Skip SSL certificate validation',
+                        type  => 'checkbox',
+                      },
   'include_fields' => { 'label' => 'Include fields',
                         'type'  => 'select',
                         'multiple' => 1,
@@ -52,45 +35,39 @@ tie %options, 'Tie::IxHash',
   'options' => \%options,
   'no_machine' => 1,
   'notes'   => <<'END',
-Send an HTTP or HTTPS GET or POST to the specified URL on customer location insert
-or replace.  Always sends cgi fields action ('insert' or 'replace') and locationnum,
-as well as any fields specified below.  Only sends on replace if one of the
-specified fields changed.
+Send an HTTP or HTTPS GET or POST to the specified URLs on customer location
+creation/update (action 'location') and package location assignment/change (action 'package').
+Always sends locationnum, action and any fields specified in the 'Include fields' 
+export option.  Action 'package' also sends pkgnum and old_pkgnum (because location
+changes usually instigate a pkgnum change.)  Action 'location' only sends on replace 
+if one of the specified fields changed.  Leave a URL blank to skip that action.
 For HTTPS support, <a href="http://search.cpan.org/dist/Crypt-SSLeay">Crypt::SSLeay</a>
 or <a href="http://search.cpan.org/dist/IO-Socket-SSL">IO::Socket::SSL</a> is required.
 END
 );
 
-sub http_queue_standard {
-  my $self = shift;
-  $self->http_queue( '',
-    ( $self->option('ssl_no_verify') ? 'ssl_no_verify' : '' ),
-    $self->option('method'),
-    $self->option('url'),
-    $self->option('success_regexp'),
-    @_
-  );
-}
-
-sub _include_fields {
-  my $self = shift;
-  split( /\s+/, $self->option('include_fields') );
-}
+# we don't do anything on deletion because we generally don't delete locations
+#
+# we don't send blank custnum/prospectnum because we do a lot of inserting/replacing 
+#   with blank values and then immediately overwriting, but that unfortunately
+#   makes it difficult to indicate if this is the first time we've sent the location
+#   to the customer--hence we don't distinguish creation from update in the cgi vars
 
+# gets invoked by FS::part_export::http _export_insert
 sub _export_command {
   my( $self, $action, $cust_location ) = ( shift, shift, shift );
 
+  # redundant--cust_location exports don't get invoked by cust_location->delete,
+  # or by any status trigger, but just to be clear, since http export has other actions...
   return '' unless $action eq 'insert';
 
-  $self->http_queue_standard(
-    'action' => $action,
+  $self->_http_queue_standard(
+    'action' => 'location',
     map { $_ => $cust_location->get($_) } ('locationnum', $self->_include_fields)
   );
 
 }
 
-# currently, only custnum can change (when converting prospect to customer)
-# but using more generic logic for ease of adding other changeable fields
 sub _export_replace {
   my( $self, $new, $old ) = ( shift, shift, shift );
 
@@ -99,13 +76,56 @@ sub _export_replace {
     next if $new->get($field) eq $old->get($field);
     next if ($field =~ /latitude|longitude/) and $new->get($field) == $old->get($field);
     $changed = 1;
+    last;
   }
   return '' unless $changed;
 
-  $self->http_queue_standard(
-    'action' => 'replace',
+  $self->_http_queue_standard(
+    'action' => 'location',
     map { $_ => $new->get($_) } ('locationnum', $self->_include_fields)
   );
 }
 
+# not to be confused with export_pkg_change, which is for svcs
+sub export_pkg_location {
+  my( $self, $cust_pkg ) = ( shift, shift, shift );
+
+  return '' unless $cust_pkg->locationnum;
+
+  my $cust_location = $cust_pkg->cust_location;
+
+  $self->_http_queue_standard(
+    'action' => 'package',
+    (map { $_ => $cust_pkg->get($_) } ('pkgnum', 'change_pkgnum', 'locationnum')),
+    (map { $_ => $cust_location->get($_) } $self->_include_fields),
+  );
+}
+
+sub _http_queue_standard {
+  my $self = shift;
+  my %opts = @_;
+  my $url;
+  if ($opts{'action'} eq 'location') {
+    $url = $self->option('location_url');
+    return '' unless $url;
+  } elsif ($opts{'action'} eq 'package') {
+    $url = $self->option('package_url');
+    return '' unless $url;
+  } else {
+    return "Bad action ".$opts{'action'};
+  }
+  $self->http_queue( '',
+    ( $self->option('ssl_no_verify') ? 'ssl_no_verify' : '' ),
+    $self->option('method'),
+    $url,
+    $self->option('success_regexp'),
+    %opts
+  );
+}
+
+sub _include_fields {
+  my $self = shift;
+  split( /\s+/, $self->option('include_fields') );
+}
+
 1;