1 package FS::part_pkg_taxproduct;
4 use vars qw( @ISA $delete_kludge );
5 use FS::Record qw( qsearch dbh );
13 FS::part_pkg_taxproduct - Object methods for part_pkg_taxproduct records
17 use FS::part_pkg_taxproduct;
19 $record = new FS::part_pkg_taxproduct \%hash;
20 $record = new FS::part_pkg_taxproduct { 'column' => 'value' };
22 $error = $record->insert;
24 $error = $new_record->replace($old_record);
26 $error = $record->delete;
28 $error = $record->check;
32 An FS::part_pkg_taxproduct object represents a tax product.
33 FS::part_pkg_taxproduct inherits from FS::Record. The following fields are
48 Tax product id from the vendor
52 A human readable description of the id in taxproduct
62 Creates a new tax product. To add the tax product to the database, see L<"insert">.
64 Note that this stores the hash reference, not a distinct copy of the hash it
65 points to. You can ask the object for a copy with the I<hash> method.
69 sub table { 'part_pkg_taxproduct'; }
73 Adds this record to the database. If there is an error, returns the error,
74 otherwise returns false.
80 Delete this record from the database.
87 return "Can't delete a tax product which has attached package tax rates!"
88 if qsearch( 'part_pkg_taxrate', { 'taxproductnum' => $self->taxproductnum } );
90 unless ( $delete_kludge ) {
91 return "Can't delete a tax product which has attached packages!"
92 if qsearch( 'part_pkg', { 'taxproductnum' => $self->taxproductnum } );
95 $self->SUPER::delete(@_);
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 product. If there is
108 an error, returns the error, otherwise returns false. Called by the insert
117 $self->ut_numbern('taxproductnum')
118 || $self->ut_textn('data_vendor')
119 || $self->ut_text('taxproduct')
120 || $self->ut_textn('description')
122 return $error if $error;
127 =item part_pkg_taxrate GEOCODE
129 Returns the L<FS::part_pkg_taxrate> records (tax definitions) that can apply
130 to this tax product category in the location identified by GEOCODE.
134 # actually only returns one arbitrary record for each taxclassnum, making
135 # it useful only for retrieving the taxclassnums
137 sub part_pkg_taxrate {
139 my $data_vendor = $self->data_vendor; # because duh
145 my $extra_sql .= "AND part_pkg_taxrate.data_vendor = '$data_vendor' ".
147 join(' OR ', map{ 'geocode = '. $dbh->quote(substr($geocode, 0, $_)) }
151 # much more CCH oddness in m2m -- this is kludgy
152 my $tpnums = join(',',
153 map { $_->taxproductnum }
154 $self->expand_cch_taxproduct
157 # if there are no taxproductnums, there are no matching tax classes
158 return if length($tpnums) == 0;
160 $extra_sql .= " AND taxproductnum IN($tpnums)";
162 my $addl_from = 'LEFT JOIN part_pkg_taxproduct USING ( taxproductnum )';
163 my $order_by = 'ORDER BY taxclassnum, length(geocode) desc, length(taxproduct) desc';
164 my $select = 'DISTINCT ON(taxclassnum) *, taxproduct';
166 # should qsearch preface columns with the table to facilitate joins?
167 qsearch( { 'table' => 'part_pkg_taxrate',
169 'hashref' => { 'taxable' => 'Y' },
170 'addl_from' => $addl_from,
171 'extra_sql' => $extra_sql,
172 'order_by' => $order_by,
176 =item expand_cch_taxproduct
178 Returns the full set of part_pkg_taxproduct records that are "implied" by
183 sub expand_cch_taxproduct {
187 my ($a,$b,$c,$d) = split ':', $self->taxproduct;
188 $a = '' unless $a; $b = '' unless $b; $c = '' unless $c; $d = '' unless $d;
189 my $taxproducts = join(',',
190 "'${a}:${b}:${c}:${d}'",
196 'table' => 'part_pkg_taxproduct',
197 'hashref' => { 'data_vendor'=>'cch' },
198 'extra_sql' => "AND taxproduct IN($taxproducts)",
208 my ($param, $job) = @_;
210 my $oldAutoCommit = $FS::UID::AutoCommit;
211 local $FS::UID::AutoCommit = 0;
214 my $fh = $param->{filehandle};
215 my $format = $param->{format};
216 die "unsupported part_pkg_taxproduct format '$format'"
217 unless $format eq 'billsoft';
219 # this is slightly silly
221 my $lines = scalar @lines;
225 my $csv = Text::CSV_XS->new;
227 # for importing the "transervdesc.txt" file
228 while ( my $row = $csv->getline($fh) ) {
230 $dbh->rollback if $oldAutoCommit;
231 return "can't parse: ". $csv->error_input();
235 $job->update_statustext(
236 int( 100 * $imported / $lines ) . ',Inserting tax product records'
240 # columns 0-2: irrelevant here
241 my $taxproduct = $row->[3] . ':' . $row->[5];
242 my $description = $row->[4];
243 $description =~ s/\s+$//;
244 $description .= ':' . $row->[6];
245 $description =~ s/\s+$//;
246 my $ppt = qsearchs('part_pkg_taxproduct', {
247 'data_vendor' => 'billsoft',
248 'taxproduct' => $taxproduct
251 $ppt->set('description', $description);
252 $ppt->set('note', $row->[7]);
253 $error = $ppt->replace;
255 $ppt = FS::part_pkg_taxproduct->new({
256 'data_vendor' => 'billsoft',
257 'taxproduct' => $taxproduct,
258 'description' => $description,
261 $error = $ppt->insert;
264 $dbh->rollback if $oldAutoCommit;
265 return "error inserting part_pkg_taxproduct $taxproduct: $error\n";
270 $dbh->commit if $oldAutoCommit;
276 Confusingly named. It has nothing to do with part_pkg.
280 L<FS::Record>, schema.html from the base documentation.