improve echeck validation for canada, deprecate echeck-nonus and cust_main-require...
[freeside.git] / FS / FS / cust_main.pm
index f49eb69..3b572fa 100644 (file)
@@ -465,6 +465,8 @@ sub insert {
 
   $self->signupdate(time) unless $self->signupdate;
 
+  $self->censusyear($conf->config('census_year')) if $self->censustract;
+
   $self->auto_agent_custid()
     if $conf->config('cust_main-auto_agent_custid') && ! $self->agent_custid;
 
@@ -607,6 +609,20 @@ sub insert {
     }
   }
 
+  # FS::geocode_Mixin::after_insert or something?
+  if ( $conf->config('tax_district_method') and !$import ) {
+    # if anything non-empty, try to look it up
+    my $queue = new FS::queue {
+      'job'     => 'FS::geocode_Mixin::process_district_update',
+      'custnum' => $self->custnum,
+    };
+    my $error = $queue->insert( ref($self), $self->custnum );
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "queueing tax district update: $error";
+    }
+  }
+
   # cust_main exports!
   warn "  exporting\n" if $DEBUG > 1;
 
@@ -1497,12 +1513,14 @@ sub replace {
 
   }
 
-  $self->set_coord
-    if ! $self->coord_auto && ! $self->latitude && ! $self->longitude;
+  unless ( $import ) {
+    $self->set_coord
+      if ! $self->coord_auto && ! $self->latitude && ! $self->longitude;
 
-  $self->set_coord('ship_')
-    if $self->has_ship_address && ! $self->ship_coord_auto
-    && ! $self->ship_latitude && ! $self->ship_longitude;
+    $self->set_coord('ship_')
+      if $self->has_ship_address && ! $self->ship_coord_auto
+      && ! $self->ship_latitude && ! $self->ship_longitude;
+  }
 
   local($ignore_expired_card) = 1
     if $old->payby  =~ /^(CARD|DCRD)$/
@@ -1514,6 +1532,12 @@ sub replace {
          || $old->payby  =~ /^(CHEK|DCHK)$/ && $self->payby =~ /^(CHEK|DCHK)$/ )
     && ( $old->payinfo eq $self->payinfo || $old->paymask eq $self->paymask );
 
+  if ( $self->censustract ne '' and $self->censustract ne $old->censustract ) {
+    # update censusyear whenever tract code changes
+    $self->censusyear($conf->config('census_year'));
+  }
+
+
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
   local $SIG{QUIT} = 'IGNORE';
@@ -1623,6 +1647,25 @@ sub replace {
     }
   }
 
+  # FS::geocode_Mixin::after_replace ?
+  # though this will go away anyway once we move customer bill/service 
+  # locations into cust_location
+  # We can trigger this on any address change--just have to make sure 
+  # not to trigger it on itself.
+  if ( $conf->config('tax_district_method') and !$import 
+      and ( $self->get('ship_address1') ne $old->get('ship_address1')
+        or  $self->get('address1')      ne $old->get('address1') ) ) {
+    my $queue = new FS::queue {
+      'job'     => 'FS::geocode_Mixin::process_district_update',
+      'custnum' => $self->custnum,
+    };
+    my $error = $queue->insert( ref($self), $self->custnum );
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "queueing tax district update: $error";
+    }
+  }
+
   # cust_main exports!
 
   my $export_args = $options{'export_args'} || [];
@@ -1722,12 +1765,14 @@ sub check {
     || $self->ut_coordn('latitude')
     || $self->ut_coordn('longitude')
     || $self->ut_enum('coord_auto', [ '', 'Y' ])
+    || $self->ut_numbern('censusyear')
     || $self->ut_anything('comments')
     || $self->ut_numbern('referral_custnum')
     || $self->ut_textn('stateid')
     || $self->ut_textn('stateid_state')
     || $self->ut_textn('invoice_terms')
     || $self->ut_alphan('geocode')
+    || $self->ut_alphan('district')
     || $self->ut_floatn('cdr_termination_percentage')
     || $self->ut_floatn('credit_limit')
     || $self->ut_numbern('billday')
@@ -1987,14 +2032,15 @@ sub check {
 
     my $payinfo = $self->payinfo;
     $payinfo =~ s/[^\d\@\.]//g;
-    if ( $conf->exists('cust_main-require-bank-branch') ) {
-      $payinfo =~ /^(\d+)\@(\d+)\.(\d+)$/ or return 'invalid echeck account@branch.bank';
+    if ( $conf->config('echeck-country') eq 'CA' ) {
+      $payinfo =~ /^(\d+)\@(\d{5})\.(\d{3})$/
+        or return 'invalid echeck account@branch.bank';
       $payinfo = "$1\@$2.$3";
-    } elsif ( $conf->exists('echeck-nonus') ) {
-      $payinfo =~ /^(\d+)\@(\d+)$/ or return 'invalid echeck account@aba';
+    } elsif ( $conf->config('echeck-country') eq 'US' ) {
+      $payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account@aba';
       $payinfo = "$1\@$2";
     } else {
-      $payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account@aba';
+      $payinfo =~ /^(\d+)\@(\d+)$/ or return 'invalid echeck account@routing';
       $payinfo = "$1\@$2";
     }
     $self->payinfo($payinfo);
@@ -2132,8 +2178,9 @@ sub has_ship_address {
 
 =item location_hash
 
-Returns a list of key/value pairs, with the following keys: address1, adddress2,
-city, county, state, zip, country, and geocode.  The shipping address is used if present.
+Returns a list of key/value pairs, with the following keys: address1, 
+adddress2, city, county, state, zip, country, district, and geocode.  The 
+shipping address is used if present.
 
 =cut
 
@@ -4919,6 +4966,36 @@ sub process_bill_and_collect {
   $cust_main->bill_and_collect( %$param );
 }
 
+=item process_censustract_update CUSTNUM
+
+Queueable function to update the census tract to the current year (as set in 
+the 'census_year' configuration variable) and retrieve the new tract code.
+
+=cut
+
+sub process_censustract_update { 
+  eval "use FS::Misc::Geo qw(get_censustract)";
+  die $@ if $@;
+  my $custnum = shift;
+  my $cust_main = qsearchs( 'cust_main', { custnum => $custnum })
+      or die "custnum '$custnum' not found!\n";
+
+  my $new_year = $conf->config('census_year') or return;
+  my $new_tract = get_censustract({ $cust_main->location_hash }, $new_year);
+  if ( $new_tract =~ /^\d/ ) {
+    # then it's a tract code
+        $cust_main->set('censustract', $new_tract);
+    $cust_main->set('censusyear',  $new_year);
+    my $error = $cust_main->replace;
+    die $error if $error;
+  }
+  else {
+    # it's an error message
+    die $new_tract;
+  }
+  return;
+}
+
 sub _upgrade_data { #class method
   my ($class, %opts) = @_;
 
@@ -4945,6 +5022,7 @@ sub _upgrade_data { #class method
   local($ignore_illegal_zip) = 1;
   local($ignore_banned_card) = 1;
   local($skip_fuzzyfiles) = 1;
+  local($import) = 1; #prevent automatic geocoding (need its own variable?)
   $class->_upgrade_otaker(%opts);
 
 }