1 package FS::part_pkg_taxrate;
7 use FS::Record qw( qsearch qsearchs );
8 use FS::part_pkg_taxproduct;
10 @ISA = qw(FS::Record);
14 FS::part_pkg_taxrate - Object methods for part_pkg_taxrate records
18 use FS::part_pkg_taxrate;
20 $record = new FS::part_pkg_taxrate \%hash;
21 $record = new FS::part_pkg_taxrate { 'column' => 'value' };
23 $error = $record->insert;
25 $error = $new_record->replace($old_record);
27 $error = $record->delete;
29 $error = $record->check;
33 An FS::part_pkg_taxrate object maps packages onto tax rates.
34 FS::part_pkg_taxrate inherits from FS::Record. The following fields are
49 Tax vendor location code
53 Class of package for tax purposes, Index into FS::part_pkg_taxproduct
77 Class of tax index into FS::tax_taxclass and FS::tax_rate
79 =item taxclassnumtaxed
81 Class of tax taxed by this entry.
99 Creates a new customer (location), package, tax rate mapping. To add the
100 mapping to the database, see L<"insert">.
102 Note that this stores the hash reference, not a distinct copy of the hash it
103 points to. You can ask the object for a copy with the I<hash> method.
107 sub table { 'part_pkg_taxrate'; }
111 Adds this record to the database. If there is an error, returns the error,
112 otherwise returns false.
118 Delete this record from the database.
122 =item replace OLD_RECORD
124 Replaces the OLD_RECORD with this one in the database. If there is an error,
125 returns the error, otherwise returns false.
131 Checks all fields to make sure this is a valid tax rate mapping. If there is
132 an error, returns the error, otherwise returns false. Called by the insert
141 $self->ut_numbern('pkgtaxratenum')
142 || $self->ut_textn('data_vendor')
143 || $self->ut_textn('geocode')
145 ut_foreign_key('taxproductnum', 'part_pkg_taxproduct', 'taxproductnum')
146 || $self->ut_textn('city')
147 || $self->ut_textn('county')
148 || $self->ut_textn('state')
149 || $self->ut_textn('local')
150 || $self->ut_text('country')
151 || $self->ut_foreign_keyn('taxclassnumtaxed', 'tax_class', 'taxclassnum')
152 || $self->ut_foreign_key('taxclassnum', 'tax_class', 'taxclassnum')
153 || $self->ut_numbern('effective_date')
154 || $self->ut_enum('taxable', [ 'Y', '' ])
156 return $error if $error;
163 Loads part_pkg_taxrate records from an external CSV file. If there is
164 an error, returns the error, otherwise returns false.
171 my $fh = $param->{filehandle};
172 my $format = $param->{'format'};
176 if ( $format eq 'cch' ) {
177 @fields = qw( city county state local geocode group groupdesc item
178 itemdesc provider customer taxtypetaxed taxcattaxed
179 taxable taxtype taxcat effdate rectype );
184 unless ( $hash->{'rectype'} eq 'R' or $hash->{'rectype'} eq 'T' ) {
185 delete($hash->{$_}) for (keys %$hash);
189 my %providers = ( '00' => 'Regulated LEC',
190 '01' => 'Regulated IXC',
191 '02' => 'Unregulated LEC',
192 '03' => 'Unregulated IXC',
197 my %customers = ( '00' => 'Residential',
198 '01' => 'Commercial',
199 '02' => 'Industrial',
201 '10' => 'Senior Citizen',
205 join(':', map{ $hash->{$_} } qw(group item provider customer ) );
207 my %part_pkg_taxproduct = ( 'data_vendor' => 'cch',
208 'taxproduct' => $taxproduct,
211 my $part_pkg_taxproduct = qsearchs( 'part_pkg_taxproduct',
212 { %part_pkg_taxproduct }
214 unless ($part_pkg_taxproduct) {
215 $part_pkg_taxproduct{'description'} =
216 join(' : ', map{ $hash->{$_} } qw(groupdesc itemdesc),
217 $providers{$hash->{'provider'}} || 'Unknown',
218 $customers{$hash->{'customer'}} || 'Unknown',
220 $part_pkg_taxproduct = new FS::part_pkg_taxproduct \%part_pkg_taxproduct;
221 my $error = $part_pkg_taxproduct->insert;
222 return "Error inserting tax product (part_pkg_taxproduct): $error"
226 $hash->{'taxproductnum'} = $part_pkg_taxproduct->taxproductnum;
229 for qw(group groupdesc item itemdesc provider customer rectype );
231 my %map = ( 'taxclassnum' => [ 'taxtype', 'taxcat' ],
232 'taxclassnumtaxed' => [ 'taxtypetaxed', 'taxcattaxed' ],
235 for my $item (keys %map) {
237 qsearchs( 'tax_class',
238 { data_vendor => 'cch',
239 'taxclass' => join(':', map($hash->{$_}, @{$map{$item}})),
242 $hash->{$item} = $tax_class->taxclassnum
245 delete($hash->{$_}) foreach @{$map{$item}};
248 $hash->{'effdate'} = str2time($hash->{'effdate'});
250 $hash->{'effdate'} = str2time($hash->{'effdate'});
251 $hash->{'country'} = 'US'; # CA is available
253 delete($hash->{'taxable'}) if ($hash->{'taxable'} eq 'N');
258 } elsif ( $format eq 'extended' ) {
259 die "unimplemented\n";
263 die "unknown format $format";
266 eval "use Text::CSV_XS;";
269 my $csv = new Text::CSV_XS;
273 local $SIG{HUP} = 'IGNORE';
274 local $SIG{INT} = 'IGNORE';
275 local $SIG{QUIT} = 'IGNORE';
276 local $SIG{TERM} = 'IGNORE';
277 local $SIG{TSTP} = 'IGNORE';
278 local $SIG{PIPE} = 'IGNORE';
280 my $oldAutoCommit = $FS::UID::AutoCommit;
281 local $FS::UID::AutoCommit = 0;
285 while ( defined($line=<$fh>) ) {
286 $csv->parse($line) or do {
287 $dbh->rollback if $oldAutoCommit;
288 return "can't parse: ". $csv->error_input();
291 my @columns = $csv->fields();
293 my %part_pkg_taxrate = ( 'data_vendor' => $format );
294 foreach my $field ( @fields ) {
295 $part_pkg_taxrate{$field} = shift @columns;
297 my $error = &{$hook}(\%part_pkg_taxrate);
299 $dbh->rollback if $oldAutoCommit;
302 next unless scalar(keys %part_pkg_taxrate);
305 my $part_pkg_taxrate = new FS::part_pkg_taxrate( \%part_pkg_taxrate );
306 $error = $part_pkg_taxrate->insert;
309 $dbh->rollback if $oldAutoCommit;
310 return "can't insert part_pkg_taxrate for $line: $error";
316 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
318 return "Empty file!" unless $imported;
330 L<FS::Record>, schema.html from the base documentation.