Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / FS / FS / quotation.pm
index 45f3522..c400493 100644 (file)
@@ -260,18 +260,39 @@ sub _items_sections {
   my %opt = @_;
   my $escape = $opt{escape}; # the only one we care about
 
-  my %subtotals; # package frequency => subtotal
+  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) {
-    my $recur_freq = $pkg->part_pkg->freq;
+
+    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;
+
+    #this is a shitty hack based on what's in part_pkg/ at the moment
+    # but its good enough for the 99% common case of preventing totals from
+    # displaying for prorate packages
+    $disable_total = 1
+      if $part_pkg->plan =~ /^(prorate|torrus|agent$)/
+      || $part_pkg->option('recur_method') eq 'prorate'
+      || ( $part_pkg->option('sync_bill_date')
+             && $self->custnum
+             && $self->cust_main->billing_pkgs #num_billing_pkgs when we have it
+         );
+
   }
   my @pkg_freq_order = keys %{ FS::Misc->pkg_freqs };
 
   my @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;
@@ -279,6 +300,7 @@ sub _items_sections {
     if ( $freq eq '0' ) {
       if ( scalar(keys(%subtotals)) == 1 ) {
         # there are no recurring packages
+        $no_recurring = 1;
         $desc = $self->mt('Charges');
       } else {
         $desc = $self->mt('Setup Charges');
@@ -295,6 +317,18 @@ sub _items_sections {
       'subtotal'    => sprintf('%.2f',$subtotals{$freq}),
     };
   }
+
+  unless ( $disable_total || $no_recurring ) {
+    my $total = 0;
+    $total += $_ for values %subtotals;
+    push @sections, {
+      'description' => 'First payment',
+      'sort_weight' => 0,
+      'category'   => 'Total category', #required but what's it used for?
+      'subtotal'    => sprintf('%.2f',$total)
+    };
+  }
+
   return \@sections, [];
 }
 
@@ -375,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
@@ -571,6 +605,7 @@ sub estimate {
 
   ###### BEGIN TRANSACTION ######
   local $@;
+  local $SIG{__DIE__};
   eval {
     my $temp_dbh = myconnect();
     local $FS::UID::dbh = $temp_dbh;
@@ -654,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];
@@ -694,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
@@ -781,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;
@@ -941,11 +979,12 @@ sub _items_pkg {
 
   foreach my $quotation_pkg (@pkgs) {
     my $part_pkg = $quotation_pkg->part_pkg;
+    my @details = $quotation_pkg->details;
     my $setuprecur;
     my $this_item = {
       'pkgnum'          => $quotation_pkg->quotationpkgnum,
       'description'     => $quotation_pkg->desc($locale),
-      'ext_description' => [],
+      'ext_description' => \@details,
       'quantity'        => $quotation_pkg->quantity,
     };
     if ($freq eq '0') {