X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=FS%2FFS%2Fcust_pkg.pm;h=cbe3411c9e8e2fb0242351ba9cd485c1bf1ffc3c;hb=2266af65988c1fa5b849dc3c617c3f642601f867;hp=3c9eab85fb346e122265111e90260bc763949a36;hpb=0b5ea482d5cb6685d3866a8940dc90eb6e8157cf;p=freeside.git diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 3c9eab85f..cbe3411c9 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -791,12 +791,22 @@ to a different pkgpart or location, and probably shouldn't be in any other case. If it's not set, the 'unused_credit_cancel' part_pkg option will be used. +=item no_delay_cancel - prevents delay_cancel behavior +no matter what other options say, for use when changing packages (or any +other time you're really sure you want an immediate cancel) + =back If there is an error, returns the error, otherwise returns false. =cut +#NOT DOCUMENTING - this should only be used when calling recursively +#=item delay_cancel - for internal use, to allow proper handling of +#supplemental packages when the main package is flagged to suspend +#before cancelling, probably shouldn't be used otherwise (set the +#corresponding package option instead) + sub cancel { my( $self, %options ) = @_; my $error; @@ -837,6 +847,21 @@ sub cancel { my $date = $options{'date'} if $options{'date'}; # expire/cancel later $date = '' if ($date && $date <= $cancel_time); # complain instead? + my $delay_cancel = $options{'no_delay_cancel'} ? 0 : $options{'delay_cancel'}; + if ( !$date && $self->part_pkg->option('delay_cancel',1) + && (($self->status eq 'active') || ($self->status eq 'suspended')) + && !$options{'no_delay_cancel'} + ) { + my $expdays = $conf->config('part_pkg-delay_cancel-days') || 1; + my $expsecs = 60*60*24*$expdays; + my $suspfor = $self->susp ? $cancel_time - $self->susp : 0; + $expsecs = $expsecs - $suspfor if $suspfor; + unless ($expsecs <= 0) { #if it's already been suspended long enough, don't re-suspend + $delay_cancel = 1; + $date = $cancel_time + $expsecs; + } + } + #race condition: usage could be ongoing until unprovisioned #resolved by performing a change package instead (which unprovisions) and #later cancelling @@ -901,12 +926,16 @@ sub cancel { return $error; } } - } #unless $date my %hash = $self->hash; if ( $date ) { $hash{'expire'} = $date; + if ($delay_cancel) { + # just to be sure these are clear + $hash{'adjourn'} = undef; + $hash{'resume'} = undef; + } } else { $hash{'cancel'} = $cancel_time; } @@ -922,7 +951,7 @@ sub cancel { $error = $new->replace( $self, options => { $self->options } ); if ( $self->change_to_pkgnum ) { my $change_to = FS::cust_pkg->by_key($self->change_to_pkgnum); - $error ||= $change_to->cancel || $change_to->delete; + $error ||= $change_to->cancel('no_delay_cancel' => 1) || $change_to->delete; } if ( $error ) { $dbh->rollback if $oldAutoCommit; @@ -930,18 +959,31 @@ sub cancel { } 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"; + } } } @@ -1255,6 +1297,9 @@ separately. =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. @@ -1304,7 +1349,7 @@ sub suspend { } # 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 @@ -1369,17 +1414,19 @@ sub suspend { 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; + } } } @@ -1410,7 +1457,7 @@ sub suspend { } 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), @@ -2188,6 +2235,7 @@ sub change { unused_credit => $unused_credit, nobill => $keep_dates, change_custnum => ( $self->custnum != $custnum ? $custnum : '' ), + no_delay_cancel => 1, ); if ($error) { $dbh->rollback if $oldAutoCommit; @@ -2285,7 +2333,7 @@ sub change_later { $error = $self->replace || $err_or_pkg->replace || - $change_to->cancel || + $change_to->cancel('no_delay_cancel' => 1) || $change_to->delete; } else { $error = $err_or_pkg; @@ -3367,6 +3415,34 @@ sub statuscolor { $statuscolor{$self->status}; } +=item is_status_delay_cancel + +Returns true if part_pkg has option delay_cancel, +cust_pkg status is 'suspended' and expire is set +to cancel package within the next day (or however +many days are set in global config part_pkg-delay_cancel-days. + +This is not a real status, this only meant for hacking display +values, because otherwise treating the package as suspended is +really the whole point of the delay_cancel option. + +=cut + +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; + my $conf = new FS::Conf; + my $expdays = $conf->config('part_pkg-delay_cancel-days') || 1; + my $expsecs = 60*60*24*$expdays; + return 0 unless $self->expire < time + $expsecs; + return 1; +} + =item pkg_label Returns a label for this package. (Currently "pkgnum: pkg - comment" or @@ -5429,7 +5505,7 @@ sub order { $dbh->rollback if $oldAutoCommit; return "Unable to transfer all services from package ".$old_pkg->pkgnum; } - $error = $old_pkg->cancel( quiet=>1 ); + $error = $old_pkg->cancel( quiet=>1, 'no_delay_cancel'=>1 ); if ($error) { $dbh->rollback; return $error;