In conjunction with I<cust_pkg>, if I<custnum_ref> is set to a scalar reference,
the scalar will be updated with the custnum value from the cust_pkg record.
+If I<tax_overrides> is set to a hashref with usage classes as keys and comma
+separated tax class numbers as values, appropriate FS::part_pkg_taxoverride
+records will be inserted.
+
If I<options> is set to a hashref of options, appropriate FS::part_pkg_option
records will be inserted.
}
}
+ warn " inserting part_pkg_taxoverride records" if $DEBUG;
+ my %overrides = %{ $options{'tax_overrides'} || {} };
+ foreach my $usage_class ( keys %overrides ) {
+ my @overrides = (grep "$_", split (',', $overrides{$usage_class}) );
+ my $error = $self->process_m2m (
+ 'link_table' => 'part_pkg_taxoverride',
+ 'target_table' => 'tax_class',
+ 'hashref' => { 'usage_class' => $usage_class },
+ 'params' => \@overrides,
+ );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
warn " inserting pkg_svc records" if $DEBUG;
my $pkg_svc = $options{'pkg_svc'} || {};
foreach my $part_svc ( qsearch('part_svc', {} ) ) {
my $pkg_svc = $options->{'pkg_svc'} || {};
foreach my $part_svc ( qsearch('part_svc', {} ) ) {
my $quantity = $pkg_svc->{$part_svc->svcpart} || 0;
- my $primary_svc = $options->{'primary_svc'} == $part_svc->svcpart ? 'Y' : '';
+ my $primary_svc =
+ ( defined($options->{'primary_svc'})
+ && $options->{'primary_svc'} == $part_svc->svcpart
+ )
+ ? 'Y'
+ : '';
+
my $old_pkg_svc = qsearchs('pkg_svc', {
'pkgpart' => $old->pkgpart,
}
}
+=item categoryname
+
+Returns the package category name, or the empty string if there is no package
+category.
+
+=cut
+
+sub categoryname {
+ my $self = shift;
+ my $pkg_class = $self->pkg_class;
+ $pkg_class
+ ? $pkg_class->categoryname
+ : '';
+}
+
=item classname
Returns the package class name, or the empty string if there is no package
=item bill_part_pkg_link
-Returns the associated part_pkg_link records (see L<FS::part_pkg_link).
+Returns the associated part_pkg_link records (see L<FS::part_pkg_link>).
=cut
=item svc_part_pkg_link
+Returns the associated part_pkg_link records (see L<FS::part_pkg_link>).
+
=cut
sub svc_part_pkg_link {
);
}
-=item part_pkg_taxoverride
+=item part_pkg_taxoverride [ CLASS ]
Returns all associated FS::part_pkg_taxoverride objects (see
-L<FS::part_pkg_taxoverride>).
+L<FS::part_pkg_taxoverride>). Limits the returned set to those
+of class CLASS if defined. Class may be one of 'setup', 'recur',
+the empty string (default), or a usage class number (see L<FS::usage_class>).
+When a class is specified, the empty string class (default) is returned
+if no more specific values exist.
=cut
sub part_pkg_taxoverride {
my $self = shift;
- qsearch('part_pkg_taxoverride', { 'pkgpart' => $self->pkgpart } );
+ my $class = shift;
+
+ my $hashref = { 'pkgpart' => $self->pkgpart };
+ $hashref->{'usage_class'} = $class if defined($class);
+ my @overrides = qsearch('part_pkg_taxoverride', $hashref );
+
+ unless ( scalar(@overrides) || !defined($class) || !$class ){
+ $hashref->{'usage_class'} = '';
+ @overrides = qsearch('part_pkg_taxoverride', $hashref );
+ }
+
+ @overrides;
}
-=item taxproduct_description
+=item has_taxproduct
+
+Returns true if this package has any taxproduct associated with it.
+
+=cut
+
+sub has_taxproduct {
+ my $self = shift;
+
+ $self->taxproductnum ||
+ scalar(grep { $_ =~/^usage_taxproductnum_/ } keys %{ {$self->options} } )
+
+}
+
+
+=item taxproduct [ CLASS ]
+
+Returns the associated tax product for this package definition (see
+L<FS::part_pkg_taxproduct>). CLASS may be one of 'setup', 'recur' or
+the usage classnum (see L<FS::usage_class>). Returns the default
+tax product for this record if the more specific CLASS value does
+not exist.
+
+=cut
+
+sub taxproduct {
+ my $self = shift;
+ my $class = shift;
+
+ my $part_pkg_taxproduct;
+
+ my $taxproductnum = $self->taxproductnum;
+ if ($class) {
+ my $class_taxproductnum = $self->option("usage_taxproductnum_$class", 1);
+ $taxproductnum = $class_taxproductnum
+ if $class_taxproductnum
+ }
+
+ $part_pkg_taxproduct =
+ qsearchs( 'part_pkg_taxproduct', { 'taxproductnum' => $taxproductnum } );
+
+ unless ($part_pkg_taxproduct || $taxproductnum eq $self->taxproductnum ) {
+ $taxproductnum = $self->taxproductnum;
+ $part_pkg_taxproduct =
+ qsearchs( 'part_pkg_taxproduct', { 'taxproductnum' => $taxproductnum } );
+ }
+
+ $part_pkg_taxproduct;
+}
+
+=item taxproduct_description [ CLASS ]
Returns the description of the associated tax product for this package
definition (see L<FS::part_pkg_taxproduct>).
sub taxproduct_description {
my $self = shift;
- my $part_pkg_taxproduct =
- qsearchs( 'part_pkg_taxproduct',
- { 'taxproductnum' => $self->taxproductnum }
- );
+ my $part_pkg_taxproduct = $self->taxproduct(@_);
$part_pkg_taxproduct ? $part_pkg_taxproduct->description : '';
}
-=item part_pkg_taxrate DATA_PROVIDER, GEOCODE
+=item part_pkg_taxrate DATA_PROVIDER, GEOCODE, [ CLASS ]
Returns the package to taxrate m2m records for this package in the location
-specified by GEOCODE (see L<FS::part_pkg_taxrate> and ).
+specified by GEOCODE (see L<FS::part_pkg_taxrate>) and usage class CLASS.
+CLASS may be one of 'setup', 'recur', or one of the usage classes numbers
+(see L<FS::usage_class>).
=cut
sub _expand_cch_taxproductnum {
my $self = shift;
- my $part_pkg_taxproduct =
- qsearchs( 'part_pkg_taxproduct',
- { 'taxproductnum' => $self->taxproductnum }
- );
+ my $class = shift;
+ my $part_pkg_taxproduct = $self->taxproduct($class);
+
my ($a,$b,$c,$d) = ( $part_pkg_taxproduct
? ( split ':', $part_pkg_taxproduct->taxproduct )
: ()
);
+ $a = '' unless $a; $b = '' unless $b; $c = '' unless $c; $d = '' unless $d;
my $extra_sql = "AND ( taxproduct = '$a:$b:$c:$d'
OR taxproduct = '$a:$b:$c:'
OR taxproduct = '$a:$b:".":$d'
sub part_pkg_taxrate {
my $self = shift;
- my ($data_vendor, $geocode) = @_;
+ my ($data_vendor, $geocode, $class) = @_;
my $dbh = dbh;
my $extra_sql = 'WHERE part_pkg_taxproduct.data_vendor = '.
).
')';
# much more CCH oddness in m2m -- this is kludgy
+ my @tpnums = $self->_expand_cch_taxproductnum($class);
$extra_sql .= ' AND ('.
- join(' OR ', map{ "taxproductnum = $_" } $self->_expand_cch_taxproductnum).
- ')';
+ join(' OR ', map{ "taxproductnum = $_" } @tpnums ).
+ ')'
+ if @tpnums;
my $addl_from = 'LEFT JOIN part_pkg_taxproduct USING ( taxproductnum )';
my $order_by = 'ORDER BY taxclassnum, length(geocode) desc, length(taxproduct) desc';
=cut
+#false laziness w/part_export & cdr
my %info;
foreach my $INC ( @INC ) {
warn "globbing $INC/FS/part_pkg/*.pm\n" if $DEBUG;
next;
}
unless ( keys %$info ) {
- warn "no %info hash found in FS::part_pkg::$mod, skipping\n"
- unless $mod =~ /^(passwdfile|null)$/; #hack but what the heck
+ warn "no %info hash found in FS::part_pkg::$mod, skipping\n";
next;
}
warn "got plan info from FS::part_pkg::$mod: $info\n" if $DEBUG;
}
tie %plans, 'Tie::IxHash',
- map { $_ => $info{$_} }
+ map { $_ => $info{$_} }
sort { $info{$a}->{'weight'} <=> $info{$b}->{'weight'} }
keys %info;