[freeside-commits] branch FREESIDE_4_BRANCH updated. 1a6932d522b102c5f1746e2d1d4a7e78bcb3c267

Mitch Jackson mitch at freeside.biz
Wed Jun 12 01:39:51 PDT 2019


The branch, FREESIDE_4_BRANCH has been updated
       via  1a6932d522b102c5f1746e2d1d4a7e78bcb3c267 (commit)
       via  885556b3b066581111b485b78ac33033f2b469db (commit)
       via  c1aab36c38e3a5a9882aa099c1d3e21cc77f99f0 (commit)
       via  11f3b56fba7821fac402321ec5ca907e59a9cf87 (commit)
       via  7050fb6c6703a6ce76aaa9b9be1827bbe32aad16 (commit)
      from  aaeae8f7ff06576507bb81af48e4868d84db819b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 1a6932d522b102c5f1746e2d1d4a7e78bcb3c267
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Wed Jun 12 03:24:26 2019 -0400

    RT# 80488 Current city value always exists in cities selectbox

diff --git a/httemplate/elements/city.html b/httemplate/elements/city.html
index 3c5e91782..f710d04db 100644
--- a/httemplate/elements/city.html
+++ b/httemplate/elements/city.html
@@ -131,6 +131,10 @@ function <% $pre %>county_changed(what, callback) {}
             <% $select_style %>
     >
 
+%   if ( $opt{city} ) {
+      <OPTION VALUE="<% $opt{city} %>" SELECTED><% $opt{city} %></OPTION>
+%   }
+
 %   unless ( $opt{'disable_empty'} ) {
       <OPTION VALUE="" <% $opt{city} eq '' ? 'SELECTED' : '' %>><% $opt{empty_label} %></OPTION>
 %   }

commit 885556b3b066581111b485b78ac33033f2b469db
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Wed Jun 12 03:22:57 2019 -0400

    RT# 80488 Ensure WA distrct taxes are properly applied

diff --git a/FS/FS/TaxEngine/internal.pm b/FS/FS/TaxEngine/internal.pm
index 6fb1ca756..d680af86e 100644
--- a/FS/FS/TaxEngine/internal.pm
+++ b/FS/FS/TaxEngine/internal.pm
@@ -39,10 +39,28 @@ sub add_sale {
   my @taxes = (); # entries are cust_main_county objects
   my %taxhash_elim = %taxhash;
   my @elim = qw( district city county state );
+
+  # WA state district city names are not stable in the WA tax tables
+  # Allow districts to match with just a district id
+  if ( $taxhash{district} ) {
+    @taxes = qsearch( cust_main_county => {
+      district => $taxhash{district},
+      taxclass => $taxhash{taxclass},
+    });
+    if ( !scalar(@taxes) && $taxhash{taxclass} ) {
+      qsearch( cust_main_county => {
+        district => $taxhash{district},
+        taxclass => '',
+      });
+    }
+  }
+
   do {
 
     #first try a match with taxclass
-    @taxes = qsearch( 'cust_main_county', \%taxhash_elim );
+    if ( !scalar(@taxes) ) {
+      @taxes = qsearch( 'cust_main_county', \%taxhash_elim );
+    }
 
     if ( !scalar(@taxes) && $taxhash_elim{'taxclass'} ) {
       #then try a match without taxclass
diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm
index 5f8dd9b4c..aadc8e1e9 100644
--- a/FS/FS/cust_main/Billing.pm
+++ b/FS/FS/cust_main/Billing.pm
@@ -1649,10 +1649,28 @@ sub _handle_taxes {
     my @taxes = (); # entries are cust_main_county objects
     my %taxhash_elim = %taxhash;
     my @elim = qw( district city county state );
+
+    # WA state district city names are not stable in the WA tax tables
+    # Allow districts to match with just a district id
+    if ( $taxhash{district} ) {
+      @taxes = qsearch( cust_main_county => {
+        district => $taxhash{district},
+        taxclass => $taxhash{taxclass},
+      });
+      if ( !scalar(@taxes) && $taxhash{taxclass} ) {
+        qsearch( cust_main_county => {
+          district => $taxhash{district},
+          taxclass => '',
+        });
+      }
+    }
+
     do { 
 
       #first try a match with taxclass
-      @taxes = qsearch( 'cust_main_county', \%taxhash_elim );
+      if ( !scalar(@taxes) ) {
+        @taxes = qsearch( 'cust_main_county', \%taxhash_elim );
+      }
 
       if ( !scalar(@taxes) && $taxhash_elim{'taxclass'} ) {
         #then try a match without taxclass

commit c1aab36c38e3a5a9882aa099c1d3e21cc77f99f0
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Wed Jun 12 03:21:10 2019 -0400

    RT# 80488 Improve WA tax table update utility

diff --git a/FS/FS/Cron/tax_rate_update.pm b/FS/FS/Cron/tax_rate_update.pm
index 5111ef4d0..fd291afbd 100755
--- a/FS/FS/Cron/tax_rate_update.pm
+++ b/FS/FS/Cron/tax_rate_update.pm
@@ -334,6 +334,8 @@ sub wa_sales_update_cust_main_county {
   my $update_count = 0;
   my $same_count   = 0;
 
+  $args->{taxname} ||= 'State Sales Tax';
+
   # Work within a SQL transaction
   local $FS::UID::AutoCommit = 0;
 
@@ -410,9 +412,12 @@ sub wa_sales_update_cust_main_county {
       ));
     }
 
-    for my $district ( @{ $args->{tax_districts} } ) {
+    DIST: for my $district ( @{ $args->{tax_districts} } ) {
       if ( my $row = $cust_main_county{ $district->{district} } ) {
 
+        # Strip whitespace from input
+        $district->{$_} =~ s/(^\s+|\s+$)//g for keys %$district;
+
         # District already exists in this taxclass, update if necessary
         #
         # If admin updates value of conf tax_district_taxname, instead of
@@ -424,20 +429,20 @@ sub wa_sales_update_cust_main_county {
           no warnings 'uninitialized';
 
           if (
-            $row->tax == ( $district->{tax_combined} * 100 )
+            sprintf('%.4f',$row->tax) == sprintf('%.4f',($district->{tax_combined} * 100))
             &&    $row->taxname eq    $args->{taxname}
             && uc $row->county  eq uc $district->{county}
             && uc $row->city    eq uc $district->{city}
           ) {
             $same_count++;
-            next;
+            next DIST;
           }
         }
 
         $row->city( uc $district->{city} );
         $row->county( uc $district->{county} );
         $row->taxclass( $taxclass );
-        $row->taxname( $args->{taxname} || undef );
+        $row->taxname( $args->{taxname} );
         $row->tax( $district->{tax_combined} * 100 );
 
         if ( my $error = $row->replace ) {
@@ -485,6 +490,8 @@ sub wa_sales_update_cust_main_county {
         $insert_count++;
       }
 
+      update_non_sales_tax_rows( $taxclass, $district );
+
     } # /foreach $district
   } # /foreach $taxclass
 
@@ -502,6 +509,47 @@ sub wa_sales_update_cust_main_county {
 
 }
 
+=head2 update_non_sales_tax_rows tax_class, $district_href
+
+The customer may have created additional taxes, such as Universal Service Fund.
+
+Ensure the columns for city and county are consistant between
+the user-created tax rows and the wa-sales-managed tax rows.
+
+=cut
+
+sub update_non_sales_tax_rows {
+  my ( $taxclass, $district ) = @_;
+
+  return unless ref $district && $district->{district};
+
+  my @rows = qsearch( cust_main_county => {
+    taxclass => $taxclass,
+    district => $district->{district},
+    state    => 'WA',
+    country  => 'US',
+    source   => { op => '!=', value => 'wa_sales' },
+  });
+
+  for my $row ( @rows ) {
+    $row->city( uc $district->{city} );
+    $row->county( uc $district->{county} );
+
+    if ( my $error = $row->replace ) {
+      dbh->rollback;
+      local $FS::UID::AutoCommit = 1;
+      log_error_and_die(
+        sprintf
+          "Error updating cust_main_county row %s for district %s: %s",
+          $row->taxnum,
+          $district->{district},
+          $error
+      );
+    }
+  }
+
+}
+
 =head2 wa_sales_parse_xlsx_file \%args
 
 Parse given XLSX file for tax district information
diff --git a/FS/bin/freeside-wa-tax-table-update b/FS/bin/freeside-wa-tax-table-update
index b197ac845..53c7324d7 100755
--- a/FS/bin/freeside-wa-tax-table-update
+++ b/FS/bin/freeside-wa-tax-table-update
@@ -60,6 +60,12 @@ https://dor.wa.gov/sites/default/files/legacy/Docs/forms/ExcsTx/LocSalUseTx/Exce
 
 https://dor.wa.gov/sites/default/files/legacy/downloads/Add_DataRates2018Q4.zip
 
+=item Other district tax rows
+
+When this tool updates the tax tables, any additional tax table rows with
+a district set, where the 'source' column is not 'wa_sales', will have the
+country, state, county, and city values kept updated to match the data
+provided in the state tax tables
 
 =item Address lookup API tool
 

commit 11f3b56fba7821fac402321ec5ca907e59a9cf87
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Wed Jun 12 03:15:31 2019 -0400

    RT# 80488 freeside-wa-tax-table-resolve --merge-all and --fix-usf

diff --git a/FS/bin/freeside-wa-tax-table-resolve b/FS/bin/freeside-wa-tax-table-resolve
index 928408a50..790dce20b 100755
--- a/FS/bin/freeside-wa-tax-table-resolve
+++ b/FS/bin/freeside-wa-tax-table-resolve
@@ -20,13 +20,17 @@ my(
   $dbh,
   $freeside_user,
   $opt_check,
+  $opt_fix_usf,
   @opt_merge,
+  $opt_merge_all,
   @opt_set_source_null,
 );
 
 GetOptions(
   'check'             => \$opt_check,
+  'fix-usf'           => \$opt_fix_usf,
   'merge=s'           => \@opt_merge,
+  'merge-all'         => \$opt_merge_all,
   'set-source-null=s' => \@opt_set_source_null,
 );
 @opt_merge = split(',',join(',', at opt_merge));
@@ -52,6 +56,10 @@ if ( $opt_check ) {
   merge();
 } elsif ( @opt_set_source_null ) {
   set_source_null();
+} elsif ( $opt_merge_all ) {
+  merge_all();
+} elsif ( $opt_fix_usf ) {
+  fix_usf();
 } else {
   error_and_help('No options selected');
 }
@@ -139,6 +147,12 @@ sub merge {
 
   ");
 
+  merge_into( $source, $target );
+}
+
+sub merge_into {
+  my ( $source, $target ) = @_;
+
   local $@;
   eval { $source->_merge_into( $target, { identical_record_check => 0 } ) };
   if ( $@ ) {
@@ -151,14 +165,117 @@ sub merge {
     $log->error( $message );
 
   } else {
-    my $message = sprintf 'Merged wa sales tax %s into %s - success',
-        $source->taxnum, $target->taxnum;
+    my $message = sprintf 'Merged wa sales tax %s into %s for district %s',
+        $source->taxnum, $target->taxnum, $source->district;
 
     say $message;
     $log->warn( $message );
   }
 }
 
+sub merge_all {
+  my @dupes = FS::cust_main_county->find_wa_tax_dupes;
+
+  unless ( @dupes ) {
+    say 'No duplicate tax rows detected for WA sales tax districts';
+    return;
+  }
+
+  confirm_to_continue(sprintf "
+
+    %s blocking duplicate rows detected
+
+    Duplicate rows will be merged using FS::cust_main_county::_merge_into()
+
+    Rows are considered duplicates when they:
+    - Share the same tax class
+    - Share the same district
+    - Contain 'wa_sales' in the source column
+
+  ", scalar @dupes);
+
+  # Sort dupes into buckets to be merged, by taxclass and district
+  # $to_merge{taxclass}->{district} = [ @rows_to_merge ]
+  my %to_merge;
+  for my $row ( @dupes ) {
+    my $taxclass = $row->taxclass || 'none';
+    $to_merge{$taxclass} ||= {};
+    $to_merge{$taxclass}->{$row->district} ||= [];
+    push @{ $to_merge{$taxclass}->{$row->district} }, $row;
+  }
+
+  # Merge the duplicates
+  for my $taxclass ( keys %to_merge ) {
+    for my $district ( keys %{ $to_merge{$taxclass} }) {
+
+      # Keep the first row in the list as the target.
+      # Merge the remaining rows into the target
+      my $rows = $to_merge{$taxclass}->{$district};
+      my $target = shift @$rows;
+
+      while ( @$rows ) {
+        merge_into( shift(@$rows), $target );
+      }
+    }
+  }
+
+  say "
+
+    Merge operations completed
+
+    Please run freeside-wa-tax-table-update.  This will update
+    the merged district rows with correct county and city names
+
+  ";
+
+}
+
+sub fix_usf {
+  confirm_to_continue("
+
+    Search for duplicate districts within the tax tables with
+    - duplicate district column values
+    - source = NULL
+    - district = NOT NULL
+    - taxclass = USF
+    - tax > 17
+
+    Merge these rows into a single USF row for each tax district
+
+  ");
+
+  my @rows = qsearch( cust_main_county => {
+    taxclass => 'USF',
+    source   => undef,
+    state    => 'WA',
+    country  => 'US',
+    tax      => { op => '>',  value => 17 },
+    district => { op => '!=', value => undef },
+  });
+
+  my %to_merge;
+  for my $row (@rows) {
+    $to_merge{$row->district} ||= [];
+    push @{ $to_merge{$row->district} }, $row;
+  }
+
+  for my $dist_rows ( values %to_merge ) {
+    my $target = shift @$dist_rows;
+    while ( @$dist_rows ) {
+      merge_into( shift(@$dist_rows), $target );
+    }
+  }
+
+  say "
+
+    USF clean up completed
+
+    Please run freeside-wa-tax-table-update.  This will update
+    the merged district rows with correct county and city names
+
+  ";
+}
+
 sub validate_opts {
 
   $freeside_user = shift @ARGV
@@ -188,7 +305,7 @@ sub check {
 
   say sprintf '=== Detected %s duplicate tax rows ===', scalar @dupes;
 
-  print_taxnum($_) for @dupes;
+  print_taxnum($_) for sort { $a->district <=> $b->district } @dupes;
 
   $log->error(
     sprintf 'Detected %s duplicate wa sales tax rows: %s',
@@ -196,6 +313,14 @@ sub check {
       join( ',', map{ $_->taxnum } @dupes )
   );
 
+  say "
+
+    Rows are considered duplicates when they:
+    - Share the same tax class
+    - Share the same district
+    - Contain 'wa_sales' in the source column
+
+  ";
 }
 
 sub print_taxnum {
@@ -238,10 +363,12 @@ freeside-wa-tax-table-resolve
 
 =head1 SYNOPSIS
 
-freeside-wa-tax-table-resolve --help
-freeside-wa-tax-table-resolve --check [freeside_user]
-freeside-wa-tax-table-resolve --merge 123,234 [freeside_user]
-freeside-wa-tax-table-resolve --set-source-null 1337,6553 [freeside_user]
+  freeside-wa-tax-table-resolve --help
+  freeside-wa-tax-table-resolve --check [freeside_user]
+  freeside-wa-tax-table-resolve --merge 123,234 [freeside_user]
+  freeside-wa-tax-table-resolve --set-source-null 1337,6553 [freeside_user]
+  freeside-wa-tax-table-resolve --merge-all [freeside_user]
+  freeside-wa-tax-table-resolve --fix-usf [freeside_user]
 
 =head1 OPTIONS
 
@@ -270,6 +397,27 @@ I<source> column to NULL.
 Used for manually entered tax entries, incorrectly labelled
 as created and managed for Washington State Sales Taxes
 
+=item B<--merge-all>
+
+Automatically merge all blocking duplicate taxnums.
+
+If after reviewing all blocking duplicate taxnum rows with --check,
+if all duplicate rows are safe to merge, this option will merge them all.
+
+=item B<--fix-usf>
+
+Fix routine for a particular USF issue
+
+Search for duplicate districts within the tax tables with
+
+  - duplicate district column values
+  - source = NULL
+  - district = NOT NULL
+  - taxclass = USF
+  - tax > 17
+
+Merge these rows into a single USF row for each tax district
+
 =back
 
 =head1 DESCRIPTION

commit 7050fb6c6703a6ce76aaa9b9be1827bbe32aad16
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Mon May 27 19:13:59 2019 -0400

    RT# 83402 Fix typo

diff --git a/FS/bin/freeside-wa-tax-table-resolve b/FS/bin/freeside-wa-tax-table-resolve
index fa6db3e39..928408a50 100755
--- a/FS/bin/freeside-wa-tax-table-resolve
+++ b/FS/bin/freeside-wa-tax-table-resolve
@@ -238,10 +238,10 @@ freeside-wa-tax-table-resolve
 
 =head1 SYNOPSIS
 
-freeside-issue-credit-for-taxnums --help
-freeside-issue-credit-for-taxnums --check [freeside_user]
-freeside-issue-credit-for-taxnums --merge 123,234 [freeside_user]
-freeside-issue-credit-for-taxnums --set-source-null 1337,6553 [freeside_user]
+freeside-wa-tax-table-resolve --help
+freeside-wa-tax-table-resolve --check [freeside_user]
+freeside-wa-tax-table-resolve --merge 123,234 [freeside_user]
+freeside-wa-tax-table-resolve --set-source-null 1337,6553 [freeside_user]
 
 =head1 OPTIONS
 

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Cron/tax_rate_update.pm        |  56 +++++++++++-
 FS/FS/TaxEngine/internal.pm          |  20 ++++-
 FS/FS/cust_main/Billing.pm           |  20 ++++-
 FS/bin/freeside-wa-tax-table-resolve | 162 +++++++++++++++++++++++++++++++++--
 FS/bin/freeside-wa-tax-table-update  |   6 ++
 httemplate/elements/city.html        |   4 +
 6 files changed, 255 insertions(+), 13 deletions(-)




More information about the freeside-commits mailing list