|| $self->ut_numbern('resume')
|| $self->ut_numbern('expire')
|| $self->ut_numbern('dundate')
- || $self->ut_enum('no_auto', [ '', 'Y' ])
- || $self->ut_enum('waive_setup', [ '', 'Y' ])
+ || $self->ut_flag('no_auto', [ '', 'Y' ])
+ || $self->ut_flag('waive_setup', [ '', 'Y' ])
+ || $self->ut_flag('separate_bill')
|| $self->ut_textn('agent_pkgid')
|| $self->ut_enum('recur_show_zero', [ '', 'Y', 'N', ])
|| $self->ut_enum('setup_show_zero', [ '', 'Y', 'N', ])
case. If it's not set, the 'unused_credit_cancel' part_pkg option will
be used.
+=item delay_cancel - for internal use, to allow proper handling of
+supplemental packages when the main package is flagged to suspend
+before cancelling
+
=back
If there is an error, returns the error, otherwise returns false.
my $date = $options{'date'} if $options{'date'}; # expire/cancel later
$date = '' if ($date && $date <= $cancel_time); # complain instead?
- my $delay_cancel = undef;
+ my $delay_cancel = $options{'delay_cancel'};
if ( !$date && $self->part_pkg->option('delay_cancel',1)
&& (($self->status eq 'active') || ($self->status eq 'suspended'))
) {
return $error;
}
}
-
} #unless $date
my %hash = $self->hash;
if ( $date ) {
$hash{'expire'} = $date;
if ($delay_cancel) {
- $hash{'susp'} = $cancel_time unless $self->susp;
+ # just to be sure these are clear
$hash{'adjourn'} = undef;
$hash{'resume'} = undef;
}
}
foreach my $supp_pkg ( $self->supplemental_pkgs ) {
- $error = $supp_pkg->cancel(%options, 'from_main' => 1);
+ $error = $supp_pkg->cancel(%options,
+ 'from_main' => 1,
+ 'date' => $date, #in case it got changed by delay_cancel
+ 'delay_cancel' => $delay_cancel,
+ );
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return "canceling supplemental pkg#".$supp_pkg->pkgnum.": $error";
}
}
- foreach my $usage ( $self->cust_pkg_usage ) {
- $error = $usage->delete;
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return "deleting usage pools: $error";
+ if ($delay_cancel && !$options{'from_main'}) {
+ $error = $new->suspend(
+ 'from_cancel' => 1,
+ 'time' => $cancel_time
+ );
+ }
+
+ unless ($date) {
+ foreach my $usage ( $self->cust_pkg_usage ) {
+ $error = $usage->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "deleting usage pools: $error";
+ }
}
}
setup
susp adjourn resume expire start_date contract_end dundate
change_date change_pkgpart change_locationnum
- manual_flag no_auto quantity agent_pkgid recur_show_zero setup_show_zero
+ manual_flag no_auto separate_bill quantity agent_pkgid
+ recur_show_zero setup_show_zero
),
};
=item from_main - allows a supplemental package to be suspended, rather
than redirecting the method call to its main package. For internal use.
+=item from_cancel - used when suspending from the cancel method, forces
+this to skip everything besides basic suspension. For internal use.
+
=back
If there is an error, returns the error, otherwise returns false.
}
# some false laziness with sub cancel
- if ( !$options{nobill} && !$date &&
+ if ( !$options{nobill} && !$date && !$options{'from_cancel'} &&
$self->part_pkg->option('bill_suspend_as_cancel',1) ) {
# kind of a kludge--'bill_suspend_as_cancel' to avoid having to
# make the entire cust_main->bill path recognize 'suspend' and
unless ( $date ) { # then we are suspending now
- # credit remaining time if appropriate
- # (if required by the package def, or the suspend reason)
- my $unused_credit = $self->part_pkg->option('unused_credit_suspend',1)
- || ( defined($reason) && $reason->unused_credit );
+ unless ($options{'from_cancel'}) {
+ # credit remaining time if appropriate
+ # (if required by the package def, or the suspend reason)
+ my $unused_credit = $self->part_pkg->option('unused_credit_suspend',1)
+ || ( defined($reason) && $reason->unused_credit );
- if ( $unused_credit ) {
- warn "crediting unused time on pkg#".$self->pkgnum."\n" if $DEBUG;
- my $error = $self->credit_remaining('suspend', $suspend_time);
- if ($error) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
+ if ( $unused_credit ) {
+ warn "crediting unused time on pkg#".$self->pkgnum."\n" if $DEBUG;
+ my $error = $self->credit_remaining('suspend', $suspend_time);
+ if ($error) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
}
}
}
my $conf = new FS::Conf;
- if ( $conf->config('suspend_email_admin') ) {
+ if ( $conf->config('suspend_email_admin') && !$options{'from_cancel'} ) {
my $error = send_email(
'from' => $conf->config('invoice_from', $self->cust_main->agentnum),
and ! $self->option('no_suspend_bill',1)
)
or $hash{'order_date'} == $hash{'susp'}
- or $self->part_pkg->option('unused_credit_suspend')
- or ( ref($reason) and $reason->unused_credit )
) {
$adjust_bill = 0;
}
- # then add the length of time suspended to the bill date
if ( $adjust_bill ) {
- $hash{'bill'} = ( $hash{'bill'} || $hash{'setup'} ) + $inactive
+ if ( $self->part_pkg->option('unused_credit_suspend')
+ or ( ref($reason) and $reason->unused_credit ) ) {
+ # then the customer was credited for the unused time before suspending,
+ # so their next bill should be immediate
+ $hash{'bill'} = time;
+ } else {
+ # add the length of time suspended to the bill date
+ $hash{'bill'} = ( $hash{'bill'} || $hash{'setup'} ) + $inactive;
+ }
}
$hash{'susp'} = '';
- start_date: the date when it will be billed
- amount: the setup fee to be charged
- quantity: the multiplier for the setup fee
+- separate_bill: whether to put the charge on a separate invoice
If you pass 'adjust_commission' => 1, and the classnum changes, and there are
commission credits linked to this charge, they will be recalculated.
}
if ( !$self->get('setup') ) {
- # not yet billed, so allow amount, setup_cost, quantity and start_date
+ # not yet billed, so allow amount, setup_cost, quantity, start_date,
+ # and separate_bill
if ( exists($opt{'amount'})
and $part_pkg->option('setup_fee') != $opt{'amount'}
$self->set('start_date', $opt{'start_date'});
}
+ if ( exists($opt{'separate_bill'})
+ and $opt{'separate_bill'} ne $self->separate_bill ) {
+
+ $self->set('separate_bill', $opt{'separate_bill'});
+ }
+
} # else simply ignore them; the UI shouldn't allow editing the fields
sub is_status_delay_cancel {
my ($self) = @_;
+ if ( $self->main_pkgnum and $self->pkglinknum ) {
+ return $self->main_pkg->is_status_delay_cancel;
+ }
return 0 unless $self->part_pkg->option('delay_cancel',1);
return 0 unless $self->status eq 'suspended';
return 0 unless $self->expire;