separate setup/recur quotation discounts, #14092
authorMark Wells <mark@freeside.biz>
Tue, 27 Oct 2015 23:20:31 +0000 (16:20 -0700)
committerMark Wells <mark@freeside.biz>
Tue, 27 Oct 2015 23:37:47 +0000 (16:37 -0700)
FS/FS/Schema.pm
FS/FS/quotation.pm
FS/FS/quotation_pkg.pm
FS/FS/quotation_pkg_discount.pm

index 7dc54f7..447302b 100644 (file)
@@ -1985,8 +1985,8 @@ sub tables_hashref {
         'quotationpkgdiscountnum', 'serial', '', '', '', '',
         'quotationpkgnum',            'int', '', '', '', '', 
         'discountnum',                'int', '', '', '', '',
-        'setup_amount',        @money_typen,         '', '',
-        'recur_amount',        @money_typen,         '', '',
+        'setuprecur',             'varchar', 'NULL', $char_d, '', '',
+        'amount',              @money_typen, '', '',
         #'end_date',              @date_type,         '', '',
       ],
       'primary_key'  => 'quotationpkgdiscountnum',
index d66b1b8..c400493 100644 (file)
@@ -260,6 +260,7 @@ sub _items_sections {
   my %opt = @_;
   my $escape = $opt{escape}; # the only one we care about
 
+  my %show; # package frequency => 1 if there's anything to display
   my %subtotals = (); # package frequency => subtotal
   my $disable_total = 0;
   foreach my $pkg ($self->quotation_pkg) {
@@ -267,6 +268,8 @@ sub _items_sections {
     my $part_pkg = $pkg->part_pkg;
 
     my $recur_freq = $part_pkg->freq;
+    $show{$recur_freq} = 1 if $pkg->unitrecur > 0;
+    $show{0} = 1 if $pkg->unitsetup > 0;
     ($subtotals{0} ||= 0) += $pkg->setup + $pkg->setup_tax;
     ($subtotals{$recur_freq} ||= 0) += $pkg->recur + $pkg->recur_tax;
 
@@ -288,7 +291,8 @@ sub _items_sections {
   my $no_recurring = 0;
   foreach my $freq (keys %subtotals) {
 
-    next if $subtotals{$freq} == 0;
+    #next if $subtotals{$freq} == 0;
+    next if !$show{$freq};
 
     my $weight = 
       List::MoreUtils::first_index { $_ eq $freq } @pkg_freq_order;
@@ -405,10 +409,10 @@ sub order {
       $cust_pkg->set( $_, $quotation_pkg->get($_) );
     }
 
-    # currently only one discount each
-    my ($pkg_discount) = $quotation_pkg->quotation_pkg_discount;
-    if ( $pkg_discount ) {
-      $cust_pkg->set('discountnum', $pkg_discount->discountnum);
+    # can now have two discounts each (setup and recur)
+    foreach my $pkg_discount ($quotation_pkg->quotation_pkg_discount) {
+      my $field = $pkg_discount->setuprecur . '_discountnum';
+      $cust_pkg->set($field, $pkg_discount->discountnum);
     }
 
     $all_cust_pkg{$cust_pkg} = []; # no services
@@ -685,7 +689,7 @@ sub estimate {
   }
 
   my %quotation_pkg_tax; # quotationpkgnum => tax name => quotation_pkg_tax obj
-  my %quotation_pkg_discount; # quotationpkgnum => quotation_pkg_discount obj
+  my %quotation_pkg_discount; # quotationpkgnum => setuprecur => quotation_pkg_discount obj
 
   for (my $i = 0; $i < scalar(@return_bill); $i++) {
     my $this_bill = $return_bill[$i]->[0];
@@ -725,25 +729,25 @@ sub estimate {
 
       # discounts
       if ( $cust_bill_pkg->get('discounts') ) {
+        # discount records are generated as (setup, recur).
+        # well, not always, sometimes it's just (recur), but fixing this
+        # is horribly invasive.
         my $discount = $cust_bill_pkg->get('discounts')->[0];
+
         if ( $discount ) {
-          # discount records are generated as (setup, recur).
-          # well, not always, sometimes it's just (recur), but fixing this
-          # is horribly invasive.
-          my $qpd = $quotation_pkg_discount{$quotationpkgnum}
+          # find the quotation_pkg_discount record for this billing pass...
+          my $setuprecur = $i ? 'recur' : 'setup';
+          my $qpd = $quotation_pkg_discount{$quotationpkgnum}{$setuprecur}
                 ||= qsearchs('quotation_pkg_discount', {
-                    'quotationpkgnum' => $quotationpkgnum
+                    'quotationpkgnum' => $quotationpkgnum,
+                    'setuprecur'      => $setuprecur,
                     });
 
           if (!$qpd) { #can't happen
-            warn "$me simulated bill returned a discount but no discount is in effect.\n";
+            warn "$me simulated bill returned a $setuprecur discount but no discount is in effect.\n";
           }
-          if ($discount and $qpd) {
-            if ( $i == 0 ) {
-              $qpd->set('setup_amount', $discount->amount);
-            } else {
-              $qpd->set('recur_amount', $discount->amount);
-            }
+          if ($qpd) {
+            $qpd->set('amount', $discount->amount);
           }
         }
       } # end of discount stuff
@@ -812,10 +816,13 @@ sub estimate {
     return "$error (recording estimate for ".$quotation_pkg->part_pkg->pkg.")"
       if $error;
   }
-  foreach my $quotation_pkg_discount (values %quotation_pkg_discount) {
-    $error = $quotation_pkg_discount->replace;
-    return "$error (recording estimated discount)"
-      if $error;
+  foreach (values %quotation_pkg_discount) {
+    # { setup => one, recur => another }
+    foreach my $quotation_pkg_discount (values %$_) {
+      $error = $quotation_pkg_discount->replace;
+      return "$error (recording estimated discount)"
+        if $error;
+    }
   }
   foreach my $quotation_pkg_tax (map { values %$_ } values %quotation_pkg_tax) {
     $error = $quotation_pkg_tax->insert;
index 10bdc2e..49d0d9a 100644 (file)
@@ -132,8 +132,8 @@ sub insert {
 
   my $error = $self->SUPER::insert;
 
-  if ( !$error and $self->discountnum ) {
-    warn "inserting discount #".$self->discountnum."\n";
+  if ( !$error and ($self->setup_discountnum || $self->recur_discountnum) ) {
+      #warn "inserting discount\n";
     $error = $self->insert_discount;
     $error .= ' (setting discount)' if $error;
   }
@@ -262,28 +262,37 @@ sub insert_discount {
   #my ($self, %options) = @_;
   my $self = shift;
 
-  my $quotation_pkg_discount = FS::quotation_pkg_discount->new( {
-    'quotationpkgnum' => $self->quotationpkgnum,
-    'discountnum'     => $self->discountnum,
-    #for the create a new discount case
-    '_type'           => $self->discountnum__type,
-    'amount'      => $self->discountnum_amount,
-    'percent'     => $self->discountnum_percent,
-    'months'      => $self->discountnum_months,
-    'setup'       => $self->discountnum_setup,
-  } );
-
-  $quotation_pkg_discount->insert;
+  foreach my $x (qw(setup recur)) {
+    if ( my $discountnum = $self->get("${x}_discountnum") ) {
+      my $cust_pkg_discount = FS::quotation_pkg_discount->new( { 
+        'quotationpkgnum' => $self->quotationpkgnum,
+        'discountnum' => $discountnum,
+        'setuprecur'  => $x,
+        #for the create a new discount case
+        'amount'      => $self->get("${x}_discountnum_amount"),
+        'percent'     => $self->get("${x}_discountnum_percent"),
+        'months'      => $self->get("${x}_discountnum_months"),
+      } );
+      if ( $x eq 'setup' ) {
+        $cust_pkg_discount->setup('Y');
+        $cust_pkg_discount->months('');
+      } 
+      my $error = $cust_pkg_discount->insert;
+      return $error if $error;
+    } 
+  } 
 }
 
 sub _item_discount {
   my $self = shift;
   my %options = @_;
   my $setuprecur = $options{'setuprecur'};
+  # a little different from cust_bill_pkg::_item_discount, in that this one
+  # is asked specifically whether to show setup or recur discounts (because
+  # on the quotation they're separate sections entirely)
 
-  # kind of silly treating this as multiple records, but it works, and will
-  # work if we allow multiple discounts at some point
-  my @pkg_discounts = $self->pkg_discount;
+  my @pkg_discounts = grep { $_->setuprecur eq $setuprecur }
+                        $self->pkg_discount;
   return if @pkg_discounts == 0;
   
   my @ext;
@@ -296,7 +305,7 @@ sub _item_discount {
   };
   foreach my $pkg_discount (@pkg_discounts) {
     push @ext, $pkg_discount->description;
-    my $amount = $pkg_discount->get($setuprecur.'_amount');
+    my $amount = $pkg_discount->get('amount');
     $d->{amount} -= $amount;
   }
   $d->{amount} = sprintf('%.2f', $d->{amount} * $self->quantity);
@@ -306,8 +315,12 @@ sub _item_discount {
 
 sub setup {
   my $self = shift;
-  ($self->unitsetup - sum(0, map { $_->setup_amount } $self->pkg_discount))
-    * ($self->quantity || 1);
+  return '0.00' if $self->waive_setup eq 'Y';;
+  my $discount_amount = sum(0, map { $_->amount }
+                               grep { $_->setuprecur eq 'setup' }
+                               $self->pkg_discount
+                           );
+  ($self->unitsetup - $discount_amount) * ($self->quantity || 1);
 
 }
 
@@ -318,8 +331,12 @@ sub setup_tax {
 
 sub recur {
   my $self = shift;
-  ($self->unitrecur - sum(0, map { $_->recur_amount } $self->pkg_discount))
-    * ($self->quantity || 1)
+  my $discount_amount = sum(0, map { $_->amount }
+                               grep { $_->setuprecur eq 'recur' }
+                               $self->pkg_discount
+                           );
+  ($self->unitrecur - $discount_amount) * ($self->quantity || 1);
+
 }
 
 sub recur_tax {
index 4389db2..1815294 100644 (file)
@@ -45,14 +45,14 @@ for.
 
 discountnum (L<FS::discount>)
 
-=item setup_amount
+=item setuprecur
 
-Amount that will be discounted from setup fees, per package quantity.
+Whether this is a setup or recur discount.
 
-=item recur_amount
+=item amount
 
-Amount that will be discounted from recurring fees in the first billing
-cycle, per package quantity.
+Amount that will be discounted from either setup or recur fees, per package 
+quantity.
 
 =back
 
@@ -106,8 +106,8 @@ sub check {
     $self->ut_numbern('quotationpkgdiscountnum')
     || $self->ut_foreign_key('quotationpkgnum', 'quotation_pkg', 'quotationpkgnum' )
     || $self->ut_foreign_key('discountnum', 'discount', 'discountnum' )
-    || $self->ut_moneyn('setup_amount')
-    || $self->ut_moneyn('recur_amount')
+    || $self->ut_enum('setuprecur', ['setup', 'recur'])
+    || $self->ut_moneyn('amount')
   ;
   return $error if $error;