1 package FS::tax_rate_location;
4 use base qw( FS::Record );
5 use FS::Record qw( qsearch qsearchs dbh );
6 use FS::Misc qw( csv_from_fixed );
10 FS::tax_rate_location - Object methods for tax_rate_location records
14 use FS::tax_rate_location;
16 $record = new FS::tax_rate_location \%hash;
17 $record = new FS::tax_rate_location { 'column' => 'value' };
19 $error = $record->insert;
21 $error = $new_record->replace($old_record);
23 $error = $record->delete;
25 $error = $record->check;
29 An FS::tax_rate_location object represents an example. FS::tax_rate_location inherits from
30 FS::Record. The following fields are currently supported:
34 =item taxratelocationnum
36 Primary key (assigned automatically for new tax_rate_locations)
44 A unique geographic location code provided by the data vendor
60 If 'Y' this record is no longer active.
71 Creates a new tax rate location. To add the record to the database, see
74 Note that this stores the hash reference, not a distinct copy of the hash it
75 points to. You can ask the object for a copy with the I<hash> method.
79 sub table { 'tax_rate_location'; }
83 Adds this record to the database. If there is an error, returns the error,
84 otherwise returns false.
90 Delete this record from the database.
95 return "Can't delete tax rate locations. Set disable to 'Y' instead.";
96 # check that it is unused in any cust_bill_pkg_tax_location records instead?
99 =item replace OLD_RECORD
101 Replaces the OLD_RECORD with this one in the database. If there is an error,
102 returns the error, otherwise returns false.
108 Checks all fields to make sure this is a valid tax rate location. If there is
109 an error, returns the error, otherwise returns false. Called by the insert
118 $self->ut_numbern('taxratelocationnum')
119 || $self->ut_textn('data_vendor')
120 || $self->ut_alpha('geocode')
121 || $self->ut_textn('city')
122 || $self->ut_textn('county')
123 || $self->ut_textn('state')
124 || $self->ut_enum('disabled', [ '', 'Y' ])
126 return $error if $error;
129 $t = qsearchs( 'tax_rate_location',
131 ( map { $_ => $self->$_ } qw( data_vendor geocode ) ),
134 unless $self->disabled;
136 $t = $self->by_key( $self->taxratelocationnum )
137 if ( !$t && $self->taxratelocationnum );
139 return "geocode ". $self->geocode. " already in use for this vendor"
140 if ( $t && $t->taxratelocationnum != $self->taxratelocationnum );
142 return "may only be disabled"
143 if ( $t && scalar( grep { $t->$_ ne $self->$_ }
144 grep { $_ ne 'disabled' }
156 =item location_sql KEY => VALUE, ...
158 Returns an SQL fragment identifying matching tax_rate_location /
159 cust_bill_pkg_tax_rate_location records.
161 Parameters are county, state, city and locationtaxid
166 my($class, %param) = @_;
169 'city' => 'tax_rate_location.city',
170 'county' => 'tax_rate_location.county',
171 'state' => 'tax_rate_location.state',
172 'locationtaxid' => 'cust_bill_pkg_tax_rate_location.locationtaxid',
175 my %ph = map { $pn{$_} => dbh->quote($param{$_}) } keys %pn;
178 map { "( $_ = $ph{$_} OR $ph{$_} = '' AND $_ IS NULL)" } keys %ph
194 my ($param, $job) = @_;
196 my $fh = $param->{filehandle};
197 my $format = $param->{'format'};
205 my @column_lengths = ();
206 my @column_callbacks = ();
207 if ( $format eq 'cch-fixed' || $format eq 'cch-fixed-update' ) {
208 $format =~ s/-fixed//;
209 my $trim = sub { my $r = shift; $r =~ s/^\s*//; $r =~ s/\s*$//; $r };
210 push @column_lengths, qw( 28 25 2 10 );
211 push @column_lengths, 1 if $format eq 'cch-update';
212 push @column_callbacks, $trim foreach (@column_lengths);
216 my ( $count, $last, $min_sec ) = (0, time, 5); #progressbar
217 if ( $job || scalar(@column_callbacks) ) {
219 csv_from_fixed(\$fh, \$count, \@column_lengths, \@column_callbacks);
220 return $error if $error;
223 if ( $format eq 'cch' || $format eq 'cch-update' ) {
224 @fields = qw( city county state geocode );
225 push @fields, 'actionflag' if $format eq 'cch-update';
230 $hash->{'data_vendor'} ='cch';
232 if (exists($hash->{'actionflag'}) && $hash->{'actionflag'} eq 'D') {
233 delete($hash->{actionflag});
235 $hash->{disabled} = '';
236 my $tax_rate_location = qsearchs('tax_rate_location', $hash);
237 return "Can't find tax_rate_location to delete: ".
238 join(" ", map { "$_ => ". $hash->{$_} } @fields)
239 unless $tax_rate_location;
241 $tax_rate_location->disabled('Y');
242 my $error = $tax_rate_location->replace;
243 return $error if $error;
245 delete($hash->{$_}) foreach (keys %$hash);
248 delete($hash->{'actionflag'});
254 } elsif ( $format eq 'extended' ) {
255 die "unimplemented\n";
259 die "unknown format $format";
262 eval "use Text::CSV_XS;";
265 my $csv = new Text::CSV_XS;
269 local $SIG{HUP} = 'IGNORE';
270 local $SIG{INT} = 'IGNORE';
271 local $SIG{QUIT} = 'IGNORE';
272 local $SIG{TERM} = 'IGNORE';
273 local $SIG{TSTP} = 'IGNORE';
274 local $SIG{PIPE} = 'IGNORE';
276 my $oldAutoCommit = $FS::UID::AutoCommit;
277 local $FS::UID::AutoCommit = 0;
280 while ( defined($line=<$fh>) ) {
281 $csv->parse($line) or do {
282 $dbh->rollback if $oldAutoCommit;
283 return "can't parse: ". $csv->error_input();
286 if ( $job ) { # progress bar
287 if ( time - $min_sec > $last ) {
288 my $error = $job->update_statustext(
289 int( 100 * $imported / $count )
291 die $error if $error;
296 my @columns = $csv->fields();
298 my %tax_rate_location = ();
299 foreach my $field ( @fields ) {
300 $tax_rate_location{$field} = shift @columns;
302 if ( scalar( @columns ) ) {
303 $dbh->rollback if $oldAutoCommit;
304 return "Unexpected trailing columns in line (wrong format?) importing tax-rate_location: $line";
307 my $error = &{$hook}(\%tax_rate_location);
309 $dbh->rollback if $oldAutoCommit;
313 if (scalar(keys %tax_rate_location)) { #inserts only
315 my $tax_rate_location = new FS::tax_rate_location( \%tax_rate_location );
316 $error = $tax_rate_location->insert;
319 $dbh->rollback if $oldAutoCommit;
320 return "can't insert tax_rate_location for $line: $error";
329 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
331 return "Empty file!" unless ($imported || $format eq 'cch-update');
339 Currently somewhat specific to CCH supplied data.
343 L<FS::Record>, schema.html from the base documentation.