[freeside-commits] branch FREESIDE_2_3_BRANCH updated. 4615cc768db4cc0bf310fa7f349b69d13a6afef9

Mark Wells mark at 420.am
Tue Aug 14 16:46:06 PDT 2012


The branch, FREESIDE_2_3_BRANCH has been updated
       via  4615cc768db4cc0bf310fa7f349b69d13a6afef9 (commit)
      from  d3f91c0823f827fe2da7197d39014dc330fb6785 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 4615cc768db4cc0bf310fa7f349b69d13a6afef9
Author: Mark Wells <mark at freeside.biz>
Date:   Tue Aug 14 16:45:45 2012 -0700

    unsuspend fees, #6587

diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 09a87f9..6425682 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -3408,6 +3408,8 @@ sub tables_hashref {
         'reason_type',   'int',  '', '', '', '', 
         'reason',        'text', '', '', '', '', 
         'disabled',      'char',    'NULL', 1, '', '', 
+        'unsuspend_pkgpart', 'int',  'NULL', '', '', '',
+        'unsuspend_hold','char',    'NULL', 1, '', '',
       ],
       'primary_key' => 'reasonnum',
       'unique' => [],
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index 10472fc..d340dc0 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -1256,7 +1256,8 @@ sub suspend {
 
 Unsuspends all services (see L<FS::cust_svc> and L<FS::part_svc>) in this
 package, then unsuspends the package itself (clears the susp field and the
-adjourn field if it is in the past).
+adjourn field if it is in the past).  If the suspend reason includes an 
+unsuspension package, that package will be ordered.
 
 Available options are:
 
@@ -1360,6 +1361,8 @@ sub unsuspend {
 
   }
 
+  my $reason = $self->last_cust_pkg_reason('susp')->reason;
+
   my %hash = $self->hash;
   my $inactive = time - $hash{'susp'};
 
@@ -1386,6 +1389,33 @@ sub unsuspend {
     return $error;
   }
 
+  my $unsusp_pkg;
+
+  if ( $reason->unsuspend_pkgpart ) {
+    my $part_pkg = FS::part_pkg->by_key($reason->unsuspend_pkgpart)
+      or $error = "Unsuspend package definition ".$reason->unsuspend_pkgpart.
+                  " not found.";
+    my $start_date = $self->cust_main->next_bill_date 
+      if $reason->unsuspend_hold;
+
+    if ( $part_pkg ) {
+      my $unsusp_pkg = FS::cust_pkg->new({
+          'custnum'     => $self->custnum,
+          'pkgpart'     => $reason->unsuspend_pkgpart,
+          'start_date'  => $start_date,
+          'locationnum' => $self->locationnum,
+          # discount? probably not...
+      });
+      
+      $error ||= $self->cust_main->order_pkg( 'cust_pkg' => $unsusp_pkg );
+    }
+
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   if ( $conf->config('unsuspend_email_admin') ) {
  
     my $error = send_email(
@@ -1399,6 +1429,10 @@ sub unsuspend {
         'Customer: #'. $self->custnum. ' '. $self->cust_main->name. "\n",
         'Package : #'. $self->pkgnum. " (". $self->part_pkg->pkg_comment. ")\n",
         ( map { "Service : $_\n" } @labels ),
+        ($unsusp_pkg ? 
+          "An unsuspension fee was charged: Package #".$unsusp_pkg->pkgnum.".\n"
+          : ''
+        ),
       ],
     );
 
diff --git a/FS/FS/reason.pm b/FS/FS/reason.pm
index 377da49..df3f5aa 100644
--- a/FS/FS/reason.pm
+++ b/FS/FS/reason.pm
@@ -46,6 +46,15 @@ FS::Record.  The following fields are currently supported:
 
 =item disabled - 'Y' or ''
 
+=item unsuspend_pkgpart - for suspension reasons only, the pkgpart (see
+L<FS::part_pkg>) of a package to be ordered when the package is unsuspended.
+Typically this will be some kind of reactivation fee.  Attaching it to 
+a suspension reason allows the reactivation fee to be charged for some
+suspensions but not others.
+
+=item unsuspend_hold - 'Y' or ''.  If unsuspend_pkgpart is set, this tells
+whether to bill the unsuspend package immediately ('') or to wait until 
+the customer's next invoice ('Y').
 
 =back
 
@@ -97,16 +106,30 @@ sub check {
 
   my $error = 
     $self->ut_numbern('reasonnum')
+    || $self->ut_number('reason_type')
+    || $self->ut_foreign_key('reason_type', 'reason_type', 'typenum')
     || $self->ut_text('reason')
+    || $self->ut_enum('disabled', [ '', 'Y' ])
   ;
   return $error if $error;
 
+  if ( $self->reasontype->class eq 'S' ) {
+    $error = $self->ut_numbern('unsuspend_pkgpart')
+          || $self->ut_foreign_keyn('unsuspend_pkgpart', 'part_pkg', 'pkgpart')
+          || $self->ut_enum('unsuspend_hold', [ '', 'Y' ])
+    ;
+    return $error if $error;
+  } else {
+    $self->set('unsuspend_pkgpart' => '');
+    $self->set('unsuspend_hold'    => '');
+  }
+
   $self->SUPER::check;
 }
 
 =item reasontype
 
-Returns the reason_type (see <I>FS::reason_type</I>) associated with this reason.
+Returns the reason_type (see L<FS::reason_type>) associated with this reason.
 
 =cut
 
@@ -118,7 +141,7 @@ sub reasontype {
 
 =head1 BUGS
 
-Here be termintes.  Don't use on wooden computers.
+Here by termintes.  Don't use on wooden computers.
 
 =head1 SEE ALSO
 
diff --git a/httemplate/browse/reason.html b/httemplate/browse/reason.html
index fe285be..14e97bf 100644
--- a/httemplate/browse/reason.html
+++ b/httemplate/browse/reason.html
@@ -17,14 +17,17 @@
                  'header'      => [ '#',
                                     ucfirst($classname) . ' Reason Type',
                                     ucfirst($classname) . ' Reason',
+                                    ($class eq 'S' ?  'Unsuspension Fee' : ()),
                                   ],
                  'fields'      => [ 'reasonnum',
                                     sub { shift->reasontype->type },
                                     'reason',
+                                    $unsuspend_pkg_comment,
                                   ],
                  'links'       => [ $link,
                                     $link,
                                     '',
+                                    $unsuspend_pkg_link,
                                   ],
              )
 %>
@@ -50,4 +53,18 @@ my $count_query = 'SELECT COUNT(*) FROM reason LEFT JOIN reason_type on ' .
 
 my $link = [ $p."edit/reason.html?class=$class&reasonnum=", 'reasonnum' ];
 
+my ($unsuspend_pkg_comment, $unsuspend_pkg_link);
+if ( $class eq 'S' ) {
+  $unsuspend_pkg_comment = sub {
+    my $pkgpart = shift->unsuspend_pkgpart or return '';
+    my $part_pkg = FS::part_pkg->by_key($pkgpart) or return '';
+    $part_pkg->pkg_comment;
+  };
+
+  my $unsuspend_pkg_link = sub {
+    my $pkgpart = shift->unsuspend_pkgpart or return '';
+    [ $p."edit/part_pkg.cgi?", $pkgpart ];
+  };
+}
+
 </%init>
diff --git a/httemplate/edit/reason.html b/httemplate/edit/reason.html
index 620a2ea..78d0447 100644
--- a/httemplate/edit/reason.html
+++ b/httemplate/edit/reason.html
@@ -1,50 +1,78 @@
-%
-% $cgi->param('class') =~ /^(\w)$/ or die "illegal class";
-% my $class=$1;
-%
-% my $classname = $FS::reason_type::class_name{$class};
-%
-% my (@types) = qsearch( 'reason_type', { 'class' => $class } );
-%
-% unless (scalar(@types)) {
-%   print $cgi->redirect( "reason_type.html?class=$class" );
-% }
-<% include( 'elements/edit.html',
-                 'name'   => ucfirst($classname) . ' Reason',
-                 'table'  => 'reason',
-                 'labels' => { 
-                               'reasonnum'   => ucfirst($classname) .  ' Reason',
-                               'reason_type' => ucfirst($classname) . ' Reason type',
-                               'reason'      => ucfirst($classname) . ' Reason',
-			       'disabled'    => 'Disabled',
-                               'class'       => '',
-                             },
-		 'fields' => [
-			       { 'field' => 'reason_type',
-			         'type'  => 'select',
-                                 #XXX use something more sane than a hashref
-                                 #then fix tr-select.html
-				 'value' => { 'vcolumn' => 'typenum',
-				              'ccolumn' => 'type',
-					      'values'  => \@types,
-					    },
-			       },
-			       'reason',
-			       { 'field' => 'class',
-			         'type'  => 'hidden',
-				 'value' => $class,
-			       },
-			       { 'field' => 'disabled',
-			         'type'  => 'checkbox',
-				 'value' => 'Y'
-			       },
-		             ],
-                 'viewall_url' => $p . "browse/reason.html?class=$class",
-           )
-%>
+<& elements/edit.html,
+  'menubar'=> [ "View all $classname Reasons" => 
+                  $p.'browse/reason.html?class='.$class,
+                "View $classname Reason Types" =>
+                  $p.'browse/reason_type.html?class='.$class,
+              ],
+  'name'   => ucfirst($classname) . ' Reason',
+  
+  'table'  => 'reason',
+  'labels' => { 
+                'reasonnum'   => $classname .  ' Reason',
+                'reason_type' => $classname . ' Reason type',
+                'reason'      => $classname . ' Reason',
+ 	        'disabled'    => 'Disabled',
+                'class'       => '',
+                'unsuspend_pkgpart' => 'Unsuspension fee',
+                'unsuspend_hold'    => 'Delay until next bill',
+              },
+  'fields' => \@fields,
+&>
 <%init>
 
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
 
+$cgi->param('class') =~ /^(\w)$/ or die "illegal class";
+my $class=$1;
+
+my $classname = ucfirst($FS::reason_type::class_name{$class});
+
+my (@types) = qsearch( 'reason_type', { 'class' => $class } );
+
+unless (scalar(@types)) {
+  print $cgi->redirect( "reason_type.html?class=$class" );
+}
+
+my @fields = (
+  { 'field' => 'reason_type',
+    'type'  => 'select-table',
+    'table' => 'reason_type',
+    'name_col'  => 'type',
+    'value_col' => 'typenum',
+    'hashref'   => { 'class' => $class },
+    'disable_empty' => 1,
+#     #then fix tr-select.html
+#
+#    'value' => { 'vcolumn' => 'typenum',
+#                 'ccolumn' => 'type',
+#   	      'values'  => \@types,
+#   	    },
+#     # that wasn't so hard...did this do something else that I'm missing?
+  },
+  'reason',
+  { 'field' => 'class',
+    'type'  => 'hidden',
+    'value' => $class,
+  },
+  { 'field' => 'disabled',
+    'type'  => 'checkbox',
+    'value' => 'Y'
+  },
+);
+
+push @fields,
+  { 'field'     => 'unsuspend_pkgpart',
+    'type'      => 'select-part_pkg',
+    'hashref'   => { 'disabled' => '',
+                     'freq'     => 0 }, # one-time charges only
+  },
+  { 'field'     => 'unsuspend_hold',
+    'type'      => 'checkbox',
+    'value'     => 'Y',
+  },
+  if ( $class eq 'S' );
+  
+
+
 </%init>
diff --git a/httemplate/elements/tr-select-reason.html b/httemplate/elements/tr-select-reason.html
index 5a79d68..c1df10b 100755
--- a/httemplate/elements/tr-select-reason.html
+++ b/httemplate/elements/tr-select-reason.html
@@ -32,8 +32,15 @@ Example:
 <SCRIPT TYPE="text/javascript">
   function sh_add<% $func_suffix %>()
   {
+    var hints = <% encode_json(\@hints) %>;
+    var select_reason = document.getElementById('<% $id %>');
 
-    if (document.getElementById('<% $id %>').selectedIndex == 0){
+% if ( $class eq 'S' ) {    
+    document.getElementById('<% $id %>_hint').innerHTML =
+      hints[select_reason.selectedIndex];
+% }
+
+    if (select_reason.selectedIndex == 0){
       <% $controlledbutton ? $controlledbutton.'.disabled = true;' : ';' %>
     }else{
       <% $controlledbutton ? $controlledbutton.'.disabled = false;' : ';' %>
@@ -41,8 +48,8 @@ Example:
 
 %if ($curuser->access_right($add_access_right)){
 
-    if (document.getElementById('<% $id %>').selectedIndex == 
-         (document.getElementById('<% $id %>').length - 1)) {
+    if (select_reason.selectedIndex == 
+         (select_reason.length - 1)) {
       document.getElementById('new<% $id %>').disabled = false;
       document.getElementById('new<% $id %>').style.display = 'inline';
       document.getElementById('new<% $id %>Label').style.display = 'inline';
@@ -113,6 +120,13 @@ Example:
 </TR>
 %   }
 
+% if ( $class eq 'S' ) {
+<TR>
+  <TD COLSPAN=2 ALIGN="center" id="<% $id %>_hint">
+  </TD>
+</TR>
+% }
+
 <TR>
   <TD ALIGN="right">
     <P id="new<% $id %>Label" style="display:<% $display %>"><% mt('New Reason') |h %></P>
@@ -184,6 +198,43 @@ my @reasons = qsearch({
   order_by  => 'ORDER BY reason_type.type ASC, reason.reason ASC',
 });
 
+my @hints;
+if ( $class eq 'S' ) {
+  my $conf = FS::Conf->new;
+  @hints = ( '' );
+  foreach my $reason (@reasons) {
+    if ( $reason->unsuspend_pkgpart ) {
+      my $part_pkg = FS::part_pkg->by_key($reason->unsuspend_pkgpart);
+      if ( $part_pkg ) {
+        if ( $part_pkg->option('setup_fee',1) > 0 and 
+             $part_pkg->option('recur_fee',1) == 0 ) {
+          # the usual case
+          push @hints,
+            mt('A [_1] unsuspension fee will apply.', 
+               ($conf->config('money_char') || '$') .
+               sprintf('%.2f', $part_pkg->option('setup_fee'))
+               );
+        } else {
+          # oddball cases--not really supported
+          push @hints,
+            mt('An unsuspension package will apply: [_1]',
+              $part_pkg->price_info
+              );
+        }
+      } else { #no $part_pkg
+        push @hints,
+          '<FONT COLOR="#ff0000">Unsuspend pkg #'.$reason->unsuspend_pkgpart.
+          ' not found.</FONT>';
+      }
+    } else { #no unsuspend_pkgpart
+      push @hints, '';
+    }
+  }
+  push @hints, ''; # for the "new reason" case
+  @hints = map {'<FONT SIZE="-1">'.$_.'</FONT>'} @hints;
+}
+
+
 my $curuser = $FS::CurrentUser::CurrentUser;
 
 </%init>

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Schema.pm                           |    2 +
 FS/FS/cust_pkg.pm                         |   36 +++++++++-
 FS/FS/reason.pm                           |   27 ++++++-
 httemplate/browse/reason.html             |   17 ++++
 httemplate/edit/reason.html               |  116 ++++++++++++++++++-----------
 httemplate/elements/tr-select-reason.html |   57 +++++++++++++-
 6 files changed, 205 insertions(+), 50 deletions(-)




More information about the freeside-commits mailing list