From eec4949e2c8f09a0b89331437186b77c4db6ff38 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 11 Oct 2010 19:00:33 +0000 Subject: [PATCH] external taxes support package locations RT10093 --- FS/FS/cust_location.pm | 80 +---- FS/FS/cust_main.pm | 102 +------ FS/FS/cust_main/Billing.pm | 13 +- FS/FS/geocode_Mixin.pm | 162 ++++++++++ httemplate/edit/cust_main/bottomfixup.js | 326 +-------------------- httemplate/edit/process/quick-cust_pkg.cgi | 2 +- httemplate/elements/standardize_locations.html | 18 ++ httemplate/elements/standardize_locations.js | 278 ++++++++++++++++++ httemplate/misc/change_pkg.cgi | 12 +- httemplate/misc/choose_tax_location.html | 90 ++++++ httemplate/misc/order_pkg.html | 14 +- .../xmlhttp-cust_main-address_standardize.html | 1 + 12 files changed, 596 insertions(+), 502 deletions(-) create mode 100644 FS/FS/geocode_Mixin.pm create mode 100644 httemplate/elements/standardize_locations.html create mode 100644 httemplate/elements/standardize_locations.js create mode 100644 httemplate/misc/choose_tax_location.html diff --git a/FS/FS/cust_location.pm b/FS/FS/cust_location.pm index 0c5c02388..ab80941f9 100644 --- a/FS/FS/cust_location.pm +++ b/FS/FS/cust_location.pm @@ -1,7 +1,7 @@ package FS::cust_location; use strict; -use base qw( FS::Record ); +use base qw( FS::geocode_Mixin FS::Record ); use Locale::Country; use FS::Record qw( qsearch ); #qsearchs ); use FS::prospect_main; @@ -163,91 +163,35 @@ sub country_full { code2country($self->country); } -=item location_label [ OPTION => VALUE ... ] - -Returns the label of the service location for this customer. - -Options are - -=over 4 - -=item join_string - -used to separate the address elements (defaults to ', ') - -=item escape_function - - -a callback used for escaping the text of the address elements +=item line -=back +Synonym for location_label =cut -# false laziness with FS::cust_main::location_label - -sub location_label { +sub line { my $self = shift; - my %opt = @_; - - my $separator = $opt{join_string} || ', '; - my $escape = $opt{escape_function} || sub{ shift }; - my $ds = $opt{double_space} || ' '; - my $line = ''; - my $cydefault = - $opt{'countrydefault'} || FS::Conf->new->config('countrydefault') || 'US'; - my $prefix = ''; - - my $notfirst = 0; - foreach (qw ( address1 address2 ) ) { - my $method = "$prefix$_"; - $line .= ($notfirst ? $separator : ''). &$escape($self->$method) - if $self->$method; - $notfirst++; - } - $notfirst = 0; - foreach (qw ( city county state zip ) ) { - my $method = "$prefix$_"; - if ( $self->$method ) { - $line .= ($notfirst ? ($method eq 'zip' ? $ds : ' ') : $separator); - $line .= '(' if $method eq 'county'; - $line .= &$escape($self->$method); - $line .= ')' if $method eq 'county'; - $notfirst++; - } - $line .= ',' if $method eq 'county'; - } - $line .= $separator. &$escape(code2country($self->country)) - if $self->country ne $cydefault; - - $line; + $self->location_label; } -=item line +=item has_ship_address -Synonym for location_label +Returns false since cust_location objects do not have a separate shipping +address. =cut -sub line { - my $self = shift; - $self->location_label; +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. +Returns a list of key/value pairs, with the following keys: address1, address2, +city, county, state, zip, country, geocode. =cut -#geocode? not yet set - -sub location_hash { - my $self = shift; - map { $_ => $self->$_ } qw( address1 address2 city county state zip country ); -} - =back =head1 BUGS diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index c7a34e189..1f9e3cdaa 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -6,6 +6,7 @@ use strict; use base qw( FS::cust_main::Packages FS::cust_main::Billing FS::cust_main::Billing_Realtime FS::otaker_Mixin FS::payinfo_Mixin FS::cust_main_Mixin + FS::geocode_Mixin FS::Record ); use vars qw( $DEBUG $me $conf @@ -1781,22 +1782,10 @@ 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. The shipping address is used if present. +city, county, state, zip, country, and geocode. The shipping address is used if present. =cut -#geocode? dependent on tax-ship_address config, not available in cust_location -#mostly. not yet then. - -sub location_hash { - my $self = shift; - my $prefix = $self->has_ship_address ? 'ship_' : ''; - - map { $_ => $self->get($prefix.$_) } - qw( address1 address2 city county state zip country geocode ); - #fields that cust_location has -} - =item cust_location Returns all locations (see L) for this customer. @@ -1808,61 +1797,6 @@ sub cust_location { qsearch('cust_location', { 'custnum' => $self->custnum } ); } -=item location_label [ OPTION => VALUE ... ] - -Returns the label of the service location (see analog in L) for this customer. - -Options are - -=over 4 - -=item join_string - -used to separate the address elements (defaults to ', ') - -=item escape_function - -a callback used for escaping the text of the address elements - -=back - -=cut - -# false laziness with FS::cust_location::line - -sub location_label { - my $self = shift; - my %opt = @_; - - my $separator = $opt{join_string} || ', '; - my $escape = $opt{escape_function} || sub{ shift }; - my $line = ''; - my $cydefault = FS::conf->new->config('countrydefault') || 'US'; - my $prefix = length($self->ship_last) ? 'ship_' : ''; - - my $notfirst = 0; - foreach (qw ( address1 address2 ) ) { - my $method = "$prefix$_"; - $line .= ($notfirst ? $separator : ''). &$escape($self->$method) - if $self->$method; - $notfirst++; - } - $notfirst = 0; - foreach (qw ( city county state zip ) ) { - my $method = "$prefix$_"; - if ( $self->$method ) { - $line .= ' (' if $method eq 'county'; - $line .= ($notfirst ? ' ' : $separator). &$escape($self->$method); - $line .= ' )' if $method eq 'county'; - $notfirst++; - } - } - $line .= $separator. &$escape(code2country($self->country)) - if $self->country ne $cydefault; - - $line; -} - =item unsuspend Unsuspends all unflagged suspended packages (see L @@ -3621,38 +3555,6 @@ Currently this only makes sense for "CCH" as DATA_VENDOR. =cut -sub geocode { - my ($self, $data_vendor) = (shift, shift); #always cch for now - - my $geocode = $self->get('geocode'); #XXX only one data_vendor for geocode - return $geocode if $geocode; - - my $prefix = ( $conf->exists('tax-ship_address') && length($self->ship_last) ) - ? 'ship_' - : ''; - - my($zip,$plus4) = split /-/, $self->get("${prefix}zip") - if $self->country eq 'US'; - - $zip ||= ''; - $plus4 ||= ''; - #CCH specific location stuff - my $extra_sql = "AND plus4lo <= '$plus4' AND plus4hi >= '$plus4'"; - - my @cust_tax_location = - qsearch( { - 'table' => 'cust_tax_location', - 'hashref' => { 'zip' => $zip, 'data_vendor' => $data_vendor }, - 'extra_sql' => $extra_sql, - 'order_by' => 'ORDER BY plus4hi',#overlapping with distinct ends - } - ); - $geocode = $cust_tax_location[0]->geocode - if scalar(@cust_tax_location); - - $geocode; -} - =item cust_status =item status diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm index 0cd304b9d..b588dc5cb 100644 --- a/FS/FS/cust_main/Billing.pm +++ b/FS/FS/cust_main/Billing.pm @@ -1048,18 +1048,14 @@ sub _handle_taxes { ) { - if ( $conf->exists('tax-pkg_address') && $cust_pkg->locationnum ) { - return "fatal: Can't (yet) use tax-pkg_address with taxproducts"; - } - foreach my $class (@classes) { - my $err_or_ref = $self->_gather_taxes( $part_pkg, $class ); + my $err_or_ref = $self->_gather_taxes( $part_pkg, $class, $cust_pkg ); return $err_or_ref unless ref($err_or_ref); $taxes{$class} = $err_or_ref; } unless (exists $taxes{''}) { - my $err_or_ref = $self->_gather_taxes( $part_pkg, '' ); + my $err_or_ref = $self->_gather_taxes( $part_pkg, '', $cust_pkg ); return $err_or_ref unless ref($err_or_ref); $taxes{''} = $err_or_ref; } @@ -1226,11 +1222,14 @@ sub _gather_taxes { my $self = shift; my $part_pkg = shift; my $class = shift; + my $cust_pkg = shift; local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG; - my @taxes = (); my $geocode = $self->geocode('cch'); + $geocode = $cust_pkg->geocode('cch') + if ( $conf->exists('tax-pkg_address') && $cust_pkg->locationnum ); + my @taxes = (); my @taxclassnums = map { $_->taxclassnum } $part_pkg->part_pkg_taxoverride($class); diff --git a/FS/FS/geocode_Mixin.pm b/FS/FS/geocode_Mixin.pm new file mode 100644 index 000000000..cf45a92ee --- /dev/null +++ b/FS/FS/geocode_Mixin.pm @@ -0,0 +1,162 @@ +package FS::geocode_Mixin; + +use strict; +use vars qw( $DEBUG $me ); +use Carp; +use Locale::Country; +use FS::Record qw( qsearchs qsearch ); +use FS::cust_pkg; +use FS::cust_location; +use FS::cust_tax_location; +use FS::part_pkg; + +$DEBUG = 0; +$me = '[FS::geocode_Mixin]'; + +=head1 NAME + +FS::geocode_Mixin - Mixin class for records that contain address and other +location fields. + +=head1 SYNOPSIS + + package FS::some_table; + use base ( FS::geocode_Mixin FS::Record ); + +=head1 DESCRIPTION + +FS::geocode_Mixin - This is a mixin class for records that contain address +and other location fields. + +=head1 METHODS + +=over 4 + +=cut + +=item location_hash + +Returns a list of key/value pairs, with the following keys: address1, address2, +city, county, state, zip, country. The shipping address is used if present. + +=cut + +#geocode dependent on tax-ship_address config + +sub location_hash { + my $self = shift; + my $prefix = $self->has_ship_address ? 'ship_' : ''; + + map { my $method = ($_ eq 'geocode') ? $_ : $prefix.$_; + $_ => $self->get($method); + } + qw( address1 address2 city county state zip country geocode ); +} + +=item location_label [ OPTION => VALUE ... ] + +Returns the label of the service location (see analog in L) for this customer. + +Options are + +=over 4 + +=item join_string + +used to separate the address elements (defaults to ', ') + +=item escape_function + +a callback used for escaping the text of the address elements + +=back + +=cut + +sub location_label { + my $self = shift; + my %opt = @_; + + my $separator = $opt{join_string} || ', '; + my $escape = $opt{escape_function} || sub{ shift }; + my $ds = $opt{double_space} || ' '; + my $line = ''; + my $cydefault = + $opt{'countrydefault'} || FS::conf->new->config('countrydefault') || 'US'; + my $prefix = $self->has_ship_address ? 'ship_' : ''; + + my $notfirst = 0; + foreach (qw ( address1 address2 ) ) { + my $method = "$prefix$_"; + $line .= ($notfirst ? $separator : ''). &$escape($self->$method) + if $self->$method; + $notfirst++; + } + $notfirst = 0; + foreach (qw ( city county state zip ) ) { + my $method = "$prefix$_"; + if ( $self->$method ) { + $line .= ' (' if $method eq 'county'; + $line .= ($notfirst ? ' ' : $separator). &$escape($self->$method); + $line .= ' )' if $method eq 'county'; + $notfirst++; + } + } + $line .= $separator. &$escape(code2country($self->country)) + if $self->country ne $cydefault; + + $line; +} + +=item geocode DATA_VENDOR + +Returns a value for the customer location as encoded by DATA_VENDOR. +Currently this only makes sense for "CCH" as DATA_VENDOR. + +=cut + +sub geocode { + my ($self, $data_vendor) = (shift, shift); #always cch for now + + my $geocode = $self->get('geocode'); #XXX only one data_vendor for geocode + return $geocode if $geocode; + + my $prefix = + ( FS::conf->new->exists('tax-ship_address') && $self->has_ship_address ) + ? 'ship_' + : ''; + + my($zip,$plus4) = split /-/, $self->get("${prefix}zip") + if $self->country eq 'US'; + + $zip ||= ''; + $plus4 ||= ''; + #CCH specific location stuff + my $extra_sql = "AND plus4lo <= '$plus4' AND plus4hi >= '$plus4'"; + + my @cust_tax_location = + qsearch( { + 'table' => 'cust_tax_location', + 'hashref' => { 'zip' => $zip, 'data_vendor' => $data_vendor }, + 'extra_sql' => $extra_sql, + 'order_by' => 'ORDER BY plus4hi',#overlapping with distinct ends + } + ); + $geocode = $cust_tax_location[0]->geocode + if scalar(@cust_tax_location); + + $geocode; +} + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L, schema.html from the base documentation. + +=cut + +1; + diff --git a/httemplate/edit/cust_main/bottomfixup.js b/httemplate/edit/cust_main/bottomfixup.js index 5d06f3c04..4d9ef070d 100644 --- a/httemplate/edit/cust_main/bottomfixup.js +++ b/httemplate/edit/cust_main/bottomfixup.js @@ -20,223 +20,14 @@ function bottomfixup(what) { } //this part does USPS address correction - - // XXX should this be first and should we update the form fields that are - // displayed??? - - var cf = document.CustomerForm; - - var state_el = cf.elements['state']; - var ship_state_el = cf.elements['ship_state']; - - //address_standardize( - var cust_main = new Array( - 'company', cf.elements['company'].value, - 'address1', cf.elements['address1'].value, - 'address2', cf.elements['address2'].value, - 'city', cf.elements['city'].value, - 'state', state_el.options[ state_el.selectedIndex ].value, - 'zip', cf.elements['zip'].value, - - 'ship_company', cf.elements['ship_company'].value, - 'ship_address1', cf.elements['ship_address1'].value, - 'ship_address2', cf.elements['ship_address2'].value, - 'ship_city', cf.elements['ship_city'].value, - 'ship_state', ship_state_el.options[ ship_state_el.selectedIndex ].value, - 'ship_zip', cf.elements['ship_zip'].value - ); - - address_standardize( cust_main, update_address ); - -} - -var standardize_address; - -function update_address(arg) { - - var argsHash = eval('(' + arg + ')'); - - var changed = argsHash['address_standardized']; - var ship_changed = argsHash['ship_address_standardized']; - var error = argsHash['error']; - var ship_error = argsHash['ship_error']; - - - //yay closures - standardize_address = function () { - - var cf = document.CustomerForm; - var state_el = cf.elements['state']; - var ship_state_el = cf.elements['ship_state']; - - if ( changed ) { - cf.elements['company'].value = argsHash['new_company']; - cf.elements['address1'].value = argsHash['new_address1']; - cf.elements['address2'].value = argsHash['new_address2']; - cf.elements['city'].value = argsHash['new_city']; - setselect(cf.elements['state'], argsHash['new_state']); - cf.elements['zip'].value = argsHash['new_zip']; - } - - if ( ship_changed ) { - cf.elements['ship_company'].value = argsHash['new_ship_company']; - cf.elements['ship_address1'].value = argsHash['new_ship_address1']; - cf.elements['ship_address2'].value = argsHash['new_ship_address2']; - cf.elements['ship_city'].value = argsHash['new_ship_city']; - setselect(cf.elements['ship_state'], argsHash['new_ship_state']); - cf.elements['ship_zip'].value = argsHash['new_ship_zip']; - } - - post_standardization(); - - } - - - - if ( changed || ship_changed ) { - -% if ( $conf->exists('cust_main-auto_standardize_address') ) { - - standardize_address(); - -% } else { - - // popup a confirmation popup - - var confirm_change = - '

Confirm address standardization

' + - ''; - - if ( changed ) { - - confirm_change = confirm_change + - '' + - ''; - // + ''; - - if ( argsHash['company'] || argsHash['new_company'] ) { - confirm_change = confirm_change + - ''; - } - - confirm_change = confirm_change + - '' + - '' + - '' + - ''; - - } - - if ( ship_changed ) { - - confirm_change = confirm_change + - '' + - ''; - // + ''; - - if ( argsHash['ship_company'] || argsHash['new_ship_company'] ) { - confirm_change = confirm_change + - ''; - } - - confirm_change = confirm_change + - '' + - '' + - '' + - ''; - - } - - var addresses = 'address'; - var height = 268; - if ( changed && ship_changed ) { - addresses = 'addresses'; - height = 396; // #what - } - - confirm_change = confirm_change + - '' + - '' + - - '
Entered billing addressStandardized billing address
  
' + argsHash['company'] + - '' + argsHash['new_company'] + '
' + argsHash['address1'] + - '' + argsHash['new_address1'] + '
' + argsHash['address2'] + - '' + argsHash['new_address2'] + '
' + argsHash['city'] + ', ' + argsHash['state'] + ' ' + argsHash['zip'] + - '' + argsHash['new_city'] + ', ' + argsHash['new_state'] + ' ' + argsHash['new_zip'] + '
  
Entered service addressStandardized service address
  
' + argsHash['ship_company'] + - '' + argsHash['new_ship_company'] + '
' + argsHash['ship_address1'] + - '' + argsHash['new_ship_address1'] + '
' + argsHash['ship_address2'] + - '' + argsHash['new_ship_address2'] + '
' + argsHash['ship_city'] + ', ' + argsHash['ship_state'] + ' ' + argsHash['ship_zip'] + - '' + argsHash['new_ship_city'] + ', ' + argsHash['new_ship_state'] + ' ' + argsHash['new_ship_zip'] + '
  
' + - '' + - '' + - '' + - '
' + - '
'; - - overlib( confirm_change, CAPTION, 'Confirm address standardization', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, height, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); - -% } - - } else { - - post_standardization(); - - } - + standardize_locations(); } -function post_standardization() { - - var cf = document.CustomerForm; - -% if ( $conf->exists('enable_taxproducts') ) { - - if ( new String(cf.elements['<% $taxpre %>zip'].value).length < 10 ) - { - - var country_el = cf.elements['<% $taxpre %>country']; - var country = country_el.options[ country_el.selectedIndex ].value; - var geocode = cf.elements['geocode'].value; - - if ( country == 'CA' || country == 'US' ) { - - var state_el = cf.elements['<% $taxpre %>state']; - var state = state_el.options[ state_el.selectedIndex ].value; - - var url = "cust_main/choose_tax_location.html" + - "?data_vendor=cch-zip" + - ";city=" + cf.elements['<% $taxpre %>city'].value + - ";state=" + state + - ";zip=" + cf.elements['<% $taxpre %>zip'].value + - ";country=" + country + - ";geocode=" + geocode + - ";"; - - // popup a chooser - OLgetAJAX( url, update_geocode, 300 ); - - } else { - - cf.elements['geocode'].value = 'DEFAULT'; - post_geocode(); - - } - - } else { - - cf.elements['geocode'].value = ''; - post_geocode(); - - } - -% } else { - - post_geocode(); - -% } - -} +<% include( '/elements/standardize_locations.js', + 'callback', 'post_geocode();' + ) +%> function post_geocode() { @@ -263,102 +54,6 @@ function post_geocode() { } -function update_geocode() { - - //yay closures - set_geocode = function (what) { - - var cf = document.CustomerForm; - - //alert(what.options[what.selectedIndex].value); - var argsHash = eval('(' + what.options[what.selectedIndex].value + ')'); - cf.elements['<% $taxpre %>city'].value = argsHash['city']; - setselect(cf.elements['<% $taxpre %>state'], argsHash['state']); - cf.elements['<% $taxpre %>zip'].value = argsHash['zip']; - cf.elements['geocode'].value = argsHash['geocode']; - post_geocode(); - - } - - // popup a chooser - - overlib( OLresponseAJAX, CAPTION, 'Select tax location', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); - -} - -var set_censustract; - -function update_censustract(arg) { - - var argsHash = eval('(' + arg + ')'); - - var cf = document.CustomerForm; - - var msacode = argsHash['msacode']; - var statecode = argsHash['statecode']; - var countycode = argsHash['countycode']; - var tractcode = argsHash['tractcode']; - var error = argsHash['error']; - - var newcensus = - new String(statecode) + - new String(countycode) + - new String(tractcode).replace(/\s$/, ''); // JSON 1 workaround - - set_censustract = function () { - - cf.elements['censustract'].value = newcensus - cf.submit(); - - } - - if (error || cf.elements['censustract'].value != newcensus) { - // popup an entry dialog - - if (error) { newcensus = error; } - newcensus.replace(/.*ndefined.*/, 'Not found'); - - var choose_censustract = - '

Confirm censustract
' + - 'Map service module location
' + - 'Map zip code center

' + - ''; - - choose_censustract = choose_censustract + - '' + - '' + - '' + - ''; - - choose_censustract = choose_censustract + - '' + - '' + - - '
Entered census tractCalculated census tract
' + cf.elements['censustract'].value + - '' + newcensus + '
  
' + - '' + - '' + - '' + - '
' + - '
'; - - overlib( choose_censustract, CAPTION, 'Confirm censustract', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); - - } else { - - cf.submit(); - - } - -} - function copyelement(from, to) { if ( from == undefined ) { to.value = ''; @@ -381,19 +76,8 @@ function copyelement(from, to) { //alert(from + " (" + from.type + "): " + to.name + " => " + to.value); } -function setselect(el, value) { - - for ( var s = 0; s < el.options.length; s++ ) { - if ( el.options[s].value == value ) { - el.selectedIndex = s; - } - } - -} <%init> my $conf = new FS::Conf; -my $taxpre = $conf->exists('tax-ship_address') ? 'ship_' : ''; - diff --git a/httemplate/edit/process/quick-cust_pkg.cgi b/httemplate/edit/process/quick-cust_pkg.cgi index 2fde17f5e..71f424ca3 100644 --- a/httemplate/edit/process/quick-cust_pkg.cgi +++ b/httemplate/edit/process/quick-cust_pkg.cgi @@ -74,7 +74,7 @@ my %opt = ( 'cust_pkg' => $cust_pkg ); if ( $locationnum == -1 ) { my $cust_location = new FS::cust_location { map { $_ => scalar($cgi->param($_)) } - qw( custnum address1 address2 city county state zip country ) + qw( custnum address1 address2 city county state zip country geocode ) }; $opt{'cust_location'} = $cust_location; } diff --git a/httemplate/elements/standardize_locations.html b/httemplate/elements/standardize_locations.html new file mode 100644 index 000000000..9f8b71c62 --- /dev/null +++ b/httemplate/elements/standardize_locations.html @@ -0,0 +1,18 @@ +<% include('/elements/init_overlib.html') %> + +<% include( '/elements/xmlhttp.html', + 'url' => $p.'misc/xmlhttp-cust_main-address_standardize.html', + 'subs' => [ 'address_standardize' ], + #'method' => 'POST', #could get too long? + ) +%> + + + +<%init> + +my (%options) = @_; + + diff --git a/httemplate/elements/standardize_locations.js b/httemplate/elements/standardize_locations.js new file mode 100644 index 000000000..e6a4aa607 --- /dev/null +++ b/httemplate/elements/standardize_locations.js @@ -0,0 +1,278 @@ +function standardize_locations() { + + var cf = document.<% $formname %>; + + var state_el = cf.elements['<% $main_prefix %>state']; + var ship_state_el = cf.elements['<% $ship_prefix %>state']; + + var address_info = new Array( +% if ( $onlyship ) { + 'onlyship', 1, +% } else { +% if ( $withfirm ) { + 'company', cf.elements['<% $main_prefix %>company'].value, +% } + 'address1', cf.elements['<% $main_prefix %>address1'].value, + 'address2', cf.elements['<% $main_prefix %>address2'].value, + 'city', cf.elements['<% $main_prefix %>city'].value, + 'state', state_el.options[ state_el.selectedIndex ].value, + 'zip', cf.elements['<% $main_prefix %>zip'].value, +% } +% if ( $withfirm ) { + 'ship_company', cf.elements['<% $ship_prefix %>company'].value, +% } + 'ship_address1', cf.elements['<% $ship_prefix %>address1'].value, + 'ship_address2', cf.elements['<% $ship_prefix %>address2'].value, + 'ship_city', cf.elements['<% $ship_prefix %>city'].value, + 'ship_state', ship_state_el.options[ ship_state_el.selectedIndex ].value, + 'ship_zip', cf.elements['<% $ship_prefix %>zip'].value + ); + + address_standardize( address_info, update_address ); + +} + +var standardize_address; + +function update_address(arg) { + + var argsHash = eval('(' + arg + ')'); + + var changed = argsHash['address_standardized']; + var ship_changed = argsHash['ship_address_standardized']; + var error = argsHash['error']; + var ship_error = argsHash['ship_error']; + + + //yay closures + standardize_address = function () { + + var cf = document.<% $formname %>; + var state_el = cf.elements['<% $main_prefix %>state']; + var ship_state_el = cf.elements['<% $ship_prefix %>state']; + +% if ( !$onlyship ) { + if ( changed ) { +% if ( $withfirm ) { + cf.elements['<% $main_prefix %>company'].value = argsHash['new_company']; +% } + cf.elements['<% $main_prefix %>address1'].value = argsHash['new_address1']; + cf.elements['<% $main_prefix %>address2'].value = argsHash['new_address2']; + cf.elements['<% $main_prefix %>city'].value = argsHash['new_city']; + setselect(cf.elements['<% $main_prefix %>state'], argsHash['new_state']); + cf.elements['<% $main_prefix %>zip'].value = argsHash['new_zip']; + } +% } + + if ( ship_changed ) { +% if ( $withfirm ) { + cf.elements['<% $ship_prefix %>company'].value = argsHash['new_ship_company']; +% } + cf.elements['<% $ship_prefix %>address1'].value = argsHash['new_ship_address1']; + cf.elements['<% $ship_prefix %>address2'].value = argsHash['new_ship_address2']; + cf.elements['<% $ship_prefix %>city'].value = argsHash['new_ship_city']; + setselect(cf.elements['<% $ship_prefix %>state'], argsHash['new_ship_state']); + cf.elements['<% $ship_prefix %>zip'].value = argsHash['new_ship_zip']; + } + + post_standardization(); + + } + + + + if ( changed || ship_changed ) { + +% if ( $conf->exists('cust_main-auto_standardize_address') ) { + + standardize_address(); + +% } else { + + // popup a confirmation popup + + var confirm_change = + '

Confirm address standardization

' + + ''; + + if ( changed ) { + + confirm_change = confirm_change + + '' + + ''; + // + ''; + + if ( argsHash['company'] || argsHash['new_company'] ) { + confirm_change = confirm_change + + ''; + } + + confirm_change = confirm_change + + '' + + '' + + '' + + ''; + + } + + if ( ship_changed ) { + + confirm_change = confirm_change + + '' + + ''; + // + ''; + + if ( argsHash['ship_company'] || argsHash['new_ship_company'] ) { + confirm_change = confirm_change + + ''; + } + + confirm_change = confirm_change + + '' + + '' + + '' + + ''; + + } + + var addresses = 'address'; + var height = 268; + if ( changed && ship_changed ) { + addresses = 'addresses'; + height = 396; // #what + } + + confirm_change = confirm_change + + '' + + '' + + + '
Entered billing addressStandardized billing address
  
' + argsHash['company'] + + '' + argsHash['new_company'] + '
' + argsHash['address1'] + + '' + argsHash['new_address1'] + '
' + argsHash['address2'] + + '' + argsHash['new_address2'] + '
' + argsHash['city'] + ', ' + argsHash['state'] + ' ' + argsHash['zip'] + + '' + argsHash['new_city'] + ', ' + argsHash['new_state'] + ' ' + argsHash['new_zip'] + '
  
Entered service addressStandardized service address
  
' + argsHash['ship_company'] + + '' + argsHash['new_ship_company'] + '
' + argsHash['ship_address1'] + + '' + argsHash['new_ship_address1'] + '
' + argsHash['ship_address2'] + + '' + argsHash['new_ship_address2'] + '
' + argsHash['ship_city'] + ', ' + argsHash['ship_state'] + ' ' + argsHash['ship_zip'] + + '' + argsHash['new_ship_city'] + ', ' + argsHash['new_ship_state'] + ' ' + argsHash['new_ship_zip'] + '
  
' + + '' + + '' + + '' + + '
' + + '
'; + + overlib( confirm_change, CAPTION, 'Confirm address standardization', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, height, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); + +% } + + } else { + + post_standardization(); + + } + + +} + +function post_standardization() { + + var cf = document.<% $formname %>; + +% if ( $conf->exists('enable_taxproducts') ) { + + if ( new String(cf.elements['<% $taxpre %>zip'].value).length < 10 ) + { + + var country_el = cf.elements['<% $taxpre %>country']; + var country = country_el.options[ country_el.selectedIndex ].value; + var geocode = cf.elements['geocode'].value; + + if ( country == 'CA' || country == 'US' ) { + + var state_el = cf.elements['<% $taxpre %>state']; + var state = state_el.options[ state_el.selectedIndex ].value; + + var url = "<% $p %>/misc/choose_tax_location.html" + + "?data_vendor=cch-zip" + + ";city=" + cf.elements['<% $taxpre %>city'].value + + ";state=" + state + + ";zip=" + cf.elements['<% $taxpre %>zip'].value + + ";country=" + country + + ";geocode=" + geocode + + ";formname=" + '<% $formname %>' + + ";"; + + // popup a chooser + OLgetAJAX( url, update_geocode, 300 ); + + } else { + + cf.elements['geocode'].value = 'DEFAULT'; + <% $post_geocode %>; + + } + + } else { + + cf.elements['geocode'].value = ''; + <% $post_geocode %>; + + } + +% } else { + + <% $post_geocode %>; + +% } + +} + +function update_geocode() { + + //yay closures + set_geocode = function (what) { + + var cf = document.<% $formname %>; + + //alert(what.options[what.selectedIndex].value); + var argsHash = eval('(' + what.options[what.selectedIndex].value + ')'); + cf.elements['<% $taxpre %>city'].value = argsHash['city']; + setselect(cf.elements['<% $taxpre %>state'], argsHash['state']); + cf.elements['<% $taxpre %>zip'].value = argsHash['zip']; + cf.elements['geocode'].value = argsHash['geocode']; + <% $post_geocode %>; + + } + + // popup a chooser + + overlib( OLresponseAJAX, CAPTION, 'Select tax location', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); + +} + +function setselect(el, value) { + + for ( var s = 0; s < el.options.length; s++ ) { + if ( el.options[s].value == value ) { + el.selectedIndex = s; + } + } + +} +<%init> + +my %opt = @_; +my $conf = new FS::Conf; + +my $withfirm = 1; + +my $formname = $opt{form} || 'CustomerForm'; +my $onlyship = $opt{onlyship} || ''; +my $main_prefix = $opt{main_prefix} || ''; +my $ship_prefix = $opt{ship_prefix} || ($onlyship ? '' : 'ship_'); +my $taxpre = $main_prefix; +$taxpre = $ship_prefix if ( $conf->exists('tax-ship_address') || $onlyship ); +my $post_geocode = $opt{callback} || 'post_geocode();'; +$withfirm = 0 if $opt{no_company}; + + diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi index 16b707121..ec10b85cf 100755 --- a/httemplate/misc/change_pkg.cgi +++ b/httemplate/misc/change_pkg.cgi @@ -2,7 +2,7 @@ <% include('/elements/error.html') %> -
+ <% ntable('#cccccc') %> @@ -31,8 +31,16 @@ +<% include( '/elements/standardize_locations.html', + 'form' => "OrderPkgForm", + 'onlyship' => 1, + 'no_company' => 1, + 'callback' => 'document.OrderPkgForm.submit();', + ) +%> +
- +
diff --git a/httemplate/misc/choose_tax_location.html b/httemplate/misc/choose_tax_location.html new file mode 100644 index 000000000..dce04c77d --- /dev/null +++ b/httemplate/misc/choose_tax_location.html @@ -0,0 +1,90 @@ +
+

Choose tax location

+

the geocode is:<% $header %>

+

<% $header %>

+ +

+ + + + + +
+ +
+
+<%init> + +my $conf = new FS::Conf; + +my %location = (); + +($location{data_vendor}) = $cgi->param('data_vendor') =~ /^([-\w]+)$/; +($location{city}) = $cgi->param('city') =~ /^([\w ]+)$/; +($location{state}) = $cgi->param('state') =~ /^(\w+)$/; +($location{zip}) = $cgi->param('zip') =~ /^([-\w ]+)$/; +($location{country}) = $cgi->param('country') =~ /^([\w ]+)$/; + +my($geocode) = $cgi->param('geocode') =~ /^([\w]+)$/; + +my($formname) = $cgi->param('formname') =~ /^([\w]*)$/; +$formname ||= 'CustomerForm'; + +my($zip5, $zip4) = split('-', $location{zip}); + +#only support US & CA +my $hashref = { 'data_vendor' => $location{data_vendor} }; +$hashref->{zip} = $location{country} eq 'CA' ? substr($zip5,0,1) : $zip5, + +my @keys = keys(%$hashref); +my @cust_tax_location = (); +until ( @cust_tax_location ) { + @cust_tax_location = qsearch({ table => 'cust_tax_location', + hashref => $hashref, + order_by => 'LIMIT 50', + }); + last unless scalar(@keys); + delete $hashref->{ shift @keys }; +} + +my %max = ( city => 4, county => 6, state => 5); +foreach my $location (@cust_tax_location) { + foreach ( qw( city county state ) ) { + my $length = length($location->$_); + $max{$_} = ($length > $max{$_}) ? $length : $max{$_}; + } +} +foreach ( qw( city county state ) ) { + $max{$_} = $location{$_} if $location{$_} > $max{$_}; + $max{$_}++; +} + +my $header = '  '; +$header .= $_. ' ' x ( $max{lc($_)} - length($_) ) + foreach qw( City County State ); +$header .= "In city?"; + +my $style = "font-family:monospace;"; + + diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html index 8479a7573..e9a56b1a5 100644 --- a/httemplate/misc/order_pkg.html +++ b/httemplate/misc/order_pkg.html @@ -9,14 +9,14 @@ function enable_order_pkg () { if ( document.OrderPkgForm.pkgpart.selectedIndex > 0 ) { - document.OrderPkgForm.submit.disabled = false; + document.OrderPkgForm.submitButton.disabled = false; if ( document.OrderPkgForm.pkgpart.options[document.OrderPkgForm.pkgpart.selectedIndex].getAttribute('data-can_discount') == 1 ) { document.OrderPkgForm.discountnum.disabled = false; } else { document.OrderPkgForm.discountnum.disabled = true; } } else { - document.OrderPkgForm.submit.disabled = true; + document.OrderPkgForm.submitButton.disabled = true; document.OrderPkgForm.discountnum.disabled = true; } } @@ -101,8 +101,16 @@ +<% include( '/elements/standardize_locations.html', + 'form' => "OrderPkgForm", + 'onlyship' => 1, + 'no_company' => 1, + 'callback' => 'document.OrderPkgForm.submit();', + ) +%> +
-> +> diff --git a/httemplate/misc/xmlhttp-cust_main-address_standardize.html b/httemplate/misc/xmlhttp-cust_main-address_standardize.html index 3b9e142f5..d0627cd59 100644 --- a/httemplate/misc/xmlhttp-cust_main-address_standardize.html +++ b/httemplate/misc/xmlhttp-cust_main-address_standardize.html @@ -28,6 +28,7 @@ if ( $sub eq 'address_standardize' ) { } ); foreach my $pre ( '', 'ship_' ) { + next unless ($pre || !$arg{onlyship}); my($zip5, $zip4) = split('-',$arg{$pre.'zip'}); -- 2.11.0