self-service access for contacts, RT#25533
[freeside.git] / FS / FS / tax_rate.pm
index a5a623d..27df9e7 100644 (file)
@@ -1,7 +1,8 @@
 package FS::tax_rate;
+use base qw( FS::Record );
 
 use strict;
-use vars qw( @ISA $DEBUG $me
+use vars qw( $DEBUG $me
              %tax_unittypes %tax_maxtypes %tax_basetypes %tax_authorities
              %tax_passtypes %GetInfoType $keep_cch_files );
 use Date::Parse;
@@ -11,6 +12,7 @@ use Storable qw( thaw nfreeze );
 use IO::File;
 use File::Temp;
 use Text::CSV_XS;
+use URI::Escape;
 use LWP::UserAgent;
 use HTTP::Request;
 use HTTP::Response;
@@ -29,10 +31,6 @@ use FS::part_pkg_taxproduct;
 use FS::cust_main;
 use FS::Misc qw( csv_from_fixed );
 
-use URI::Escape;
-
-@ISA = qw( FS::Record );
-
 $DEBUG = 0;
 $me = '[FS::tax_rate]';
 $keep_cch_files = 0;
@@ -413,7 +411,7 @@ sub taxline {
   }
 
   my $maxtype = $self->maxtype || 0;
-  if ($maxtype != 0 && $maxtype != 9) {
+  if ($maxtype != 0 && $maxtype != 1 && $maxtype != 9) {
     return $self->_fatal_or_null( 'tax with "'.
                                     $self->maxtype_name. '" threshold'
                                 );
@@ -476,12 +474,12 @@ sub taxline {
 
   }
 
-  #
-  # XXX insert exemption handling here
+  # XXX handle excessrate (use_excessrate) / excessfee /
+  #            taxbase/feebase / taxmax/feemax
+  #            and eventually exemptions
   #
   # the tax or fee is applied to taxbase or feebase and then
   # the excessrate or excess fee is applied to taxmax or feemax
-  #
 
   $amount += $taxable_charged * $self->tax;
   $amount += $taxable_units * $self->fee;
@@ -514,10 +512,10 @@ sub _fatal_or_null {
   }
 }
 
-=item tax_on_tax CUST_MAIN
+=item tax_on_tax CUST_LOCATION
 
 Returns a list of taxes which are candidates for taxing taxes for the
-given customer (see L<FS::cust_main>)
+given service location (see L<FS::cust_location>)
 
 =cut
 
@@ -525,13 +523,13 @@ given customer (see L<FS::cust_main>)
 sub tax_on_tax {
        #akshun
   my $self = shift;
-  my $cust_main = shift;
+  my $cust_location = shift;
 
   warn "looking up taxes on tax ". $self->taxnum. " for customer ".
-    $cust_main->custnum
+    $cust_location->custnum
     if $DEBUG;
 
-  my $geocode = $cust_main->geocode($self->data_vendor);
+  my $geocode = $cust_location->geocode($self->data_vendor);
 
   # CCH oddness in m2m
   my $dbh = dbh;
@@ -785,7 +783,8 @@ sub batch_import {
 
   }
 
-  for (grep { !exists($delete{$_}) } keys %insert) {
+  my @replace = grep { exists($delete{$_}) } keys %insert;
+  for (@replace) {
     if ( $job ) {  # progress bar
       if ( time - $min_sec > $last ) {
         my $error = $job->update_statustext(
@@ -799,20 +798,35 @@ sub batch_import {
       }
     }
 
-    my $tax_rate = new FS::tax_rate( $insert{$_} );
-    my $error = $tax_rate->insert;
+    my $old = qsearchs( 'tax_rate', $delete{$_} );
 
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      my $hashref = $insert{$_};
-      $line = join(", ", map { "$_ => ". $hashref->{$_} } keys(%$hashref) );
-      return "can't insert tax_rate for $line: $error";
+    if ( $old ) {
+
+      my $new = new FS::tax_rate({ $old->hash, %{$insert{$_}}, 'manual' => ''  });
+      $new->taxnum($old->taxnum);
+      my $error = $new->replace($old);
+
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        my $hashref = $insert{$_};
+        $line = join(", ", map { "$_ => ". $hashref->{$_} } keys(%$hashref) );
+        return "can't replace tax_rate for $line: $error";
+      }
+
+      $imported++;
+
+    } else {
+
+      $old = delete $delete{$_};
+      warn "WARNING: can't find tax_rate to replace (inserting instead and continuing) for: ".
+        #join(" ", map { "$_ => ". $old->{$_} } @fields);
+        join(" ", map { "$_ => ". $old->{$_} } keys(%$old) );
     }
 
     $imported++;
   }
 
-  for (grep { exists($delete{$_}) } keys %insert) {
+  for (grep { !exists($delete{$_}) } keys %insert) {
     if ( $job ) {  # progress bar
       if ( time - $min_sec > $last ) {
         my $error = $job->update_statustext(
@@ -826,27 +840,17 @@ sub batch_import {
       }
     }
 
-    my $old = qsearchs( 'tax_rate', $delete{$_} );
-    unless ($old) {
-      $dbh->rollback if $oldAutoCommit;
-      $old = $delete{$_};
-      return "can't find tax_rate to replace for: ".
-        #join(" ", map { "$_ => ". $old->{$_} } @fields);
-        join(" ", map { "$_ => ". $old->{$_} } keys(%$old) );
-    }
-    my $new = new FS::tax_rate({ $old->hash, %{$insert{$_}}, 'manual' => ''  });
-    $new->taxnum($old->taxnum);
-    my $error = $new->replace($old);
+    my $tax_rate = new FS::tax_rate( $insert{$_} );
+    my $error = $tax_rate->insert;
 
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
       my $hashref = $insert{$_};
       $line = join(", ", map { "$_ => ". $hashref->{$_} } keys(%$hashref) );
-      return "can't replace tax_rate for $line: $error";
+      return "can't insert tax_rate for $line: $error";
     }
 
     $imported++;
-    $imported++;
   }
 
   for (grep { !exists($insert{$_}) } keys %delete) {
@@ -961,7 +965,7 @@ sub _perform_batch_import {
       my $file = lc($name). 'file';
 
       unless ($files{$file}) {
-        $error = "No $name supplied";
+        #$error = "No $name supplied";
         next;
       }
       next if $name eq 'DETAIL' && $format =~ /update/;
@@ -978,7 +982,7 @@ sub _perform_batch_import {
         unlink $filename or warn "Can't delete $filename: $!"
           unless $keep_cch_files;
         push @insert_list, $name, $insertname, $import_sub, $format;
-        if ( $name eq 'GEOCODE' ) { #handle this whole ordering issue better
+        if ( $name eq 'GEOCODE' || $name eq 'CODE' ) { #handle this whole ordering issue better
           unshift @predelete_list, $name, $deletename, $import_sub, $format;
         } else {
           unshift @delete_list, $name, $deletename, $import_sub, $format;
@@ -996,10 +1000,17 @@ sub _perform_batch_import {
       'DETAIL', "$dir/".$files{detailfile}, \&FS::tax_rate::batch_import, $format
       if $format =~ /update/;
 
+    my %addl_param = ();
+    if ( $param->{'delete_only'} ) {
+      $addl_param{'delete_only'} = $param->{'delete_only'};
+      @insert_list = () 
+    }
+
     $error ||= _perform_cch_tax_import( $job,
                                         [ @predelete_list ],
                                         [ @insert_list ],
                                         [ @delete_list ],
+                                        \%addl_param,
     );
     
     
@@ -1024,7 +1035,8 @@ sub _perform_batch_import {
 
 
 sub _perform_cch_tax_import {
-  my ( $job, $predelete_list, $insert_list, $delete_list ) = @_;
+  my ( $job, $predelete_list, $insert_list, $delete_list, $addl_param ) = @_;
+  $addl_param ||= {};
 
   my $error = '';
   foreach my $list ($predelete_list, $insert_list, $delete_list) {
@@ -1033,7 +1045,11 @@ sub _perform_cch_tax_import {
       my $fmt = "$format-update";
       $fmt = $format. ( lc($name) eq 'zip' ? '-zip' : '' );
       open my $fh, "< $file" or $error ||= "Can't open $name file $file: $!";
-      $error ||= &{$method}({ 'filehandle' => $fh, 'format' => $fmt }, $job);
+      my $param = { 'filehandle' => $fh,
+                    'format'     => $fmt,
+                    %$addl_param,
+                  };
+      $error ||= &{$method}($param, $job);
       close $fh;
     }
   }
@@ -2102,8 +2118,7 @@ EOF
 
 =head1 SEE ALSO
 
-L<FS::Record>, L<FS::cust_main>, L<FS::cust_bill>, schema.html from the base
-documentation.
+L<FS::Record>, L<FS::cust_location>, L<FS::cust_bill>
 
 =cut