[freeside-commits] branch FREESIDE_4_BRANCH updated. bb863b9ae9612ae40a922a2f0d0cd82f949cad09

Mitch Jackson mitch at freeside.biz
Sun Jan 20 13:56:06 PST 2019


The branch, FREESIDE_4_BRANCH has been updated
       via  bb863b9ae9612ae40a922a2f0d0cd82f949cad09 (commit)
       via  033d235172023f4ac44088808cc735f86e092477 (commit)
       via  e5c397093b5ee87f4178f4479235101bb4431591 (commit)
       via  9f179ee5fc7fc07a3f5e03ad1ad58cd3cadf1a56 (commit)
      from  338485d75b27ea0e5ab561856720633f890374c4 (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 bb863b9ae9612ae40a922a2f0d0cd82f949cad09
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Sun Jan 20 16:25:50 2019 -0500

    RT# 80488 Banner on customer page when missing tax districts

diff --git a/httemplate/elements/header-cust_main.html b/httemplate/elements/header-cust_main.html
index b743f5acf..6906cb3f6 100644
--- a/httemplate/elements/header-cust_main.html
+++ b/httemplate/elements/header-cust_main.html
@@ -35,6 +35,57 @@ Examples:
 %   }
 </TABLE>
 % }
+% if ( scalar @cust_locations_missing_district ) {
+  <div style="margin: 0 1em; padding: 1em; border: solid 1px #999; background-color: #fee;">
+    <h4 style="margin: 0; border-bottom: solid 1px #aaa; color: red;">Customer will not be billed:</h4>
+    <p style="margin: .5em;">
+    The following customer locations are missing tax districts for Washington State.<br>
+    Sales taxes cannot be calculated for this customer.<br>
+    Correct the address information, or enter a tax district number.
+    <ul>
+%   for my $cust_location ( @cust_locations_missing_district ) {
+      <li>
+        (<a href="#" onclick="overlib_edit_location(<% $cust_location->locationnum %>);">
+          EDIT
+        </a>)
+        <% $cust_location->address1 %>
+        <% $cust_location->city %>
+        <% $cust_location->state %>
+        <% $cust_location->zip %>
+        (<% $cust_location->locationnum %>)
+      </li>
+%   } # /for my $cust_location
+    </ul>
+  </div>
+  <script>
+    function overlib_edit_location(locationnum) {
+      overlib(
+        OLiframeContent(
+          '<% $fsurl %>edit/cust_location.cgi?locationnum=' + locationnum,
+          700, 355,
+          'popup-1548013977-3901-3256727185.50958',
+          0,
+          'auto'
+        ),
+        CAPTION, 'Edit location',
+        STICKY,
+        AUTOSTATUSCAP,
+        MIDX, 0,
+        MIDY, 0,
+        DRAGGABLE,
+        CLOSECLICK,
+        TEXTPADDING, 0,
+        BASE, 0,
+        BGCOLOR, '#333399',
+        CGCOLOR, '#333399',
+        FGCOLOR, '#f8f8f8',
+        CLOSETEXT, 'Close'
+      );
+      return false;
+    }
+  </script>
+  <br>
+% } # /if @cust_locations_missing_district
 <& /view/cust_main/menu.html, cust_main => $cust_main, show => $opt{'view'} &>
 <BR>
 
@@ -93,4 +144,10 @@ if ( $ie_compat ) {
   $head = qq(<meta http-equiv="X-UA-Compatible" content="IE=$ie_compat" />);
 }
 
+my @cust_locations_missing_district;
+my $tax_district_method = $conf->config('tax_district_method');
+if ( $tax_district_method && $tax_district_method eq 'wa_sales' ) {
+  @cust_locations_missing_district = $cust_main->cust_locations_missing_district();
+}
+
 </%init>

commit 033d235172023f4ac44088808cc735f86e092477
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Sun Jan 20 16:22:50 2019 -0500

    RT# 80488 Block billing for customer missing tax district

diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index d42bd813b..165b9fc6b 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -5781,6 +5781,51 @@ sub pending_invoice_count {
   FS::cust_bill->count( 'custnum = '.shift->custnum."AND pending = 'Y'" );
 }
 
+=item cust_locations_missing_district
+
+Always returns empty list, unless tax_district_method eq 'wa_sales'
+
+Return cust_location rows for this customer, associated with active
+customer packages, where tax district column is empty.  Presense of
+these rows should block billing, because invoice would be generated
+with incorrect taxes
+
+=cut
+
+sub cust_locations_missing_district {
+  my ( $self ) = @_;
+
+  my $tax_district_method = FS::Conf->new->config('tax_district_method');
+
+  return ()
+    unless $tax_district_method
+        && $tax_district_method eq 'wa_sales';
+
+  qsearch({
+    table => 'cust_location',
+    select => 'cust_location.*',
+    addl_from => '
+      LEFT JOIN cust_main USING (custnum)
+      LEFT JOIN cust_pkg ON cust_location.locationnum = cust_pkg.locationnum
+    ',
+    extra_sql => sprintf(q{
+        WHERE cust_location.state = 'WA'
+        AND   cust_location.custnum = %s
+        AND (
+             cust_location.district IS NULL
+          or cust_location.district = ''
+        )
+        AND cust_pkg.pkgnum IS NOT NULL
+        AND (
+             cust_pkg.cancel > %s
+          OR cust_pkg.cancel IS NULL
+        )
+      },
+      $self->custnum, time()
+    ),
+  });
+}
+
 #starting to take quite a while for big dbs
 #   (JRNL: journaled so it only happens once per database)
 # - seq scan of h_cust_main (yuck), but not going to index paycvv, so
diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm
index 1be7d39f9..5f8dd9b4c 100644
--- a/FS/FS/cust_main/Billing.pm
+++ b/FS/FS/cust_main/Billing.pm
@@ -152,6 +152,41 @@ sub bill_and_collect {
     else                                                     { die    $error; }
   }
 
+  my $tax_district_method = $conf->config('tax_district_method');
+  if ( $tax_district_method && $tax_district_method eq 'wa_sales' ) {
+    # When using Washington State Sales Tax Districts,
+    # Bail out of billing customer if sales tax district for location is missing
+
+    $log->debug('checking cust_location tax districts', %logopt);
+
+    if (
+      my @cust_locations_missing_district =
+        $self->cust_locations_missing_district
+    ) {
+      $error = sprintf
+        'cust_location missing tax district: '.
+        join( ', ' => (
+          map(
+            {
+              sprintf
+                'locationnum(%s) %s %s %s %s',
+                 $_->locationnum,
+                 $_->address1,
+                 $_->city,
+                 $_->state,
+                 $_->zip
+            }
+            @cust_locations_missing_district
+          )
+        ));
+    }
+  }
+  if ( $error ) {
+    $error = "Error calculating taxes ".$self->custnum. ": $error";
+    if    ( $options{fatal} && $options{fatal} eq 'return' ) { return $error; }
+    else                                                     { die    $error; }
+  }
+
   $job->update_statustext('20,billing packages') if $job;
   $log->debug('billing packages', %logopt);
   $error = $self->bill( %options );

commit e5c397093b5ee87f4178f4479235101bb4431591
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Sun Jan 20 16:14:12 2019 -0500

    RT# 80488 Validation on cust_location.district values

diff --git a/FS/FS/cust_location.pm b/FS/FS/cust_location.pm
index 4521bd39b..a2bda7162 100644
--- a/FS/FS/cust_location.pm
+++ b/FS/FS/cust_location.pm
@@ -443,6 +443,26 @@ sub check {
     && $conf->exists('prospect_main-alt_address_format')
     && ! $self->location_kind;
 
+  # Do not allow bad tax district values in cust_location when
+  # using Washington State district sales tax calculation - would result
+  # in incorrect or missing sales tax on invoices.
+  my $tax_district_method = FS::Conf->new->config('tax_district_method');
+  if (
+    $tax_district_method
+    && $tax_district_method eq 'wa_sales'
+    && $self->district
+  ) {
+    my $cust_main_county = qsearchs(
+      cust_main_county => { district => $self->district }
+    );
+    unless ( ref $cust_main_county ) {
+      return sprintf (
+        'WA State tax district %s does not exist in tax table',
+        $self->district
+      );
+    }
+  }
+
   unless ( $import or qsearch('cust_main_county', {
     'country' => $self->country,
     'state'   => '',

commit 9f179ee5fc7fc07a3f5e03ad1ad58cd3cadf1a56
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Sat Jan 19 07:41:08 2019 -0500

    RT# 80488 Live look up of WA state tax district
    
    When conf flag 'tax_district_method' is set, tax district
    is queried for address before form is submitted
    
    Affected Pages:
    * New Customer
    * Edit Customer
    * Order Package
    * Change Package
    * Edit Package Location

diff --git a/FS/FS/cust_location.pm b/FS/FS/cust_location.pm
index e1b853383..4521bd39b 100644
--- a/FS/FS/cust_location.pm
+++ b/FS/FS/cust_location.pm
@@ -265,8 +265,15 @@ sub insert {
     return $error;
   }
 
-  #false laziness with cust_main, will go away eventually
-  if ( !$import and $conf->config('tax_district_method') ) {
+  # If using tax_district_method, for rows in state of Washington,
+  # without a tax district already specified, queue a job to find
+  # the tax district
+  if (
+       !$import
+    && !$self->district
+    && lc $self->state eq 'wa'
+    && $conf->config('tax_district_method')
+  ) {
 
     my $queue = new FS::queue {
       'job' => 'FS::geocode_Mixin::process_district_update'
@@ -943,7 +950,11 @@ sub _upgrade_data {
       die "$error (fixing whitespace in $field, locationnum ".$location->locationnum.')'
         if $error;
 
-      if ( $use_districts ) {
+      if (
+        $use_districts
+        && !$location->district
+        && lc $location->state eq 'wa'
+      ) {
         my $queue = new FS::queue {
           'job' => 'FS::geocode_Mixin::process_district_update'
         };
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index afc21a97f..d42bd813b 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -743,20 +743,6 @@ 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;
 
diff --git a/httemplate/edit/cust_location.cgi b/httemplate/edit/cust_location.cgi
index 38816db7a..93311c5c3 100755
--- a/httemplate/edit/cust_location.cgi
+++ b/httemplate/edit/cust_location.cgi
@@ -17,10 +17,21 @@ ACTION="<% $p %>edit/process/cust_location.cgi" METHOD=POST>
 &>
 <& /elements/standardize_locations.html,
             'form'          => 'EditLocationForm',
-            'callback'      => 'document.EditLocationForm.submit();',
+            'callback'    => $conf->exists('tax_district_method')
+                              ? 'wa_state_tax_district()'
+                              : 'submit_continue()',
             'with_census'   => 1,
             'with_census_functions' => 1,
 &>
+<script>
+  <& /elements/wa_state_tax_district.js &>
+
+  // wa_sate_tax_district() will call submit_continue() upon success,
+  //   or submit_abort() upon error
+  function submit_continue() {
+    document.EditLocationForm.submit();
+  }
+</script>
 </TABLE>
 
 <BR>
diff --git a/httemplate/edit/cust_main/bottomfixup.js b/httemplate/edit/cust_main/bottomfixup.js
index 97816aad7..d2a277b2f 100644
--- a/httemplate/edit/cust_main/bottomfixup.js
+++ b/httemplate/edit/cust_main/bottomfixup.js
@@ -7,6 +7,9 @@ my $company_longitude = $conf->config('company_longitude');
 
 my @fixups = ('standardize_locations');
 
+push @fixups, 'wa_state_tax_district'
+  if $conf->exists('tax_district_method');
+
 push @fixups, 'confirm_censustract_bill', 'confirm_censustract_ship'
     if $conf->exists('cust_main-require_censustract');
 
@@ -57,6 +60,8 @@ function do_submit() {
   'with_census' => 1, # no with_firm, apparently
 &>
 
+<& /elements/wa_state_tax_district.js &>
+
 % # the value in pre+'censustract' is the confirmed censustract (either from
 % # the previous saved record, or from address standardization (if the backend
 % # supports it), or from an aborted previous submit. only need to reconfirm
diff --git a/httemplate/elements/tr-select-cust_location.html b/httemplate/elements/tr-select-cust_location.html
index 7a2d886d3..1e6cf5b7f 100644
--- a/httemplate/elements/tr-select-cust_location.html
+++ b/httemplate/elements/tr-select-cust_location.html
@@ -202,6 +202,7 @@ Example:
      'alt_format'         => $opt{'alt_format'},
      'enable_coords'      => 1,
      'enable_censustract' => 1,
+     'enable_district'    => $conf->exists('tax_district_method') ? 1 : 0,
 &>
 
 <SCRIPT TYPE="text/javascript">
diff --git a/httemplate/elements/wa_state_tax_district.js b/httemplate/elements/wa_state_tax_district.js
new file mode 100644
index 000000000..03f262b52
--- /dev/null
+++ b/httemplate/elements/wa_state_tax_district.js
@@ -0,0 +1,159 @@
+<%doc>
+
+Provide js function in support of a lookup hook for wa_state_tax_districts
+
+wa_state_tax_district()
+* Checks form_address_info() to collect address data
+* If any addresses are in Washington State,
+* Uses misc/xmlhttp-wa_state-find_district_for_address.html to query
+  wa state tax districting database
+* Displays error, or updates the district input element for the addresses
+* Calls submit_continue() upon success
+* Calls submit_abort() upon error
+
+</%doc>
+
+function wa_state_tax_district() {
+  // Queries the WA State API to get a Tax District for this address
+  // upon failure: User can choose to skip or cancel
+  // upon success: set value of district input box and submit_continue()
+
+  address_info = form_address_info();
+  // console.log( address_info );
+
+  if (
+       address_info['state'] != 'WA'
+    && address_info['state'] != 'wa'
+    && address_info['bill_state'] != 'WA'
+    && address_info['bill_state'] != 'wa'
+    && (
+      address_info['same']
+      || (
+        address_info['ship_state'] != 'WA'
+        && address_info['ship_state'] != 'wa'
+      )
+    )
+  ) {
+    // nothing to do, not in Washington state
+    submit_continue();
+    return;
+  }
+
+  wa_state_tax_district_overlib( 'Looking up tax district... please wait...' );
+
+  $.post({
+    url: "<% $fsurl %>misc/xmlhttp-wa_state-find_district_for_address.html",
+    data: address_info,
+    success: function(response) {
+      // console.log(response);
+
+      let error = '';
+      if ( response['error'] ) {
+        error = error + response['error'] + ' ';
+      }
+
+      // populate Billing Address district into form, or record error
+      if ( response['bill'] && response['bill']['district'] ) {
+        $('#bill_district').val( response['bill']['district'] );
+      }
+      else if ( response['bill'] && response['bill']['error'] ) {
+        error = error + 'Cound not set tax district for billing address. ';
+      }
+
+      // populate Shipping Address district into form, or record error
+      if (
+        ! address_info['same']
+        && response['ship']
+        && response['ship']['district']
+      ) {
+        $('#ship_district').val( response['ship']['district'] );
+      }
+      else if (
+        ! address_info['same']
+        && response['ship']
+        && response['ship']['error']
+      ) {
+        error = error + 'Could not set tax district for service address. ';
+      }
+
+      // populate Plain Address district into form, or record error
+      if (
+        response['address']
+        && response['address']['district']
+      ) {
+        $('#district').val( response['address']['district'] );
+      }
+      else if (
+        response['address']
+        && response['address']['error']
+      ) {
+        error = error + 'Could not set tax district for address. ';
+      }
+
+      if ( error ) {
+        wa_state_tax_district_overlib(
+          'An error occured determining Washington state tax district:<br>'
+          + '<br>'
+          + error + '<br>'
+          + '<br>'
+          + 'If you choose to skip this step, taxes will not be calculated '
+          + 'for this customer, unless you enter a tax district manually.'
+          + '<br>'
+          + '<a href="https://webgis.dor.wa.gov/taxratelookup/SalesTax.aspx" target="_blank">See WA Dept of Revenue</a>'
+        );
+      }
+      else {
+        cClick();
+        submit_continue();
+        return;
+      }
+
+    }
+  })
+  .fail(function() {
+    wa_state_tax_district_overlib(
+      'A network error occured determining Washington state tax district:<br>'
+      + '<br>'
+      + 'If you choose to skip this step, taxes will not be calculated '
+      + 'for this customer, unless you enter a tax district manually.'
+      + '<br>'
+      + '<a href="https://webgis.dor.wa.gov/taxratelookup/SalesTax.aspx" target="_blank">See WA Dept of Revenue</a>'
+    );
+  });
+}
+
+function wa_state_tax_district_overlib(html) {
+  html =
+      '<div style="text-align: center;">'
+    +   '<h2>Washington State Tax District Lookup</h2>'
+    +   '<p>' + html + '</p>'
+    + '<a href="#" onclick="wa_state_tax_district_skip()">skip</a>'
+    + ' | '
+    + '<a href="#" onclick="wa_state_tax_district_cancel()">cancel</a>'
+    + '</div>';
+
+  overlib(
+    html,
+    CAPTION, 'WA State Tax District',
+    STICKY,
+    CLOSETEXT, '',
+    MIDX, 0,
+    MIDY, 0,
+    WIDTH, 500,
+    BGCOLOR, '#339',
+    CGCOLOR, '#339',
+    TEXTSIZE, 3
+  );
+}
+
+function wa_state_tax_district_skip() {
+  // Click target to skip tax district determination
+  cClick()
+  submit_continue();
+}
+
+function wa_state_tax_district_cancel() {
+  // Click target to cancel submit from tax district determination
+  cClick()
+  submit_abort();
+}
diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi
index c588c9e6c..9729c6b5f 100755
--- a/httemplate/misc/change_pkg.cgi
+++ b/httemplate/misc/change_pkg.cgi
@@ -119,9 +119,21 @@
             'form'        => "OrderPkgForm",
             'with_census' => 1,
             'with_census_functions' => 1,
-            'callback'   => 'document.OrderPkgForm.submit()',
+            'callback'    => $conf->exists('tax_district_method')
+                              ? 'wa_state_tax_district()'
+                              : 'submit_continue()',
 &>
 
+<script>
+  <& /elements/wa_state_tax_district.js &>
+
+  // wa_sate_tax_district() will call submit_continue() upon success,
+  //   or submit_abort() upon error
+  function submit_continue() {
+    document.OrderPkgForm.submit();
+  }
+</script>
+
 <INPUT NAME    = "submitButton"
        TYPE    = "button"
        VALUE   = "<% mt("Change package") |h %>"
diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html
index 1efe7456e..7a63b5c2b 100644
--- a/httemplate/misc/order_pkg.html
+++ b/httemplate/misc/order_pkg.html
@@ -188,11 +188,23 @@
 
   <& /elements/standardize_locations.html,
                 'form'        => "OrderPkgForm",
-                'callback'    => 'document.OrderPkgForm.submit()',
+                'callback'    => $conf->exists('tax_district_method')
+                                 ? 'wa_state_tax_district()'
+                                 : 'submit_continue()',
                 'with_census' => 1,
                 'with_census_functions' => 1,
   &>
 
+  <script>
+    <& /elements/wa_state_tax_district.js &>
+
+    // wa_sate_tax_district() will call submit_continue() upon success,
+    //   or submit_abort() upon error
+    function submit_continue() {
+      document.OrderPkgForm.submit();
+    }
+  </script>
+
 % }
 
 % if ($quotationnum) {
diff --git a/httemplate/misc/xmlhttp-wa_state-find_district_for_address.html b/httemplate/misc/xmlhttp-wa_state-find_district_for_address.html
new file mode 100644
index 000000000..e59789bd1
--- /dev/null
+++ b/httemplate/misc/xmlhttp-wa_state-find_district_for_address.html
@@ -0,0 +1,76 @@
+<%doc>
+
+Expects POST keys:
+* address1
+* address2
+* city
+* state
+* zip
+* country
+
+Also accepts all the above keys with the prefixes bill_ and ship_
+
+Returns json with a key for each given address, e.g., whose value is
+the tax district number. e.g.
+{
+  address: {
+    district: 1234
+    tax: 7.9
+    exempt_amount: 0
+    city: MOXEE CITY
+    state: WA
+  },
+  bill: {
+    error: district not found
+    district:
+  },
+}
+
+</%doc>
+<% encode_json($return) %>
+<%init>
+use Data::Dumper;
+use FS::Misc::Geo;
+
+http_header('Content-Type' => 'application/json');
+
+my $DEBUG = 0;
+my %param = ( $cgi->Vars );
+my $return = {};
+
+warn '$param: '.Dumper( \%param )."\n"
+  if $DEBUG;
+
+my %address;
+for my $prefix ( '', 'bill', 'ship' ) {
+  my $addr_key = $prefix || 'address';
+  $address{$addr_key} = {};
+  $address{$addr_key}->{$_} = $param{ $prefix ? "${prefix}_${_}" : $_ }
+    for qw/ address1 address2 city state zip country /;
+  delete $address{$addr_key}
+    unless $address{$addr_key}->{address1}
+        && $address{$addr_key}->{city};
+}
+warn Dumper( \%address )
+  if $DEBUG;
+
+for my $k ( keys %address ) {
+  next unless lc $address{$k}->{state} eq 'wa';
+  my $response = FS::Misc::Geo::wa_sales( $address{$k} );
+  warn Dumper( $response )
+    if $DEBUG;
+
+  if ( ref $response ) {
+    $return->{$k} = $response;
+  } else {
+    $return->{$k} = { error => 'Lookup Failed' };
+  }
+}
+
+unless ( keys %$return ) {
+  $return->{error} = 'No WA addresses passed for lookup - nothing to do';
+}
+
+warn '$return: '.Dumper( $return )."\n"
+  if $DEBUG;
+</%init>

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

Summary of changes:
 FS/FS/cust_location.pm                             |  37 ++++-
 FS/FS/cust_main.pm                                 |  59 ++++++--
 FS/FS/cust_main/Billing.pm                         |  35 +++++
 httemplate/edit/cust_location.cgi                  |  13 +-
 httemplate/edit/cust_main/bottomfixup.js           |   5 +
 httemplate/elements/header-cust_main.html          |  57 ++++++++
 httemplate/elements/tr-select-cust_location.html   |   1 +
 httemplate/elements/wa_state_tax_district.js       | 159 +++++++++++++++++++++
 httemplate/misc/change_pkg.cgi                     |  14 +-
 httemplate/misc/order_pkg.html                     |  14 +-
 ...xmlhttp-wa_state-find_district_for_address.html |  76 ++++++++++
 11 files changed, 450 insertions(+), 20 deletions(-)
 create mode 100644 httemplate/elements/wa_state_tax_district.js
 create mode 100644 httemplate/misc/xmlhttp-wa_state-find_district_for_address.html




More information about the freeside-commits mailing list