[freeside-commits] branch FREESIDE_3_BRANCH updated. 9d96031e79187a549c2c150e96363d421e59efc5

Mark Wells mark at 420.am
Tue Sep 16 16:10:46 PDT 2014


The branch, FREESIDE_3_BRANCH has been updated
       via  9d96031e79187a549c2c150e96363d421e59efc5 (commit)
      from  32834b6e8a92ca3ec0bbf58075956a7d0edca79a (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 9d96031e79187a549c2c150e96363d421e59efc5
Author: Mark Wells <mark at freeside.biz>
Date:   Tue Sep 16 01:44:26 2014 -0700

    package start_on_hold flag, and better behavior for automatic timers + packages on hold, #25853

diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 3eedc5c..3c12f0f 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -2150,6 +2150,7 @@ sub tables_hashref {
         'successor',     'int',     'NULL', '', '', '',
         'family_pkgpart','int',     'NULL', '', '', '',
         'delay_start',   'int',     'NULL', '', '', '',
+        'start_on_hold', 'char',    'NULL',  1, '', '',
         'agent_pkgpartid', 'varchar', 'NULL', 20, '', '',
       ],
       'primary_key' => 'pkgpart',
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index 0593849..e0b0eac 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -243,6 +243,39 @@ sub cust_unlinked_msg {
   ' (cust_pkg.pkgnum '. $self->pkgnum. ')';
 }
 
+=item set_initial_timers
+
+If required by the package definition, sets any automatic expire, adjourn,
+or contract_end timers to some number of months after the start date 
+(or setup date, if the package has already been setup). If the package has
+a delayed setup fee after a period of "free days", will also set the 
+start date to the end of that period.
+
+=cut
+
+sub set_initial_timers {
+  my $self = shift;
+  my $part_pkg = $self->part_pkg;
+  foreach my $action ( qw(expire adjourn contract_end) ) {
+    my $months = $part_pkg->option("${action}_months",1);
+    if($months and !$self->get($action)) {
+      my $start = $self->start_date || $self->setup || time;
+      $self->set($action, $part_pkg->add_freq($start, $months) );
+    }
+  }
+
+  # if this package has "free days" and delayed setup fee, then
+  # set start date that many days in the future.
+  # (this should have been set in the UI, but enforce it here)
+  if ( $part_pkg->option('free_days',1)
+       && $part_pkg->option('delay_setup',1)
+     )
+  {
+    $self->start_date( $part_pkg->default_start_date );
+  }
+  '';
+}
+
 =item insert [ OPTION => VALUE ... ]
 
 Adds this billing item to the database ("Orders" the item).  If there is an
@@ -301,6 +334,9 @@ sub insert {
 
   if ( ! $options{'change'} ) {
 
+    # set order date to now
+    $self->order_date(time);
+
     # if the package def says to start only on the first of the month:
     if ( $part_pkg->option('start_1st', 1) && !$self->start_date ) {
       my ($sec,$min,$hour,$mday,$mon,$year) = (localtime(time) )[0,1,2,3,4,5];
@@ -309,32 +345,17 @@ sub insert {
       $self->start_date( timelocal_nocheck(0,0,0,1,$mon,$year) );
     }
 
-    # set up any automatic expire/adjourn/contract_end timers
-    # based on the start date
-    foreach my $action ( qw(expire adjourn contract_end) ) {
-      my $months = $part_pkg->option("${action}_months",1);
-      if($months and !$self->$action) {
-        my $start = $self->start_date || $self->setup || time;
-        $self->$action( $part_pkg->add_freq($start, $months) );
-      }
-    }
-
-    # if this package has "free days" and delayed setup fee, then
-    # set start date that many days in the future.
-    # (this should have been set in the UI, but enforce it here)
-    if (    ! $options{'change'}
-         && $part_pkg->option('free_days',1)
-         && $part_pkg->option('delay_setup',1)
-         #&& ! $self->start_date
-       )
-    {
-      $self->start_date( $part_pkg->default_start_date );
+    if ($self->susp eq 'now' or $part_pkg->start_on_hold) {
+      # if the package was ordered on hold:
+      # - suspend it
+      # - don't set the start date (it will be started manually)
+      $self->set('susp', $self->order_date);
+      $self->set('start_date', '');
+    } else {
+      # set expire/adjourn/contract_end timers, and free days, if appropriate
+      $self->set_initial_timers;
     }
-
-  }
-
-  # set order date unless this was previously a different package
-  $self->order_date(time) unless $self->change_pkgnum;
+  } # else this is a package change, and shouldn't have "new package" behavior
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -343,8 +364,6 @@ sub insert {
   local $SIG{TSTP} = 'IGNORE';
   local $SIG{PIPE} = 'IGNORE';
 
-  $self->susp( $self->order_date ) if $self->susp eq 'now';
-
   my $oldAutoCommit = $FS::UID::AutoCommit;
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
@@ -1510,6 +1529,8 @@ sub unsuspend {
     return "";  # no error                     # complain instead?
   }
 
+  # handle the case of setting a future unsuspend (resume) date
+  # and do not continue to actually unsuspend the package
   my $date = $opt{'date'};
   if ( $date and $date > time ) { # return an error if $date <= time?
 
@@ -1533,6 +1554,11 @@ sub unsuspend {
   
   } #if $date 
 
+  if (!$self->setup) {
+    # then this package is being released from on-hold status
+    $self->set_initial_timers;
+  }
+
   my @labels = ();
 
   foreach my $cust_svc (
diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm
index c6e4c39..b7b9be5 100644
--- a/FS/FS/part_pkg.pm
+++ b/FS/FS/part_pkg.pm
@@ -120,6 +120,10 @@ part_pkg, will be equal to pkgpart.
 
 =item delay_start - Number of days to delay package start, by default
 
+=item start_on_hold - 'Y' to suspend this package immediately when it is 
+ordered. The package will not start billing or have a setup fee charged 
+until it is manually unsuspended.
+
 =back
 
 =head1 METHODS
@@ -601,14 +605,15 @@ sub check {
     || $self->ut_textn('comment')
     || $self->ut_textn('promo_code')
     || $self->ut_alphan('plan')
-    || $self->ut_enum('setuptax', [ '', 'Y' ] )
-    || $self->ut_enum('recurtax', [ '', 'Y' ] )
+    || $self->ut_flag('setuptax')
+    || $self->ut_flag('recurtax')
     || $self->ut_textn('taxclass')
-    || $self->ut_enum('disabled', [ '', 'Y' ] )
-    || $self->ut_enum('custom', [ '', 'Y' ] )
-    || $self->ut_enum('no_auto', [ '', 'Y' ])
-    || $self->ut_enum('recur_show_zero', [ '', 'Y' ])
-    || $self->ut_enum('setup_show_zero', [ '', 'Y' ])
+    || $self->ut_flag('disabled')
+    || $self->ut_flag('custom')
+    || $self->ut_flag('no_auto')
+    || $self->ut_flag('recur_show_zero')
+    || $self->ut_flag('setup_show_zero')
+    || $self->ut_flag('start_on_hold')
     #|| $self->ut_moneyn('setup_cost')
     #|| $self->ut_moneyn('recur_cost')
     || $self->ut_floatn('setup_cost')
@@ -1082,7 +1087,10 @@ sub is_free {
 sub can_discount { 0; }
 
 # whether the plan allows changing the start date
-sub can_start_date { 1; }
+sub can_start_date {
+  my $self = shift;
+  $self->start_on_hold ? 0 : 1;
+}
 
 # the delay start date if present
 sub delay_start_date {
diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm
index f3a2b85..5fd2696 100644
--- a/FS/FS/part_pkg/flat.pm
+++ b/FS/FS/part_pkg/flat.pm
@@ -256,6 +256,7 @@ sub is_prepaid { 0; } #no, we're postpaid
 sub can_start_date {
   my $self = shift;
   my %opt = @_;
+  return 0 if $self->start_on_hold;
 
   ! $self->option('start_1st', 1) && (   ! $self->option('sync_bill_date',1)
                                       || ! $self->option('prorate_defer_bill',1)
diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi
index a007a92..f40d4a9 100755
--- a/httemplate/edit/part_pkg.cgi
+++ b/httemplate/edit/part_pkg.cgi
@@ -43,6 +43,7 @@
                             'plan'             => 'Price plan',
                             'disabled'         => 'Disable new orders',
                             'disable_line_item_date_ranges' => 'Disable line item date ranges',
+                            'start_on_hold'    => 'Start on hold',
                             'setup_cost'       => 'Setup cost',
                             'recur_cost'       => 'Recur cost',
                             'pay_weight'       => 'Payment weight',
@@ -102,6 +103,10 @@
                               ),
                               {field=>'disabled', type=>$disabled_type, value=>'Y'},
                               {field=>'disable_line_item_date_ranges', type=>$disabled_type, value=>'Y'},
+                              { field => 'start_on_hold',
+                                type => 'checkbox',
+                                value => 'Y'
+                              },
 
                               { type     => 'tablebreak-tr-title',
                                 value    => 'Pricing', #better name?
diff --git a/httemplate/elements/order_pkg.js b/httemplate/elements/order_pkg.js
index 8cd0f5f..d7a9091 100644
--- a/httemplate/elements/order_pkg.js
+++ b/httemplate/elements/order_pkg.js
@@ -10,7 +10,7 @@ function pkg_changed () {
     var date_text = document.getElementById('start_date_text');
 
     var radio_now = document.getElementById('start_now');
-    //var radio_on_hold = document.getElementById('start_on_hold');
+    var radio_on_hold = document.getElementById('start_on_hold');
     var radio_on_date = document.getElementById('start_on_date');
 
     form.submitButton.disabled = false;
@@ -36,23 +36,35 @@ function pkg_changed () {
       date_button.style.display = '';
       date_button_disabled.style.display = 'none';
       if ( radio_on_date ) {
+        // un-disable all the buttons that might get disabled
         radio_on_date.disabled = false;
-        if ( form.start_date_text.value.length > 0 && radio_now.checked ) {
+        radio_now.disabled = false;
+        // if a start date has been entered, assume the user wants it
+        if ( form.start_date_text.value.length > 0 ) {
           radio_now.checked = false;
           radio_on_date.checked = true;
+        } else {
+          // if not, default to now
+          radio_now.checked = true;
         }
       }
-    } else {
+    } else { // the package is either fixed start date or start-on-hold
       date_text.style.backgroundColor = '#dddddd';
       date_text.disabled = true;
       date_button.style.display = 'none';
       date_button_disabled.style.display = '';
       if ( radio_on_date ) {
-        if ( radio_on_date.checked ) {
-          radio_on_date.checked = false;
+        if ( opt.getAttribute('data-start_on_hold') == 1 ) {
+          // disallow all options but "On hold"
+          radio_on_hold.checked = true;
+          radio_now.checked = false;
+          radio_now.disabled = true;
+        } else {
+          // disallow all options but "On date"
+          radio_on_hold.checked = false;
           radio_now.checked = true;
+          radio_now.disabled = false;
         }
-        radio_on_date.disabled = true;
       }
     }
 
diff --git a/httemplate/elements/tr-select-cust-part_pkg.html b/httemplate/elements/tr-select-cust-part_pkg.html
index 696baff..0db989a 100644
--- a/httemplate/elements/tr-select-cust-part_pkg.html
+++ b/httemplate/elements/tr-select-cust-part_pkg.html
@@ -5,9 +5,10 @@
 
   <SCRIPT TYPE="text/javascript">
 
-    function part_pkg_opt(what, value, text, can_discount, can_start_date, start_date) {
+    function part_pkg_opt(what, value, text, can_discount, start_on_hold, can_start_date, start_date) {
       var optionName = new Option(text, value, false, false);
       optionName.setAttribute('data-can_discount',   can_discount);
+      optionName.setAttribute('data-start_on_hold',  start_on_hold);
       optionName.setAttribute('data-can_start_date', can_start_date);
       optionName.setAttribute('data-start_date',     start_date || '');
       var length = what.length;
@@ -37,14 +38,16 @@
         // add the new packages
         opt(what.form.pkgpart, '', 'Select package');
         var packagesArray = eval('(' + part_pkg + ')' );
-        for ( var s = 0; s < packagesArray.length; s=s+5 ) {
+        while (packagesArray.length > 0) {
           //surely this should be some kind of JSON structure
-          var packagesLabel  = packagesArray[s+1];
-          var can_discount   = packagesArray[s+2];
-          var can_start_date = packagesArray[s+3];
-          var start_date     = packagesArray[s+4];
+          var pkgpart        = packagesArray.shift();
+          var label          = packagesArray.shift();
+          var can_discount   = packagesArray.shift();
+          var start_on_hold  = packagesArray.shift();
+          var can_start_date = packagesArray.shift();
+          var start_date     = packagesArray.shift();
           part_pkg_opt(
-            what.form.pkgpart, packagesArray[s], packagesLabel, can_discount, can_start_date, start_date
+            what.form.pkgpart, pkgpart, label, can_discount, start_on_hold, can_start_date, start_date
           );
         }
 
diff --git a/httemplate/misc/cust-part_pkg.cgi b/httemplate/misc/cust-part_pkg.cgi
index e129347..dc9ba2a 100644
--- a/httemplate/misc/cust-part_pkg.cgi
+++ b/httemplate/misc/cust-part_pkg.cgi
@@ -56,6 +56,7 @@ my @return = map  {
                     ( $_->pkgpart,
                       $_->pkg_comment,
                       $_->can_discount,
+                      ($_->start_on_hold ? 1 : 0),
                       $_->can_start_date(
                         num_ncancelled_pkgs => $num_ncancelled_pkgs,
                       ),

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

Summary of changes:
 FS/FS/Schema.pm                                  |    1 +
 FS/FS/cust_pkg.pm                                |   80 ++++++++++++++--------
 FS/FS/part_pkg.pm                                |   24 ++++---
 FS/FS/part_pkg/flat.pm                           |    1 +
 httemplate/edit/part_pkg.cgi                     |    5 ++
 httemplate/elements/order_pkg.js                 |   24 +++++--
 httemplate/elements/tr-select-cust-part_pkg.html |   17 +++--
 httemplate/misc/cust-part_pkg.cgi                |    1 +
 8 files changed, 105 insertions(+), 48 deletions(-)




More information about the freeside-commits mailing list