my @errors = ();
- foreach my $cust_pkg ( @cancel_pkgs ) {
+ CUST_PKG: foreach my $cust_pkg ( @cancel_pkgs ) {
my $cpr = $cust_pkg->last_cust_pkg_reason('expire');
- my $error = $cust_pkg->cancel($cpr ? ( 'reason' => $cpr->reasonnum,
+ my $error;
+
+ if ( $cust_pkg->change_to_pkgnum ) {
+
+ my $new_pkg = FS::cust_pkg->by_key($cust_pkg->change_to_pkgnum);
+ if ( !$new_pkg ) {
+ push @errors, 'can\'t change pkgnum '.$cust_pkg->pkgnum.' to pkgnum '.
+ $cust_pkg->change_to_pkgnum.'; not expiring';
+ next CUST_PKG;
+ }
+ $error = $cust_pkg->change( 'cust_pkg' => $new_pkg,
+ 'unprotect_svcs' => 1 );
+ $error = '' if ref $error eq 'FS::cust_pkg';
+
+ } else { # just cancel it
+ $error = $cust_pkg->cancel($cpr ? ( 'reason' => $cpr->reasonnum,
'reason_otaker' => $cpr->otaker,
'time' => $time,
)
: ()
);
+ }
push @errors, 'pkgnum '.$cust_pkg->pkgnum.": $error" if $error;
}
my $time = $options{'time'} || time;
my $invoice_time = $options{'invoice_time'} || $time;
+ my $cmp_time = ( $conf->exists('next-bill-ignore-time')
+ ? day_end( $time )
+ : $time
+ );
+
$options{'not_pkgpart'} ||= {};
$options{'not_pkgpart'} = { map { $_ => 1 }
split(/\s*,\s*/, $options{'not_pkgpart'})
my $next_bill = $cust_pkg->getfield('bill') || 0;
my $error;
# let this run once if this is the last bill upon cancellation
- while ( $next_bill <= $time or $options{cancel} ) {
+ while ( $next_bill <= $cmp_time or $options{cancel} ) {
$error =
$self->_make_lines( 'part_pkg' => $part_pkg,
'cust_pkg' => $cust_pkg,
local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG;
+ my $location = $cust_pkg->tax_location;
+
return if ( $self->payby eq 'COMP' ); #dubious
if ( $conf->exists('enable_taxproducts')
}
- my %tax_cust_bill_pkg = $cust_bill_pkg->disintegrate;
+ my %tax_cust_bill_pkg = $cust_bill_pkg->disintegrate; # grrr
foreach my $key (keys %tax_cust_bill_pkg) {
# $key is "setup", "recur", or a usage class name. ('' is a usage class.)
# $tax_cust_bill_pkg{$key} is a cust_bill_pkg for that component of
# this is the tax identifier, not the taxname
my $taxname = ref( $tax ). ' '. $tax->taxnum;
- $taxname .= ' billpkgnum'. $cust_bill_pkg->billpkgnum;
- # We need to create a separate $taxlisthash entry for each billpkgnum
- # on the invoice, so that cust_bill_pkg_tax_location records will
- # be linked correctly.
-
# $taxlisthash: keys are "setup", "recur", and usage classes.
# Values are arrayrefs, first the tax object (cust_main_county
# or tax_rate) and then any cust_bill_pkg objects that the
if $DEBUG > 2;
next unless $tax_object->can('tax_on_tax');
- foreach my $tot ( $tax_object->tax_on_tax( $self ) ) {
+ foreach my $tot ( $tax_object->tax_on_tax( $location ) ) {
my $totname = ref( $tot ). ' '. $tot->taxnum;
warn "checking $totname which we call ". $tot->taxname. " as applicable\n"
next unless exists( $localtaxlisthash{ $totname } ); # only increase
# existing taxes
warn "adding $totname to taxed taxes\n" if $DEBUG > 2;
- # we're calling taxline() right here? wtf?
+ # calculate the tax amount that the tax_on_tax will apply to
my $hashref_or_error =
$tax_object->taxline( $localtaxlisthash{$tax},
'custnum' => $self->custnum,
return $hashref_or_error
unless ref($hashref_or_error);
+ # and append it to the list of taxable items
$taxlisthash->{ $totname } ||= [ $tot ];
push @{ $taxlisthash->{ $totname } }, $hashref_or_error->{amount};
# because we need to record that fact.
my @loc_keys = qw( district city county state country );
- my $location = $cust_pkg->tax_location;
my %taxhash = map { $_ => $location->$_ } @loc_keys;
$taxhash{'taxclass'} = $part_pkg->taxclass;
local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG;
- my $geocode;
- if ( $cust_pkg->locationnum && $conf->exists('tax-pkg_address') ) {
- $geocode = $cust_pkg->cust_location->geocode('cch');
- } else {
- $geocode = $self->geocode('cch');
- }
+ my $geocode = $cust_pkg->tax_location->geocode('cch');
my @taxes = ();