push out event triggered suspensions
authorjeff <jeff>
Fri, 26 Sep 2008 03:54:25 +0000 (03:54 +0000)
committerjeff <jeff>
Fri, 26 Sep 2008 03:54:25 +0000 (03:54 +0000)
FS/FS/AccessRight.pm
FS/FS/Schema.pm
FS/FS/cust_main.pm
FS/FS/part_bill_event.pm
FS/FS/part_event/Condition/dundate.pm [new file with mode: 0644]
httemplate/edit/part_bill_event.cgi
httemplate/misc/delay_susp_pkg.html [new file with mode: 0755]
httemplate/misc/process/delay_susp_pkg.html [new file with mode: 0755]
httemplate/view/cust_main/packages.html

index 9ef3524..b016d18 100644 (file)
@@ -119,6 +119,7 @@ tie my %rights, 'Tie::IxHash',
     'Unsuspend customer package',
     'Cancel customer package immediately',
     'Cancel customer package later',
+    'Delay suspension events',
     'Add on-the-fly cancel reason', #NEW
     'Add on-the-fly suspend reason', #NEW
     'Edit customer package invoice details', #NEW
index b3cce9a..5c9f624 100644 (file)
@@ -605,6 +605,7 @@ sub tables_hashref {
         'stateid_state', 'varchar', 'NULL', $char_d, '', '', 
         'birthdate' ,@date_type, '', '', 
         'signupdate',@date_type, '', '', 
+        'dundate',   @date_type, '', '', 
         'company',  'varchar', 'NULL', $char_d, '', '', 
         'address1', 'varchar', '',     $char_d, '', '', 
         'address2', 'varchar', 'NULL', $char_d, '', '', 
index ec2ac3c..b348aaa 100644 (file)
@@ -227,6 +227,8 @@ Card Verification Value, "CVV2" (also known as CVC2 or CID), the 3 or 4 digit nu
 
 =item spool_cdr - Enable individual CDR spooling, empty or `Y'
 
+=item dundate - a suggestion to events (see L<FS::part_bill_event">) to delay until this unix timestamp
+
 =item squelch_cdr - Discourage individual CDR printing, empty or `Y'
 
 =back
@@ -2976,14 +2978,16 @@ sub due_cust_event {
   # 3: insert
   ##
 
-  foreach my $cust_event ( @cust_event ) {
+  unless( $opt{testonly} ) {
+    foreach my $cust_event ( @cust_event ) {
 
-    my $error = $cust_event->insert();
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      return $error;
-    }
+      my $error = $cust_event->insert();
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
                                        
+    }
   }
 
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
index 1d48af9..4e7aa52 100644 (file)
@@ -5,6 +5,8 @@ use vars qw( @ISA $DEBUG @EXPORT_OK );
 use Carp qw(cluck confess);
 use FS::Record qw( dbh qsearch qsearchs );
 use FS::Conf;
+use FS::cust_main;
+use FS::cust_bill;
 
 @ISA = qw( FS::Record );
 @EXPORT_OK = qw( due_events );
@@ -244,6 +246,9 @@ sub due_events {
   sort {    $a->seconds   <=> $b->seconds
          || $a->weight    <=> $b->weight
         || $a->eventpart <=> $b->eventpart }
+    grep { ref($record) ne 'FS::cust_bill' || $_->eventcode !~ /honor_dundate/
+           || $event_time > $record->cust_main->dundate
+         }
     grep { $_->seconds <= ( $interval )
            && ! qsearch( 'cust_bill_event', {
                           'invnum' => $record->get($record->dbdef_table->primary_key),
diff --git a/FS/FS/part_event/Condition/dundate.pm b/FS/FS/part_event/Condition/dundate.pm
new file mode 100644 (file)
index 0000000..ee2a95f
--- /dev/null
@@ -0,0 +1,26 @@
+package FS::part_event::Condition::dundate;
+
+use strict;
+
+use base qw( FS::part_event::Condition );
+
+sub description {
+  "Skip until customer dun date is reached";
+}
+
+sub condition {
+  my($self, $object, %opt) = @_;
+
+  my $cust_main = $self->cust_main($object);
+
+  $cust_main->dundate <= $opt{time};
+
+}
+
+#sub condition_sql {
+#  my( $self, $table ) = @_;
+#
+#  'true';
+#}
+
+1;
index 8e7b6da..3b51141 100755 (executable)
@@ -96,6 +96,18 @@ Invoice Event #<% $hashref->{eventpart} ? $hashref->{eventpart} : "(NEW)" %>
 %  '</SELECT>';
 %}
 %
+%sub honor_dundate {
+%  my $label = shift;
+%  my $plandata = shift;
+%  '<TABLE>'.
+%  '<TR><TD ALIGN="right">Allow delay until dun date? </TD>'.
+%  qq(<TD><INPUT TYPE="checkbox" NAME="$label" VALUE="$label => 1," ).
+%    ( $plandata->{$label} eq "$label => 1," ? 'CHECKED' : '' ).
+%  '>'.
+%  '</TD></TR>'.
+%  '</TABLE>'
+%}
+%
 %my $conf = new FS::Conf;
 %my $money_char = $conf->config('money_char') || '$';
 %
@@ -137,28 +149,29 @@ Invoice Event #<% $hashref->{eventpart} ? $hashref->{eventpart} : "(NEW)" %>
 %  },
 %  'suspend' => {
 %    'name'   => 'Suspend',
-%    'code'   => '$cust_main->suspend(reason => %%%sreason%%%);',
+%    'code'   => '$cust_main->suspend(reason => %%%sreason%%%, %%%honor_dundate%%% );',
+%    'html'   => sub { &honor_dundate('honor_dundate', @_) },
 %    'weight' => 10,
 %    'reason' => 'S',
 %  },
 %  'suspend-if-balance' => {
 %    'name'   => 'Suspend if balance (this invoice and previous) over',
-%    'code'   => '$cust_bill->cust_suspend_if_balance_over( %%%balanceover%%%, reason => %%%sreason%%%, );',
-%    'html'   => " $money_char ". '<INPUT TYPE="text" SIZE="7" NAME="balanceover" VALUE="%%%balanceover%%%">',
+%    'code'   => '$cust_bill->cust_suspend_if_balance_over( %%%balanceover%%%, reason => %%%sreason%%%, %%%balance_honor_dundate%%% );',
+%    'html'   => sub { " $money_char ". '<INPUT TYPE="text" SIZE="7" NAME="balanceover" VALUE="%%%balanceover%%%"> '. &honor_dundate('balance_honor_dundate', @_) },
 %    'weight' => 10,
 %    'reason' => 'S',
 %  },
 %  'suspend-if-pkgpart' => {
 %    'name'   => 'Suspend packages',
-%    'code'   => '$cust_main->suspend_if_pkgpart({pkgparts => [%%%if_pkgpart%%%,], reason => %%%sreason%%%,});',
-%    'html'   => sub { &select_pkgpart('if_pkgpart', @_) },
+%    'code'   => '$cust_main->suspend_if_pkgpart({pkgparts => [%%%if_pkgpart%%%,], reason => %%%sreason%%%, %%%if_pkgpart_honor_dundate%%% });',
+%    'html'   => sub { &select_pkgpart('if_pkgpart', @_). &honor_dundate('if_pkgpart_honor_dundate', @_) },
 %    'weight' => 10,
 %    'reason' => 'S',
 %  },
 %  'suspend-unless-pkgpart' => {
 %    'name'   => 'Suspend packages except',
-%    'code'   => '$cust_main->suspend_unless_pkgpart({unless_pkgpart => [%%%unless_pkgpart%%%], reason => %%%sreason%%%,});',
-%    'html'   => sub { &select_pkgpart('unless_pkgpart', @_) },
+%    'code'   => '$cust_main->suspend_unless_pkgpart({unless_pkgpart => [%%%unless_pkgpart%%%], reason => %%%sreason%%%, %%%unless_pkgpart_honor_dundate%%% });',
+%    'html'   => sub { &select_pkgpart('unless_pkgpart', @_). &honor_dundate('unless_pkgpart_honor_dundate' => @_) },
 %    'weight' => 10,
 %    'reason' => 'S',
 %  },
diff --git a/httemplate/misc/delay_susp_pkg.html b/httemplate/misc/delay_susp_pkg.html
new file mode 100755 (executable)
index 0000000..0755309
--- /dev/null
@@ -0,0 +1,73 @@
+%# if ( $link eq 'popup' ) { 
+  <% include('/elements/header-popup.html', $title ) %>
+%# } else { 
+%#  <%  include("/elements/header.html", $title, '') %>
+%# } 
+
+<LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT>
+
+<% include('/elements/error.html') %>
+
+<FORM NAME="ds_popup" ACTION="<% popurl(1) %>process/delay_susp_pkg.html" METHOD=POST>
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>">
+
+<BR><BR>
+<% "Delay automatic suspension of $pkgnum: " .$part_pkg->pkg. ' - ' .$part_pkg->comment %>
+<% ntable("#cccccc", 2) %>
+
+<TR>
+  <TD>Delay until</TD>
+    <TD><INPUT TYPE="text" NAME="date" ID="dun_date" VALUE="<% $date |h %>">
+        <IMG SRC="<% $p %>images/calendar.png" ID="dun_button" STYLE="cursor:pointer" TITLE="Select date">
+        <BR><I>m/d/y</I>
+    </TD>
+</TR>
+<SCRIPT TYPE="text/javascript">
+  Calendar.setup({
+    inputField: "dun_date",
+    ifFormat:   "%m/%d/%Y",
+    button:     "dun_button",
+    align:      "BR"
+  });
+</SCRIPT>
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" NAME="submit" VALUE="<% $submit %>">
+
+</FORM>
+</BODY>
+</HTML>
+
+<%init>
+
+my $date = time2str("%m/%d/%Y", time);
+
+my($pkgnum);
+if ( $cgi->param('error') ) {
+  $pkgnum    = $cgi->param('pkgnum');
+  $date      = $cgi->param('date');
+} elsif ( $cgi->param('pkgnum') =~ /^(\d+)$/ ) {
+  $pkgnum    = $1;
+} else {
+  die "illegal query ". $cgi->keywords;
+}
+
+my $submit = 'Delay Suspension';
+my $right  = 'Delay suspension events';
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+die "access denied" unless $curuser->access_right($right);
+
+my $title = 'Delay Suspension of Package';
+
+my $cust_pkg = qsearchs('cust_pkg', {'pkgnum' => $pkgnum})
+  or die "Unknown pkgnum: $pkgnum";
+
+my $part_pkg = $cust_pkg->part_pkg;
+
+</%init>
diff --git a/httemplate/misc/process/delay_susp_pkg.html b/httemplate/misc/process/delay_susp_pkg.html
new file mode 100755 (executable)
index 0000000..c7cc7de
--- /dev/null
@@ -0,0 +1,41 @@
+<% header("Package suspension delayed") %>
+  <SCRIPT TYPE="text/javascript">
+    window.top.location.reload();
+  </SCRIPT>
+  </BODY>
+</HTML>
+<%once>
+
+my $right = 'Delay suspension events';
+
+</%once>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right($right);
+
+my ($pkgnum, $date, $cust_pkg, $cust_main, $error);
+
+#untaint pkgnum
+$cgi->param('pkgnum') =~ /^(\d+)$/ or die "Illegal pkgnum";
+$pkgnum = $1;
+
+#untaint date
+str2time($cgi->param('date')) =~ /^(\d+)$/ or die "Illegal date";
+my $date = $1;
+
+$cust_pkg = qsearchs( 'cust_pkg', {'pkgnum'=>$pkgnum} );
+if ($cust_pkg) {
+  $cust_main = $cust_pkg->cust_main;
+  $cust_main->dundate( $date );
+  $error = $cust_main->replace;
+} else {
+  $error = "Invalid pkgnum";
+}
+
+if ($error) {
+  $cgi->param('error', $error);
+  print $cgi->redirect(popurl(2). "cancel_pkg.html?". $cgi->query_string );
+}
+
+</%init>
index ad5595c..5f1db4a 100755 (executable)
@@ -456,10 +456,13 @@ Current packages
 %       } 
 %
 %     } 
+%   my $autosuspend = pkg_autosuspend_time( $cust_pkg );
+%   $cust_pkg->set('autosuspend', $autosuspend) if $autosuspend;
 
       <% pkg_status_row_changed( $cust_pkg, conf=>$conf ) %>
       <% pkg_status_row_if( $cust_pkg, $last_bill_or_renewed, 'last_bill', conf=>$conf, curuser=>$curuser ) %>
       <% pkg_status_row_if( $cust_pkg, $next_bill_or_prepaid_until, 'bill', conf=>$conf, curuser=>$curuser ) %>
+      <% pkg_status_row_if($cust_pkg, 'Will automatically suspend by', 'autosuspend', conf=>$conf) %>
       <% pkg_status_row_if( $cust_pkg, 'Will suspend on', 'adjourn', conf=>$conf, curuser=>$curuser ) %>
       <% pkg_status_row_if( $cust_pkg, 'Expires', 'expire', conf=>$conf, curuser=>$curuser ) %>
 
@@ -474,6 +477,9 @@ Current packages
 %             if ( $curuser->access_right('Suspend customer package later') ) { 
                 (&nbsp;<% pkg_adjourn_link($cust_pkg) %>&nbsp;)
 %             } 
+%             if ( $curuser->access_right('Delay suspension events') ) { 
+                (&nbsp;<% pkg_delay_link($cust_pkg) %>&nbsp;)
+%             } 
 %             if ( $curuser->access_right('Cancel customer package immediately') ) { 
                 (&nbsp;<% pkg_cancel_link($cust_pkg) %>&nbsp;)
 %             } 
@@ -759,10 +765,19 @@ sub pkg_adjourn_link { include( '/elements/popup_link-cust_pkg.html',
                               )
                      }
 
+sub pkg_delay_link   { include( '/elements/popup_link-cust_pkg.html',
+                                { 'action'      => $p. 'misc/delay_susp_pkg.html',
+                                  'label'       => 'Delay&nbsp;suspend',
+                                  'actionlabel' => 'Delay suspend for',
+                                  'cust_pkg'    => shift,
+                                }
+                              )
+                     }
+
 sub pkg_unsuspend_link { pkg_link('misc/unsusp_pkg',    'Unsuspend',           @_ ); }
 sub pkg_dates_link     { pkg_link('edit/REAL_cust_pkg', 'Edit&nbsp;dates',     @_ ); }
-sub pkg_unadjourn_link     { pkg_link('misc/unadjourn_pkg', 'Abort',               @_ ); }
-sub pkg_unexpire_link      { pkg_link('misc/unexpire_pkg',  'Abort',               @_ ); }
+sub pkg_unadjourn_link { pkg_link('misc/unadjourn_pkg', 'Abort',               @_ ); }
+sub pkg_unexpire_link  { pkg_link('misc/unexpire_pkg',  'Abort',               @_ ); }
 
 sub pkg_cancel_link { include( '/elements/popup_link-cust_pkg.html',
                                { 'action'      => $p. 'misc/cancel_pkg.html?method=cancel',
@@ -827,4 +842,25 @@ sub pkg_customize_link {
     qq!">Customize</A>!;
 }
 
+sub pkg_autosuspend_time {
+  my $cust_pkg = shift or return '';
+  my $days = 7;
+  my $time = time;
+  my $pending_suspend = 0;
+  while ( $days > 0 &&
+          scalar(
+            grep { $_->part_event->action eq 'suspend' }
+            @{$cust_pkg->cust_main->due_cust_event( time => $time + 86400*$days,
+                                                    testonly => 1,
+                                                  ) }
+          )
+        )
+  {
+    $pending_suspend = 1;
+    $days--;
+  }
+
+  $pending_suspend ? time + ($days + 1) * 86400 : '';
+
+}
 </%init>