[freeside-commits] branch FREESIDE_4_BRANCH updated. c46aa55bdeb3e09437c7ab18288f209a6fa44796

Mitch Jackson mitch at freeside.biz
Fri Feb 23 16:16:00 PST 2018


The branch, FREESIDE_4_BRANCH has been updated
       via  c46aa55bdeb3e09437c7ab18288f209a6fa44796 (commit)
       via  db13eb8cb9645a6fd8979541e831fe60ee771e7d (commit)
       via  538be6f5067b982715c1ad062f2201fe1a44ccba (commit)
      from  4df06d48a1f7ae016e7bb02654e7820c8cd27975 (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 c46aa55bdeb3e09437c7ab18288f209a6fa44796
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Sat Feb 24 00:09:38 2018 +0000

    RT# 79284  Fix UI bug for Change Package screen

diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index 9accc3407..604b49941 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -3017,6 +3017,7 @@ sub _parse_new_discounts {
         discountnum => $opt->{"${type}_discountnum"},
         amount      => $opt->{"${type}_discountnum_amount"},
         percent     => $opt->{"${type}_discountnum_percent"},
+        months      => $opt->{"${type}_discountnum_months"},
       };
     }
 
diff --git a/httemplate/edit/process/change-cust_pkg.html b/httemplate/edit/process/change-cust_pkg.html
index 02b01f8de..c8c623641 100644
--- a/httemplate/edit/process/change-cust_pkg.html
+++ b/httemplate/edit/process/change-cust_pkg.html
@@ -80,6 +80,7 @@ for my $type (qw|setup_discountnum recur_discountnum|) {
     $change{$type} = $dnum;
     $change{"${type}_amount"}  = $cgi->param("${type}_amount");
     $change{"${type}_percent"} = $cgi->param("${type}_percent");
+    $change{"${type}_months"}  = $cgi->param("${type}_months");
   } elsif ($dnum eq '') {
     # Set discount as no discount
     $change{"${type}"} = 0;

commit db13eb8cb9645a6fd8979541e831fe60ee771e7d
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Tue Feb 13 18:11:03 2018 -0600

    RT# 79284 Updated discounts UI for Change Package screen

diff --git a/httemplate/elements/select-table.html b/httemplate/elements/select-table.html
index 6fb6b388b..a52fdfaaa 100644
--- a/httemplate/elements/select-table.html
+++ b/httemplate/elements/select-table.html
@@ -195,13 +195,22 @@ if ( ref( $value ) eq 'ARRAY' ) {
   $value = { map { $_ => 1 } @$value };
 }
 
-unless (    !ref($value) && $value < 1 # !$value #ignore negatives too
-         or ! exists( $opt{hashref}->{disabled} ) #??
-         #or grep { $value == $_->$key() } @records
-       ) {
+
+if (
+     (ref $value && $value)
+  or (ref $opt{hashref} && exists $opt{hashref}->{disabled})
+  or $opt{also_show_option}
+) {
+
   delete $opt{hashref}->{disabled};
 
-  foreach my $v ( ref($value) ? keys %$value : ($value) ) {
+  # also_show_option: (hack for change_pkg form):
+  #   Include an absent select option, without selecting it
+  #   as the curr_value
+  my @also_show = ref($value) ? keys %$value : ($value);
+  push @also_show, $opt{also_show_option} if $opt{also_show_option};
+
+  foreach my $v ( @also_show ) {
     next if grep { $v == $_->$key() } @records;
 
     $opt{hashref}->{$key} = $v;
diff --git a/httemplate/elements/tr-select-pkg-discount.html b/httemplate/elements/tr-select-pkg-discount.html
index 39b0ff31f..810e46230 100644
--- a/httemplate/elements/tr-select-pkg-discount.html
+++ b/httemplate/elements/tr-select-pkg-discount.html
@@ -7,7 +7,9 @@ In order_pkg.html or similar:
   curr_value_recur    => ($cgi->param('recur_discountnum') || ''),
   disable_setup       => 0,
   disable_recur       => 0,
-  disable_waive_setup => 0
+  disable_waive_setup => 0,
+  carry_value_setup   => $carry_setup_discountnum,
+  carry_value_recur   => $carry_recur_discountnum,
 &>
 
 This provides the following:
@@ -20,6 +22,8 @@ This provides the following:
   checkbox to waive setup fee.
 - Same for recurring fee, but without the "waive setup fee" stuff, obviously.
 - Custom recurring discounts also have an option for a duration in months.
+- When changing a package, the original package's discount option is
+  labeled in the select options
 
 "disable_setup" locks the setup discount, but will still show a static
 description if curr_value_setup is set. Likewise "disable_recur".
@@ -47,6 +51,8 @@ description if curr_value_setup is set. Likewise "disable_recur".
       curr_value  => $opt{'curr_value_setup'},
       disable_empty => 1,
       pre_options => $pre_options,
+      also_show_option => $opt{carry_value_setup},
+      label_callback   => $opt{carry_value_setup} ? $carry_setup_sub : undef,
     &>
   </td>
 </tr>
@@ -107,6 +113,8 @@ description if curr_value_setup is set. Likewise "disable_recur".
       id          => 'recur_discountnum',
       hashref     =>  { disabled => '' },
       curr_value  => $opt{'curr_value_recur'},
+      also_show_option => $opt{carry_value_recur},
+      label_callback   => $opt{carry_value_recur} ? $carry_recur_sub : undef,
     &>
 
   </td>
@@ -196,4 +204,18 @@ my %opt = (
 my $curuser = $FS::CurrentUser::CurrentUser;
 my $money_char = FS::Conf->new->config('money_char') || '$';
 
+# Change the label for the select-option when it matches the carryover
+# discountnum
+my $carry_recur_sub =  sub {
+  my ($rec) = @_;
+  $rec->discountnum eq $opt{carry_value_recur}
+    ? $rec->description() . ' [Continues existing discount]'
+    : $rec->description();
+};
+my $carry_setup_sub =  sub {
+  my ($rec) = @_;
+  $rec->discountnum eq $opt{carry_value_setup}
+    ? $rec->description() . ' [Continues existing discount]'
+    : $rec->description();
+};
 </%init>
diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi
index 2470ee135..c588c9e6c 100755
--- a/httemplate/misc/change_pkg.cgi
+++ b/httemplate/misc/change_pkg.cgi
@@ -91,11 +91,13 @@
   <FONT CLASS="fsinnerbox-title"><% mt('Discounting') |h %></FONT>
   <TABLE CLASS="fsinnerbox">
     <& /elements/tr-select-pkg-discount.html,
-      curr_value_setup    => $discount{setup},
-      curr_value_recur    => $discount{recur},
+      # curr_value_setup    => $discount{setup},
+      # curr_value_recur    => $discount{recur},
       disable_setup       => 0,
       disable_recur       => 0,
-      disable_waive_setup => 0
+      disable_waive_setup => 0,
+      carry_value_setup   => $discount{setup},
+      carry_value_recur   => $discount{recur},
     &>
   </TABLE><BR>
 

commit 538be6f5067b982715c1ad062f2201fe1a44ccba
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Sat Feb 10 00:05:16 2018 -0600

    RT# 79284 Option to set/carry recur discount at Change Package

diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index e1fa2ae93..9accc3407 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -6,7 +6,7 @@ use base qw( FS::cust_pkg::Search FS::cust_pkg::API
            );
 
 use strict;
-use Carp qw(cluck);
+use Carp qw(cluck croak);
 use Scalar::Util qw( blessed );
 use List::Util qw(min max sum);
 use Tie::IxHash;
@@ -2379,8 +2379,20 @@ sub change {
     $same_pkgpart = 0;
   }
 
-  if ($opt->{'waive_setup'}) { $self->set('waive_setup', $opt->{'waive_setup'}) }
-  else { $self->set('waive_setup', ''); }
+  # Discounts:
+  #   When a new discount level is specified in $opt:
+  #     If new discountnum matches old discountnum, months_used/end_date are
+  #       carried over as the discount is applied to the new cust_pkg
+  #
+  #   Legacy behavior:
+  #     Unless discount-related fields have been set within $opt, change()
+  #     sets no discounts on the changed packages unless the new pkgpart is the
+  #     same as the old pkgpart.  In that case, discounts from the old cust_pkg
+  #     are copied onto the new cust_pkg
+
+  # Read discount fields from $opt
+  my %new_discount = $self->_parse_new_discounts($opt);
+  $self->set(waive_setup => $opt->{waive_setup} ? $opt->{waive_setup} : '');
 
   # 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 
@@ -2436,6 +2448,22 @@ sub change {
 
     } # done transferring services
 
+    # Set waive_setup as directed
+    if ( !$error && exists $opt->{waive_setup} ) {
+      $self->set(waive_setup => $opt->{waive_setup});
+      $error = $self->replace;
+    }
+
+    # Set discounts if explicitly specified in $opt
+    if ( !$error && %new_discount ) {
+      $error = $self->change_discount(%new_discount);
+    }
+
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+
     $dbh->commit if $oldAutoCommit;
     return $self;
 
@@ -2625,8 +2653,18 @@ sub change {
     }
   }
 
-  # transfer discounts, if we're not changing pkgpart
-  if ( $same_pkgpart ) {
+  if (%new_discount && !$error) {
+
+    # If discounts were explicitly specified in $opt
+    $error = $cust_pkg->change_discount(%new_discount);
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "applying discounts: $error";
+    }
+
+  } elsif ( $same_pkgpart ) {
+
+    # transfer discounts, if we're not changing pkgpart
     foreach my $old_discount ($self->cust_pkg_discount_active) {
       # don't remove the old discount, we may still need to bill that package.
       my $new_discount = new FS::cust_pkg_discount {
@@ -2843,6 +2881,20 @@ sub change_later {
     $opt->{'locationnum'} = $opt->{'cust_location'}->locationnum;
   }
 
+  # Discounts:
+  #   Applies discounts to the newly created future_change package
+  #
+  #   If a new discount is the same as the old discount, carry over the
+  #     old discount's months_used/end_date fields too
+  #
+  #   Legacy behavior:
+  #     Legacy behavior was to create the next package with no discount.
+  #     This behavior is preserved.  Without the discount fields in $opt,
+  #     the new package will be created with no discounts.
+
+  # parse discount information from $opt
+  my %new_discount = $self->_parse_new_discounts($opt);
+
   if ( $self->change_to_pkgnum ) {
     my $change_to = FS::cust_pkg->by_key($self->change_to_pkgnum);
     my $new_pkgpart = $opt->{'pkgpart'}
@@ -2880,6 +2932,16 @@ sub change_later {
       $change_to->set('start_date', $date);
       $error = $self->replace || $change_to->replace;
     }
+
+    if ( !$error && exists $opt->{waive_setup} ) {
+      $change_to->set(waive_setup => $opt->{waive_setup} );
+      $error = $change_to->insert();
+    }
+
+    if ( !$error && %new_discount ) {
+      $error = $change_to->change_discount(%new_discount);
+    }
+
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
       return $error;
@@ -2913,11 +2975,17 @@ sub change_later {
   } );
   $error = $new->insert('change' => 1, 
                         'allow_pkgpart' => ($new_pkgpart ? 0 : 1));
+
+  if ( !$error && %new_discount ) {
+    $error = $new->change_discount(%new_discount);
+  }
+
   if ( !$error ) {
     $self->set('change_to_pkgnum', $new->pkgnum);
     $self->set('expire', $date);
     $error = $self->replace;
   }
+
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
   } else {
@@ -2927,6 +2995,66 @@ sub change_later {
   $error;
 }
 
+# Helper method reads $opt hashref from change() and change_later()
+# Returns a hash of %new_discount suitable for passing to change_discount()
+sub _parse_new_discounts {
+  my ($self, $opt) = @_;
+
+  croak "Bad parameter list" unless ref $opt;
+
+  my %old_discount =
+    map { $_->setuprecur => $_ }
+    qsearch('cust_pkg_discount', {
+      pkgnum   => $self->pkgnum,
+      disabled => '',
+    });
+
+  my %new_discount;
+  for my $type(qw|setup recur|) {
+
+    if (exists $opt->{"${type}_discountnum"}) {
+      $new_discount{$type} = {
+        discountnum => $opt->{"${type}_discountnum"},
+        amount      => $opt->{"${type}_discountnum_amount"},
+        percent     => $opt->{"${type}_discountnum_percent"},
+      };
+    }
+
+    # Specified discountnum same as old discountnum, carry over addl fields
+    if (
+      exists $opt->{"${type}_discountnum"}
+      && exists $old_discount{$type}
+      && $opt->{"${type}_discountnum"} eq $old_discount{$type}->discountnum
+    ){
+      $new_discount{$type}->{months}   = $old_discount{$type}->months;
+      $new_discount{$type}->{end_date} = $old_discount{$type}->end_date;
+    }
+
+    # No new discount specified, carryover old discount
+    #   If we wanted to abandon legacy behavior, and always carry old discounts
+    #   uncomment this:
+
+    # if (!exists $new_discount{$type} && $old_discount{$type}) {
+    #   $new_discount{$type} = {
+    #     discountnum => $old_discount{$type}->discountnum,
+    #     amount      => $old_discount{$type}->amount,
+    #     percent     => $old_discount{$type}->percent,
+    #     months      => $old_discount{$type}->months,
+    #     end_date    => $old_discount{$type}->end_date,
+    #   };
+    # }
+  }
+
+  if ($DEBUG) {
+    warn "_parse_new_discounts(), pkgnum: ".$self->pkgnum." \n";
+    warn "Determine \%old_discount, \%new_discount: \n";
+    warn Dumper(\%old_discount);
+    warn Dumper(\%new_discount);
+  }
+
+  %new_discount;
+}
+
 =item abort_change
 
 Cancels a future package change scheduled by C<change_later>.
@@ -4738,6 +4866,149 @@ sub insert_discount {
   '';
 }
 
+=item change_discount %opt
+
+Method checks if the given values represent a change in either setup or
+discount level.  If so, the existing discounts are revoked, the new
+discounts are recorded.
+
+Usage:
+
+$error = change_discount(
+  setup => {
+
+    # -1: Indicates a "custom discount"
+    #  0: Indicates to remove any discount
+    # >0: discountnum to apply
+    discountnum => [-1, 0, discountnum],
+
+    # When discountnum is "-1" to indicate custom discount, include
+    # the additional fields:
+    amount      => AMOUNT_DISCOUNT
+    percent     => PERCENTAGE_DISCOUNT
+    months      => -1,
+  },
+
+  recur => {...}
+);
+
+
+=cut
+
+sub change_discount {
+  my ($self, %opt) = @_;
+  return "change_discount() called with bad \%opt"
+    unless %opt;
+
+  for (keys %opt) {
+    return "change_discount() called with unknown bad key $_"
+      unless $_ eq 'setup' || $_ eq 'recur';
+  }
+
+  my @old_discount =
+    qsearch('cust_pkg_discount',{
+      pkgnum   => $self->pkgnum,
+      disabled => '',
+    });
+
+  if ($DEBUG) {
+    warn "change_discount() pkgnum: ".$self->pkgnum." \n";
+    warn "change_discount() \%opt: \n";
+    warn Dumper(\%opt);
+  }
+
+  my @to_be_disabled;
+
+  for my $type (qw|setup recur|) {
+    next unless ref $opt{$type};
+    my %change = %{$opt{$type}};
+
+    return "change_discount() called with bad \$opt($type)"
+      unless $change{discountnum} =~ /^-?\d+$/;
+
+    if ($change{discountnum} eq 0) {
+      # Removing old discount
+
+      delete $opt{$type};
+      push @to_be_disabled, grep {$_->setuprecur eq $type} @old_discount;
+    } else {
+
+      if (
+        grep {
+          $_->discountnum   eq $change{discountnum}
+          && $_->setuprecur eq $type
+        } @old_discount
+      ){
+        # Duplicate, disregard this entry
+        delete $opt{$type};
+        next;
+      } else {
+        # Mark any discounts we're replacing
+        push @to_be_disabled, grep{ $_->setuprecur eq $type} @old_discount;
+      }
+
+    }
+  }
+
+
+  # If we still have changes queued, pass them to insert_discount()
+  # by setting values into object fields
+  for my $type (keys %opt) {
+    $self->set("${type}_discountnum", $opt{$type}->{discountnum});
+
+    if ($opt{$type}->{discountnum} eq '-1') {
+      $self->set("${type}_discountnum_${_}", $opt{$type}->{$_})
+        for qw(amount percent months);
+    }
+
+  }
+
+  if ($DEBUG) {
+    warn "change_discount() \% opt before insert \n";
+    warn Dumper \%opt;
+    warn "\@to_be_disabled \n";
+    warn Dumper \@to_be_disabled;
+  }
+
+  # Roll these updates into a transaction
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $error;
+
+  # The "waive setup fee" flag has traditionally been handled by setting
+  # $cust_pkg->waive_setup_fee = Y.  This has been appropriately, and separately
+  # handled, and it operates on a differetnt table than cust_pkg_discount,
+  # so the "-2 for waive setup fee" option is not being reimplemented
+  # here.  Perhaps this may change later.
+  #
+  # When a setup discount is entered, we still need unset waive_setup
+  if ( $opt{setup} && $opt{setup} > -2 && $self->waive_setup ) {
+    $self->set(waive_setup => '');
+    $error = $self->replace();
+  }
+
+  # Create new discounts
+  $error ||= $self->insert_discount();
+
+  # Disabling old discounts
+  for my $tbd (@to_be_disabled) {
+    unless ($error) {
+      $tbd->set(disabled => 'Y');
+      $error = $tbd->replace();
+    }
+  }
+
+  if ($error) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit if $oldAutoCommit;
+  return undef;
+}
+
 =item set_usage USAGE_VALUE_HASHREF 
 
 USAGE_VALUE_HASHREF is a hashref of svc_acct usage columns and the amounts
@@ -5707,4 +5978,3 @@ L<FS::pkg_svc>, schema.html from the base documentation
 =cut
 
 1;
-
diff --git a/httemplate/edit/process/change-cust_pkg.html b/httemplate/edit/process/change-cust_pkg.html
index 7fcc1da07..02b01f8de 100644
--- a/httemplate/edit/process/change-cust_pkg.html
+++ b/httemplate/edit/process/change-cust_pkg.html
@@ -40,19 +40,54 @@ if ( $cgi->param('locationnum') == -1 ) {
   $change{'cust_location'} = $cust_location;
 }
 
+my $error;
+
+# Discounts:
+# setup_discountnum and change_discountnum may contain one of the following:
+# - "-1" Represents the 'other' option.  Results in a new entry to the
+#        discount table.
+# - "-2" Represents the "waive setup fee" option. Sets cust_pkg.waive_setup = Y
+# - int  Represents the id for a discount row: discount.discountnum
+# my %discount;
+# $change{waive_setup} = '';
+# for my $type (qw|setup recur|) {
+#   my $dnum = $cgi->param("${type}_discountnum");
+
+#   if ($dnum eq '-2' && $type eq 'setup') {
+#     $change{waive_setup} = 'Y';
+#   } elsif ($val =~ /^-?\d+$/) {
+#     $discount{$type} = {discountnum => $dnum};
+#     if ($dnum eq '-1') {
+#       $discount{$type}->{amount}  = $cgi->param("${type}_discountnum_amount");
+#       $discount{$type}->{percent} = $cgi->param("${type}_discountnum_percent");
+#     }
+#   } else {
+#     # Shouldn't happen without funny business
+#     $error = "Bad value ${type}_discountnum ($val)";
+#   }
+# }
+
+
 $change{waive_setup} = '';
+for my $type (qw|setup_discountnum recur_discountnum|) {
+  my $dnum = $cgi->param($type);
 
-if ( $cgi->param('setup_discountnum') =~ /^(-?\d+)$/ ) { 
-  if ( $1 == -2 ) {
+  if ($dnum eq '-2' && $type eq 'setup_discountnum') {
+    # Waive Discount
     $change{waive_setup} = 'Y';
+  } elsif ($dnum =~ /^-?\d+$/) {
+    # Set discountnum
+    $change{$type} = $dnum;
+    $change{"${type}_amount"}  = $cgi->param("${type}_amount");
+    $change{"${type}_percent"} = $cgi->param("${type}_percent");
+  } elsif ($dnum eq '') {
+    # Set discount as no discount
+    $change{"${type}"} = 0;
   } else {
-    $change{setup_discountnum} = $1;
-    $change{setup_discountnum_amount} = $cgi->param('setup_discountnum_amount');
-    $change{setup_discountnum_percent} = $cgi->param('setup_discountnum_percent');
+    $error = "Bad value ${type}_discountnum ($dnum)";
   }
 }
 
-my $error;
 my $now = time;
 if (defined($cgi->param('contract_end'))) {
   $change{'contract_end'} = parse_datetime($cgi->param('contract_end'));
diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi
index 121df40cb..2470ee135 100755
--- a/httemplate/misc/change_pkg.cgi
+++ b/httemplate/misc/change_pkg.cgi
@@ -89,8 +89,14 @@
 %
 % if ( $discount_cust_pkg || $waive_setup_fee ) {
   <FONT CLASS="fsinnerbox-title"><% mt('Discounting') |h %></FONT>
-  <% ntable("#cccccc") %>
-    <& /elements/tr-select-pkg-discount.html, disable_recur => 1, &>
+  <TABLE CLASS="fsinnerbox">
+    <& /elements/tr-select-pkg-discount.html,
+      curr_value_setup    => $discount{setup},
+      curr_value_recur    => $discount{recur},
+      disable_setup       => 0,
+      disable_recur       => 0,
+      disable_waive_setup => 0
+    &>
   </TABLE><BR>
 
 % }
@@ -168,4 +174,14 @@ if ( $cust_pkg->change_to_pkgnum ) {
   }
   $title = "Edit Scheduled Package Change";
 }
+
+# Get current values of discounts for selectboxes
+my %discount = (setup => undef, recur => undef);
+$discount{$_->setuprecur} = $_->discountnum
+  for qsearch('cust_pkg_discount', {
+    pkgnum   => $cust_pkg->pkgnum,
+    disabled => '',
+  });
+$discount{setup} = '-2' if $cust_pkg->waive_setup;
+
 </%init>

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

Summary of changes:
 FS/FS/cust_pkg.pm                               | 283 +++++++++++++++++++++++-
 httemplate/edit/process/change-cust_pkg.html    |  48 +++-
 httemplate/elements/select-table.html           |  19 +-
 httemplate/elements/tr-select-pkg-discount.html |  24 +-
 httemplate/misc/change_pkg.cgi                  |  22 +-
 5 files changed, 376 insertions(+), 20 deletions(-)




More information about the freeside-commits mailing list