in invoice rendering, treat administrative fees more like package charges, #28883
authorMark Wells <mark@freeside.biz>
Mon, 28 Apr 2014 20:54:33 +0000 (13:54 -0700)
committerMark Wells <mark@freeside.biz>
Mon, 28 Apr 2014 20:54:33 +0000 (13:54 -0700)
FS/FS/Template_Mixin.pm
FS/FS/part_fee.pm

index 426386b..2781748 100644 (file)
@@ -1022,7 +1022,8 @@ sub print_generic {
     warn "$me   searching for line items\n"
       if $DEBUG > 1;
 
-    foreach my $line_item ( $self->_items_pkg(%options) ) {
+    foreach my $line_item ( $self->_items_pkg(%options),
+                            $self->_items_fee(%options) ) {
 
       warn "$me     adding line item $line_item\n"
         if $DEBUG > 1;
@@ -1865,10 +1866,13 @@ sub _items_sections {
 
         my $section = $display->section;
         my $type    = $display->type;
-        $section = undef unless $opt{by_category};
+        # Set $section = undef if we're sectioning by location and this
+        # line item _has_ a location (i.e. isn't a fee).
+        $section = undef if $locationnum;
 
+        # set this flag if the section is not tax-only
         $not_tax{$locationnum}{$section} = 1
-          unless $cust_bill_pkg->pkgnum == 0;
+          if $cust_bill_pkg->pkgnum  or $cust_bill_pkg->feepart;
 
         # there's actually a very important piece of logic buried in here:
         # incrementing $late_subtotal{$section} CREATES 
@@ -1904,7 +1908,9 @@ sub _items_sections {
         } else { # it's a pre-total (normal) section
 
           # skip tax items unless they're explicitly included in a section
-          next if $cust_bill_pkg->pkgnum == 0 && ! $section;
+          next if $cust_bill_pkg->pkgnum == 0 and
+                  ! $cust_bill_pkg->feepart   and
+                  ! $section;
 
           if (! $type || $type eq 'S') {
             $subtotal{$locationnum}{$section} += $cust_bill_pkg->setup
@@ -2260,6 +2266,42 @@ sub _items_nontax {
   grep { $_->pkgnum } $self->cust_bill_pkg;
 }
 
+sub _items_fee {
+  my $self = shift;
+  my %options = @_;
+  my @cust_bill_pkg = grep { $_->feepart } $self->cust_bill_pkg;
+  my @items;
+  foreach my $cust_bill_pkg (@cust_bill_pkg) {
+    # cache this, so we don't look it up again in every section
+    my $part_fee = $cust_bill_pkg->get('part_fee')
+       || $cust_bill_pkg->part_fee;
+    $cust_bill_pkg->set('part_fee', $part_fee);
+    if (!$part_fee) {
+      #die "fee definition not found for line item #".$cust_bill_pkg->billpkgnum."\n"; # might make more sense
+      warn "fee definition not found for line item #".$cust_bill_pkg->billpkgnum."\n";
+      next;
+    }
+    if ( exists($options{section}) and exists($options{section}{category}) )
+    {
+      my $categoryname = $options{section}{category};
+      # then filter for items that have that section
+      if ( $part_fee->categoryname ne $categoryname ) {
+        warn "skipping fee '".$part_fee->itemdesc."'--not in section $categoryname\n" if $DEBUG;
+        next;
+      }
+    } # otherwise include them all in the main section
+    # XXX what to do when sectioning by location?
+    push @items,
+      { feepart     => $cust_bill_pkg->feepart,
+        amount      => sprintf('%.2f', $cust_bill_pkg->setup + $cust_bill_pkg->recur),
+        description => $part_fee->itemdesc_locale($self->cust_main->locale),
+        # sdate/edate?
+        # ext_description referencing the base_invnum?
+      };
+  }
+  @items;
+}
+
 sub _items_pkg {
   my $self = shift;
   my %options = @_;
@@ -2315,7 +2357,8 @@ sub _taxsort {
 
 sub _items_tax {
   my $self = shift;
-  my @cust_bill_pkg = sort _taxsort grep { ! $_->pkgnum } $self->cust_bill_pkg;
+  my @cust_bill_pkg = sort _taxsort grep { ! $_->pkgnum and ! $_->feepart } 
+    $self->cust_bill_pkg;
   my @items = $self->_items_cust_bill_pkg(\@cust_bill_pkg, @_);
 
   if ( $self->conf->exists('always_show_tax') ) {
@@ -2406,7 +2449,7 @@ sub _items_cust_bill_pkg {
     if ( $locationnum ) {
       # this is a location section; skip packages that aren't at this
       # service location.
-      next if $cust_bill_pkg->pkgnum == 0;
+      next if $cust_bill_pkg->pkgnum == 0; # skips fees...
       next if $self->cust_pkg_hash->{ $cust_bill_pkg->pkgnum }->locationnum 
               != $locationnum;
     }
index ccf1351..370005c 100644 (file)
@@ -4,6 +4,7 @@ use strict;
 use base qw( FS::o2m_Common FS::Record );
 use vars qw( $DEBUG );
 use FS::Record qw( qsearch qsearchs );
+use FS::cust_bill_pkg_display;
 
 $DEBUG = 0;
 
@@ -375,11 +376,19 @@ sub lineitem {
   # set the amount that we'll charge
   $cust_bill_pkg->set( $self->setuprecur, $amount );
 
+  # create display record
+  my $categoryname = '';
   if ( $self->classnum ) {
     my $pkg_category = $self->pkg_class->pkg_category;
-    $cust_bill_pkg->set('section' => $pkg_category->categoryname)
-      if $pkg_category;
+    $categoryname = $pkg_category->categoryname if $pkg_category;
   }
+  my $displaytype = ($self->setuprecur eq 'setup') ? 'S' : 'R';
+  my $display = FS::cust_bill_pkg_display->new({
+      type    => $displaytype,
+      section => $categoryname,
+      # post_total? summary? who the hell knows?
+  });
+  $cust_bill_pkg->set('display', [ $display ]);
 
   # if this is a percentage fee and has line item fractions,
   # adjust them to be proportional and to add up correctly.
@@ -484,6 +493,19 @@ sub tax_rates {
   return @taxes;
 }
 
+=item categoryname 
+
+Returns the package category name, or the empty string if there is no package
+category.
+
+=cut
+
+sub categoryname {
+  my $self = shift;
+  my $pkg_class = $self->pkg_class;
+  $pkg_class ? $pkg_class->categoryname : '';
+}
+
 sub part_pkg_taxoverride {} # we don't do overrides here
 
 sub has_taxproduct {