add an $import global flag to cust_location so we can avoid geocoding on batch import...
[freeside.git] / FS / FS / cust_location.pm
index ab80941..a5250ec 100644 (file)
@@ -1,13 +1,18 @@
 package FS::cust_location;
 package FS::cust_location;
+use base qw( FS::geocode_Mixin FS::Record );
 
 use strict;
 
 use strict;
-use base qw( FS::geocode_Mixin FS::Record );
+use vars qw( $import );
 use Locale::Country;
 use Locale::Country;
+use FS::UID qw( dbh );
 use FS::Record qw( qsearch ); #qsearchs );
 use FS::Record qw( qsearch ); #qsearchs );
+use FS::Conf;
 use FS::prospect_main;
 use FS::cust_main;
 use FS::cust_main_county;
 
 use FS::prospect_main;
 use FS::cust_main;
 use FS::cust_main_county;
 
+$import = 0;
+
 =head1 NAME
 
 FS::cust_location - Object methods for cust_location records
 =head1 NAME
 
 FS::cust_location - Object methods for cust_location records
@@ -74,6 +79,14 @@ Country (see L<FS::cust_main_county>)
 
 Geocode
 
 
 Geocode
 
+=item district
+
+Tax district code (optional)
+
+=item disabled
+
+Disabled flag; set to 'Y' to disable the location.
+
 =back
 
 =head1 METHODS
 =back
 
 =head1 METHODS
@@ -96,6 +109,26 @@ sub table { 'cust_location'; }
 Adds this record to the database.  If there is an error, returns the error,
 otherwise returns false.
 
 Adds this record to the database.  If there is an error, returns the error,
 otherwise returns false.
 
+=cut
+
+sub insert {
+  my $self = shift;
+  my $error = $self->SUPER::insert(@_);
+
+  #false laziness with cust_main, will go away eventually
+  my $conf = new FS::Conf;
+  if ( !$error and $conf->config('tax_district_method') ) {
+
+    my $queue = new FS::queue {
+      'job' => 'FS::geocode_Mixin::process_district_update'
+    };
+    $error = $queue->insert( ref($self), $self->locationnum );
+
+  }
+
+  $error || '';
+}
+
 =item delete
 
 Delete this record from the database.
 =item delete
 
 Delete this record from the database.
@@ -105,6 +138,30 @@ Delete this record from the database.
 Replaces the OLD_RECORD with this one in the database.  If there is an error,
 returns the error, otherwise returns false.
 
 Replaces the OLD_RECORD with this one in the database.  If there is an error,
 returns the error, otherwise returns false.
 
+=cut
+
+sub replace {
+  my $self = shift;
+  my $old = shift;
+  $old ||= $self->replace_old;
+  my $error = $self->SUPER::replace($old);
+
+  #false laziness with cust_main, will go away eventually
+  my $conf = new FS::Conf;
+  if ( !$error and $conf->config('tax_district_method') 
+    and $self->get('address1') ne $old->get('address1') ) {
+
+    my $queue = new FS::queue {
+      'job' => 'FS::geocode_Mixin::process_district_update'
+    };
+    $error = $queue->insert( ref($self), $self->locationnum );
+
+  }
+
+  $error || '';
+}
+
+
 =item check
 
 Checks all fields to make sure this is a valid location.  If there is
 =item check
 
 Checks all fields to make sure this is a valid location.  If there is
@@ -129,13 +186,29 @@ sub check {
     || $self->ut_textn('state')
     || $self->ut_country('country')
     || $self->ut_zip('zip', $self->country)
     || $self->ut_textn('state')
     || $self->ut_country('country')
     || $self->ut_zip('zip', $self->country)
+    || $self->ut_coordn('latitude')
+    || $self->ut_coordn('longitude')
+    || $self->ut_enum('coord_auto', [ '', 'Y' ])
+    || $self->ut_alphan('location_type')
+    || $self->ut_textn('location_number')
+    || $self->ut_enum('location_kind', [ '', 'R', 'B' ] )
     || $self->ut_alphan('geocode')
     || $self->ut_alphan('geocode')
+    || $self->ut_alphan('district')
   ;
   return $error if $error;
 
   ;
   return $error if $error;
 
+  $self->set_coord
+    unless $import || ($self->latitude && $self->longitude);
+
   return "No prospect or customer!" unless $self->prospectnum || $self->custnum;
   return "Prospect and customer!"       if $self->prospectnum && $self->custnum;
 
   return "No prospect or customer!" unless $self->prospectnum || $self->custnum;
   return "Prospect and customer!"       if $self->prospectnum && $self->custnum;
 
+  my $conf = new FS::Conf;
+  return 'Location kind is required'
+    if $self->prospectnum
+    && $conf->exists('prospect_main-alt_address_format')
+    && ! $self->location_kind;
+
   unless ( qsearch('cust_main_county', {
     'country' => $self->country,
     'state'   => '',
   unless ( qsearch('cust_main_county', {
     'country' => $self->country,
     'state'   => '',
@@ -188,10 +261,153 @@ sub has_ship_address {
 =item location_hash
 
 Returns a list of key/value pairs, with the following keys: address1, address2,
 =item location_hash
 
 Returns a list of key/value pairs, with the following keys: address1, address2,
-city, county, state, zip, country, geocode.
+city, county, state, zip, country, geocode, location_type, location_number,
+location_kind.
+
+=cut
+
+=item move_to HASHREF
+
+Takes a hashref with one or more cust_location fields.  Creates a duplicate 
+of the existing location with all fields set to the values in the hashref.  
+Moves all packages that use the existing location to the new one, then sets 
+the "disabled" flag on the old location.  Returns nothing on success, an 
+error message on error.
 
 =cut
 
 
 =cut
 
+sub move_to {
+  my $old = shift;
+  my $hashref = shift;
+
+  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 $error = '';
+
+  my $new = FS::cust_location->new({
+      $old->location_hash,
+      'custnum'     => $old->custnum,
+      'prospectnum' => $old->prospectnum,
+      %$hashref
+    });
+  $error = $new->insert;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return "Error creating location: $error";
+  }
+
+  my @pkgs = qsearch('cust_pkg', { 
+      'locationnum' => $old->locationnum,
+      'cancel' => '' 
+    });
+  foreach my $cust_pkg (@pkgs) {
+    $error = $cust_pkg->change(
+      'locationnum' => $new->locationnum,
+      'keep_dates'  => 1
+    );
+    if ( $error and not ref($error) ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "Error moving pkgnum ".$cust_pkg->pkgnum.": $error";
+    }
+  }
+
+  $old->disabled('Y');
+  $error = $old->replace;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return "Error disabling old location: $error";
+  }
+
+  $dbh->commit if $oldAutoCommit;
+  return;
+}
+
+=item alternize
+
+Attempts to parse data for location_type and location_number from address1
+and address2.
+
+=cut
+
+sub alternize {
+  my $self = shift;
+
+  return '' if $self->get('location_type')
+            || $self->get('location_number');
+
+  my %parse;
+  if ( 1 ) { #ikano, switch on via config
+    { no warnings 'void';
+      eval { 'use FS::part_export::ikano;' };
+      die $@ if $@;
+    }
+    %parse = FS::part_export::ikano->location_types_parse;
+  } else {
+    %parse = (); #?
+  }
+
+  foreach my $from ('address1', 'address2') {
+    foreach my $parse ( keys %parse ) {
+      my $value = $self->get($from);
+      if ( $value =~ s/(^|\W+)$parse\W+(\w+)\W*$//i ) {
+        $self->set('location_type', $parse{$parse});
+        $self->set('location_number', $2);
+        $self->set($from, $value);
+        return '';
+      }
+    }
+  }
+
+  #nothing matched, no changes
+  $self->get('address2')
+    ? "Can't parse unit type and number from address2"
+    : '';
+}
+
+=item dealternize
+
+Moves data from location_type and location_number to the end of address1.
+
+=cut
+
+sub dealternize {
+  my $self = shift;
+
+  #false laziness w/geocode_Mixin.pm::line
+  my $lt = $self->get('location_type');
+  if ( $lt ) {
+
+    my %location_type;
+    if ( 1 ) { #ikano, switch on via config
+      { no warnings 'void';
+        eval { 'use FS::part_export::ikano;' };
+        die $@ if $@;
+      }
+      %location_type = FS::part_export::ikano->location_types;
+    } else {
+      %location_type = (); #?
+    }
+
+    $self->address1( $self->address1. ' '. $location_type{$lt} || $lt );
+    $self->location_type('');
+  }
+
+  if ( length($self->location_number) ) {
+    $self->address1( $self->address1. ' '. $self->location_number );
+    $self->location_number('');
+  }
+  '';
+}
+
 =back
 
 =head1 BUGS
 =back
 
 =head1 BUGS