X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Ftax_rate_location.pm;h=ad3618a9835dd347f5012318f724cb420e992082;hp=0e0dafebbdb7194610a1eea82aeaffacb5fcadcf;hb=5f7c4a6025b9e3a49bee72dbc06cac37a45e6f10;hpb=b3f5d82f666ad38799cae84f0b50bad2b0450d40 diff --git a/FS/FS/tax_rate_location.pm b/FS/FS/tax_rate_location.pm index 0e0dafebb..ad3618a98 100644 --- a/FS/FS/tax_rate_location.pm +++ b/FS/FS/tax_rate_location.pm @@ -26,39 +26,32 @@ FS::tax_rate_location - Object methods for tax_rate_location records =head1 DESCRIPTION -An FS::tax_rate_location object represents an example. FS::tax_rate_location inherits from -FS::Record. The following fields are currently supported: +An FS::tax_rate_location object represents a tax jurisdiction. The only +functional field is "geocode", a foreign key to tax rates (L) +that apply in the jurisdiction. The city, county, state, and country fields +are provided for description and reporting. -=over 4 - -=item taxratelocationnum - -Primary key (assigned automatically for new tax_rate_locations) - -=item data_vendor - -The tax data vendor - -=item geocode - -A unique geographic location code provided by the data vendor +FS::tax_rate_location inherits from FS::Record. The following fields are +currently supported: -=item city +=over 4 -City +=item taxratelocationnum - Primary key (assigned automatically for new +tax_rate_locations) -=item county +=item data_vendor - The tax data vendor ('cch' or 'billsoft'). -County +=item geocode - A unique geographic location code provided by the data vendor -=item state +=item city - City -State +=item county - County -=item disabled +=item state - State (2-letter code) -If 'Y' this record is no longer active. +=item country - Country (2-letter code, optional) +=item disabled - If 'Y' this record is no longer active. =back @@ -125,11 +118,14 @@ sub check { ; return $error if $error; - my $t = qsearchs( 'tax_rate_location', - { map { $_ => $self->$_ } qw( data_vendor geocode ) }, - ); + my $t = ''; + $t = $self->existing_search + unless $self->disabled; + + $t = $self->by_key( $self->taxratelocationnum ) + if !$t && $self->taxratelocationnum; - return "geocode already in use for this vendor" + return "geocode ". $self->geocode. " already in use for this vendor" if ( $t && $t->taxratelocationnum != $self->taxratelocationnum ); return "may only be disabled" @@ -142,16 +138,98 @@ sub check { $self->SUPER::check; } +=item find_or_insert + +Finds an existing, non-disabled tax jurisdiction matching the data_vendor +and geocode fields. If there is one, updates its city, county, state, and +country to match this record. If there is no existing record, inserts this +record. + +=cut + +sub find_or_insert { + my $self = shift; + my $existing = $self->existing_search; + if ($existing) { + my $update = 0; + foreach (qw(city county state country)) { + if ($self->get($_) ne $existing->get($_)) { + $update++; + } + } + $self->set(taxratelocationnum => $existing->taxratelocationnum); + if ($update) { + return $self->replace($existing); + } else { + return; + } + } else { + return $self->insert; + } +} + +sub existing_search { + my $self = shift; + + my @unique = qw( data_vendor geocode ); + push @unique, qw( state country ) + if $self->data_vendor eq 'compliance_solutions'; + + qsearchs( 'tax_rate_location', + { disabled => '', + map { $_ => $self->$_ } @unique + } + ); +} + +=back + +=head1 CLASS METHODS + +=item location_sql KEY => VALUE, ... + +Returns an SQL fragment identifying matching tax_rate_location / +cust_bill_pkg_tax_rate_location records. + +Parameters are county, state, city and locationtaxid + +=cut + +sub location_sql { + my($class, %param) = @_; + + my %pn = ( + 'city' => 'tax_rate_location.city', + 'county' => 'tax_rate_location.county', + 'state' => 'tax_rate_location.state', + 'locationtaxid' => 'cust_bill_pkg_tax_rate_location.locationtaxid', + ); + + my %ph = map { $pn{$_} => dbh->quote($param{$_}) } keys %pn; + + join( ' AND ', + map { "( $_ = $ph{$_} OR $ph{$_} = '' AND $_ IS NULL)" } keys %ph + ); + +} + =back =head1 SUBROUTINES =over 4 -=item batch_import +=item batch_import HASHREF, JOB + +Starts importing tax_rate_location records from a file. HASHREF must contain +'filehandle' (an open handle to the input file) and 'format' (one of 'cch', +'cch-fixed', 'cch-update', 'cch-fixed-update', or 'billsoft'). JOB is an +L object to receive progress messages. =cut +# XXX move this into TaxEngine modules at some point + sub batch_import { my ($param, $job) = @_; @@ -176,7 +254,7 @@ sub batch_import { my $line; my ( $count, $last, $min_sec ) = (0, time, 5); #progressbar - if ( $job || scalar(@column_callbacks) ) { + if ( $job || scalar(@column_callbacks) ) { # this makes zero sense my $error = csv_from_fixed(\$fh, \$count, \@column_lengths, \@column_callbacks); return $error if $error; @@ -194,7 +272,7 @@ sub batch_import { if (exists($hash->{'actionflag'}) && $hash->{'actionflag'} eq 'D') { delete($hash->{actionflag}); - $hash->{deleted} = ''; + $hash->{disabled} = ''; my $tax_rate_location = qsearchs('tax_rate_location', $hash); return "Can't find tax_rate_location to delete: ". join(" ", map { "$_ => ". $hash->{$_} } @fields) @@ -213,6 +291,29 @@ sub batch_import { }; + } elsif ( $format eq 'billsoft' ) { + @fields = ( qw( geocode alt_location country state county city ), '', '' ); + + $hook = sub { + my $hash = shift; + if ($hash->{alt_location}) { + # don't import these; the jurisdiction should be named using its + # primary city + %$hash = (); + return; + } + + $hash->{data_vendor} = 'billsoft'; + # unlike cust_tax_location, keep the whole-country and whole-state + # rows, but strip the whitespace + $hash->{county} =~ s/^ //g; + $hash->{state} =~ s/^ //g; + $hash->{country} =~ s/^ //g; + $hash->{city} =~ s/[^\w ]//g; # remove asterisks and other bad things + $hash->{country} = substr($hash->{country}, 0, 2); + ''; + } + } elsif ( $format eq 'extended' ) { die "unimplemented\n"; @fields = qw( ); @@ -248,7 +349,8 @@ sub batch_import { if ( $job ) { # progress bar if ( time - $min_sec > $last ) { my $error = $job->update_statustext( - int( 100 * $imported / $count ) + int( 100 * $imported / $count ) . + ',Creating tax jurisdiction records' ); die $error if $error; $last = time; @@ -263,7 +365,7 @@ sub batch_import { } if ( scalar( @columns ) ) { $dbh->rollback if $oldAutoCommit; - return "Unexpected trailing columns in line (wrong format?): $line"; + return "Unexpected trailing columns in line (wrong format?) importing tax-rate_location: $line"; } my $error = &{$hook}(\%tax_rate_location); @@ -279,7 +381,7 @@ sub batch_import { if ( $error ) { $dbh->rollback if $oldAutoCommit; - return "can't insert tax_rate for $line: $error"; + return "can't insert tax_rate_location for $line: $error"; } } @@ -296,6 +398,16 @@ sub batch_import { } +sub _upgrade_data { + my $class = shift; + + my $sql = "UPDATE tax_rate_location SET data_vendor = 'compliance_solutions' WHERE data_vendor = 'compliance solutions'"; + + my $sth = dbh->prepare($sql) or die $DBI::errstr; + $sth->execute() or die $sth->errstr; + +} + =head1 BUGS Currently somewhat specific to CCH supplied data.