|| $self->ut_numbern('susp')
|| $self->ut_numbern('cancel')
|| $self->ut_numbern('adjourn')
+ || $self->ut_numbern('resume')
|| $self->ut_numbern('expire')
|| $self->ut_numbern('dundate')
|| $self->ut_enum('no_auto', [ '', 'Y' ])
return "A package with both start date (future start) and setup date (already started) will never bill"
if $self->start_date && $self->setup;
+ return "A future unsuspend date can only be set for a package with a suspend date"
+ if $self->resume and !$self->susp and !$self->adjourn;
+
$self->usernum($FS::CurrentUser::CurrentUser->usernum) unless $self->usernum;
if ( $self->dbdef_table->column('manual_flag') ) {
$do_credit = $self->part_pkg->option('unused_credit_cancel', 1);
}
if ( $do_credit ) {
- my $error = $self->credit_remaining($cancel_time);
+ my $error = $self->credit_remaining('cancel', $cancel_time);
if ($error) {
$dbh->rollback if $oldAutoCommit;
return $error;
=over 4
-=item reason - can be set to a cancellation reason (see L<FS:reason>), either a reasonnum of an existing reason, or passing a hashref will create a new reason. The hashref should have the following keys: typenum - Reason type (see L<FS::reason_type>, reason - Text of the new reason.
+=item reason - can be set to a cancellation reason (see L<FS:reason>),
+either a reasonnum of an existing reason, or passing a hashref will create
+a new reason. The hashref should have the following keys:
+- typenum - Reason type (see L<FS::reason_type>
+- reason - Text of the new reason.
+
+=item date - can be set to a unix style timestamp to specify when to
+suspend (adjourn)
+
+=item time - can be set to override the current time, for calculation
+of final invoices or unused-time credits
-=item date - can be set to a unix style timestamp to specify when to suspend (adjourn)
+=item resume_date - can be set to a time when the package should be
+unsuspended. This may be more convenient than calling C<unsuspend()>
+separately.
=back
my $suspend_time = $options{'time'} || time;
my $date = $options{date} if $options{date}; # adjourn/suspend later
- $date = '' if ($date && $date <= time); # complain instead?
+ $date = '' if ($date && $date <= $suspend_time); # complain instead?
if ( $date && $old->get('expire') && $old->get('expire') < $date ) {
dbh->rollback if $oldAutoCommit;
} else {
$hash{'susp'} = $suspend_time;
}
+
+ my $resume_date = $options{'resume_date'} || 0;
+ if ( $resume_date > ($date || $suspend_time) ) {
+ $hash{'resume'} = $resume_date;
+ }
+
my $new = new FS::cust_pkg ( \%hash );
$error = $new->replace( $self, options => { $self->options } );
if ( $error ) {
unless ( $date ) {
# credit remaining time if appropriate
if ( $self->part_pkg->option('unused_credit_suspend', 1) ) {
- my $error = $self->credit_remaining($suspend_time);
+ my $error = $self->credit_remaining('suspend', $suspend_time);
if ($error) {
$dbh->rollback if $oldAutoCommit;
return $error;
''; #no errors
}
+=item credit_remaining MODE TIME
+
+Generate a credit for this package for the time remaining in the current
+billing period. MODE is either "suspend" or "cancel" (determines the
+credit type). TIME is the time of suspension/cancellation. Both arguments
+are mandatory.
+
+=cut
+
sub credit_remaining {
# Add a credit for remaining service
- my $self = shift;
- my $time = shift or die 'no suspend/cancel time';
+ my ($self, $mode, $time) = @_;
+ die 'credit_remaining requires suspend or cancel'
+ unless $mode eq 'suspend' or $mode eq 'cancel';
+ die 'no suspend/cancel time' unless $time > 0;
+
my $conf = FS::Conf->new;
+ my $reason_type = $conf->config($mode.'_credit_type');
+
my $last_bill = $self->getfield('last_bill') || 0;
my $next_bill = $self->getfield('bill') || 0;
if ( $last_bill > 0 # the package has been billed
my $error = $self->cust_main->credit(
$remaining_value,
'Credit for unused time on '. $self->part_pkg->pkg,
- 'reason_type' => $conf->config('cancel_credit_type'),
- ); # need 'suspend_credit_type'?
+ 'reason_type' => $reason_type,
+ );
return "Error crediting customer \$$remaining_value for unused time".
" on ". $self->part_pkg->pkg. ": $error"
if $error;
=over 4
+=item date
+
+Can be set to a date to unsuspend the package in the future (the 'resume'
+field).
+
=item adjust_next_bill
Can be set true to adjust the next bill date forward by
my $pkgnum = $old->pkgnum;
if ( $old->get('cancel') || $self->get('cancel') ) {
- dbh->rollback if $oldAutoCommit;
+ $dbh->rollback if $oldAutoCommit;
return "Can't unsuspend cancelled package $pkgnum";
}
unless ( $old->get('susp') && $self->get('susp') ) {
- dbh->rollback if $oldAutoCommit;
+ $dbh->rollback if $oldAutoCommit;
return ""; # no error # complain instead?
}
+ my $date = $opt{'date'};
+ if ( $date and $date > time ) { # return an error if $date <= time?
+
+ if ( $old->get('expire') && $old->get('expire') < $date ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Package $pkgnum expires before it would be unsuspended.";
+ }
+
+ my $new = new FS::cust_pkg { $self->hash };
+ $new->set('resume', $date);
+ $error = $new->replace($self, options => $self->options);
+
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ else {
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ return '';
+ }
+
+ } #if $date
+
foreach my $cust_svc (
qsearch('cust_svc',{'pkgnum'=> $self->pkgnum } )
) {
}
$hash{'susp'} = '';
- $hash{'adjourn'} = '' if $hash{'adjourn'} < time;
+ $hash{'adjourn'} = '' if $hash{'adjourn'} and $hash{'adjourn'} < time;
+ $hash{'resume'} = '' if !$hash{'adjourn'};
my $new = new FS::cust_pkg ( \%hash );
$error = $new->replace( $self, options => { $self->options } );
if ( $error ) {
my %hash = $self->hash;
$hash{'adjourn'} = '';
+ $hash{'resume'} = '';
my $new = new FS::cust_pkg ( \%hash );
$error = $new->replace( $self, options => { $self->options } );
if ( $error ) {
if ( $keep_dates ) {
foreach my $date ( qw(setup bill last_bill susp adjourn cancel expire
- start_date contract_end ) ) {
+ resume start_date contract_end ) ) {
$hash{$date} = $self->getfield($date);
}
}
} elsif ( @c_where ) {
push @where, ' ( '. join(' OR ', @c_where). ' ) ';
}
- warn $where[-1];
}
$params->{'cust_fields'}
),
),
- 'extra_sql' => "$extra_sql $orderby",
+ 'extra_sql' => $extra_sql,
+ 'order_by' => $orderby,
'addl_from' => $addl_from,
'count_query' => $count_query,
};