during scheduled package changes, keep setup and bill dates, #30223
[freeside.git] / FS / FS / cust_pkg.pm
index 4def528..3e87aad 100644 (file)
@@ -1750,7 +1750,7 @@ sub unsuspend {
 
   if ( $reason ) {
     if ( $reason->unsuspend_pkgpart ) {
-      #warn "Suspend reason '".$reason->reason."' uses deprecated unsuspend_pkgpart feature.\n"; # in 4.x
+      warn "Suspend reason '".$reason->reason."' uses deprecated unsuspend_pkgpart feature.\n";
       my $part_pkg = FS::part_pkg->by_key($reason->unsuspend_pkgpart)
         or $error = "Unsuspend package definition ".$reason->unsuspend_pkgpart.
                     " not found.";
@@ -1967,6 +1967,40 @@ sub change {
 
   my $error;
 
+  if ( $opt->{'cust_location'} ) {
+    $error = $opt->{'cust_location'}->find_or_insert;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "creating location record: $error";
+    }
+    $opt->{'locationnum'} = $opt->{'cust_location'}->locationnum;
+  }
+
+  # Before going any further here: if the package is still in the pre-setup
+  # state, it's safe to modify it in place. No need to charge/credit for 
+  # partial period, transfer services, transfer usage pools, copy invoice
+  # details, or change any dates.
+  if ( ! $self->setup and ! $opt->{cust_pkg} and ! $opt->{cust_main} ) {
+    foreach ( qw( locationnum pkgpart quantity refnum salesnum ) ) {
+      if ( length($opt->{$_}) ) {
+        $self->set($_, $opt->{$_});
+      }
+    }
+    # almost. if the new pkgpart specifies start/adjourn/expire timers, 
+    # apply those.
+    if ( $opt->{'pkgpart'} and $opt->{'pkgpart'} != $self->pkgpart ) {
+      $self->set_initial_timers;
+    }
+    $error = $self->replace;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "modifying package: $error";
+    } else {
+      $dbh->commit if $oldAutoCommit;
+      return '';
+    }
+  }
+
   my %hash = (); 
 
   my $time = time;
@@ -1977,15 +2011,6 @@ sub change {
   $hash{"change_$_"}  = $self->$_()
     foreach qw( pkgnum pkgpart locationnum );
 
-  if ( $opt->{'cust_location'} ) {
-    $error = $opt->{'cust_location'}->find_or_insert;
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      return "creating location record: $error";
-    }
-    $opt->{'locationnum'} = $opt->{'cust_location'}->locationnum;
-  }
-
   if ( $opt->{'cust_pkg'} ) {
     # treat changing to a package with a different pkgpart as a 
     # pkgpart change (because it is)
@@ -2000,6 +2025,7 @@ sub change {
 
   my $unused_credit = 0;
   my $keep_dates = $opt->{'keep_dates'};
+
   # Special case.  If the pkgpart is changing, and the customer is
   # going to be credited for remaining time, don't keep setup, bill, 
   # or last_bill dates, and DO pass the flag to cancel() to credit 
@@ -2032,6 +2058,9 @@ sub change {
   # 2. (more importantly) changing a package before it's billed
   $hash{'waive_setup'} = $self->waive_setup;
 
+  # if this package is scheduled for a future package change, preserve that
+  $hash{'change_to_pkgnum'} = $self->change_to_pkgnum;
+
   my $custnum = $self->custnum;
   if ( $opt->{cust_main} ) {
     my $cust_main = $opt->{cust_main};
@@ -2057,6 +2086,15 @@ sub change {
       $cust_pkg->set("change_$_", $self->get($_));
     }
     $cust_pkg->set('change_date', $time);
+    $cust_pkg->set('start_date', ''); # it's starting now
+    # if we are crediting unused time, then create the new package as a new
+    # package, charge its setup fee, etc. (same as an immediate change)
+    if (! $unused_credit) {
+      foreach my $date ( qw(setup bill last_bill susp adjourn resume 
+                            contract_end ) ) {
+        $cust_pkg->set($date, $self->getfield($date));
+      }
+    }
     $error = $cust_pkg->replace;
 
   } else {