RT#14671: Usage for current day when billing outstanding usage (for cancelling customers)
authorJonathan Prykop <jonathan@freeside.biz>
Tue, 10 Feb 2015 20:18:31 +0000 (14:18 -0600)
committerJonathan Prykop <jonathan@freeside.biz>
Tue, 10 Feb 2015 20:18:31 +0000 (14:18 -0600)
FS/FS/Conf.pm
FS/FS/cust_main.pm
FS/FS/cust_pkg.pm
FS/FS/part_pkg/global_Mixin.pm
httemplate/view/cust_main/misc.html

index a4e26f7..091070e 100644 (file)
@@ -4627,6 +4627,16 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'part_pkg-delay_cancel-days',
+    'section'     => '',
+    'description' => 'Expire packages in this many days when using delay_cancel (default is 1)',
+    'type'        => 'text',
+    'validate'    => sub { (($_[0] =~ /^\d*$/) && (($_[0] eq '') || $_[0]))
+                           ? 'Must specify an integer number of days'
+                           : '' }
+  },
+
+  {
     'key'         => 'mcp_svcpart',
     'section'     => '',
     'description' => 'Master Control Program svcpart.  Leave this blank.',
index d38f3d0..c3b141e 100644 (file)
@@ -3900,6 +3900,27 @@ sub cust_status {
   }
 }
 
+=item is_status_delay_cancel
+
+Returns true if customer status is 'suspended'
+and all suspended cust_pkg return true for
+cust_pkg->is_status_delay_cancel.
+
+This is not a real status, this only meant for hacking display 
+values, because otherwise treating the customer as suspended is 
+really the whole point of the delay_cancel option.
+
+=cut
+
+sub is_status_delay_cancel {
+  my ($self) = @_;
+  return 0 unless $self->status eq 'suspended';
+  foreach my $cust_pkg ($self->ncancelled_pkgs) {
+    return 0 unless $cust_pkg->is_status_delay_cancel;
+  }
+  return 1;
+}
+
 =item ucfirst_cust_status
 
 =item ucfirst_status
index 56e4c90..1cc83b6 100644 (file)
@@ -823,6 +823,20 @@ sub cancel {
   my $date = $options{'date'} if $options{'date'}; # expire/cancel later
   $date = '' if ($date && $date <= $cancel_time);      # complain instead?
 
+  my $delay_cancel = undef;
+  if ( !$date && $self->part_pkg->option('delay_cancel',1)
+       && (($self->status eq 'active') || ($self->status eq 'suspended'))
+  ) {
+    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
@@ -893,6 +907,11 @@ sub cancel {
   my %hash = $self->hash;
   if ( $date ) {
     $hash{'expire'} = $date;
+    if ($delay_cancel) {
+      $hash{'susp'} = $cancel_time unless $self->susp;
+      $hash{'adjourn'} = undef;
+      $hash{'resume'} = undef;
+    }
   } else {
     $hash{'cancel'} = $cancel_time;
   }
@@ -3343,6 +3362,31 @@ 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) = @_;
+  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
index 2637729..2318c3e 100644 (file)
@@ -40,6 +40,10 @@ tie my %a2billing_simultaccess, 'Tie::IxHash', (
                 'changing packages',
       'type' => 'checkbox',
     },
+    'delay_cancel' => {
+      'name' => 'Automatically suspend for one day before cancelling',
+      'type' => 'checkbox',
+    },
 
     # miscellany--maybe put this in a separate module?
 
@@ -109,6 +113,7 @@ tie my %a2billing_simultaccess, 'Tie::IxHash', (
     unused_credit_cancel
     unused_credit_suspend
     unused_credit_change
+    delay_cancel
 
     a2billing_tariff
     a2billing_type
index 15def32..fe0e329 100644 (file)
@@ -7,7 +7,7 @@
 
 <TR>
   <TD ALIGN="right"><% mt('Status') |h %></TD>
-  <TD BGCOLOR="#ffffff"><FONT COLOR="#<% $cust_main->statuscolor %>"><B><% $cust_main->status_label %></B></FONT></TD>
+  <TD BGCOLOR="#ffffff"><FONT COLOR="#<% $cust_main->statuscolor %>"><B><% $status_label %></B></FONT></TD>
 </TR>
 
 % my @part_tag = $cust_main->part_tag;
@@ -204,4 +204,9 @@ my $curuser = $FS::CurrentUser::CurrentUser;
 
 my @agentnums = $curuser->agentnums;
 
+my $status_label = $cust_main->status_label;
+if ($cust_main->is_status_delay_cancel) {
+  $status_label .= ' (Cancelled)';
+}
+
 </%init>