1 package FS::tax_rate_location;
4 use base qw( FS::Record );
5 use FS::Record qw( qsearch qsearchs dbh );
9 FS::tax_rate_location - Object methods for tax_rate_location records
13 use FS::tax_rate_location;
15 $record = new FS::tax_rate_location \%hash;
16 $record = new FS::tax_rate_location { 'column' => 'value' };
18 $error = $record->insert;
20 $error = $new_record->replace($old_record);
22 $error = $record->delete;
24 $error = $record->check;
28 An FS::tax_rate_location object represents an example. FS::tax_rate_location inherits from
29 FS::Record. The following fields are currently supported:
33 =item taxratelocationnum
35 Primary key (assigned automatically for new tax_rate_locations)
43 A unique geographic location code provided by the data vendor
59 If 'Y' this record is no longer active.
70 Creates a new tax rate location. To add the record to the database, see
73 Note that this stores the hash reference, not a distinct copy of the hash it
74 points to. You can ask the object for a copy with the I<hash> method.
78 sub table { 'tax_rate_location'; }
82 Adds this record to the database. If there is an error, returns the error,
83 otherwise returns false.
89 Delete this record from the database.
94 return "Can't delete tax rate locations. Set disable to 'Y' instead.";
95 # check that it is unused in any cust_bill_pkg_tax_location records instead?
98 =item replace OLD_RECORD
100 Replaces the OLD_RECORD with this one in the database. If there is an error,
101 returns the error, otherwise returns false.
107 Checks all fields to make sure this is a valid tax rate location. If there is
108 an error, returns the error, otherwise returns false. Called by the insert
117 $self->ut_numbern('taxratelocationnum')
118 || $self->ut_textn('data_vendor')
119 || $self->ut_alpha('geocode')
120 || $self->ut_textn('city')
121 || $self->ut_textn('county')
122 || $self->ut_textn('state')
123 || $self->ut_enum('disabled', [ '', 'Y' ])
125 return $error if $error;
127 my $t = qsearchs( 'tax_rate_location',
128 { map { $_ => $self->$_ } qw( data_vendor geocode ) },
131 return "geocode already in use for this vendor"
132 if ( $t && $t->taxratelocationnum != $self->taxratelocationnum );
134 return "may only be disabled"
135 if ( $t && scalar( grep { $t->$_ ne $self->$_ }
136 grep { $_ ne 'disabled' }
155 my ($param, $job) = @_;
157 my $fh = $param->{filehandle};
158 my $format = $param->{'format'};
166 my @column_lengths = ();
167 my @column_callbacks = ();
168 if ( $format eq 'cch-fixed' || $format eq 'cch-fixed-update' ) {
169 $format =~ s/-fixed//;
170 my $trim = sub { my $r = shift; $r =~ s/^\s*//; $r =~ s/\s*$//; $r };
171 push @column_lengths, qw( 28 25 2 10 );
172 push @column_lengths, 1 if $format eq 'cch-update';
173 push @column_callbacks, $trim foreach (@column_lengths);
177 my ( $count, $last, $min_sec ) = (0, time, 5); #progressbar
178 if ( $job || scalar(@column_callbacks) ) {
180 csv_from_fixed(\$fh, \$count, \@column_lengths, \@column_callbacks);
181 return $error if $error;
184 if ( $format eq 'cch' || $format eq 'cch-update' ) {
185 @fields = qw( city county state geocode );
186 push @fields, 'actionflag' if $format eq 'cch-update';
191 $hash->{'data_vendor'} ='cch';
193 if (exists($hash->{'actionflag'}) && $hash->{'actionflag'} eq 'D') {
194 delete($hash->{actionflag});
196 $hash->{deleted} = '';
197 my $tax_rate_location = qsearchs('tax_rate_location', $hash);
198 return "Can't find tax_rate_location to delete: ".
199 join(" ", map { "$_ => ". $hash->{$_} } @fields)
200 unless $tax_rate_location;
202 $tax_rate_location->disabled('Y');
203 my $error = $tax_rate_location->replace;
204 return $error if $error;
206 delete($hash->{$_}) foreach (keys %$hash);
209 delete($hash->{'actionflag'});
215 } elsif ( $format eq 'extended' ) {
216 die "unimplemented\n";
220 die "unknown format $format";
223 eval "use Text::CSV_XS;";
226 my $csv = new Text::CSV_XS;
230 local $SIG{HUP} = 'IGNORE';
231 local $SIG{INT} = 'IGNORE';
232 local $SIG{QUIT} = 'IGNORE';
233 local $SIG{TERM} = 'IGNORE';
234 local $SIG{TSTP} = 'IGNORE';
235 local $SIG{PIPE} = 'IGNORE';
237 my $oldAutoCommit = $FS::UID::AutoCommit;
238 local $FS::UID::AutoCommit = 0;
241 while ( defined($line=<$fh>) ) {
242 $csv->parse($line) or do {
243 $dbh->rollback if $oldAutoCommit;
244 return "can't parse: ". $csv->error_input();
247 if ( $job ) { # progress bar
248 if ( time - $min_sec > $last ) {
249 my $error = $job->update_statustext(
250 int( 100 * $imported / $count )
252 die $error if $error;
257 my @columns = $csv->fields();
259 my %tax_rate_location = ();
260 foreach my $field ( @fields ) {
261 $tax_rate_location{$field} = shift @columns;
263 if ( scalar( @columns ) ) {
264 $dbh->rollback if $oldAutoCommit;
265 return "Unexpected trailing columns in line (wrong format?): $line";
268 my $error = &{$hook}(\%tax_rate_location);
270 $dbh->rollback if $oldAutoCommit;
274 if (scalar(keys %tax_rate_location)) { #inserts only
276 my $tax_rate_location = new FS::tax_rate_location( \%tax_rate_location );
277 $error = $tax_rate_location->insert;
280 $dbh->rollback if $oldAutoCommit;
281 return "can't insert tax_rate for $line: $error";
290 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
292 return "Empty file!" unless ($imported || $format eq 'cch-update');
300 Currently somewhat specific to CCH supplied data.
304 L<FS::Record>, schema.html from the base documentation.