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;
128 my $t = qsearchs( 'tax_rate_location',
129 { map { $_ => $self->$_ } qw( data_vendor geocode ) },
132 return "geocode already in use for this vendor"
133 if ( $t && $t->taxratelocationnum != $self->taxratelocationnum );
135 return "may only be disabled"
136 if ( $t && scalar( grep { $t->$_ ne $self->$_ }
137 grep { $_ ne 'disabled' }
156 my ($param, $job) = @_;
158 my $fh = $param->{filehandle};
159 my $format = $param->{'format'};
167 my @column_lengths = ();
168 my @column_callbacks = ();
169 if ( $format eq 'cch-fixed' || $format eq 'cch-fixed-update' ) {
170 $format =~ s/-fixed//;
171 my $trim = sub { my $r = shift; $r =~ s/^\s*//; $r =~ s/\s*$//; $r };
172 push @column_lengths, qw( 28 25 2 10 );
173 push @column_lengths, 1 if $format eq 'cch-update';
174 push @column_callbacks, $trim foreach (@column_lengths);
178 my ( $count, $last, $min_sec ) = (0, time, 5); #progressbar
179 if ( $job || scalar(@column_callbacks) ) {
181 csv_from_fixed(\$fh, \$count, \@column_lengths, \@column_callbacks);
182 return $error if $error;
185 if ( $format eq 'cch' || $format eq 'cch-update' ) {
186 @fields = qw( city county state geocode );
187 push @fields, 'actionflag' if $format eq 'cch-update';
192 $hash->{'data_vendor'} ='cch';
194 if (exists($hash->{'actionflag'}) && $hash->{'actionflag'} eq 'D') {
195 delete($hash->{actionflag});
197 $hash->{deleted} = '';
198 my $tax_rate_location = qsearchs('tax_rate_location', $hash);
199 return "Can't find tax_rate_location to delete: ".
200 join(" ", map { "$_ => ". $hash->{$_} } @fields)
201 unless $tax_rate_location;
203 $tax_rate_location->disabled('Y');
204 my $error = $tax_rate_location->replace;
205 return $error if $error;
207 delete($hash->{$_}) foreach (keys %$hash);
210 delete($hash->{'actionflag'});
216 } elsif ( $format eq 'extended' ) {
217 die "unimplemented\n";
221 die "unknown format $format";
224 eval "use Text::CSV_XS;";
227 my $csv = new Text::CSV_XS;
231 local $SIG{HUP} = 'IGNORE';
232 local $SIG{INT} = 'IGNORE';
233 local $SIG{QUIT} = 'IGNORE';
234 local $SIG{TERM} = 'IGNORE';
235 local $SIG{TSTP} = 'IGNORE';
236 local $SIG{PIPE} = 'IGNORE';
238 my $oldAutoCommit = $FS::UID::AutoCommit;
239 local $FS::UID::AutoCommit = 0;
242 while ( defined($line=<$fh>) ) {
243 $csv->parse($line) or do {
244 $dbh->rollback if $oldAutoCommit;
245 return "can't parse: ". $csv->error_input();
248 if ( $job ) { # progress bar
249 if ( time - $min_sec > $last ) {
250 my $error = $job->update_statustext(
251 int( 100 * $imported / $count )
253 die $error if $error;
258 my @columns = $csv->fields();
260 my %tax_rate_location = ();
261 foreach my $field ( @fields ) {
262 $tax_rate_location{$field} = shift @columns;
264 if ( scalar( @columns ) ) {
265 $dbh->rollback if $oldAutoCommit;
266 return "Unexpected trailing columns in line (wrong format?): $line";
269 my $error = &{$hook}(\%tax_rate_location);
271 $dbh->rollback if $oldAutoCommit;
275 if (scalar(keys %tax_rate_location)) { #inserts only
277 my $tax_rate_location = new FS::tax_rate_location( \%tax_rate_location );
278 $error = $tax_rate_location->insert;
281 $dbh->rollback if $oldAutoCommit;
282 return "can't insert tax_rate for $line: $error";
291 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
293 return "Empty file!" unless ($imported || $format eq 'cch-update');
301 Currently somewhat specific to CCH supplied data.
305 L<FS::Record>, schema.html from the base documentation.