Merge branch 'patch-1' of https://github.com/gjones2/Freeside
[freeside.git] / FS / FS / cust_bill_pkg.pm
index b8ae81d..a83af13 100644 (file)
@@ -581,9 +581,10 @@ appropriate FS::cust_bill_pkg_display objects.
 
 Options are passed as a list of name/value pairs.  Options are:
 
-part_pkg: FS::part_pkg object from th
+part_pkg: FS::part_pkg object from this line item's package.
 
-real_pkgpart: if this line item comes from a bundled package, the pkgpart of the owning package.  Otherwise the same as the part_pkg's pkgpart above.
+real_pkgpart: if this line item comes from a bundled package, the pkgpart 
+of the owning package.  Otherwise the same as the part_pkg's pkgpart above.
 
 =cut
 
@@ -594,13 +595,19 @@ sub set_display {
 
   my $conf = new FS::Conf;
 
+  # whether to break this down into setup/recur/usage
   my $separate = $conf->exists('separate_usage');
+
   my $usage_mandate =            $part_pkg->option('usage_mandate', 'Hush!')
                     || $cust_pkg->part_pkg->option('usage_mandate', 'Hush!');
 
   # or use the category from $opt{'part_pkg'} if its not bundled?
   my $categoryname = $cust_pkg->part_pkg->categoryname;
 
+  # if we don't have to separate setup/recur/usage, or put this in a 
+  # package-specific section, or display a usage summary, then don't 
+  # even create one of these.  The item will just display in the unnamed
+  # section as a single line plus details.
   return $self->set('display', [])
     unless $separate || $categoryname || $usage_mandate;
   
@@ -608,34 +615,46 @@ sub set_display {
 
   my %hash = ( 'section' => $categoryname );
 
+  # whether to put usage details in a separate section, and if so, which one
   my $usage_section =            $part_pkg->option('usage_section', 'Hush!')
                     || $cust_pkg->part_pkg->option('usage_section', 'Hush!');
 
+  # whether to show a usage summary line (total usage charges, no details)
   my $summary =            $part_pkg->option('summarize_usage', 'Hush!')
               || $cust_pkg->part_pkg->option('summarize_usage', 'Hush!');
 
   if ( $separate ) {
+    # create lines for setup and (non-usage) recur, in the main section
     push @display, new FS::cust_bill_pkg_display { type => 'S', %hash };
     push @display, new FS::cust_bill_pkg_display { type => 'R', %hash };
   } else {
+    # display everything in a single line
     push @display, new FS::cust_bill_pkg_display
                      { type => '',
                        %hash,
+                       # and if usage_mandate is enabled, hide details
+                       # (this only works on multisection invoices...)
                        ( ( $usage_mandate ) ? ( 'summary' => 'Y' ) : () ),
                      };
   }
 
   if ($separate && $usage_section && $summary) {
+    # create a line for the usage summary in the main section
     push @display, new FS::cust_bill_pkg_display { type    => 'U',
                                                    summary => 'Y',
                                                    %hash,
                                                  };
   }
+
   if ($usage_mandate || ($usage_section && $summary) ) {
     $hash{post_total} = 'Y';
   }
 
   if ($separate || $usage_mandate) {
+    # show call details for this line item in the usage section.
+    # if usage_mandate is on, this will display below the section subtotal.
+    # this also happens if usage is in a separate section and there's a 
+    # summary in the main section, though I'm not sure why.
     $hash{section} = $usage_section if $usage_section;
     push @display, new FS::cust_bill_pkg_display { type => 'U', %hash };
   }
@@ -646,8 +665,9 @@ sub set_display {
 
 =item disintegrate
 
-Returns a list of cust_bill_pkg objects each with no more than a single class
-(including setup or recur) of charge.
+Returns a hash: keys are "setup", "recur" or usage classnum, values are
+FS::cust_bill_pkg objects, each with no more than a single class (setup or
+recur) of charge.
 
 =cut
 
@@ -824,6 +844,18 @@ sub _X_show_zero {
   $self->cust_pkg->_X_show_zero($what);
 }
 
+=item credited [ BEFORE, AFTER, OPTIONS ]
+
+Returns the sum of credits applied to this item.  Arguments are the same as
+owed_sql/paid_sql/credited_sql.
+
+=cut
+
+sub credited {
+  my $self = shift;
+  $self->scalar_sql('SELECT '. $self->credited_sql(@_).' FROM cust_bill_pkg WHERE billpkgnum = ?', $self->billpkgnum);
+}
+
 =back
 
 =head1 CLASS METHODS
@@ -894,7 +926,7 @@ sub paid_sql {
   my $paid = "( SELECT COALESCE(SUM(cust_bill_pay_pkg.amount),0)
      FROM cust_bill_pay_pkg JOIN cust_bill_pay USING (billpaynum)
      WHERE cust_bill_pay_pkg.billpkgnum = cust_bill_pkg.billpkgnum
-           $s $e$setuprecur )";
+           $s $e $setuprecur )";
 
   if ( $opt{no_usage} ) {
     # cap the amount paid at the sum of non-usage charges, 
@@ -940,15 +972,14 @@ sub upgrade_tax_location {
   # they were calculated on a package-location basis.  Create them here, 
   # along with any necessary cust_location records and any tax exemption 
   # records.
-  #
-  # This probably shouldn't run from freeside-upgrade.
 
   my ($class, %opt) = @_;
   # %opt may include 's' and 'e': start and end date ranges
   # and 'X': abort on any error, instead of just rolling back changes to 
   # that invoice
   my $dbh = dbh;
-  $FS::UID::AutoCommit = 0;
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
 
   eval {
     use FS::h_cust_main;
@@ -1108,7 +1139,8 @@ sub upgrade_tax_location {
         push @{ $nontax_items{$taxclass} }, $item;
       }
     }
-    printf("%d tax items: \$%.2f\n", scalar(@tax_items), map {$_->setup} @tax_items);
+    printf("%d tax items: \$%.2f\n", scalar(@tax_items), map {$_->setup} @tax_items)
+      if @tax_items;
 
     # Use a variation on the procedure in 
     # FS::cust_main::Billing::_handle_taxes to identify taxes that apply 
@@ -1378,21 +1410,41 @@ sub upgrade_tax_location {
       } #foreach (@tax_links)
     } #foreach $tax_item
 
-    $dbh->commit if $commit_each_invoice;
+    $dbh->commit if $commit_each_invoice and $oldAutoCommit;
     $committed = 1;
 
   } #foreach $invnum
   continue {
     if (!$committed) {
-      $dbh->rollback;
+      $dbh->rollback if $oldAutoCommit;
       die "Upgrade halted.\n" unless $commit_each_invoice;
     }
   }
 
-  $dbh->commit unless $commit_each_invoice;
+  $dbh->commit if $oldAutoCommit and !$commit_each_invoice;
   '';
 }
 
+sub _upgrade_data {
+  # Create a queue job to run upgrade_tax_location from January 1, 2012 to 
+  # the present date.
+  eval {
+    use FS::queue;
+    use Date::Parse 'str2time';
+  };
+  my $class = shift;
+  my $upgrade = 'tax_location_2012';
+  return if FS::upgrade_journal->is_done($upgrade);
+  my $job = FS::queue->new({
+      'job' => 'FS::cust_bill_pkg::upgrade_tax_location'
+  });
+  # call it kind of like a class method, not that it matters much
+  $job->insert($class, 's' => str2time('2012-01-01'));
+  # Then mark the upgrade as done, so that we don't queue the job twice
+  # and somehow run two of them concurrently.
+  FS::upgrade_journal->set_done($upgrade);
+}
+
 =back
 
 =head1 BUGS