RT#29296: API stuff: Add new locations [v3 reconcile]
authorJonathan Prykop <jonathan@freeside.biz>
Thu, 21 Apr 2016 00:48:53 +0000 (19:48 -0500)
committerJonathan Prykop <jonathan@freeside.biz>
Fri, 22 Apr 2016 20:26:06 +0000 (15:26 -0500)
FS/FS/API.pm
FS/FS/cust_location/API.pm [deleted file]
FS/FS/cust_pkg/API.pm
FS/FS/part_export/cust_http.pm
FS/FS/part_export/cust_location_http.pm

index 5db29b2..4e6cb6c 100644 (file)
@@ -755,6 +755,8 @@ secret
 
 locationnum - pass this, or the following keys (don't pass both)
 
+locationname
+
 address1
 
 address2
@@ -767,8 +769,22 @@ state
 
 zip
 
+addr_clean
+
 country
 
+censustract
+
+censusyear
+
+location_type
+
+location_number
+
+location_kind
+
+incorporated
+
 On error, returns a hashref with an 'error' key.
 On success, returns a hashref with 'pkgnum' and 'locationnum' keys,
 containing the new values.
@@ -785,7 +801,24 @@ sub change_package_location {
 
   my %changeopt;
 
-  foreach my $field ('locationnum',FS::cust_location::API::API_editable_fields()) {
+  foreach my $field ( qw(
+    locationnum
+    locationname
+    address1
+    address2
+    city
+    county
+    state
+    zip
+    addr_clean
+    country
+    censustract
+    censusyear
+    location_type
+    location_number
+    location_kind
+    incorporated
+  )) {
     $changeopt{$field} = $opt{$field} if $opt{$field};
   }
 
diff --git a/FS/FS/cust_location/API.pm b/FS/FS/cust_location/API.pm
deleted file mode 100644 (file)
index 7d9140f..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-package FS::cust_location::API;
-
-use strict;
-
-# this gets used by FS::cust_main::API and FS::cust_pkg::API,
-# so don't use FS::cust_main or FS::cust_pkg here
-
-# some of these could probably be included, but in general,
-# probably a bad idea to expose everything in 
-# cust_main::Location::location_fields by default
-#
-#locationname
-#district
-#latitude
-#longitude
-#censustract
-#censusyear
-#geocode
-#coord_auto
-#addr_clean
-
-sub API_editable_fields {
-  return qw(
-    address1
-    address2
-    city
-    county
-    state
-    zip
-    country
-  );
-}
-
-1;
index 7ef3f72..837cf40 100644 (file)
@@ -2,8 +2,6 @@ package FS::cust_pkg::API;
 
 use strict;
 
-use FS::cust_location::API;
-
 sub API_getinfo {
   my $self = shift;
 
@@ -25,7 +23,23 @@ sub API_change {
 
   # update location--accepts raw fields OR location
   my %location_hash;
-  foreach my $field (FS::cust_location::API::API_editable_fields()) {
+  foreach my $field ( qw(
+    locationname
+    address1
+    address2
+    city
+    county
+    state
+    zip
+    addr_clean
+    country
+    censustract
+    censusyear
+    location_type
+    location_number
+    location_kind
+    incorporated
+  ) ) {
     $location_hash{$field} = $opt{$field} if $opt{$field};
   }
   return { 'error' => 'Cannot pass both locationnum and location fields' }
index f72d006..c13e18d 100644 (file)
@@ -55,7 +55,7 @@ tie %options, 'Tie::IxHash',
 ;
 
 %info = (
-  'svc'     => [qw( cust_main cust_location )],
+  'svc'     => [qw( cust_main )],
   'desc'    => 'Send an HTTP or HTTPS GET or POST request, for customers.',
   'options' => \%options,
   'no_machine' => 1,
index e2830db..fe77223 100644 (file)
@@ -4,9 +4,28 @@ use strict;
 use base qw( FS::part_export::http );
 use vars qw( %options %info );
 
-use FS::cust_main::Location;
-
-my @location_fields = ( qw( custnum prospectnum ), FS::cust_main::Location->location_fields );
+my @location_fields = qw(
+  custnum
+  prospectnum
+  locationname
+  address1
+  address2
+  city
+  county
+  state
+  zip
+  country
+  latitude
+  longitude
+  censustract
+  censusyear
+  district
+  geocode
+  location_type
+  location_number
+  location_kind
+  incorporated
+);
 
 tie %options, 'Tie::IxHash',
   'method' => { label   =>'Method',
@@ -23,6 +42,10 @@ tie %options, 'Tie::IxHash',
                         'type'  => 'select',
                         'multiple' => 1,
                         'options' => [ @location_fields ] },
+  'location_data'  => { 'label'   => 'Location data',
+                        'type'    => 'textarea' },
+  'package_data'   => { 'label'   => 'Package data',
+                        'type'    => 'textarea' },
   'success_regexp' => {
     label  => 'Success Regexp',
     default => '',
@@ -37,10 +60,16 @@ tie %options, 'Tie::IxHash',
   'notes'   => <<'END',
 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.
+Leave a URL blank to skip that action.
+Always sends locationnum, action, and fields specified in the export options.
+Action 'package' also sends pkgnum and change_pkgnum (the previous pkgnum,
+because location changes usually instigate a pkgnum change.)
+Simple field values can be selected in 'Include fields', and more complex
+values can be specified in the data field options as perl code using vars
+$cust_location, $cust_main and (where relevant) $cust_pkg.
+Action 'location' only sends on update if a specified field changed.
+Note that scheduled future package changes are currently sent when the change is scheduled
+(this may not be the case in future versions of this export.)
 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
@@ -51,11 +80,11 @@ END
 # 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
+#   to the customer--hence we don't distinguish insert 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 );
+  my( $self, $action, $cust_location ) = @_;
 
   # 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...
@@ -63,32 +92,55 @@ sub _export_command {
 
   $self->_http_queue_standard(
     'action' => 'location',
-    map { $_ => $cust_location->get($_) } ('locationnum', $self->_include_fields)
+    (map { $_ => $cust_location->get($_) } ('locationnum', $self->_include_fields)),
+    $self->_eval_replace('location_data',$cust_location,$cust_location->cust_main),
   );
 
 }
 
 sub _export_replace {
-  my( $self, $new, $old ) = ( shift, shift, shift );
+  my( $self, $new, $old ) = @_;
 
   my $changed = 0;
+
+  # even if they don't want custnum/prospectnum exported,
+  # inserts that lack custnum/prospectnum don't trigger exports,
+  # so we might not have previously reported these
+  $changed = 1 if $new->custnum && !$old->custnum;
+  $changed = 1 if $new->prospectnum && !$old->prospectnum;
+
   foreach my $field ($self->_include_fields) {
+    last if $changed;
     next if $new->get($field) eq $old->get($field);
     next if ($field =~ /latitude|longitude/) and $new->get($field) == $old->get($field);
     $changed = 1;
-    last;
   }
+
+  my %old_eval;
+  unless ($changed) {
+    %old_eval = $self->_eval_replace('location_data', $old, $old->cust_main),
+  }
+
+  my %eval = $self->_eval_replace('location_data', $new, $new->cust_main);
+
+  foreach my $key (keys %eval) {
+    last if $changed;
+    next if $eval{$key} eq $old_eval{$key};
+    $changed = 1;
+  }
+
   return '' unless $changed;
 
   $self->_http_queue_standard(
     'action' => 'location',
-    map { $_ => $new->get($_) } ('locationnum', $self->_include_fields)
+    (map { $_ => $new->get($_) } ('locationnum', $self->_include_fields)),
+    %eval,
   );
 }
 
 # not to be confused with export_pkg_change, which is for svcs
 sub export_pkg_location {
-  my( $self, $cust_pkg ) = ( shift, shift, shift );
+  my ($self, $cust_pkg) = @_;
 
   return '' unless $cust_pkg->locationnum;
 
@@ -98,6 +150,7 @@ sub export_pkg_location {
     'action' => 'package',
     (map { $_ => $cust_pkg->get($_) } ('pkgnum', 'change_pkgnum', 'locationnum')),
     (map { $_ => $cust_location->get($_) } $self->_include_fields),
+    $self->_eval_replace('package_data',$cust_location,$cust_pkg->cust_main,$cust_pkg),
   );
 }
 
@@ -128,4 +181,16 @@ sub _include_fields {
   split( /\s+/, $self->option('include_fields') );
 }
 
+sub _eval_replace {
+  my ($self,$option,$cust_location,$cust_main,$cust_pkg) = @_;
+  return
+    map {
+      /^\s*(\S+)\s+(.*)$/ or /()()/;
+      my( $field, $value_expression ) = ( $1, $2 );
+      my $value = eval $value_expression;
+      die $@ if $@;
+      ( $field, $value );
+    } split(/\n/, $self->option($option) );
+}
+
 1;