From 4e77f6927631e226e13da84082be66867b71330f Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 3 Dec 2008 01:42:26 +0000 Subject: [PATCH] support zip5 tax lookups, correct errors with fixed format cch import, inital import performance improvements, noise reduction on imports, tool for inital import --- FS/FS/Misc.pm | 2 +- FS/FS/Schema.pm | 9 +- FS/FS/cust_main.pm | 5 +- FS/FS/cust_tax_location.pm | 77 ++++++++- FS/FS/part_pkg_taxrate.pm | 6 +- FS/FS/tax_class.pm | 2 +- FS/FS/tax_rate.pm | 50 +++++- bin/import-tax-rates | 56 +++++++ httemplate/edit/cust_main.cgi | 36 +++- httemplate/edit/cust_main/choose_tax_location.html | 74 +++++++++ httemplate/edit/cust_main/contact.html | 4 + httemplate/elements/ajaxcontentmws.js | 185 +++++++++++++++++++++ httemplate/misc/tax-import.cgi | 2 + .../xmlhttp-cust_main-address_standardize.html | 4 +- 14 files changed, 489 insertions(+), 23 deletions(-) create mode 100755 bin/import-tax-rates create mode 100644 httemplate/edit/cust_main/choose_tax_location.html create mode 100644 httemplate/elements/ajaxcontentmws.js diff --git a/FS/FS/Misc.pm b/FS/FS/Misc.pm index d79f86e0c..5231350fa 100644 --- a/FS/FS/Misc.pm +++ b/FS/FS/Misc.pm @@ -799,7 +799,7 @@ sub csv_from_fixed { my $template = join('', map {$total += $_; "A$_"} @$lengths) if $lengths; my $dir = "%%%FREESIDE_CACHE%%%/cache.$FS::UID::datasrc"; - my $fh = new File::Temp( TEMPLATE => "CODE.csv.XXXXXXXX", + my $fh = new File::Temp( TEMPLATE => "FILE.csv.XXXXXXXX", DIR => $dir, UNLINK => 0, ) or return "can't open temp file: $!\n" diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 73f4f264f..719f3a87b 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -648,6 +648,7 @@ sub tables_hashref { 'paystate', 'varchar', 'NULL', $char_d, '', '', 'paytype', 'varchar', 'NULL', $char_d, '', '', 'payip', 'varchar', 'NULL', 15, '', '', + 'geocode', 'varchar', 'NULL', 20, '', '', 'tax', 'char', 'NULL', 1, '', '', 'otaker', 'varchar', '', 32, '', '', 'refnum', 'int', '', '', '', '', @@ -754,11 +755,15 @@ sub tables_hashref { 'columns' => [ 'custlocationnum', 'serial', '', '', '', '', 'data_vendor', 'varchar', 'NULL', $char_d, '', '', # update source + 'city', 'varchar', 'NULL', $char_d, '', '', + 'postalcity', 'varchar', 'NULL', $char_d, '', '', + 'county', 'varchar', 'NULL', $char_d, '', '', 'zip', 'char', '', 5, '', '', 'state', 'char', '', 2, '', '', - 'plus4hi', 'char', '', 4, '', '', - 'plus4lo', 'char', '', 4, '', '', + 'plus4hi', 'char', 'NULL', 4, '', '', + 'plus4lo', 'char', 'NULL', 4, '', '', 'default_location','char', 'NULL', 1, '', '', # Y = default for zip + 'cityflag', 'char', 'NULL', 1, '', '', # I(n)/O(out)/B(oth)/NULL 'geocode', 'varchar', '', 20, '', '', ], 'primary_key' => 'custlocationnum', diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 8b57b934c..c572bea36 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1262,6 +1262,7 @@ sub check { || $self->ut_textn('stateid') || $self->ut_textn('stateid_state') || $self->ut_textn('invoice_terms') + || $self->ut_alphan('geocode') ; #barf. need message catalogs. i18n. etc. @@ -5227,6 +5228,9 @@ Currently this only makes sense for "CCH" as DATA_VENDOR. 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_' : ''; @@ -5237,7 +5241,6 @@ sub geocode { #CCH specific location stuff my $extra_sql = "AND plus4lo <= '$plus4' AND plus4hi >= '$plus4'"; - my $geocode = ''; my @cust_tax_location = qsearch( { 'table' => 'cust_tax_location', diff --git a/FS/FS/cust_tax_location.pm b/FS/FS/cust_tax_location.pm index cd24cc8a8..f77ad3709 100644 --- a/FS/FS/cust_tax_location.pm +++ b/FS/FS/cust_tax_location.pm @@ -113,15 +113,33 @@ sub check { my $error = $self->ut_numbern('custlocationnum') || $self->ut_text('data_vendor') - || $self->ut_number('zip') + || $self->ut_textn('city') + || $self->ut_textn('postalcity') + || $self->ut_textn('county') || $self->ut_text('state') - || $self->ut_number('plus4hi') - || $self->ut_number('plus4lo') - || $self->ut_enum('default', [ '', ' ', 'Y' ] ) - || $self->ut_number('geocode') + || $self->ut_numbern('plus4hi') + || $self->ut_numbern('plus4lo') + || $self->ut_enum('default', [ '', ' ', 'Y' ] ) # wtf? + || $self->ut_enum('cityflag', [ '', 'I', 'O', 'B' ] ) + || $self->ut_alpha('geocode') ; return $error if $error; + #ugh! cch canada weirdness + if ($self->state eq 'CN') { + $error = "Illegal cch canadian zip" + unless $self->zip =~ /^[A-Z]$/; + } else { + $error = $self->ut_number('zip', $self->state eq 'CN' ? 'CA' : 'US'); + } + return $error if $error; + + #ugh! cch canada weirdness + return "must specify either city/county or plus4lo/plus4hi" + unless ( $self->plus4lo && $self->plus4hi || + ($self->city || $self->state eq 'CN') && $self->county + ); + $self->SUPER::check; } @@ -138,15 +156,24 @@ sub batch_import { my @column_lengths = (); my @column_callbacks = (); - if ( $format eq 'cch-fixed' || $format eq 'cch-fixed-update' ) { + if ( $format =~ /^cch-fixed/ ) { $format =~ s/-fixed//; - push @column_lengths, qw( 5 2 4 4 10 1 ); - push @column_lengths, 1 if $format eq 'cch-update'; + my $f = $format; + my $update = 0; + $f =~ s/-update// && ($update = 1); + if ($f eq 'cch') { + push @column_lengths, qw( 5 2 4 4 10 1 ); + } elsif ( $f eq 'cch-zip' ) { + push @column_lengths, qw( 5 28 25 2 28 5 1 1 10 1 2 ); + } else { + return "Unknown format: $format"; + } + push @column_lengths, 1 if $update; } my $line; my ( $count, $last, $min_sec ) = (0, time, 5); #progressbar - if ( $job || scalar(@column_callbacks) ) { + if ( $job || scalar(@column_lengths) ) { my $error = csv_from_fixed(\$fh, \$count, \@column_lengths); return $error if $error; } @@ -182,6 +209,38 @@ sub batch_import { }; + } elsif ( $format eq 'cch-zip' || $format eq 'cch-update-zip' ) { + @fields = qw( zip city county state postalcity countyfips countydef default geocode cityflag unique ); + push @fields, 'actionflag' if $format eq 'cch-update'; + + $imported++ if $format eq 'cch-update'; #empty file ok + + $hook = sub { + my $hash = shift; + + $hash->{'data_vendor'} = 'cch-zip'; + delete($hash->{$_}) foreach qw( countyfips countydef unique ); + + if (exists($hash->{actionflag}) && $hash->{actionflag} eq 'D') { + delete($hash->{actionflag}); + + my $cust_tax_location = qsearchs('cust_tax_location', $hash); + return "Can't find cust_tax_location to delete: ". + join(" ", map { "$_ => ". $hash->{$_} } @fields) + unless $cust_tax_location; + + my $error = $cust_tax_location->delete; + return $error if $error; + + delete($hash->{$_}) foreach (keys %$hash); + } + + delete($hash->{'actionflag'}); + + ''; + + }; + } elsif ( $format eq 'extended' ) { die "unimplemented\n"; @fields = qw( ); diff --git a/FS/FS/part_pkg_taxrate.pm b/FS/FS/part_pkg_taxrate.pm index 15636217b..9e1c723d0 100644 --- a/FS/FS/part_pkg_taxrate.pm +++ b/FS/FS/part_pkg_taxrate.pm @@ -244,7 +244,7 @@ sub batch_import { unless ($part_pkg_taxproduct) { return "Can't find part_pkg_taxproduct for txmatrix deletion: ". join(" ", map { "$_ => ". $hash->{$_} } @fields) - if $hash->{'actionflag'} eq 'D'; + if ($hash->{'actionfield'} && $hash->{'actionflag'} eq 'D'); $part_pkg_taxproduct{'description'} = join(' : ', (map{ $hash->{$_} } qw(groupdesc itemdesc)), @@ -279,7 +279,9 @@ sub batch_import { return "Can't find tax class for txmatrix deletion: ". join(" ", map { "$_ => ". $hash->{$_} } @fields) - if ($hash->{'actionflag'} eq 'D' && !$tax_class && $class ne ':'); + if ( $hash->{'actionflag'} && $hash->{'actionflag'} eq 'D' && + !$tax_class && $class ne ':' + ); delete($hash->{$_}) foreach @{$map{$item}}; } diff --git a/FS/FS/tax_class.pm b/FS/FS/tax_class.pm index 8ce70f5c3..51d87ab10 100644 --- a/FS/FS/tax_class.pm +++ b/FS/FS/tax_class.pm @@ -158,7 +158,7 @@ sub batch_import { my $line; my ( $count, $last, $min_sec ) = (0, time, 5); #progressbar - if ( $job || scalar(@column_callbacks) ) { + if ( $job || scalar(@column_lengths) ) { my $error = csv_from_fixed(\$fh, \$count, \@column_lengths); return $error if $error; } diff --git a/FS/FS/tax_rate.pm b/FS/FS/tax_rate.pm index f45d0143e..2837f9cc0 100644 --- a/FS/FS/tax_rate.pm +++ b/FS/FS/tax_rate.pm @@ -570,14 +570,22 @@ sub batch_import { } my $actionflag = delete($hash->{'actionflag'}); + + $hash->{'taxname'} =~ s/`/'/g; + $hash->{'taxname'} =~ s|\\|/|g; + + return '' if $format eq 'cch'; # but not cch-update + if ($actionflag eq 'I') { - $insert{ $hash->{'geocode'}. ':'. $hash->{'taxclassnum'} } = $hash; + $insert{ $hash->{'geocode'}. ':'. $hash->{'taxclassnum'} } = { %$hash }; }elsif ($actionflag eq 'D') { - $delete{ $hash->{'geocode'}. ':'. $hash->{'taxclassnum'} } = $hash; + $delete{ $hash->{'geocode'}. ':'. $hash->{'taxclassnum'} } = { %$hash }; }else{ return "Unexpected action flag: ". $hash->{'actionflag'}; } + delete($hash->{$_}) for keys %$hash; + ''; }; @@ -641,6 +649,18 @@ sub batch_import { return $error; } + if (scalar(keys %tax_rate)) { #inserts only, not updates for cch + + my $tax_rate = new FS::tax_rate( \%tax_rate ); + $error = $tax_rate->insert; + + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "can't insert tax_rate for $line: $error"; + } + + } + $imported++; } @@ -765,23 +785,30 @@ sub process_batch { local $FS::UID::AutoCommit = 0; my $dbh = dbh; my $error = ''; + my $have_location = 0; my @list = ( 'CODE', 'codefile', \&FS::tax_class::batch_import, 'PLUS4', 'plus4file', \&FS::cust_tax_location::batch_import, + 'ZIP', 'zipfile', \&FS::cust_tax_location::batch_import, 'TXMATRIX', 'txmatrix', \&FS::part_pkg_taxrate::batch_import, 'DETAIL', 'detail', \&FS::tax_rate::batch_import, ); while( scalar(@list) ) { my ($name, $file, $import_sub) = (shift @list, shift @list, shift @list); unless ($files{$file}) { + next if $name eq 'PLUS4'; $error = "No $name supplied"; + $error = "Neither PLUS4 nor ZIP supplied" + if ($name eq 'ZIP' && !$have_location); next; } + $have_location = 1 if $name eq 'PLUS4'; + my $fmt = $format. ( $name eq 'ZIP' ? '-zip' : '' ); my $dir = '%%%FREESIDE_CACHE%%%/cache.'. $FS::UID::datasrc; my $filename = "$dir/". $files{$file}; open my $fh, "< $filename" or $error ||= "Can't open $name file: $!"; - $error ||= &{$import_sub}({ 'filehandle' => $fh, 'format' => $format }, $job); + $error ||= &{$import_sub}({ 'filehandle' => $fh, 'format' => $fmt }, $job); close $fh; unlink $filename or warn "Can't delete $filename: $!"; } @@ -804,12 +831,23 @@ sub process_batch { my @list = ( 'CODE', 'codefile', \&FS::tax_class::batch_import, 'PLUS4', 'plus4file', \&FS::cust_tax_location::batch_import, + 'ZIP', 'zipfile', \&FS::cust_tax_location::batch_import, 'TXMATRIX', 'txmatrix', \&FS::part_pkg_taxrate::batch_import, ); my $dir = '%%%FREESIDE_CACHE%%%/cache.'. $FS::UID::datasrc; while( scalar(@list) ) { my ($name, $file, $import_sub) = (shift @list, shift @list, shift @list); unless ($files{$file}) { + my $vendor = $name eq 'ZIP' ? 'cch' : 'cch-zip'; + next # update expected only for previously installed location data + if ( ($name eq 'PLUS4' || $name eq 'ZIP') + && !scalar( qsearch( { table => 'cust_tax_location', + hashref => { data_vendor => $vendor }, + select => 'DISTINCT data_vendor', + } ) + ) + ); + $error = "No $name supplied"; next; } @@ -849,9 +887,10 @@ sub process_batch { my ($name, $file, $import_sub) = (shift @insert_list, shift @insert_list, shift @insert_list); + my $fmt = $format. ( $name eq 'ZIP' ? '-zip' : '' ); open my $fh, "< $file" or $error ||= "Can't open $name file $file: $!"; $error ||= - &{$import_sub}({ 'filehandle' => $fh, 'format' => $format }, $job); + &{$import_sub}({ 'filehandle' => $fh, 'format' => $fmt }, $job); close $fh; unlink $file or warn "Can't delete $file: $!"; } @@ -871,9 +910,10 @@ sub process_batch { my ($name, $file, $import_sub) = (shift @delete_list, shift @delete_list, shift @delete_list); + my $fmt = $format. ( $name eq 'ZIP' ? '-zip' : '' ); open my $fh, "< $file" or $error ||= "Can't open $name file $file: $!"; $error ||= - &{$import_sub}({ 'filehandle' => $fh, 'format' => $format }, $job); + &{$import_sub}({ 'filehandle' => $fh, 'format' => $fmt }, $job); close $fh; unlink $file or warn "Can't delete $file: $!"; } diff --git a/bin/import-tax-rates b/bin/import-tax-rates new file mode 100755 index 000000000..1cb76e0ba --- /dev/null +++ b/bin/import-tax-rates @@ -0,0 +1,56 @@ +#!/usr/bin/perl -Tw + +use strict; +use vars qw($opt_c $opt_p $opt_t $opt_d $opt_z $opt_f); +use vars qw($DEBUG); +use Getopt::Std; +use FS::UID qw(adminsuidsetup); +use FS::Conf; +use FS::tax_rate; +use FS::cust_tax_location; + +getopts('c:p:t:d:z:f:'); + +my $user = shift or die &usage; +my $dbh = adminsuidsetup $user; + +my ($format) = $opt_f =~ /^([-\w]+)$/; + +my @list = ( + 'CODE', $opt_c, \&FS::tax_class::batch_import, + 'PLUS4', $opt_p, \&FS::cust_tax_location::batch_import, + 'ZIP', $opt_z, \&FS::cust_tax_location::batch_import, + 'TXMATRIX', $opt_t, \&FS::part_pkg_taxrate::batch_import, + 'DETAIL', $opt_d, \&FS::tax_rate::batch_import, +); + +my $oldAutoCommit = $FS::UID::AutoCommit; +local $FS::UID::AutoCommit = 0; + +my $error = ''; + +while(@list) { + my ($name, $file, $method) = splice(@list, 0, 3); + + my $fh; + + $file =~ /^([\s\d\w.]+)$/ or die "Illegal filename: $file\n"; + $file = $1; + + my $f = $format; + $f .= '-zip' if $name eq 'ZIP'; + + open $fh, '<', $file or die "can't open $name file: $!\n"; + $error ||= &{$method}( { filehandle => $fh, 'format' => $f, } ); + + die "error while processing $file: $error" if $error; + close $fh; +} + +if ($error) { + $dbh->rollback or die $dbh->errstr if $oldAutoCommit; +}else{ + $dbh->commit or die $dbh->errstr if $oldAutoCommit; +} + +sub usage { die "Usage:\nimport-tax-rates f FORMAT -c CODEFILE -p PLUS4FILE -z ZIPFILE -t TXMATRIXFILE -d DETAILFILE user\n\n"; } diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index 8de73c513..8336183b8 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -5,6 +5,7 @@ ) %> <% include('/elements/init_overlib.html') %> + <% include('/elements/error.html') %> @@ -249,6 +250,8 @@ function bottomfixup(what) { 'ship_county', 'ship_state', 'ship_zip', 'ship_country', 'ship_daytime','ship_night', 'ship_fax', + 'geocode', + 'select' // XXX key ); @@ -329,6 +332,8 @@ function update_address(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 () { @@ -355,7 +360,14 @@ function update_address(arg) { } - if ( changed || ship_changed ) { + if ( error || ship_error ) { + + var url = "cust_main/choose_tax_location.html?data_vendor=cch-zip;city="+document.bottomform.elements['city'].value+";state="+document.bottomform.elements['state'].value+";zip="+document.bottomform.elements['zip'].value+";"; + // popup a chooser + OLgetAJAX( url, update_geocode, 300 ); + + + } else if ( changed || ship_changed ) { % if ( $conf->exists('cust_main-auto_standardize_address') ) { @@ -448,6 +460,26 @@ function update_address(arg) { } +function update_geocode() { + + //yay closures + set_geocode = function (what) { + + //alert(what.options[what.selectedIndex].value); + var argsHash = eval('(' + what.options[what.selectedIndex].value + ')'); + document.bottomform.elements['city'].value = argsHash['city']; + document.bottomform.elements['state'].value = argsHash['state']; + document.bottomform.elements['zip'].value = argsHash['zip']; + document.bottomform.elements['geocode'].value = argsHash['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 copyelement(from, to) { if ( from == undefined ) { to.value = ''; @@ -490,6 +522,8 @@ function copyelement(from, to) { % 'ship_county', 'ship_state', 'ship_zip', 'ship_country', % 'ship_daytime','ship_night', 'ship_fax', % +% 'geocode', +% % 'select', #XXX key % % 'payauto', diff --git a/httemplate/edit/cust_main/choose_tax_location.html b/httemplate/edit/cust_main/choose_tax_location.html new file mode 100644 index 000000000..23fdbf282 --- /dev/null +++ b/httemplate/edit/cust_main/choose_tax_location.html @@ -0,0 +1,74 @@ +
+

Choose tax location

+

<% $header %>

+ +

+ + + + + +
+ +
+
+<%init> + +my $conf = new FS::Conf; +my $have_selected = 0; + +my ($data_vendor) = $cgi->param('data_vendor') =~ /^([-\w]+)$/; +my ($city) = $cgi->param('city') =~ /^([\w ]+)$/; +my ($state) = $cgi->param('state') =~ /^(\w+)$/; +my ($zip) = $cgi->param('zip') =~ /^([-\w]+)$/; + +my($zip5, $zip4) = split('-', $zip); + +my $hashref = { data_vendor => $data_vendor, + #city => $city, + #state => $state, + zip => $zip5, + }; +#my @keys = qw ( city state zip ); +my @keys = qw ( zip ); +my @cust_tax_location = (); +until ( @cust_tax_location ) { + @cust_tax_location = qsearch( 'cust_tax_location', $hashref ); + 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{$_}; + } +} +$max{$_}++ foreach qw( city county state ); + +my $header = '  '; +$header .= $_. ' ' x ( $max{lc($_)} - length($_) ) + foreach qw( City County State ); +$header .= "In city?"; + +my $style = "font-family:monospace;"; + + diff --git a/httemplate/edit/cust_main/contact.html b/httemplate/edit/cust_main/contact.html index 21c6b2990..2d37dc895 100644 --- a/httemplate/edit/cust_main/contact.html +++ b/httemplate/edit/cust_main/contact.html @@ -69,6 +69,10 @@ <%$r%>Country <% include('select-country.html', %select_hash ) %> +% if ( !$pre ) { + +% } + diff --git a/httemplate/elements/ajaxcontentmws.js b/httemplate/elements/ajaxcontentmws.js new file mode 100644 index 000000000..917704902 --- /dev/null +++ b/httemplate/elements/ajaxcontentmws.js @@ -0,0 +1,185 @@ +/* + ajaxcontentmws.js - Foteos Macrides (author and Copyright holder) + Initial: June 22, 2006 - Last Revised: March 24, 2008 + Wrapper function set for getting and using the responseText and / or + responseXML from a GET or POST XMLHttpRequest, which can be used to + generate dynamic content for overlib or overlib2 calls, or to modify + the content of a displayed STICKY popup dynamically. + + For GET Use: + onmouseover="return OLgetAJAX(url, command, delay, css);" + onmouseout="OLclearAJAX();" (if delay > 0) + or: + onclick="OLgetAJAX(url, command, 0, css); return false;" + or: + onload="OLgetAJAX(url, command, 0, css); + + Where: + url (required) + is a quoted string, or unquoted string variable name or array entry, with + the full, relative, or partial URL for a file or a server-side script (php, + asp, or cgi, e.g. perl), and may have a query string appended (e.g., + 'http://my.domain.com/scripts/myScript.php?foo=bar&life=grand'). + And: + command (required) + is the function reference (unquoted name without parens) of a function to + be called when the server's response has been received (it could instead be + an inline function, i.e., defined within the 2nd argument, or a quoted string + for a function with parens and any args) + And: + delay (may be omitted unless css is included) + is an unquoted number indicating the number of millisecs to wait before + initiating an XMLHttpRequest GET request. It should be 0 when using onclick + or onload, but may be a modest value such as 300 for onmouseover to avoid + any chatter of requests. When used with onmouseover, include: + onmouseout="OLclearAJAX();" + to clear the request if the user does not hover for at least that long. If + the popup is not STICKY, include an nd or nd2 call, e.g., + onmouseout="OLclearAJAX(); nd();" + And: + css (may be omitted) + is a quoted string with the CSS class (e.g. 'ovfl510' for + .ovfl510 {width:510px; height:145px; overflow:auto; ...} ) for a div to + encase the responseText and set the width, height and scrollbars in the + main text area of the popup, or the unquoted number 0 if no encasing div + is to be used. + + For POST substitute OLpostAJAX(url, qry, command, delay, css); + Where + qry (required) + is the string to be posted, typically a query string (without a lead ?) + and the other arguments are as above. + + See http://www.macridesweb.com/oltest/AJAX.html for more information. +*/ + +// Initialize our global variables for this function set. +var OLhttp=false,OLcommandAJAX=null,OLdelayidAJAX=0,OLclassAJAX='', +OLresponseAJAX='',OLabortAJAX=0,OLdebugAJAX=0; + +// Create a series of wrapper functions (e.g. OLcmdT#() for ones which +// use OLhttp.responseText via the OLresponseAJAX global, and OLcmdX#() +// for ones which use OLhttp.responseXML) whose reference (unquoted name +// without parens) is the 2nd argument in OLgetAJAX(url,command,delay,css) +// calls. This one is for the first example in the AJAX.html support +// document, to use the OLresponseAJAX global as the lead argument for an +// overlib popup. Put your functions in the head, or in another imported +// .js file, so that they will not be affected by updates of this .js file. +// +function OLcmdExT1() { + return overlib(OLresponseAJAX, TEXTPADDING,0, CAPTIONPADDING,4, + CAPTION,'Example with AJAX content via responseText.  Popup scrolls with the window.', + WRAP, BORDER,2, STICKY, CLOSECLICK, SCROLL, + MIDX,0, RELY,100, + STATUS,'Example with AJAX content via responseText of XMLHttpResponse'); +} + +// Alert for old browsers which lack XMLHttpRequest support. +function OLsorryAJAX() { + alert('Sorry, AJAX is not supported by your browser.'); + return false; +} + +// Check 2nd arg for function +function OLchkFuncAJAX(ar){ + var t=typeof ar;return (((t=='function'))||((t=='string')&&(/.+\(.*\)/.test(ar)))); +} + +// Alert for bad 2nd argument +function OLnotFuncAJAX(m) { + if(over)cClick(); + alert('The 2nd arg of OL'+m+'AJAX is not a function reference, nor an inline function, ' + +'nor a quoted string with a function indicated.'); + return OLclearAJAX(); +} + +// Alert for indicating an XMLHttpRequest network error. +function OLerrorAJAX() { + if(OLhttp.status&&OLhttp.status!=2147746065)alert('Network error '+OLhttp.status+'. Try again later.'); + return false; +} + +// Returns a new XMLHttpRequest object, or false for older browsers +// which did not yet support it. Called as OLhttp=OLnewXMLHttp() via +// the OLgetAJAX(url,command,delay,css) wrapper function. +// +function OLnewXMLHttp() { + var f=false,req=f; + if(window.XMLHttpRequest)eval(new Array('try{', + 'req=new XMLHttpRequest();','}catch(e){','req=f;','}').join('\n')); + /*@cc_on @if(@_jscript_version>=5)if(!req) + eval(new Array('try{','req=new ActiveXObject("Msxml2.XMLHTTP");', + '}catch(e){','try{','req=new ActiveXObject("Microsoft.XMLHTTP");', + '}catch(e){','req=f;','}}').join('\n')); @end @*/ + return req; +} + +// Handle the OLhttp.responseText string from the XMLHttpRequest object. +function OLdoAJAX() { + if(OLhttp.readyState==4){ + if(OLdebugAJAX)alert( + 'OLhttp.status = '+OLhttp.status+'\n' + +'OLhttp.statusText = '+OLhttp.statusText+'\n' + +'OLhttp.getAllResponseHeaders() = \n' + +OLhttp.getAllResponseHeaders()+'\n' + +'OLhttp.getResponseHeader("Content-Type") = ' + +OLhttp.getResponseHeader("Content-Type")+'\n'); + if(OLhttp.status==200||(OLhttp.status==0&&!OLabortAJAX&&!OLie55)){ + OLresponseAJAX=OLclassAJAX?'
':''; + OLresponseAJAX += OLhttp.responseText; + OLresponseAJAX += OLclassAJAX?'
':''; + if(OLdebugAJAX)alert('OLresponseAJAX = \n'+OLresponseAJAX); + OLclassAJAX=0; + return (typeof OLcommandAJAX=='string')?eval(OLcommandAJAX):OLcommandAJAX(); + }else{ + OLclassAJAX=0; + OLabortAJAX=0; + return OLerrorAJAX(); + } + } +} + +// Actually make the request initiated via OLgetAJAX or OLpostAJAX, or +// invoke a "permission denied" alert if a cross-domain URL was used. +function OLsetAJAX(url,qry) { + if(window.location.protocol.indexOf('http')==0&& + (url.indexOf('file:')==0||url.indexOf('ftp:')==0)){ + alert('[object Error]\n(Cross-domain access not permitted)');return false;} + qry=(qry||null);var s='',m=(qry)?'POST':'GET';OLabortAJAX=0; + OLdelayidAJAX=0;eval(new Array('try{','OLhttp.open(m,url,true);', + '}catch(e){','s=e','OLhttp=false;','}').join('\n'));if(!OLhttp){ + alert(s+'\n(Cross-domain access not permitted)');return false;}if(qry) + OLhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded'); + OLhttp.onreadystatechange=OLdoAJAX; + OLhttp.send(qry); +} + +// Clear or abort any delayed OLsetAJAX call or pending request. +function OLclearAJAX() { + if(OLdelayidAJAX){clearTimeout(OLdelayidAJAX);OLdelayidAJAX=0;} + if(OLhttp&&!OLdebugAJAX){OLabortAJAX=1;OLhttp.abort();} + return false; +} + +// Load a new XMLHttpRequest object into the OLhttp global, load the +// OLcommandAJAX and OLclassAJAX globals, and initiate a GET request +// via OLsetAJAX(url) to populate OLhttp. +function OLgetAJAX(url,command,delay,css) { + if(!OLchkFuncAJAX(command))return OLnotFuncAJAX('get'); + OLclearAJAX();OLhttp=OLnewXMLHttp();if(!OLhttp)return OLsorryAJAX(); + OLcommandAJAX=command;delay=(delay||0);css=(css||0);OLclassAJAX=css; + if(delay)OLdelayidAJAX=setTimeout("OLsetAJAX('"+url+"')",delay); + else OLsetAJAX(url); +} + +// Load a new XMLHttpRequest object into the OLhttp global, load the +// OLcommandAJAX and OLclassAJAX globals, and initiate a POST request +// via OLsetAJAX(url,qry) to populate OLhttp. +function OLpostAJAX(url,qry,command,delay,css) { + if(!OLchkFuncAJAX(command))return OLnotFuncAJAX('post'); + OLclearAJAX();OLhttp=OLnewXMLHttp();if(!OLhttp)return OLsorryAJAX(); + qry=(qry||0);OLcommandAJAX=command;delay=(delay||0);css=(css||0);OLclassAJAX=css; + if(delay)OLdelayidAJAX=setTimeout("OLsetAJAX('"+url+"','"+qry+"')",delay); + else OLsetAJAX(url,qry); +} diff --git a/httemplate/misc/tax-import.cgi b/httemplate/misc/tax-import.cgi index 2bae6f10a..bca623fed 100644 --- a/httemplate/misc/tax-import.cgi +++ b/httemplate/misc/tax-import.cgi @@ -29,11 +29,13 @@ Import a CSV file set containing tax rate records. <% include( '/elements/file-upload.html', 'field' => [ 'codefile', 'plus4file', + 'zipfile', 'txmatrix', 'detail', ], 'label' => [ 'code filename', 'plus4 filename', + 'zip filename', 'txmatrix filename', 'detail filename', ], diff --git a/httemplate/misc/xmlhttp-cust_main-address_standardize.html b/httemplate/misc/xmlhttp-cust_main-address_standardize.html index 8532bb23a..72fa4a464 100644 --- a/httemplate/misc/xmlhttp-cust_main-address_standardize.html +++ b/httemplate/misc/xmlhttp-cust_main-address_standardize.html @@ -72,7 +72,9 @@ if ( $sub eq 'address_standardize' ) { } else { - warn "USPS WebTools error: ". $verifier->response. "\n"; + $return->{$pre.'error'} = "USPS WebTools error: ". + $verifier->{error}{description}; + } -- 2.11.0