tax engine refactoring for Avalara and Billsoft tax vendors, #25718
[freeside.git] / FS / FS / cust_location.pm
index eb4a723..e5d2e72 100644 (file)
@@ -2,7 +2,9 @@ package FS::cust_location;
 use base qw( FS::geocode_Mixin FS::Record );
 
 use strict;
-use vars qw( $import $DEBUG );
+use vars qw( $import $DEBUG $conf $label_prefix );
+use Data::Dumper;
+use Date::Format qw( time2str );
 use Locale::Country;
 use FS::UID qw( dbh driver_name );
 use FS::Record qw( qsearch qsearchs );
@@ -10,15 +12,18 @@ use FS::Conf;
 use FS::prospect_main;
 use FS::cust_main;
 use FS::cust_main_county;
+use FS::part_export;
 use FS::GeocodeCache;
-use Date::Format qw( time2str );
-
-use Data::Dumper;
 
 $import = 0;
 
 $DEBUG = 0;
 
+FS::UID->install_callback( sub {
+  $conf = FS::Conf->new;
+  $label_prefix = $conf->config('cust_location-label_prefix') || '';
+});
+
 =head1 NAME
 
 FS::cust_location - Object methods for cust_location records
@@ -89,6 +94,11 @@ Geocode
 
 Tax district code (optional)
 
+=item incorporated
+
+Incorporated city flag: set to 'Y' if the address is in the legal borders 
+of an incorporated city.
+
 =item disabled
 
 Disabled flag; set to 'Y' to disable the location.
@@ -196,25 +206,54 @@ otherwise returns false.
 
 sub insert {
   my $self = shift;
-  my $conf = new FS::Conf;
 
   if ( $self->censustract ) {
     $self->set('censusyear' => $conf->config('census_year') || 2012);
   }
 
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
   my $error = $self->SUPER::insert(@_);
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
 
   #false laziness with cust_main, will go away eventually
-  if ( !$import and !$error and $conf->config('tax_district_method') ) {
+  if ( !$import 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 );
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
 
   }
 
-  $error || '';
+  # 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";
+    }
+  }
+
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
 }
 
 =item delete
@@ -239,7 +278,35 @@ sub replace {
     }
   }
 
-  $self->SUPER::replace($old);
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $error = $self->SUPER::replace($old);
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  # 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";
+    }
+  }
+
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
 }
 
 
@@ -253,7 +320,6 @@ and replace methods.
 
 sub check {
   my $self = shift;
-  my $conf = new FS::Conf;
 
   return '' if $self->disabled; # so that disabling locations never fails
 
@@ -261,6 +327,7 @@ sub check {
     $self->ut_numbern('locationnum')
     || $self->ut_foreign_keyn('prospectnum', 'prospect_main', 'prospectnum')
     || $self->ut_foreign_keyn('custnum', 'cust_main', 'custnum')
+    || $self->ut_alphan('locationname')
     || $self->ut_text('address1')
     || $self->ut_textn('address2')
     || $self->ut_text('city')
@@ -278,6 +345,7 @@ sub check {
     || $self->ut_alphan('geocode')
     || $self->ut_alphan('district')
     || $self->ut_numbern('censusyear')
+    || $self->ut_flag('incorporated')
   ;
   return $error if $error;
   if ( $self->censustract ne '' ) {
@@ -343,7 +411,7 @@ Synonym for location_label
 
 sub line {
   my $self = shift;
-  $self->location_label;
+  $self->location_label(@_);
 }
 
 =item has_ship_address
@@ -377,8 +445,8 @@ sub disable_if_unused {
 
   my $self = shift;
   my $locationnum = $self->locationnum;
-  return '' if FS::cust_main->count('bill_locationnum = '.$locationnum)
-            or FS::cust_main->count('ship_locationnum = '.$locationnum)
+  return '' if FS::cust_main->count('bill_locationnum = '.$locationnum.' OR
+                                     ship_locationnum = '.$locationnum)
             or FS::contact->count(      'locationnum  = '.$locationnum)
             or FS::cust_pkg->count('cancel IS NULL AND 
                                          locationnum  = '.$locationnum)
@@ -543,26 +611,72 @@ sub dealternize {
 
 =item location_label
 
-Returns the label of the location object, with an optional site ID
-string (based on the cust_location-label_prefix config option).
+Returns the label of the location object.
+
+Options:
+
+=over 4
+
+=item cust_main
+
+Customer object (see L<FS::cust_main>)
+
+=item prospect_main
+
+Prospect object (see L<FS::prospect_main>)
+
+=item join_string
+
+String used to join location elements
+
+=back
 
 =cut
 
 sub location_label {
-  my $self = shift;
-  my %opt = @_;
-  my $conf = new FS::Conf;
-  my $prefix = '';
-  my $format = $conf->config('cust_location-label_prefix') || '';
-  my $cust_or_prospect;
-  if ( $self->custnum ) {
-    $cust_or_prospect = FS::cust_main->by_key($self->custnum);
-  }
-  elsif ( $self->prospectnum ) {
-    $cust_or_prospect = FS::prospect_main->by_key($self->prospectnum);
+  my( $self, %opt ) = @_;
+
+  my $prefix = $self->label_prefix;
+  $prefix .= ($opt{join_string} ||  ': ') if $prefix;
+
+  $prefix . $self->SUPER::location_label(%opt);
+}
+
+=item label_prefix
+
+Returns the optional site ID string (based on the cust_location-label_prefix
+config option), "Default service location", or the empty string.
+
+Options:
+
+=over 4
+
+=item cust_main
+
+Customer object (see L<FS::cust_main>)
+
+=item prospect_main
+
+Prospect object (see L<FS::prospect_main>)
+
+=back
+
+=cut
+
+sub label_prefix {
+  my( $self, %opt ) = @_;
+
+  my $cust_or_prospect = $opt{cust_main} || $opt{prospect_main};
+  unless ( $cust_or_prospect ) {
+    if ( $self->custnum ) {
+      $cust_or_prospect = FS::cust_main->by_key($self->custnum);
+    } elsif ( $self->prospectnum ) {
+      $cust_or_prospect = FS::prospect_main->by_key($self->prospectnum);
+    }
   }
 
-  if ( $format eq 'CoStAg' ) {
+  my $prefix = '';
+  if ( $label_prefix eq 'CoStAg' ) {
     my $agent = $conf->config('cust_main-custnum-display_prefix',
                   $cust_or_prospect->agentnum)
                 || $cust_or_prospect->agent->agent;
@@ -573,13 +687,16 @@ sub location_label {
         ($agent =~ /^(..)/),
         sprintf('%05d', $self->locationnum)
     ) );
-  }
-  elsif ( $self->custnum and 
-          $self->locationnum == $cust_or_prospect->ship_locationnum ) {
+
+  } elsif ( $label_prefix eq '_location' && $self->locationname ) {
+    $prefix = $self->locationname;
+
+  } elsif (    ( $opt{'cust_main'} || $self->custnum )
+          && $self->locationnum == $cust_or_prospect->ship_locationnum ) {
     $prefix = 'Default service location';
   }
-  $prefix .= ($opt{join_string} ||  ': ') if $prefix;
-  $prefix . $self->SUPER::location_label(%opt);
+
+  $prefix;
 }
 
 =item county_state_county
@@ -669,7 +786,6 @@ sub process_censustract_update {
     qsearchs( 'cust_location', { locationnum => $locationnum })
       or die "locationnum '$locationnum' not found!\n";
 
-  my $conf = FS::Conf->new;
   my $new_year = $conf->config('census_year') or return;
   my $loc = FS::GeocodeCache->new( $cust_location->location_hash );
   $loc->set_censustract;